mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
5.1.68
This commit is contained in:
commit
7fb5f8abe2
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## [Unreleased (daily channel)](https://github.com/invoiceninja/invoiceninja/tree/v5-develop)
|
## [Unreleased (daily channel)](https://github.com/invoiceninja/invoiceninja/tree/v5-develop)
|
||||||
- Add Cache-control: no-cache to prevent overaggressive caching of assets
|
- Add Cache-control: no-cache to prevent overaggressive caching of assets
|
||||||
|
- Improved labelling in the settings (client portal)
|
||||||
|
- Client portal: Multiple accounts access improvements (#5703)
|
||||||
|
- Client portal: "Credits" updates (#5734)
|
||||||
|
- Client portal: Make sidebar white color, in order to make logo displaying more simple. (#5753)
|
||||||
|
|
||||||
## [v5.1.56-release](https://github.com/invoiceninja/invoiceninja/releases/tag/v5.1.56-release)
|
## [v5.1.56-release](https://github.com/invoiceninja/invoiceninja/releases/tag/v5.1.56-release)
|
||||||
## Fixed:
|
## Fixed:
|
||||||
|
@ -1 +1 @@
|
|||||||
5.1.62
|
5.1.68
|
||||||
|
@ -65,7 +65,7 @@ class CheckData extends Command
|
|||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $name = 'ninja:check-data';
|
protected $signature = 'ninja:check-data {--database=} {--fix=} {--client_id=}';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
|
@ -105,6 +105,9 @@ class CreateAccount extends Command
|
|||||||
'password' => Hash::make($password),
|
'password' => Hash::make($password),
|
||||||
'confirmation_code' => $this->createDbHash(config('database.default')),
|
'confirmation_code' => $this->createDbHash(config('database.default')),
|
||||||
'email_verified_at' => now(),
|
'email_verified_at' => now(),
|
||||||
|
'first_name' => 'New',
|
||||||
|
'last_name' => 'User',
|
||||||
|
'phone' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$company_token = new CompanyToken;
|
$company_token = new CompanyToken;
|
||||||
|
@ -34,6 +34,7 @@ use App\Models\Project;
|
|||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
|
use App\Models\TaxRate;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Vendor;
|
use App\Models\Vendor;
|
||||||
use App\Models\VendorContact;
|
use App\Models\VendorContact;
|
||||||
@ -105,8 +106,18 @@ class CreateSingleAccount extends Command
|
|||||||
'account_id' => $account->id,
|
'account_id' => $account->id,
|
||||||
'slack_webhook_url' => config('ninja.notification.slack'),
|
'slack_webhook_url' => config('ninja.notification.slack'),
|
||||||
'default_password_timeout' => 30*60000,
|
'default_password_timeout' => 30*60000,
|
||||||
|
'portal_mode' => 'domain',
|
||||||
|
'portal_domain' => 'http://ninja.test:8000',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$settings = $company->settings;
|
||||||
|
$settings->invoice_terms = 'Default company invoice terms';
|
||||||
|
$settings->quote_terms = 'Default company quote terms';
|
||||||
|
$settings->invoice_footer = 'Default invoice footer';
|
||||||
|
|
||||||
|
$company->settings = $settings;
|
||||||
|
$company->save();
|
||||||
|
|
||||||
$account->default_company_id = $company->id;
|
$account->default_company_id = $company->id;
|
||||||
$account->save();
|
$account->save();
|
||||||
|
|
||||||
@ -144,6 +155,29 @@ class CreateSingleAccount extends Command
|
|||||||
'company_id' => $company->id,
|
'company_id' => $company->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
TaxRate::factory()->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'company_id' => $company->id,
|
||||||
|
'name' => 'GST',
|
||||||
|
'rate' => 10
|
||||||
|
]);
|
||||||
|
|
||||||
|
TaxRate::factory()->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'company_id' => $company->id,
|
||||||
|
'name' => 'VAT',
|
||||||
|
'rate' => 17.5
|
||||||
|
]);
|
||||||
|
|
||||||
|
TaxRate::factory()->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'company_id' => $company->id,
|
||||||
|
'name' => 'CA Sales Tax',
|
||||||
|
'rate' => 5
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
$this->info('Creating '.$this->count.' clients');
|
$this->info('Creating '.$this->count.' clients');
|
||||||
|
|
||||||
for ($x = 0; $x < $this->count; $x++) {
|
for ($x = 0; $x < $this->count; $x++) {
|
||||||
|
@ -128,7 +128,7 @@ class DemoMode extends Command
|
|||||||
{
|
{
|
||||||
$faker = \Faker\Factory::create();
|
$faker = \Faker\Factory::create();
|
||||||
|
|
||||||
$this->count = 50;
|
$this->count = 25;
|
||||||
|
|
||||||
$this->info('Creating Small Account and Company');
|
$this->info('Creating Small Account and Company');
|
||||||
|
|
||||||
@ -486,7 +486,7 @@ class DemoMode extends Command
|
|||||||
if (rand(0, 1)) {
|
if (rand(0, 1)) {
|
||||||
$invoice->assigned_user_id = $assigned_user_id;
|
$invoice->assigned_user_id = $assigned_user_id;
|
||||||
}
|
}
|
||||||
|
$invoice->number = $this->getNextRecurringInvoiceNumber($client);
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,12 +12,12 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Jobs\Ninja\SendReminders;
|
use App\Jobs\Ninja\SendReminders;
|
||||||
use App\Jobs\Util\WebHookHandler;
|
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use App\Models\Webhook;
|
use App\Models\Webhook;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use App\Jobs\Util\WebhookHandler;
|
||||||
|
|
||||||
class SendRemindersCron extends Command
|
class SendRemindersCron extends Command
|
||||||
{
|
{
|
||||||
@ -54,8 +54,8 @@ class SendRemindersCron extends Command
|
|||||||
{
|
{
|
||||||
SendReminders::dispatchNow();
|
SendReminders::dispatchNow();
|
||||||
|
|
||||||
$this->webHookOverdueInvoices();
|
$this->webHookOverdueInvoices();
|
||||||
$this->webHookExpiredQuotes();
|
$this->webHookExpiredQuotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function webHookOverdueInvoices()
|
private function webHookOverdueInvoices()
|
||||||
@ -90,6 +90,7 @@ class SendRemindersCron extends Command
|
|||||||
|
|
||||||
$invoices->each(function ($invoice) {
|
$invoices->each(function ($invoice) {
|
||||||
WebHookHandler::dispatch(Webhook::EVENT_LATE_INVOICE, $invoice, $invoice->company);
|
WebHookHandler::dispatch(Webhook::EVENT_LATE_INVOICE, $invoice, $invoice->company);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$quotes = Quote::where('is_deleted', 0)
|
$quotes = Quote::where('is_deleted', 0)
|
||||||
|
@ -11,8 +11,9 @@
|
|||||||
|
|
||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
use App\Jobs\Cron\SubscriptionCron;
|
use App\Jobs\Cron\AutoBillCron;
|
||||||
use App\Jobs\Cron\RecurringInvoicesCron;
|
use App\Jobs\Cron\RecurringInvoicesCron;
|
||||||
|
use App\Jobs\Cron\SubscriptionCron;
|
||||||
use App\Jobs\Ninja\AdjustEmailQuota;
|
use App\Jobs\Ninja\AdjustEmailQuota;
|
||||||
use App\Jobs\Ninja\CompanySizeCheck;
|
use App\Jobs\Ninja\CompanySizeCheck;
|
||||||
use App\Jobs\Util\ReminderJob;
|
use App\Jobs\Util\ReminderJob;
|
||||||
@ -46,7 +47,7 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
$schedule->job(new VersionCheck)->daily();
|
$schedule->job(new VersionCheck)->daily();
|
||||||
|
|
||||||
$schedule->command('ninja:check-data')->daily()->withoutOverlapping();
|
$schedule->command('ninja:check-data --database=db-ninja-01')->daily()->withoutOverlapping();
|
||||||
|
|
||||||
$schedule->job(new ReminderJob)->daily()->withoutOverlapping();
|
$schedule->job(new ReminderJob)->daily()->withoutOverlapping();
|
||||||
|
|
||||||
@ -58,6 +59,8 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
$schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping();
|
$schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping();
|
||||||
|
|
||||||
|
$schedule->job(new AutoBillCron)->dailyAt('00:30')->withoutOverlapping();
|
||||||
|
|
||||||
$schedule->job(new SchedulerCheck)->everyFiveMinutes();
|
$schedule->job(new SchedulerCheck)->everyFiveMinutes();
|
||||||
|
|
||||||
/* Run hosted specific jobs */
|
/* Run hosted specific jobs */
|
||||||
@ -65,6 +68,7 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
$schedule->job(new AdjustEmailQuota)->daily()->withoutOverlapping();
|
$schedule->job(new AdjustEmailQuota)->daily()->withoutOverlapping();
|
||||||
$schedule->job(new SendFailedEmails)->daily()->withoutOverlapping();
|
$schedule->job(new SendFailedEmails)->daily()->withoutOverlapping();
|
||||||
|
$schedule->command('ninja:check-data --database=db-ninja-02')->daily()->withoutOverlapping();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ class CompanySettings extends BaseSettings
|
|||||||
public $inclusive_taxes = false; //@implemented
|
public $inclusive_taxes = false; //@implemented
|
||||||
public $quote_footer = ''; //@implmented
|
public $quote_footer = ''; //@implmented
|
||||||
|
|
||||||
public $translations; //@TODO not used anywhere
|
public $translations;
|
||||||
|
|
||||||
public $counter_number_applied = 'when_saved'; // when_saved , when_sent //@implemented
|
public $counter_number_applied = 'when_saved'; // when_saved , when_sent //@implemented
|
||||||
public $quote_number_applied = 'when_saved'; // when_saved , when_sent //@implemented
|
public $quote_number_applied = 'when_saved'; // when_saved , when_sent //@implemented
|
||||||
@ -202,7 +202,7 @@ class CompanySettings extends BaseSettings
|
|||||||
public $schedule_reminder2 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
public $schedule_reminder2 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
||||||
public $schedule_reminder3 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
public $schedule_reminder3 = ''; // (enum: after_invoice_date, before_due_date, after_due_date) implmemented
|
||||||
|
|
||||||
public $reminder_send_time = 32400; //number of seconds from UTC +0 to send reminders @TODO
|
public $reminder_send_time = 0; //number of seconds from UTC +0 to send reminders @TODO
|
||||||
|
|
||||||
public $late_fee_amount1 = 0; //@implemented
|
public $late_fee_amount1 = 0; //@implemented
|
||||||
public $late_fee_amount2 = 0; //@implemented
|
public $late_fee_amount2 = 0; //@implemented
|
||||||
@ -245,8 +245,8 @@ class CompanySettings extends BaseSettings
|
|||||||
|
|
||||||
public $hide_paid_to_date = false; //@TODO where?
|
public $hide_paid_to_date = false; //@TODO where?
|
||||||
public $embed_documents = false; //@TODO where?
|
public $embed_documents = false; //@TODO where?
|
||||||
public $all_pages_header = false; //@implemented
|
public $all_pages_header = false; //@deprecated 31-05-2021
|
||||||
public $all_pages_footer = false; //@implemented
|
public $all_pages_footer = false; //@deprecated 31-05-2021
|
||||||
public $pdf_variables = ''; //@implemented
|
public $pdf_variables = ''; //@implemented
|
||||||
|
|
||||||
public $portal_custom_head = ''; //@TODO @BEN
|
public $portal_custom_head = ''; //@TODO @BEN
|
||||||
@ -667,8 +667,9 @@ class CompanySettings extends BaseSettings
|
|||||||
'$custom_surcharge4',
|
'$custom_surcharge4',
|
||||||
'$total_taxes',
|
'$total_taxes',
|
||||||
'$line_taxes',
|
'$line_taxes',
|
||||||
'$paid_to_date',
|
|
||||||
'$total',
|
'$total',
|
||||||
|
'$paid_to_date',
|
||||||
|
'$outstanding',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ namespace App\Exceptions;
|
|||||||
use App\Exceptions\FilePermissionsFailure;
|
use App\Exceptions\FilePermissionsFailure;
|
||||||
use App\Exceptions\InternalPDFFailure;
|
use App\Exceptions\InternalPDFFailure;
|
||||||
use App\Exceptions\PhantomPDFFailure;
|
use App\Exceptions\PhantomPDFFailure;
|
||||||
|
use App\Utils\Ninja;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
@ -75,7 +76,28 @@ class Handler extends ExceptionHandler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app()->bound('sentry') && $this->shouldReport($exception)) {
|
if(Ninja::isHosted()){
|
||||||
|
|
||||||
|
app('sentry')->configureScope(function (Scope $scope): void {
|
||||||
|
|
||||||
|
if(auth()->guard('contact') && auth()->guard('contact')->user())
|
||||||
|
$key = auth()->guard('contact')->user()->company->account->key;
|
||||||
|
elseif (auth()->guard('user') && auth()->guard('user')->user())
|
||||||
|
$key = auth()->user()->account->key;
|
||||||
|
else
|
||||||
|
$key = 'Anonymous';
|
||||||
|
|
||||||
|
$scope->setUser([
|
||||||
|
'id' => 'Hosted_User',
|
||||||
|
'email' => 'hosted@invoiceninja.com',
|
||||||
|
'name' => $key,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
app('sentry')->captureException($exception);
|
||||||
|
|
||||||
|
}
|
||||||
|
elseif (app()->bound('sentry') && $this->shouldReport($exception)) {
|
||||||
app('sentry')->configureScope(function (Scope $scope): void {
|
app('sentry')->configureScope(function (Scope $scope): void {
|
||||||
if (auth()->guard('contact') && auth()->guard('contact')->user() && auth()->guard('contact')->user()->company->account->report_errors) {
|
if (auth()->guard('contact') && auth()->guard('contact')->user() && auth()->guard('contact')->user()->company->account->report_errors) {
|
||||||
$scope->setUser([
|
$scope->setUser([
|
||||||
|
10
app/Exceptions/ImportCompanyFailed.php
Normal file
10
app/Exceptions/ImportCompanyFailed.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class ImportCompanyFailed extends Exception
|
||||||
|
{
|
||||||
|
// ..
|
||||||
|
}
|
10
app/Exceptions/NonExistingBackupFile.php
Normal file
10
app/Exceptions/NonExistingBackupFile.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class NonExistingBackupFile extends Exception
|
||||||
|
{
|
||||||
|
// ..
|
||||||
|
}
|
@ -33,9 +33,6 @@ class ClientFactory
|
|||||||
$client->client_hash = Str::random(40);
|
$client->client_hash = Str::random(40);
|
||||||
$client->settings = ClientSettings::defaults();
|
$client->settings = ClientSettings::defaults();
|
||||||
|
|
||||||
// $client_contact = ClientContactFactory::create($company_id, $user_id);
|
|
||||||
// $client->contacts->add($client_contact);
|
|
||||||
|
|
||||||
return $client;
|
return $client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,9 @@
|
|||||||
namespace App\Factory;
|
namespace App\Factory;
|
||||||
|
|
||||||
use App\DataMapper\CompanySettings;
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
class CompanyFactory
|
class CompanyFactory
|
||||||
@ -33,7 +35,12 @@ class CompanyFactory
|
|||||||
$company->db = config('database.default');
|
$company->db = config('database.default');
|
||||||
//$company->custom_fields = (object) ['invoice1' => '1', 'invoice2' => '2', 'client1'=>'3'];
|
//$company->custom_fields = (object) ['invoice1' => '1', 'invoice2' => '2', 'client1'=>'3'];
|
||||||
$company->custom_fields = (object) [];
|
$company->custom_fields = (object) [];
|
||||||
$company->subdomain = '';
|
|
||||||
|
if(Ninja::isHosted())
|
||||||
|
$company->subdomain = MultiDB::randomSubdomainGenerator();
|
||||||
|
else
|
||||||
|
$company->subdomain = '';
|
||||||
|
|
||||||
$company->enabled_modules = config('ninja.enabled_modules'); //32767;//8191; //4095
|
$company->enabled_modules = config('ninja.enabled_modules'); //32767;//8191; //4095
|
||||||
$company->default_password_timeout = 1800000;
|
$company->default_password_timeout = 1800000;
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ class CompanyGatewayFactory
|
|||||||
$company_gateway = new CompanyGateway;
|
$company_gateway = new CompanyGateway;
|
||||||
$company_gateway->company_id = $company_id;
|
$company_gateway->company_id = $company_id;
|
||||||
$company_gateway->user_id = $user_id;
|
$company_gateway->user_id = $user_id;
|
||||||
|
$company_gateway->require_billing_address = false;
|
||||||
|
$company_gateway->require_shipping_address = false;
|
||||||
// $company_gateway->fees_and_limits = new FeesAndLimits;
|
// $company_gateway->fees_and_limits = new FeesAndLimits;
|
||||||
|
|
||||||
return $company_gateway;
|
return $company_gateway;
|
||||||
|
@ -37,10 +37,10 @@ class CreditFactory
|
|||||||
$credit->tax_rate1 = 0;
|
$credit->tax_rate1 = 0;
|
||||||
$credit->tax_name2 = '';
|
$credit->tax_name2 = '';
|
||||||
$credit->tax_rate2 = 0;
|
$credit->tax_rate2 = 0;
|
||||||
$credit->custom_value1 = 0;
|
$credit->custom_value1 = '';
|
||||||
$credit->custom_value2 = 0;
|
$credit->custom_value2 = '';
|
||||||
$credit->custom_value3 = 0;
|
$credit->custom_value3 = '';
|
||||||
$credit->custom_value4 = 0;
|
$credit->custom_value4 = '';
|
||||||
$credit->amount = 0;
|
$credit->amount = 0;
|
||||||
$credit->balance = 0;
|
$credit->balance = 0;
|
||||||
$credit->partial = 0;
|
$credit->partial = 0;
|
||||||
|
@ -38,10 +38,10 @@ class InvoiceFactory
|
|||||||
$invoice->tax_rate2 = 0;
|
$invoice->tax_rate2 = 0;
|
||||||
$invoice->tax_name3 = '';
|
$invoice->tax_name3 = '';
|
||||||
$invoice->tax_rate3 = 0;
|
$invoice->tax_rate3 = 0;
|
||||||
$invoice->custom_value1 = 0;
|
$invoice->custom_value1 = '';
|
||||||
$invoice->custom_value2 = 0;
|
$invoice->custom_value2 = '';
|
||||||
$invoice->custom_value3 = 0;
|
$invoice->custom_value3 = '';
|
||||||
$invoice->custom_value4 = 0;
|
$invoice->custom_value4 = '';
|
||||||
$invoice->amount = 0;
|
$invoice->amount = 0;
|
||||||
$invoice->balance = 0;
|
$invoice->balance = 0;
|
||||||
$invoice->paid_to_date = 0;
|
$invoice->paid_to_date = 0;
|
||||||
|
@ -36,10 +36,10 @@ class RecurringInvoiceFactory
|
|||||||
$invoice->tax_rate1 = 0;
|
$invoice->tax_rate1 = 0;
|
||||||
$invoice->tax_name2 = '';
|
$invoice->tax_name2 = '';
|
||||||
$invoice->tax_rate2 = 0;
|
$invoice->tax_rate2 = 0;
|
||||||
$invoice->custom_value1 = 0;
|
$invoice->custom_value1 = '';
|
||||||
$invoice->custom_value2 = 0;
|
$invoice->custom_value2 = '';
|
||||||
$invoice->custom_value3 = 0;
|
$invoice->custom_value3 = '';
|
||||||
$invoice->custom_value4 = 0;
|
$invoice->custom_value4 = '';
|
||||||
$invoice->amount = 0;
|
$invoice->amount = 0;
|
||||||
$invoice->balance = 0;
|
$invoice->balance = 0;
|
||||||
$invoice->partial = 0;
|
$invoice->partial = 0;
|
||||||
|
@ -35,10 +35,10 @@ class RecurringQuoteFactory
|
|||||||
$quote->tax_rate1 = 0;
|
$quote->tax_rate1 = 0;
|
||||||
$quote->tax_name2 = '';
|
$quote->tax_name2 = '';
|
||||||
$quote->tax_rate2 = 0;
|
$quote->tax_rate2 = 0;
|
||||||
$quote->custom_value1 = 0;
|
$quote->custom_value1 = '';
|
||||||
$quote->custom_value2 = 0;
|
$quote->custom_value2 = '';
|
||||||
$quote->custom_value3 = 0;
|
$quote->custom_value3 = '';
|
||||||
$quote->custom_value4 = 0;
|
$quote->custom_value4 = '';
|
||||||
$quote->amount = 0;
|
$quote->amount = 0;
|
||||||
$quote->balance = 0;
|
$quote->balance = 0;
|
||||||
$quote->partial = 0;
|
$quote->partial = 0;
|
||||||
|
@ -169,4 +169,27 @@ abstract class QueryFilters
|
|||||||
|
|
||||||
return $this->builder->where('created_at', '>=', $created_at);
|
return $this->builder->where('created_at', '>=', $created_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function is_deleted($value)
|
||||||
|
{
|
||||||
|
|
||||||
|
return $this->builder->where('is_deleted', $value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function filter_deleted_clients($value)
|
||||||
|
{
|
||||||
|
|
||||||
|
if($value == 'true'){
|
||||||
|
|
||||||
|
return $this->builder->whereHas('client', function (Builder $query) {
|
||||||
|
|
||||||
|
$query->where('is_deleted', 0);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->builder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ function isActive($page, bool $boolean = false)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($page == $current_page) {
|
if ($page == $current_page) {
|
||||||
return 'bg-primary-darken';
|
return 'bg-gray-200';
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -142,7 +142,7 @@ class AccountController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function store(CreateAccountRequest $request)
|
public function store(CreateAccountRequest $request)
|
||||||
{
|
{
|
||||||
$account = CreateAccount::dispatchNow($request->all());
|
$account = CreateAccount::dispatchNow($request->all(), $request->getClientIp());
|
||||||
|
|
||||||
if (! ($account instanceof Account)) {
|
if (! ($account instanceof Account)) {
|
||||||
return $account;
|
return $account;
|
||||||
|
@ -13,6 +13,7 @@ namespace App\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Account;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -50,11 +51,15 @@ class ContactForgotPasswordController extends Controller
|
|||||||
*
|
*
|
||||||
* @return Factory|View
|
* @return Factory|View
|
||||||
*/
|
*/
|
||||||
public function showLinkRequestForm()
|
public function showLinkRequestForm(Request $request)
|
||||||
{
|
{
|
||||||
|
$account_id = $request->get('account_id');
|
||||||
|
$account = Account::find($account_id);
|
||||||
|
|
||||||
return $this->render('auth.passwords.request', [
|
return $this->render('auth.passwords.request', [
|
||||||
'title' => 'Client Password Reset',
|
'title' => 'Client Password Reset',
|
||||||
'passwordEmailRoute' => 'client.password.email',
|
'passwordEmailRoute' => 'client.password.email',
|
||||||
|
'account' => $account
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +77,7 @@ class ContactForgotPasswordController extends Controller
|
|||||||
{
|
{
|
||||||
//MultiDB::userFindAndSetDb($request->input('email'));
|
//MultiDB::userFindAndSetDb($request->input('email'));
|
||||||
|
|
||||||
$user = MultiDB::hasContact(['email' => $request->input('email')]);
|
$user = MultiDB::hasContact($request->input('email'));
|
||||||
|
|
||||||
$this->validateEmail($request);
|
$this->validateEmail($request);
|
||||||
|
|
||||||
@ -84,6 +89,10 @@ class ContactForgotPasswordController extends Controller
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($request->ajax()) {
|
if ($request->ajax()) {
|
||||||
|
|
||||||
|
if($response == Password::RESET_THROTTLED)
|
||||||
|
return response()->json(['message' => ctrans('passwords.throttled'), 'status' => false], 429);
|
||||||
|
|
||||||
return $response == Password::RESET_LINK_SENT
|
return $response == Password::RESET_LINK_SENT
|
||||||
? response()->json(['message' => 'Reset link sent to your email.', 'status' => true], 201)
|
? response()->json(['message' => 'Reset link sent to your email.', 'status' => true], 201)
|
||||||
: response()->json(['message' => 'Email not found', 'status' => false], 401);
|
: response()->json(['message' => 'Email not found', 'status' => false], 401);
|
||||||
|
@ -13,6 +13,7 @@ namespace App\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use App\Events\Contact\ContactLoggedIn;
|
use App\Events\Contact\ContactLoggedIn;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Account;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use Auth;
|
use Auth;
|
||||||
@ -31,9 +32,13 @@ class ContactLoginController extends Controller
|
|||||||
$this->middleware('guest:contact', ['except' => ['logout']]);
|
$this->middleware('guest:contact', ['except' => ['logout']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function showLoginForm()
|
public function showLoginForm(Request $request)
|
||||||
{
|
{
|
||||||
return $this->render('auth.login');
|
$account_id = $request->get('account_id');
|
||||||
|
$account = Account::find($account_id);
|
||||||
|
|
||||||
|
return $this->render('auth.login', ['account' => $account]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login(Request $request)
|
public function login(Request $request)
|
||||||
|
@ -24,7 +24,7 @@ class ContactRegisterController extends Controller
|
|||||||
|
|
||||||
$company = Company::where('company_key', $key)->firstOrFail();
|
$company = Company::where('company_key', $key)->firstOrFail();
|
||||||
|
|
||||||
return render('auth.register', ['company' => $company]);
|
return render('auth.register', ['company' => $company, 'account' => $company->account]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function register(RegisterRequest $request)
|
public function register(RegisterRequest $request)
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Account;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -62,8 +63,11 @@ class ContactResetPasswordController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showResetForm(Request $request, $token = null)
|
public function showResetForm(Request $request, $token = null)
|
||||||
{
|
{
|
||||||
|
$account_id = $request->get('account_id');
|
||||||
|
$account = Account::find($account_id);
|
||||||
|
|
||||||
return $this->render('auth.passwords.reset')->with(
|
return $this->render('auth.passwords.reset')->with(
|
||||||
['token' => $token, 'email' => $request->email]
|
['token' => $token, 'email' => $request->email, 'account' => $account]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ namespace App\Http\Controllers\Auth;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Account;
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Password;
|
use Illuminate\Support\Facades\Password;
|
||||||
@ -104,8 +105,7 @@ class ForgotPasswordController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function sendResetLinkEmail(Request $request)
|
public function sendResetLinkEmail(Request $request)
|
||||||
{
|
{
|
||||||
//MultiDB::userFindAndSetDb($request->input('email'));
|
MultiDB::userFindAndSetDb($request->input('email'));
|
||||||
|
|
||||||
$user = MultiDB::hasUser(['email' => $request->input('email')]);
|
$user = MultiDB::hasUser(['email' => $request->input('email')]);
|
||||||
|
|
||||||
$this->validateEmail($request);
|
$this->validateEmail($request);
|
||||||
@ -118,6 +118,10 @@ class ForgotPasswordController extends Controller
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($request->ajax()) {
|
if ($request->ajax()) {
|
||||||
|
|
||||||
|
if($response == Password::RESET_THROTTLED)
|
||||||
|
return response()->json(['message' => ctrans('passwords.throttled'), 'status' => false], 429);
|
||||||
|
|
||||||
return $response == Password::RESET_LINK_SENT
|
return $response == Password::RESET_LINK_SENT
|
||||||
? response()->json(['message' => 'Reset link sent to your email.', 'status' => true], 201)
|
? response()->json(['message' => 'Reset link sent to your email.', 'status' => true], 201)
|
||||||
: response()->json(['message' => 'Email not found', 'status' => false], 401);
|
: response()->json(['message' => 'Email not found', 'status' => false], 401);
|
||||||
|
@ -23,6 +23,7 @@ use App\Libraries\MultiDB;
|
|||||||
use App\Libraries\OAuth\OAuth;
|
use App\Libraries\OAuth\OAuth;
|
||||||
use App\Libraries\OAuth\Providers\Google;
|
use App\Libraries\OAuth\Providers\Google;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
|
use App\Models\Company;
|
||||||
use App\Models\CompanyToken;
|
use App\Models\CompanyToken;
|
||||||
use App\Models\CompanyUser;
|
use App\Models\CompanyUser;
|
||||||
use App\Models\SystemLog;
|
use App\Models\SystemLog;
|
||||||
@ -30,6 +31,7 @@ use App\Models\User;
|
|||||||
use App\Transformers\CompanyUserTransformer;
|
use App\Transformers\CompanyUserTransformer;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\UserSessionAttributes;
|
use App\Utils\Traits\UserSessionAttributes;
|
||||||
|
use App\Utils\Traits\User\LoginCache;
|
||||||
use Google_Client;
|
use Google_Client;
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -54,6 +56,7 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
use AuthenticatesUsers;
|
use AuthenticatesUsers;
|
||||||
use UserSessionAttributes;
|
use UserSessionAttributes;
|
||||||
|
use LoginCache;
|
||||||
|
|
||||||
protected $entity_type = CompanyUser::class;
|
protected $entity_type = CompanyUser::class;
|
||||||
|
|
||||||
@ -177,8 +180,7 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
event(new UserLoggedIn($user, $user->account->default_company, Ninja::eventVars($user->id)));
|
event(new UserLoggedIn($user, $user->account->default_company, Ninja::eventVars($user->id)));
|
||||||
|
|
||||||
//if user has 2fa enabled - lets check this now:
|
//2FA
|
||||||
|
|
||||||
if($user->google_2fa_secret && $request->has('one_time_password'))
|
if($user->google_2fa_secret && $request->has('one_time_password'))
|
||||||
{
|
{
|
||||||
$google2fa = new Google2FA();
|
$google2fa = new Google2FA();
|
||||||
@ -202,14 +204,7 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
$user->setCompany($user->account->default_company);
|
$user->setCompany($user->account->default_company);
|
||||||
|
|
||||||
$timeout = $user->company()->default_password_timeout;
|
$this->setLoginCache($user);
|
||||||
|
|
||||||
if($timeout == 0)
|
|
||||||
$timeout = 30*60*1000*1000;
|
|
||||||
else
|
|
||||||
$timeout = $timeout/1000;
|
|
||||||
|
|
||||||
Cache::put($user->hashed_id.'_logged_in', Str::random(64), $timeout);
|
|
||||||
|
|
||||||
$cu = CompanyUser::query()
|
$cu = CompanyUser::query()
|
||||||
->where('user_id', auth()->user()->id);
|
->where('user_id', auth()->user()->id);
|
||||||
@ -227,7 +222,7 @@ class LoginController extends BaseController
|
|||||||
});
|
});
|
||||||
|
|
||||||
return $this->timeConstrainedResponse($cu);
|
return $this->timeConstrainedResponse($cu);
|
||||||
// return $this->listResponse($cu);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -236,11 +231,12 @@ class LoginController extends BaseController
|
|||||||
->batch();
|
->batch();
|
||||||
|
|
||||||
SystemLogger::dispatch(
|
SystemLogger::dispatch(
|
||||||
request()->getClientIp(),
|
json_encode(['ip' => request()->getClientIp()]),
|
||||||
SystemLog::CATEGORY_SECURITY,
|
SystemLog::CATEGORY_SECURITY,
|
||||||
SystemLog::EVENT_USER,
|
SystemLog::EVENT_USER,
|
||||||
SystemLog::TYPE_LOGIN_FAILURE,
|
SystemLog::TYPE_LOGIN_FAILURE,
|
||||||
Client::first(),
|
null,
|
||||||
|
Company::first(),
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->incrementLoginAttempts($request);
|
$this->incrementLoginAttempts($request);
|
||||||
@ -349,6 +345,7 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
if (is_array($user)) {
|
if (is_array($user)) {
|
||||||
|
|
||||||
|
//
|
||||||
$query = [
|
$query = [
|
||||||
'oauth_user_id' => $google->harvestSubField($user),
|
'oauth_user_id' => $google->harvestSubField($user),
|
||||||
'oauth_provider_id'=> 'google',
|
'oauth_provider_id'=> 'google',
|
||||||
@ -359,15 +356,7 @@ class LoginController extends BaseController
|
|||||||
Auth::login($existing_user, true);
|
Auth::login($existing_user, true);
|
||||||
$existing_user->setCompany($existing_user->account->default_company);
|
$existing_user->setCompany($existing_user->account->default_company);
|
||||||
|
|
||||||
$timeout = $existing_user->company()->default_password_timeout;
|
$this->setLoginCache($existing_user);
|
||||||
|
|
||||||
if($timeout == 0)
|
|
||||||
$timeout = 30*60*1000*1000;
|
|
||||||
else
|
|
||||||
$timeout = $timeout/1000;
|
|
||||||
|
|
||||||
|
|
||||||
Cache::put($existing_user->hashed_id.'_logged_in', Str::random(64), $timeout);
|
|
||||||
|
|
||||||
$cu = CompanyUser::query()
|
$cu = CompanyUser::query()
|
||||||
->where('user_id', auth()->user()->id);
|
->where('user_id', auth()->user()->id);
|
||||||
@ -383,10 +372,68 @@ class LoginController extends BaseController
|
|||||||
return $this->timeConstrainedResponse($cu);
|
return $this->timeConstrainedResponse($cu);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If this is a result user/email combo - lets add their OAuth details details
|
||||||
|
if($existing_login_user = MultiDB::hasUser(['email' => $google->harvestEmail($user)]))
|
||||||
|
{
|
||||||
|
Auth::login($existing_login_user, true);
|
||||||
|
$existing_login_user->setCompany($existing_login_user->account->default_company);
|
||||||
|
|
||||||
|
$this->setLoginCache($existing_login_user);
|
||||||
|
|
||||||
|
auth()->user()->update([
|
||||||
|
'oauth_user_id' => $google->harvestSubField($user),
|
||||||
|
'oauth_provider_id'=> 'google',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$cu = CompanyUser::query()
|
||||||
|
->where('user_id', auth()->user()->id);
|
||||||
|
|
||||||
|
$cu->first()->account->companies->each(function ($company) use($cu){
|
||||||
|
|
||||||
|
if($company->tokens()->where('is_system', true)->count() == 0)
|
||||||
|
{
|
||||||
|
CreateCompanyToken::dispatchNow($company, $cu->first()->user, request()->server('HTTP_USER_AGENT'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->timeConstrainedResponse($cu);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($user) {
|
if ($user) {
|
||||||
|
|
||||||
|
//check the user doesn't already exist in some form
|
||||||
|
|
||||||
|
if($existing_login_user = MultiDB::hasUser(['email' => $google->harvestEmail($user)]))
|
||||||
|
{
|
||||||
|
Auth::login($existing_login_user, true);
|
||||||
|
$existing_login_user->setCompany($existing_login_user->account->default_company);
|
||||||
|
|
||||||
|
$this->setLoginCache($existing_login_user);
|
||||||
|
|
||||||
|
auth()->user()->update([
|
||||||
|
'oauth_user_id' => $google->harvestSubField($user),
|
||||||
|
'oauth_provider_id'=> 'google',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$cu = CompanyUser::query()
|
||||||
|
->where('user_id', auth()->user()->id);
|
||||||
|
|
||||||
|
$cu->first()->account->companies->each(function ($company) use($cu){
|
||||||
|
|
||||||
|
if($company->tokens()->where('is_system', true)->count() == 0)
|
||||||
|
{
|
||||||
|
CreateCompanyToken::dispatchNow($company, $cu->first()->user, request()->server('HTTP_USER_AGENT'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->timeConstrainedResponse($cu);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//user not found anywhere - lets sign them up.
|
||||||
$name = OAuth::splitName($google->harvestName($user));
|
$name = OAuth::splitName($google->harvestName($user));
|
||||||
|
|
||||||
$new_account = [
|
$new_account = [
|
||||||
@ -402,22 +449,14 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
MultiDB::setDefaultDatabase();
|
MultiDB::setDefaultDatabase();
|
||||||
|
|
||||||
$account = CreateAccount::dispatchNow($new_account);
|
$account = CreateAccount::dispatchNow($new_account, request()->getClientIp());
|
||||||
|
|
||||||
Auth::login($account->default_company->owner(), true);
|
Auth::login($account->default_company->owner(), true);
|
||||||
|
|
||||||
auth()->user()->email_verified_at = now();
|
auth()->user()->email_verified_at = now();
|
||||||
auth()->user()->save();
|
auth()->user()->save();
|
||||||
|
|
||||||
$timeout = auth()->user()->company()->default_password_timeout;
|
$this->setLoginCache(auth()->user());
|
||||||
|
|
||||||
if($timeout == 0)
|
|
||||||
$timeout = 30*60*1000*1000;
|
|
||||||
else
|
|
||||||
$timeout = $timeout/1000;
|
|
||||||
|
|
||||||
|
|
||||||
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
|
|
||||||
|
|
||||||
$cu = CompanyUser::whereUserId(auth()->user()->id);
|
$cu = CompanyUser::whereUserId(auth()->user()->id);
|
||||||
|
|
||||||
@ -437,4 +476,62 @@ class LoginController extends BaseController
|
|||||||
->header('X-App-Version', config('ninja.app_version'))
|
->header('X-App-Version', config('ninja.app_version'))
|
||||||
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function redirectToProvider(string $provider)
|
||||||
|
{
|
||||||
|
//'https://www.googleapis.com/auth/gmail.send','email','profile','openid'
|
||||||
|
$scopes = [];
|
||||||
|
|
||||||
|
if($provider == 'google'){
|
||||||
|
$scopes = ['https://www.googleapis.com/auth/gmail.send','email','profile','openid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request()->has('code')) {
|
||||||
|
return $this->handleProviderCallback($provider);
|
||||||
|
} else {
|
||||||
|
return Socialite::driver($provider)->scopes($scopes)->redirect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleProviderCallback(string $provider)
|
||||||
|
{
|
||||||
|
$socialite_user = Socialite::driver($provider)
|
||||||
|
->stateless()
|
||||||
|
->user();
|
||||||
|
|
||||||
|
// if($user = OAuth::handleAuth($socialite_user, $provider))
|
||||||
|
// {
|
||||||
|
// Auth::login($user, true);
|
||||||
|
|
||||||
|
// return redirect($this->redirectTo);
|
||||||
|
// }
|
||||||
|
// else if(MultiDB::checkUserEmailExists($socialite_user->getEmail()))
|
||||||
|
// {
|
||||||
|
// Session::flash('error', 'User exists in system, but not with this authentication method'); //todo add translations
|
||||||
|
|
||||||
|
// return view('auth.login');
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// //todo
|
||||||
|
// $name = OAuth::splitName($socialite_user->getName());
|
||||||
|
|
||||||
|
// $new_account = [
|
||||||
|
// 'first_name' => $name[0],
|
||||||
|
// 'last_name' => $name[1],
|
||||||
|
// 'password' => '',
|
||||||
|
// 'email' => $socialite_user->getEmail(),
|
||||||
|
// 'oauth_user_id' => $socialite_user->getId(),
|
||||||
|
// 'oauth_provider_id' => $provider
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// $account = CreateAccount::dispatchNow($new_account);
|
||||||
|
|
||||||
|
// Auth::login($account->default_company->owner(), true);
|
||||||
|
|
||||||
|
// $cookie = cookie('db', $account->default_company->db);
|
||||||
|
|
||||||
|
// return redirect($this->redirectTo)->withCookie($cookie);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ class BaseController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function notFoundClient()
|
public function notFoundClient()
|
||||||
{
|
{
|
||||||
return abort(404);
|
abort(404, 'Page not found in client portal.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,10 +189,7 @@ class BaseController extends Controller
|
|||||||
{
|
{
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
if ($user->getCompany()->is_large)
|
$this->manager->parseIncludes($this->first_load);
|
||||||
$this->manager->parseIncludes($this->mini_load);
|
|
||||||
else
|
|
||||||
$this->manager->parseIncludes($this->first_load);
|
|
||||||
|
|
||||||
$this->serializer = request()->input('serializer') ?: EntityTransformer::API_SERIALIZER_ARRAY;
|
$this->serializer = request()->input('serializer') ?: EntityTransformer::API_SERIALIZER_ARRAY;
|
||||||
|
|
||||||
@ -312,10 +309,6 @@ class BaseController extends Controller
|
|||||||
},
|
},
|
||||||
'company.tax_rates' => function ($query) use ($updated_at, $user) {
|
'company.tax_rates' => function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at);
|
$query->where('updated_at', '>=', $updated_at);
|
||||||
|
|
||||||
if(!$user->isAdmin())
|
|
||||||
$query->where('tax_rates.user_id', $user->id);
|
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.vendors'=> function ($query) use ($updated_at, $user) {
|
'company.vendors'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at)->with('contacts', 'documents');
|
$query->where('updated_at', '>=', $updated_at)->with('contacts', 'documents');
|
||||||
@ -326,15 +319,9 @@ class BaseController extends Controller
|
|||||||
},
|
},
|
||||||
'company.expense_categories'=> function ($query) use ($updated_at, $user) {
|
'company.expense_categories'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at);
|
$query->where('updated_at', '>=', $updated_at);
|
||||||
|
|
||||||
if(!$user->isAdmin())
|
|
||||||
$query->where('expense_categories.user_id', $user->id);
|
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.task_statuses'=> function ($query) use ($updated_at, $user) {
|
'company.task_statuses'=> function ($query) use ($updated_at, $user) {
|
||||||
$query->where('updated_at', '>=', $updated_at);
|
$query->where('updated_at', '>=', $updated_at);
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
'company.activities'=> function ($query) use($user) {
|
'company.activities'=> function ($query) use($user) {
|
||||||
|
|
||||||
@ -366,13 +353,92 @@ class BaseController extends Controller
|
|||||||
return $this->response($this->manager->createData($resource)->toArray());
|
return $this->response($this->manager->createData($resource)->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function miniLoadResponse($query)
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
|
||||||
|
$this->serializer = request()->input('serializer') ?: EntityTransformer::API_SERIALIZER_ARRAY;
|
||||||
|
|
||||||
|
if ($this->serializer === EntityTransformer::API_SERIALIZER_JSON) {
|
||||||
|
$this->manager->setSerializer(new JsonApiSerializer());
|
||||||
|
} else {
|
||||||
|
$this->manager->setSerializer(new ArraySerializer());
|
||||||
|
}
|
||||||
|
|
||||||
|
$transformer = new $this->entity_transformer($this->serializer);
|
||||||
|
$created_at = request()->has('created_at') ? request()->input('created_at') : 0;
|
||||||
|
|
||||||
|
$created_at = date('Y-m-d H:i:s', $created_at);
|
||||||
|
|
||||||
|
$query->with(
|
||||||
|
[
|
||||||
|
'company' => function ($query) use ($created_at, $user) {
|
||||||
|
$query->whereNotNull('created_at')->with('documents');
|
||||||
|
},
|
||||||
|
'company.designs'=> function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at)->with('company');
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('designs.user_id', $user->id);
|
||||||
|
},
|
||||||
|
'company.documents'=> function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at);
|
||||||
|
},
|
||||||
|
'company.groups' => function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('group_settings.user_id', $user->id);
|
||||||
|
},
|
||||||
|
'company.payment_terms'=> function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('payment_terms.user_id', $user->id);
|
||||||
|
|
||||||
|
},
|
||||||
|
'company.tax_rates' => function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('tax_rates.user_id', $user->id);
|
||||||
|
|
||||||
|
},
|
||||||
|
'company.activities'=> function ($query) use($user) {
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('activities.user_id', $user->id);
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($query instanceof Builder) {
|
||||||
|
$limit = request()->input('per_page', 20);
|
||||||
|
|
||||||
|
$paginator = $query->paginate($limit);
|
||||||
|
$query = $paginator->getCollection();
|
||||||
|
$resource = new Collection($query, $transformer, $this->entity_type);
|
||||||
|
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||||
|
} else {
|
||||||
|
$resource = new Collection($query, $transformer, $this->entity_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response($this->manager->createData($resource)->toArray());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function timeConstrainedResponse($query)
|
protected function timeConstrainedResponse($query)
|
||||||
{
|
{
|
||||||
|
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
if ($user->getCompany()->is_large)
|
if ($user->getCompany()->is_large){
|
||||||
$this->manager->parseIncludes($this->mini_load);
|
$this->manager->parseIncludes($this->mini_load);
|
||||||
|
return $this->miniLoadResponse($query);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
$this->manager->parseIncludes($this->first_load);
|
$this->manager->parseIncludes($this->first_load);
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ use App\Events\Client\ClientWasCreated;
|
|||||||
use App\Events\Client\ClientWasUpdated;
|
use App\Events\Client\ClientWasUpdated;
|
||||||
use App\Factory\ClientFactory;
|
use App\Factory\ClientFactory;
|
||||||
use App\Filters\ClientFilters;
|
use App\Filters\ClientFilters;
|
||||||
|
use App\Http\Requests\Client\AdjustClientLedgerRequest;
|
||||||
use App\Http\Requests\Client\CreateClientRequest;
|
use App\Http\Requests\Client\CreateClientRequest;
|
||||||
use App\Http\Requests\Client\DestroyClientRequest;
|
use App\Http\Requests\Client\DestroyClientRequest;
|
||||||
use App\Http\Requests\Client\EditClientRequest;
|
use App\Http\Requests\Client\EditClientRequest;
|
||||||
@ -585,4 +586,64 @@ class ClientController extends BaseController
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param UploadClientRequest $request
|
||||||
|
* @param Client $client
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/clients/{id}/adjust_ledger",
|
||||||
|
* operationId="adjustLedger",
|
||||||
|
* tags={"clients"},
|
||||||
|
* summary="Adjust the client ledger to rebalance",
|
||||||
|
* description="Adjust the client ledger to rebalance",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Client Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the client object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Client"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
//@deprecated - not available
|
||||||
|
public function adjustLedger(AdjustClientLedgerRequest $request, Client $client)
|
||||||
|
{
|
||||||
|
// $adjustment = $request->input('adjustment');
|
||||||
|
// $notes = $request->input('notes');
|
||||||
|
|
||||||
|
// $client->service()->updateBalance
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,12 @@ class ContactHashLoginController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function login(string $contact_key)
|
public function login(string $contact_key)
|
||||||
{
|
{
|
||||||
return redirect('/client/login');
|
return redirect('/client/invoices');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function magicLink(string $magic_link)
|
public function magicLink(string $magic_link)
|
||||||
{
|
{
|
||||||
return redirect('/client/login');
|
return redirect('/client/invoices');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function errorPage()
|
public function errorPage()
|
||||||
|
@ -22,8 +22,15 @@ class CreditController extends Controller
|
|||||||
|
|
||||||
public function show(ShowCreditRequest $request, Credit $credit)
|
public function show(ShowCreditRequest $request, Credit $credit)
|
||||||
{
|
{
|
||||||
return $this->render('credits.show', [
|
set_time_limit(0);
|
||||||
'credit' => $credit,
|
|
||||||
]);
|
$data = ['credit' => $credit];
|
||||||
|
|
||||||
|
|
||||||
|
if ($request->query('mode') === 'fullscreen') {
|
||||||
|
return render('credits.show-fullscreen', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('credits.show', $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ class DocumentController extends Controller
|
|||||||
|
|
||||||
$documents->map(function ($document) {
|
$documents->map(function ($document) {
|
||||||
if (auth()->user('contact')->client->id != $document->documentable->id) {
|
if (auth()->user('contact')->client->id != $document->documentable->id) {
|
||||||
abort(401);
|
abort(401, 'Permission denied');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class EntityViewController extends Controller
|
|||||||
public function index(string $entity_type, string $invitation_key)
|
public function index(string $entity_type, string $invitation_key)
|
||||||
{
|
{
|
||||||
if (! in_array($entity_type, $this->entity_types)) {
|
if (! in_array($entity_type, $this->entity_types)) {
|
||||||
abort(404);
|
abort(404, 'Entity not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
$invitation_entity = sprintf('App\\Models\\%sInvitation', ucfirst($entity_type));
|
$invitation_entity = sprintf('App\\Models\\%sInvitation', ucfirst($entity_type));
|
||||||
@ -91,7 +91,7 @@ class EntityViewController extends Controller
|
|||||||
public function handlePassword(string $entity_type, string $invitation_key)
|
public function handlePassword(string $entity_type, string $invitation_key)
|
||||||
{
|
{
|
||||||
if (! in_array($entity_type, $this->entity_types)) {
|
if (! in_array($entity_type, $this->entity_types)) {
|
||||||
abort(404);
|
abort(404, 'Entity not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
$invitation_entity = sprintf('App\\Models\\%sInvitation', ucfirst($entity_type));
|
$invitation_entity = sprintf('App\\Models\\%sInvitation', ucfirst($entity_type));
|
||||||
|
@ -57,7 +57,7 @@ class InvitationController extends Controller
|
|||||||
/* Return early if we have the correct client_hash embedded */
|
/* Return early if we have the correct client_hash embedded */
|
||||||
|
|
||||||
if (request()->has('client_hash') && request()->input('client_hash') == $invitation->contact->client->client_hash) {
|
if (request()->has('client_hash') && request()->input('client_hash') == $invitation->contact->client->client_hash) {
|
||||||
auth()->guard('contact')->login($invitation->contact, true);
|
auth()->guard('contact')->loginUsingId($invitation->contact->id, true);
|
||||||
|
|
||||||
} elseif ((bool) $invitation->contact->client->getSetting('enable_client_portal_password') !== false) {
|
} elseif ((bool) $invitation->contact->client->getSetting('enable_client_portal_password') !== false) {
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ class InvitationController extends Controller
|
|||||||
return redirect()->route('client.login');
|
return redirect()->route('client.login');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
auth()->guard('contact')->login($invitation->contact, true);
|
auth()->guard('contact')->loginUsingId($invitation->contact->id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -164,10 +164,10 @@ class InvoiceController extends Controller
|
|||||||
|
|
||||||
//if only 1 pdf, output to buffer for download
|
//if only 1 pdf, output to buffer for download
|
||||||
if ($invoices->count() == 1) {
|
if ($invoices->count() == 1) {
|
||||||
return response()->streamDownload(function () use ($invoices) {
|
|
||||||
echo file_get_contents($invoices->first()->pdf_file_path());
|
$file = $invoices->first()->pdf_file_path();
|
||||||
}, basename($invoices->first()->pdf_file_path()), ['Cache-Control:' => 'no-cache']);
|
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);;
|
||||||
//return response()->download(TempFile::path($invoices->first()->pdf_file_path()), basename($invoices->first()->pdf_file_path()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable output of HTTP headers
|
// enable output of HTTP headers
|
||||||
|
@ -290,7 +290,8 @@ class PaymentController extends Controller
|
|||||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||||
SystemLog::EVENT_GATEWAY_ERROR,
|
SystemLog::EVENT_GATEWAY_ERROR,
|
||||||
SystemLog::TYPE_FAILURE,
|
SystemLog::TYPE_FAILURE,
|
||||||
auth('contact')->user()->client
|
auth('contact')->user()->client,
|
||||||
|
auth('contact')->user()->client->company
|
||||||
);
|
);
|
||||||
|
|
||||||
throw new PaymentFailed($e->getMessage());
|
throw new PaymentFailed($e->getMessage());
|
||||||
|
@ -149,6 +149,6 @@ class PaymentMethodController extends Controller
|
|||||||
return $gateway = auth()->user()->client->getBankTransferGateway();
|
return $gateway = auth()->user()->client->getBankTransferGateway();
|
||||||
}
|
}
|
||||||
|
|
||||||
return abort(404);
|
abort(404, 'Gateway not found.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,10 +76,9 @@ class QuoteController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($quotes->count() == 1) {
|
if ($quotes->count() == 1) {
|
||||||
return response()->streamDownload(function () use ($quotes) {
|
|
||||||
echo file_get_contents($quotes->first()->pdf_file_path());
|
$file = $quotes->first()->pdf_file_path();
|
||||||
}, basename($quotes->first()->pdf_file_path()), ['Cache-Control:' => 'no-cache']);
|
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||||
//return response()->download(TempFile::path($invoices->first()->pdf_file_path()), basename($quotes->first()->pdf_file_path()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable output of HTTP headers
|
// enable output of HTTP headers
|
||||||
|
34
app/Http/Controllers/ClientPortal/TaskController.php
Normal file
34
app/Http/Controllers/ClientPortal/TaskController.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\ClientPortal;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\ClientPortal\Tasks\ShowTasksRequest;
|
||||||
|
|
||||||
|
class TaskController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Show the tasks in the client portal.
|
||||||
|
*
|
||||||
|
* @param ShowTasksRequest $request
|
||||||
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
|
*/
|
||||||
|
public function index(ShowTasksRequest $request)
|
||||||
|
{
|
||||||
|
\Carbon\Carbon::setLocale(
|
||||||
|
auth('contact')->user()->preferredLocale()
|
||||||
|
);
|
||||||
|
|
||||||
|
return render('tasks.index');
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ use App\Models\CompanyUser;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Transformers\CompanyUserTransformer;
|
use App\Transformers\CompanyUserTransformer;
|
||||||
use App\Transformers\UserTransformer;
|
use App\Transformers\UserTransformer;
|
||||||
|
use App\Utils\Traits\User\LoginCache;
|
||||||
use Google_Client;
|
use Google_Client;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
@ -24,6 +25,7 @@ use Illuminate\Support\Str;
|
|||||||
|
|
||||||
class ConnectedAccountController extends BaseController
|
class ConnectedAccountController extends BaseController
|
||||||
{
|
{
|
||||||
|
use LoginCache;
|
||||||
|
|
||||||
protected $entity_type = User::class;
|
protected $entity_type = User::class;
|
||||||
|
|
||||||
@ -113,8 +115,7 @@ class ConnectedAccountController extends BaseController
|
|||||||
auth()->user()->email_verified_at = now();
|
auth()->user()->email_verified_at = now();
|
||||||
auth()->user()->save();
|
auth()->user()->save();
|
||||||
|
|
||||||
$timeout = auth()->user()->company()->default_password_timeout;
|
$this->setLoginCache(auth()->user());
|
||||||
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
|
|
||||||
|
|
||||||
return $this->itemResponse(auth()->user());
|
return $this->itemResponse(auth()->user());
|
||||||
|
|
||||||
@ -160,6 +161,9 @@ class ConnectedAccountController extends BaseController
|
|||||||
'email_verified_at' =>now()
|
'email_verified_at' =>now()
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if(auth()->user()->email != $google->harvestEmail($user))
|
||||||
|
return response()->json(['message' => 'Primary Email differs to OAuth email. Emails must match.'], 400);
|
||||||
|
|
||||||
auth()->user()->update($connected_account);
|
auth()->user()->update($connected_account);
|
||||||
auth()->user()->email_verified_at = now();
|
auth()->user()->email_verified_at = now();
|
||||||
auth()->user()->save();
|
auth()->user()->save();
|
||||||
|
@ -93,11 +93,16 @@ class LoginController extends BaseController
|
|||||||
public function redirectToProvider(string $provider)
|
public function redirectToProvider(string $provider)
|
||||||
{
|
{
|
||||||
//'https://www.googleapis.com/auth/gmail.send','email','profile','openid'
|
//'https://www.googleapis.com/auth/gmail.send','email','profile','openid'
|
||||||
//
|
$scopes = [];
|
||||||
|
|
||||||
|
if($provider == 'google'){
|
||||||
|
$scopes = ['https://www.googleapis.com/auth/gmail.send','email','profile','openid'];
|
||||||
|
}
|
||||||
|
|
||||||
if (request()->has('code')) {
|
if (request()->has('code')) {
|
||||||
return $this->handleProviderCallback($provider);
|
return $this->handleProviderCallback($provider);
|
||||||
} else {
|
} else {
|
||||||
return Socialite::driver($provider)->scopes()->redirect();
|
return Socialite::driver($provider)->scopes($scopes)->redirect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,43 +236,5 @@ class LoginController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Received the returning object from the provider
|
|
||||||
* which we will use to resolve the user, we return the response in JSON format
|
|
||||||
*
|
|
||||||
* @return json
|
|
||||||
|
|
||||||
public function handleProviderCallbackApiUser(string $provider)
|
|
||||||
{
|
|
||||||
$socialite_user = Socialite::driver($provider)->stateless()->user();
|
|
||||||
|
|
||||||
if($user = OAuth::handleAuth($socialite_user, $provider))
|
|
||||||
{
|
|
||||||
return $this->itemResponse($user);
|
|
||||||
}
|
|
||||||
else if(MultiDB::checkUserEmailExists($socialite_user->getEmail()))
|
|
||||||
{
|
|
||||||
|
|
||||||
return $this->errorResponse(['message'=>'User exists in system, but not with this authentication method'], 400);
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//todo
|
|
||||||
$name = OAuth::splitName($socialite_user->getName());
|
|
||||||
|
|
||||||
$new_account = [
|
|
||||||
'first_name' => $name[0],
|
|
||||||
'last_name' => $name[1],
|
|
||||||
'password' => '',
|
|
||||||
'email' => $socialite_user->getEmail(),
|
|
||||||
];
|
|
||||||
|
|
||||||
$account = CreateAccount::dispatchNow($new_account);
|
|
||||||
|
|
||||||
return $this->itemResponse($account->default_company->owner());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@ -536,10 +536,8 @@ class CreditController extends BaseController
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'download':
|
case 'download':
|
||||||
return response()->streamDownload(function () use ($credit) {
|
$file = $credit->pdf_file_path();
|
||||||
echo file_get_contents($credit->pdf_file_path());
|
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||||
}, basename($credit->pdf_file_path()), ['Cache-Control:' => 'no-cache']);
|
|
||||||
//return response()->download(TempFile::path($credit->pdf_file_path()), basename($credit->pdf_file_path()));
|
|
||||||
break;
|
break;
|
||||||
case 'archive':
|
case 'archive':
|
||||||
$this->credit_repository->archive($credit);
|
$this->credit_repository->archive($credit);
|
||||||
@ -589,7 +587,7 @@ class CreditController extends BaseController
|
|||||||
|
|
||||||
$file_path = $credit->service()->getCreditPdf($invitation);
|
$file_path = $credit->service()->getCreditPdf($invitation);
|
||||||
|
|
||||||
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache']);
|
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
64
app/Http/Controllers/ExportController.php
Normal file
64
app/Http/Controllers/ExportController.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\Export\StoreExportRequest;
|
||||||
|
use App\Jobs\Company\CompanyExport;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
class ExportController extends BaseController
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/export",
|
||||||
|
* operationId="getExport",
|
||||||
|
* tags={"export"},
|
||||||
|
* summary="Export data from the system",
|
||||||
|
* description="Export data from the system",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="success",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function index(StoreExportRequest $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
CompanyExport::dispatch(auth()->user()->getCompany(), auth()->user());
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Processing'], 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
96
app/Http/Controllers/ImportJsonController.php
Normal file
96
app/Http/Controllers/ImportJsonController.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\Import\ImportJsonRequest;
|
||||||
|
use App\Jobs\Company\CompanyExport;
|
||||||
|
use App\Jobs\Company\CompanyImport;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class ImportJsonController extends BaseController
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/import_json",
|
||||||
|
* operationId="getImportJson",
|
||||||
|
* tags={"import"},
|
||||||
|
* summary="Import data from the system",
|
||||||
|
* description="Import data from the system",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="success",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function index(ImportJsonRequest $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$import_file = $request->file('files');
|
||||||
|
|
||||||
|
$contents = $this->unzipFile($import_file->getPathname());
|
||||||
|
|
||||||
|
$hash = Str::random(32);
|
||||||
|
|
||||||
|
Cache::put( $hash, base64_encode( $contents ), 3600 );
|
||||||
|
|
||||||
|
CompanyImport::dispatch(auth()->user()->getCompany(), auth()->user(), $hash, $request->all());
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Processing'], 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function unzipFile($file_contents)
|
||||||
|
{
|
||||||
|
$zip = new ZipArchive();
|
||||||
|
$archive = $zip->open($file_contents);
|
||||||
|
|
||||||
|
$filename = pathinfo($file_contents, PATHINFO_FILENAME);
|
||||||
|
$zip->extractTo(public_path("storage/backups/{$filename}"));
|
||||||
|
$zip->close();
|
||||||
|
$file_location = public_path("storage/backups/$filename/backup.json");
|
||||||
|
|
||||||
|
if (! file_exists($file_location))
|
||||||
|
throw new NonExistingMigrationFile('Backup file does not exist, or it is corrupted.');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents($file_location));
|
||||||
|
|
||||||
|
unlink($file_contents);
|
||||||
|
unlink($file_location);
|
||||||
|
|
||||||
|
return $data
|
||||||
|
}
|
||||||
|
}
|
@ -671,10 +671,10 @@ class InvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'download':
|
case 'download':
|
||||||
return response()->streamDownload(function () use ($invoice) {
|
|
||||||
echo file_get_contents($invoice->pdf_file_path());
|
$file = $invoice->pdf_file_path();
|
||||||
}, basename($invoice->pdf_file_path()), ['Cache-Control:' => 'no-cache']);
|
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||||
//return response()->download(TempFile::path($invoice->pdf_file_path()), basename($invoice->pdf_file_path()));
|
|
||||||
break;
|
break;
|
||||||
case 'restore':
|
case 'restore':
|
||||||
$this->invoice_repo->restore($invoice);
|
$this->invoice_repo->restore($invoice);
|
||||||
@ -793,9 +793,10 @@ class InvoiceController extends BaseController
|
|||||||
$contact = $invitation->contact;
|
$contact = $invitation->contact;
|
||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
|
|
||||||
$file_path = $invoice->service()->getInvoicePdf($contact);
|
$file = $invoice->service()->getInvoicePdf($contact);
|
||||||
|
|
||||||
|
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);;
|
||||||
|
|
||||||
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -844,16 +845,11 @@ class InvoiceController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function deliveryNote(ShowInvoiceRequest $request, Invoice $invoice)
|
public function deliveryNote(ShowInvoiceRequest $request, Invoice $invoice)
|
||||||
{
|
{
|
||||||
$file_path = $invoice->service()->getInvoiceDeliveryNote($invoice, $invoice->invitations->first()->contact);
|
|
||||||
|
|
||||||
try {
|
$file = $invoice->service()->getInvoiceDeliveryNote($invoice, $invoice->invitations->first()->contact);
|
||||||
$file = public_path("storage/{$file_path}");
|
|
||||||
|
|
||||||
|
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||||
|
|
||||||
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache']);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return response(['message' => 'Oops, something went wrong. Make sure you have symlink to storage/ in public/ directory.'], 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,6 +107,12 @@ class LicenseController extends BaseController
|
|||||||
'errors' => new stdClass,
|
'errors' => new stdClass,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$account->plan_term = Account::PLAN_TERM_YEARLY;
|
||||||
|
$account->plan_paid = null;
|
||||||
|
$account->plan_expires = null;
|
||||||
|
$account->plan = Account::PLAN_FREE;
|
||||||
|
$account->save();
|
||||||
|
|
||||||
return response()->json($error, 400);
|
return response()->json($error, 400);
|
||||||
} else {
|
} else {
|
||||||
$account = auth()->user()->company()->account;
|
$account = auth()->user()->company()->account;
|
||||||
|
@ -25,7 +25,6 @@ class OneTimeTokenController extends BaseController
|
|||||||
{
|
{
|
||||||
|
|
||||||
private $contexts = [
|
private $contexts = [
|
||||||
'stripe_connect' => 'https://connect.stripe.com/oauth/authorize?response_type=code&client_id=ca_J2Fh2tZfMlaaItUfbUwBBx4JPss8jCz9&scope=read_write'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
|
@ -21,13 +21,18 @@ class PaymentWebhookController extends Controller
|
|||||||
public function __invoke(PaymentWebhookRequest $request, string $company_key, string $company_gateway_id)
|
public function __invoke(PaymentWebhookRequest $request, string $company_key, string $company_gateway_id)
|
||||||
{
|
{
|
||||||
|
|
||||||
MultiDB::findAndSetDbByCompanyKey($company_key);
|
// MultiDB::findAndSetDbByCompanyKey($company_key);
|
||||||
|
|
||||||
$payment = $request->getPayment();
|
$payment = $request->getPayment();
|
||||||
|
|
||||||
|
if(!$payment)
|
||||||
|
return response()->json(['message' => 'Payment record not found.'], 400);
|
||||||
|
|
||||||
$client = is_null($payment) ? $request->getClient() : $payment->client;
|
$client = is_null($payment) ? $request->getClient() : $payment->client;
|
||||||
|
|
||||||
// $contact= $client->primary_contact()->first();
|
if(!$client)
|
||||||
// Auth::guard('contact')->login($contact, true);
|
return response()->json(['message' => 'Client record not found.'], 400);
|
||||||
|
|
||||||
|
|
||||||
return $request->getCompanyGateway()
|
return $request->getCompanyGateway()
|
||||||
->driver($client)
|
->driver($client)
|
||||||
|
@ -125,7 +125,13 @@ class PostMarkController extends BaseController
|
|||||||
$this->invitation->email_status = 'delivered';
|
$this->invitation->email_status = 'delivered';
|
||||||
$this->invitation->save();
|
$this->invitation->save();
|
||||||
|
|
||||||
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_DELIVERY, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client);
|
SystemLogger::dispatch($request->all(),
|
||||||
|
SystemLog::CATEGORY_MAIL,
|
||||||
|
SystemLog::EVENT_MAIL_DELIVERY,
|
||||||
|
SystemLog::TYPE_WEBHOOK_RESPONSE,
|
||||||
|
$this->invitation->contact->client,
|
||||||
|
$this->invitation->company
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
@ -167,7 +173,7 @@ class PostMarkController extends BaseController
|
|||||||
|
|
||||||
LightLogs::create($bounce)->batch();
|
LightLogs::create($bounce)->batch();
|
||||||
|
|
||||||
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client);
|
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company);
|
||||||
}
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
@ -209,7 +215,7 @@ class PostMarkController extends BaseController
|
|||||||
|
|
||||||
LightLogs::create($bounce)->batch();
|
LightLogs::create($bounce)->batch();
|
||||||
|
|
||||||
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client);
|
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function discoverInvitation($message_id)
|
private function discoverInvitation($message_id)
|
||||||
|
@ -99,9 +99,10 @@ class PreviewController extends BaseController
|
|||||||
|
|
||||||
$entity_obj->load('client');
|
$entity_obj->load('client');
|
||||||
|
|
||||||
App::setLocale($entity_obj->client->primary_contact()->preferredLocale());
|
|
||||||
App::forgetInstance('translator');
|
App::forgetInstance('translator');
|
||||||
Lang::replace(Ninja::transformTranslations($entity_obj->client->getMergedSettings()));
|
$t = app('translator');
|
||||||
|
App::setLocale($entity_obj->client->primary_contact()->preferredLocale());
|
||||||
|
$t->replace(Ninja::transformTranslations($entity_obj->client->getMergedSettings()));
|
||||||
|
|
||||||
$html = new HtmlEngine($entity_obj->invitations()->first());
|
$html = new HtmlEngine($entity_obj->invitations()->first());
|
||||||
|
|
||||||
@ -151,7 +152,8 @@ class PreviewController extends BaseController
|
|||||||
private function blankEntity()
|
private function blankEntity()
|
||||||
{
|
{
|
||||||
App::forgetInstance('translator');
|
App::forgetInstance('translator');
|
||||||
Lang::replace(Ninja::transformTranslations(auth()->user()->company()->settings));
|
$t = app('translator');
|
||||||
|
$t->replace(Ninja::transformTranslations(auth()->user()->company()->settings));
|
||||||
|
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
|
|
||||||
|
@ -675,10 +675,10 @@ class QuoteController extends BaseController
|
|||||||
// code...
|
// code...
|
||||||
break;
|
break;
|
||||||
case 'download':
|
case 'download':
|
||||||
return response()->streamDownload(function () use ($quote) {
|
|
||||||
echo file_get_contents($quote->pdf_file_path());
|
$file = $quote->pdf_file_path();
|
||||||
}, basename($quote->pdf_file_path()), ['Cache-Control:' => 'no-cache']);
|
return response()->download($file, basename($file), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||||
//return response()->download(TempFile::path($quote->pdf_file_path()), basename($quote->pdf_file_path()));
|
|
||||||
break;
|
break;
|
||||||
case 'restore':
|
case 'restore':
|
||||||
$this->quote_repo->restore($quote);
|
$this->quote_repo->restore($quote);
|
||||||
@ -730,7 +730,7 @@ class QuoteController extends BaseController
|
|||||||
|
|
||||||
$file_path = $quote->service()->getQuotePdf($contact);
|
$file_path = $quote->service()->getQuotePdf($contact);
|
||||||
|
|
||||||
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache']);
|
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -497,7 +497,7 @@ class RecurringInvoiceController extends BaseController
|
|||||||
|
|
||||||
$file_path = $recurring_invoice->service()->getInvoicePdf($contact);
|
$file_path = $recurring_invoice->service()->getInvoicePdf($contact);
|
||||||
|
|
||||||
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache']);
|
return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,7 +163,7 @@ class SetupController extends Controller
|
|||||||
|
|
||||||
/* Create the first account. */
|
/* Create the first account. */
|
||||||
if (Account::count() == 0) {
|
if (Account::count() == 0) {
|
||||||
CreateAccount::dispatchNow($request->all());
|
CreateAccount::dispatchNow($request->all(), $request->getClientIp());
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionCheck::dispatchNow();
|
VersionCheck::dispatchNow();
|
||||||
@ -275,6 +275,8 @@ class SetupController extends Controller
|
|||||||
|
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
|
// if(Ninja::isHosted())
|
||||||
|
// return redirect('/');
|
||||||
|
|
||||||
// if( Ninja::isNinja() || !request()->has('secret') || (request()->input('secret') != config('ninja.update_secret')) )
|
// if( Ninja::isNinja() || !request()->has('secret') || (request()->input('secret') != config('ninja.update_secret')) )
|
||||||
if(!request()->has('secret') || (request()->input('secret') != config('ninja.update_secret')) )
|
if(!request()->has('secret') || (request()->input('secret') != config('ninja.update_secret')) )
|
||||||
@ -290,6 +292,11 @@ class SetupController extends Controller
|
|||||||
unlink ($cacheServices);
|
unlink ($cacheServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$cacheRoute = base_path('bootstrap/cache/routes-v7.php');
|
||||||
|
if (file_exists($cacheRoute)) {
|
||||||
|
unlink ($cacheRoute);
|
||||||
|
}
|
||||||
|
|
||||||
Artisan::call('clear-compiled');
|
Artisan::call('clear-compiled');
|
||||||
Artisan::call('route:clear');
|
Artisan::call('route:clear');
|
||||||
Artisan::call('view:clear');
|
Artisan::call('view:clear');
|
||||||
|
@ -17,8 +17,11 @@ use App\Factory\CompanyGatewayFactory;
|
|||||||
use App\Http\Requests\StripeConnect\InitializeStripeConnectRequest;
|
use App\Http\Requests\StripeConnect\InitializeStripeConnectRequest;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
|
use App\Models\Company;
|
||||||
use App\Models\CompanyGateway;
|
use App\Models\CompanyGateway;
|
||||||
|
use App\Models\GatewayType;
|
||||||
use App\PaymentDrivers\Stripe\Connect\Account;
|
use App\PaymentDrivers\Stripe\Connect\Account;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Stripe\Exception\ApiErrorException;
|
use Stripe\Exception\ApiErrorException;
|
||||||
|
|
||||||
class StripeConnectController extends BaseController
|
class StripeConnectController extends BaseController
|
||||||
@ -38,6 +41,8 @@ class StripeConnectController extends BaseController
|
|||||||
|
|
||||||
MultiDB::findAndSetDbByCompanyKey($request->getTokenContent()['company_key']);
|
MultiDB::findAndSetDbByCompanyKey($request->getTokenContent()['company_key']);
|
||||||
|
|
||||||
|
$company = Company::where('company_key', $request->getTokenContent()['company_key'])->first();
|
||||||
|
|
||||||
$company_gateway = CompanyGateway::query()
|
$company_gateway = CompanyGateway::query()
|
||||||
->where('gateway_key', 'd14dd26a47cecc30fdd65700bfb67b34')
|
->where('gateway_key', 'd14dd26a47cecc30fdd65700bfb67b34')
|
||||||
->where('company_id', $request->getCompany()->id)
|
->where('company_id', $request->getCompany()->id)
|
||||||
@ -45,53 +50,84 @@ class StripeConnectController extends BaseController
|
|||||||
|
|
||||||
if ($company_gateway) {
|
if ($company_gateway) {
|
||||||
|
|
||||||
$config = decrypt($company_gateway->config);
|
$config = $company_gateway->getConfig();
|
||||||
|
|
||||||
if(property_exists($config, 'account_id'))
|
if(property_exists($config, 'account_id'))
|
||||||
return render('gateways.stripe.connect.existing');
|
return view('auth.connect.existing');
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
$company_gateway = CompanyGatewayFactory::create($request->getCompany()->id, $request->getContact()->id);
|
|
||||||
|
|
||||||
/* Set Credit Card To Enabled */
|
$stripe_client_id = config('ninja.ninja_stripe_client_id');
|
||||||
$gateway_types = $company_gateway->driver(new Client)->gatewayTypes();
|
$redirect_uri = 'https://invoicing.co/stripe/completed';
|
||||||
$fees_and_limits = new \stdClass;
|
$endpoint = "https://connect.stripe.com/oauth/authorize?response_type=code&client_id={$stripe_client_id}&redirect_uri={$redirect_uri}&scope=read_write&state={$token}";
|
||||||
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
|
|
||||||
|
|
||||||
$company_gateway->gateway_key = 'd14dd26a47cecc30fdd65700bfb67b34';
|
// if($email = $request->getContact()->email)
|
||||||
$company_gateway->fees_and_limits = $fees_and_limits;
|
// $endpoint .= "&stripe_user[email]={$email}";
|
||||||
$company_gateway->save();
|
|
||||||
|
|
||||||
/* Link account if existing account exists */
|
// $company_name = str_replace(" ", "_", $company->present()->name());
|
||||||
if($account_id = $this->checkAccountAlreadyLinkToEmail($company_gateway, $request->getContact()->email)) {
|
// $endpoint .= "&stripe_user[business_name]={$company_name}";
|
||||||
|
|
||||||
$config = json_decode(decrypt($company_gateway->config));
|
return redirect($endpoint);
|
||||||
|
|
||||||
$config->account_id = $account_id;
|
|
||||||
$company_gateway->config = encrypt(json_encode($config));
|
|
||||||
$company_gateway->save();
|
|
||||||
|
|
||||||
return render('gateways.stripe.connect.existing');
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'type' => 'standard',
|
|
||||||
'email' => $request->getContact()->email,
|
|
||||||
'country' => $request->getCompany()->country()->iso_3166_2,
|
|
||||||
];
|
|
||||||
|
|
||||||
$account = Account::create($data);
|
|
||||||
$link = Account::link($account->id, $token);
|
|
||||||
$company_gateway->config = encrypt(json_encode(['account_id' => $account->id]));
|
|
||||||
$company_gateway->save();
|
|
||||||
|
|
||||||
return redirect($link['url']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function completed()
|
public function completed(InitializeStripeConnectRequest $request)
|
||||||
{
|
{
|
||||||
return render('gateways.stripe.connect.completed');
|
|
||||||
|
\Stripe\Stripe::setApiKey(config('ninja.ninja_stripe_key'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = \Stripe\OAuth::token([
|
||||||
|
'grant_type' => 'authorization_code',
|
||||||
|
'code' => $request->input('code'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
}catch(\Exception $e)
|
||||||
|
{
|
||||||
|
|
||||||
|
nlog($e->getMessage());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// nlog($response);
|
||||||
|
|
||||||
|
$company = Company::where('company_key', $request->getTokenContent()['company_key'])->first();
|
||||||
|
|
||||||
|
$company_gateway = CompanyGatewayFactory::create($company->id, $company->owner()->id);
|
||||||
|
$fees_and_limits = new \stdClass;
|
||||||
|
$fees_and_limits->{GatewayType::CREDIT_CARD} = new FeesAndLimits;
|
||||||
|
$company_gateway->gateway_key = 'd14dd26a47cecc30fdd65700bfb67b34';
|
||||||
|
$company_gateway->fees_and_limits = $fees_and_limits;
|
||||||
|
$company_gateway->setConfig([]);
|
||||||
|
// $company_gateway->save();
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'account_id' => $response->stripe_user_id,
|
||||||
|
"token_type" => 'bearer',
|
||||||
|
"stripe_publishable_key" => $response->stripe_publishable_key,
|
||||||
|
"scope" => $response->scope,
|
||||||
|
"livemode" => $response->livemode,
|
||||||
|
"stripe_user_id" => $response->stripe_user_id,
|
||||||
|
"refresh_token" => $response->refresh_token,
|
||||||
|
"access_token" => $response->access_token
|
||||||
|
];
|
||||||
|
|
||||||
|
/* Link account if existing account exists */
|
||||||
|
// if($account_id = $this->checkAccountAlreadyLinkToEmail($company_gateway, $request->getContact()->email)) {
|
||||||
|
|
||||||
|
// $payload['account_id'] = $account_id;
|
||||||
|
// $payload['stripe_user_id'] = $account_id;
|
||||||
|
// $company_gateway->setConfig($payload);
|
||||||
|
// $company_gateway->save();
|
||||||
|
|
||||||
|
// return view('auth.connect.existing');
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
$company_gateway->setConfig($payload);
|
||||||
|
$company_gateway->save();
|
||||||
|
|
||||||
|
//response here
|
||||||
|
return view('auth.connect.completed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -111,4 +147,22 @@ class StripeConnectController extends BaseController
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* Stripe OAuth
|
||||||
|
*/
|
||||||
|
|
||||||
|
// public function initialize(InitializeStripeConnectRequest $request, string $token)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// $stripe_key = config('ninja.ninja_stripe_key');
|
||||||
|
|
||||||
|
// $endpoint = "https://connect.stripe.com/oauth/authorize?response_type=code&client_id={$stripe_key}&scope=read_write";
|
||||||
|
|
||||||
|
// return redirect($endpoint);
|
||||||
|
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
52
app/Http/Controllers/StripeController.php
Normal file
52
app/Http/Controllers/StripeController.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Jobs\Util\ImportStripeCustomers;
|
||||||
|
use App\Jobs\Util\StripeUpdatePaymentMethods;
|
||||||
|
|
||||||
|
class StripeController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
if(auth()->user()->isAdmin())
|
||||||
|
{
|
||||||
|
|
||||||
|
StripeUpdatePaymentMethods::dispatch(auth()->user()->company());
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Processing'], 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Unauthorized'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function import()
|
||||||
|
{
|
||||||
|
|
||||||
|
if(auth()->user()->isAdmin())
|
||||||
|
{
|
||||||
|
|
||||||
|
ImportStripeCustomers::dispatch(auth()->user()->company());
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Processing'], 200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Unauthorized'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -41,7 +41,7 @@ class SubdomainController extends BaseController
|
|||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
|
||||||
if(in_array(request()->input('subdomain'), $this->protected) || MultiDB::findAndSetDbByDomain(request()->input('subdomain')))
|
if(in_array(request()->input('subdomain'), $this->protected) || MultiDB::findAndSetDbByDomain(['subdomain' => request()->input('subdomain')]))
|
||||||
return response()->json(['message' => 'Domain not available'] , 401);
|
return response()->json(['message' => 'Domain not available'] , 401);
|
||||||
|
|
||||||
return response()->json(['message' => 'Domain available'], 200);
|
return response()->json(['message' => 'Domain available'], 200);
|
||||||
|
@ -631,6 +631,7 @@ class TaskController extends BaseController
|
|||||||
|
|
||||||
$task_status = TaskStatus::where('id', $this->decodePrimaryKey($task_status_hashed_id))
|
$task_status = TaskStatus::where('id', $this->decodePrimaryKey($task_status_hashed_id))
|
||||||
->where('company_id', auth()->user()->company()->id)
|
->where('company_id', auth()->user()->company()->id)
|
||||||
|
->withTrashed()
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
$task_status->status_order = $key;
|
$task_status->status_order = $key;
|
||||||
@ -643,19 +644,14 @@ class TaskController extends BaseController
|
|||||||
|
|
||||||
$sort_status_id = $this->decodePrimaryKey($key);
|
$sort_status_id = $this->decodePrimaryKey($key);
|
||||||
|
|
||||||
// nlog($task_list);
|
|
||||||
|
|
||||||
foreach ($task_list as $key => $task)
|
foreach ($task_list as $key => $task)
|
||||||
{
|
{
|
||||||
|
|
||||||
// nlog($task);
|
|
||||||
|
|
||||||
$task_record = Task::where('id', $this->decodePrimaryKey($task))
|
$task_record = Task::where('id', $this->decodePrimaryKey($task))
|
||||||
->where('company_id', auth()->user()->company()->id)
|
->where('company_id', auth()->user()->company()->id)
|
||||||
|
->withTrashed()
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
// nlog($task_record->id);
|
|
||||||
|
|
||||||
$task_record->status_order = $key;
|
$task_record->status_order = $key;
|
||||||
$task_record->status_id = $sort_status_id;
|
$task_record->status_id = $sort_status_id;
|
||||||
$task_record->save();
|
$task_record->save();
|
||||||
@ -663,6 +659,6 @@ class TaskController extends BaseController
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(['message' => 'Ok'],200);
|
return response()->json(['message' => 'Ok'], 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,11 @@ class UserController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function __construct(UserRepository $user_repo)
|
public function __construct(UserRepository $user_repo)
|
||||||
{
|
{
|
||||||
|
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$this->user_repo = $user_repo;
|
$this->user_repo = $user_repo;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -209,11 +211,12 @@ class UserController extends BaseController
|
|||||||
|
|
||||||
$ct = CreateCompanyToken::dispatchNow($company, $user, $user_agent);
|
$ct = CreateCompanyToken::dispatchNow($company, $user, $user_agent);
|
||||||
|
|
||||||
nlog("in the store method of the usercontroller class");
|
|
||||||
|
|
||||||
event(new UserWasCreated($user, auth()->user(), $company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
event(new UserWasCreated($user, auth()->user(), $company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||||
|
|
||||||
return $this->itemResponse($user->fresh());
|
$user->setCompany($company);
|
||||||
|
$user->company_id = $company->id;
|
||||||
|
|
||||||
|
return $this->itemResponse($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -376,7 +379,6 @@ class UserController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function update(UpdateUserRequest $request, User $user)
|
public function update(UpdateUserRequest $request, User $user)
|
||||||
{
|
{
|
||||||
|
|
||||||
$old_company_user = $user->company_user;
|
$old_company_user = $user->company_user;
|
||||||
$old_user = json_encode($user);
|
$old_user = json_encode($user);
|
||||||
$old_user_email = $user->getOriginal('email');
|
$old_user_email = $user->getOriginal('email');
|
||||||
|
@ -16,6 +16,7 @@ use App\Http\Middleware\Authenticate;
|
|||||||
use App\Http\Middleware\CheckClientExistence;
|
use App\Http\Middleware\CheckClientExistence;
|
||||||
use App\Http\Middleware\CheckForMaintenanceMode;
|
use App\Http\Middleware\CheckForMaintenanceMode;
|
||||||
use App\Http\Middleware\ClientPortalEnabled;
|
use App\Http\Middleware\ClientPortalEnabled;
|
||||||
|
use App\Http\Middleware\ContactAccount;
|
||||||
use App\Http\Middleware\ContactKeyLogin;
|
use App\Http\Middleware\ContactKeyLogin;
|
||||||
use App\Http\Middleware\ContactRegister;
|
use App\Http\Middleware\ContactRegister;
|
||||||
use App\Http\Middleware\ContactSetDb;
|
use App\Http\Middleware\ContactSetDb;
|
||||||
@ -110,7 +111,6 @@ class Kernel extends HttpKernel
|
|||||||
ShareErrorsFromSession::class,
|
ShareErrorsFromSession::class,
|
||||||
VerifyCsrfToken::class,
|
VerifyCsrfToken::class,
|
||||||
SubstituteBindings::class,
|
SubstituteBindings::class,
|
||||||
//\App\Http\Middleware\StartupCheck::class,
|
|
||||||
QueryLogging::class,
|
QueryLogging::class,
|
||||||
],
|
],
|
||||||
'shop' => [
|
'shop' => [
|
||||||
@ -142,6 +142,7 @@ class Kernel extends HttpKernel
|
|||||||
'api_secret_check' => ApiSecretCheck::class,
|
'api_secret_check' => ApiSecretCheck::class,
|
||||||
'contact_token_auth' => ContactTokenAuth::class,
|
'contact_token_auth' => ContactTokenAuth::class,
|
||||||
'contact_db' => ContactSetDb::class,
|
'contact_db' => ContactSetDb::class,
|
||||||
|
'contact_account' => ContactAccount::class,
|
||||||
'domain_db' => SetDomainNameDb::class,
|
'domain_db' => SetDomainNameDb::class,
|
||||||
'email_db' => SetEmailDb::class,
|
'email_db' => SetEmailDb::class,
|
||||||
'invite_db' => SetInviteDb::class,
|
'invite_db' => SetInviteDb::class,
|
||||||
@ -160,4 +161,29 @@ class Kernel extends HttpKernel
|
|||||||
'check_client_existence' => CheckClientExistence::class,
|
'check_client_existence' => CheckClientExistence::class,
|
||||||
'user_verified' => UserVerified::class,
|
'user_verified' => UserVerified::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
protected $middlewarePriority = [
|
||||||
|
SetDomainNameDb::class,
|
||||||
|
SetDb::class,
|
||||||
|
SetWebDb::class,
|
||||||
|
UrlSetDb::class,
|
||||||
|
ContactSetDb::class,
|
||||||
|
SetEmailDb::class,
|
||||||
|
SetInviteDb::class,
|
||||||
|
SetDbByCompanyKey::class,
|
||||||
|
TokenAuth::class,
|
||||||
|
ContactTokenAuth::class,
|
||||||
|
ContactKeyLogin::class,
|
||||||
|
Authenticate::class,
|
||||||
|
ShopTokenAuth::class,
|
||||||
|
ContactRegister::class,
|
||||||
|
PhantomSecret::class,
|
||||||
|
CheckClientExistence::class,
|
||||||
|
ClientPortalEnabled::class,
|
||||||
|
PasswordProtection::class,
|
||||||
|
Locale::class,
|
||||||
|
SubstituteBindings::class,
|
||||||
|
ContactAccount::class,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -181,14 +181,16 @@ class BillingPortalPurchase extends Component
|
|||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
|
|
||||||
$contact = ClientContact::where('email', $this->email)->first();
|
$contact = ClientContact::where('email', $this->email)
|
||||||
|
->where('company_id', $this->subscription->company_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
if ($contact && $this->steps['existing_user'] === false) {
|
if ($contact && $this->steps['existing_user'] === false) {
|
||||||
return $this->steps['existing_user'] = true;
|
return $this->steps['existing_user'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($contact && $this->steps['existing_user']) {
|
if ($contact && $this->steps['existing_user']) {
|
||||||
$attempt = Auth::guard('contact')->attempt(['email' => $this->email, 'password' => $this->password]);
|
$attempt = Auth::guard('contact')->attempt(['email' => $this->email, 'password' => $this->password, 'company_id' => $this->subscription->company_id]);
|
||||||
|
|
||||||
return $attempt
|
return $attempt
|
||||||
? $this->getPaymentMethods($contact)
|
? $this->getPaymentMethods($contact)
|
||||||
|
@ -9,6 +9,7 @@ class NameWebsiteLogo extends Component
|
|||||||
public $profile;
|
public $profile;
|
||||||
|
|
||||||
public $name;
|
public $name;
|
||||||
|
public $vat_number;
|
||||||
public $website;
|
public $website;
|
||||||
public $phone;
|
public $phone;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ class NameWebsiteLogo extends Component
|
|||||||
|
|
||||||
public $rules = [
|
public $rules = [
|
||||||
'name' => ['sometimes', 'min:3'],
|
'name' => ['sometimes', 'min:3'],
|
||||||
|
'vat_number' => ['sometimes'],
|
||||||
'website' => ['sometimes'],
|
'website' => ['sometimes'],
|
||||||
'phone' => ['sometimes', 'string', 'max:255'],
|
'phone' => ['sometimes', 'string', 'max:255'],
|
||||||
];
|
];
|
||||||
@ -25,6 +27,7 @@ class NameWebsiteLogo extends Component
|
|||||||
$this->fill([
|
$this->fill([
|
||||||
'profile' => auth()->user('contact')->client,
|
'profile' => auth()->user('contact')->client,
|
||||||
'name' => auth()->user('contact')->client->present()->name,
|
'name' => auth()->user('contact')->client->present()->name,
|
||||||
|
'vat_number' => auth()->user('contact')->client->present()->vat_number,
|
||||||
'website' => auth()->user('contact')->client->present()->website,
|
'website' => auth()->user('contact')->client->present()->website,
|
||||||
'phone' => auth()->user('contact')->client->present()->phone,
|
'phone' => auth()->user('contact')->client->present()->phone,
|
||||||
'saved' => ctrans('texts.save'),
|
'saved' => ctrans('texts.save'),
|
||||||
@ -41,6 +44,7 @@ class NameWebsiteLogo extends Component
|
|||||||
$data = $this->validate($this->rules);
|
$data = $this->validate($this->rules);
|
||||||
|
|
||||||
$this->profile->name = $data['name'];
|
$this->profile->name = $data['name'];
|
||||||
|
$this->profile->vat_number = $data['vat_number'];
|
||||||
$this->profile->website = $data['website'];
|
$this->profile->website = $data['website'];
|
||||||
$this->profile->phone = $data['phone'];
|
$this->profile->phone = $data['phone'];
|
||||||
|
|
||||||
|
39
app/Http/Livewire/TasksTable.php
Normal file
39
app/Http/Livewire/TasksTable.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Livewire;
|
||||||
|
|
||||||
|
use App\Models\Task;
|
||||||
|
use App\Utils\Traits\WithSorting;
|
||||||
|
use Livewire\Component;
|
||||||
|
use Livewire\WithPagination;
|
||||||
|
|
||||||
|
class TasksTable extends Component
|
||||||
|
{
|
||||||
|
use WithSorting;
|
||||||
|
use WithPagination;
|
||||||
|
|
||||||
|
public $per_page = 10;
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
$query = Task::query()
|
||||||
|
->where('client_id', auth('contact')->user()->client->id)
|
||||||
|
->whereNotNull('invoice_id')
|
||||||
|
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||||
|
->paginate($this->per_page);
|
||||||
|
|
||||||
|
return render('components.livewire.tasks-table', [
|
||||||
|
'tasks' => $query,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Utils\Ninja;
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
@ -26,7 +27,7 @@ class ApiSecretCheck
|
|||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
if (! config('ninja.api_secret')) {
|
if (! config('ninja.api_secret') || Ninja::isHosted()) {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ class CheckClientExistence
|
|||||||
$multiple_contacts = ClientContact::query()
|
$multiple_contacts = ClientContact::query()
|
||||||
->where('email', auth('contact')->user()->email)
|
->where('email', auth('contact')->user()->email)
|
||||||
->whereNotNull('email')
|
->whereNotNull('email')
|
||||||
|
->where('email', '<>', '')
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->distinct('company_id')
|
->distinct('company_id')
|
||||||
->distinct('email')
|
->distinct('email')
|
||||||
@ -38,6 +39,9 @@ class CheckClientExistence
|
|||||||
->whereHas('client', function ($query) {
|
->whereHas('client', function ($query) {
|
||||||
return $query->whereNull('deleted_at');
|
return $query->whereNull('deleted_at');
|
||||||
})
|
})
|
||||||
|
->whereHas('client.company', function ($query){
|
||||||
|
return $query->where('account_id', auth('contact')->user()->client->company->account->id);
|
||||||
|
})
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
if (count($multiple_contacts) == 0) {
|
if (count($multiple_contacts) == 0) {
|
||||||
|
41
app/Http/Middleware/ContactAccount.php
Normal file
41
app/Http/Middleware/ContactAccount.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ContactAccount
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(!Ninja::isHosted()) {
|
||||||
|
|
||||||
|
$account_id = Account::first()->id;
|
||||||
|
$request->attributes->add(['account_id' => $account_id]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ use Auth;
|
|||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class ContactKeyLogin
|
class ContactKeyLogin
|
||||||
{
|
{
|
||||||
@ -42,13 +43,20 @@ class ContactKeyLogin
|
|||||||
if (MultiDB::findAndSetDbByContactKey($request->segment(3))) {
|
if (MultiDB::findAndSetDbByContactKey($request->segment(3))) {
|
||||||
|
|
||||||
if($client_contact = ClientContact::where('contact_key', $request->segment(3))->first()){
|
if($client_contact = ClientContact::where('contact_key', $request->segment(3))->first()){
|
||||||
auth()->guard('contact')->login($client_contact, true);
|
if(empty($client_contact->email))
|
||||||
|
$client_contact->email = Str::random(6) . "@example.com"; $client_contact->save();
|
||||||
|
|
||||||
|
Auth::guard('contact')->login($client_contact, true);
|
||||||
return redirect()->to('client/dashboard');
|
return redirect()->to('client/dashboard');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} elseif ($request->segment(2) && $request->segment(2) == 'key_login' && $request->segment(3)) {
|
} elseif ($request->segment(2) && $request->segment(2) == 'key_login' && $request->segment(3)) {
|
||||||
if ($client_contact = ClientContact::where('contact_key', $request->segment(3))->first()) {
|
if ($client_contact = ClientContact::where('contact_key', $request->segment(3))->first()) {
|
||||||
|
|
||||||
|
if(empty($client_contact->email))
|
||||||
|
$client_contact->email = Str::random(6) . "@example.com"; $client_contact->save();
|
||||||
|
|
||||||
auth()->guard('contact')->login($client_contact, true);
|
auth()->guard('contact')->login($client_contact, true);
|
||||||
return redirect()->to('client/dashboard');
|
return redirect()->to('client/dashboard');
|
||||||
}
|
}
|
||||||
@ -56,19 +64,36 @@ class ContactKeyLogin
|
|||||||
if (MultiDB::findAndSetDbByClientHash($request->input('client_hash'))) {
|
if (MultiDB::findAndSetDbByClientHash($request->input('client_hash'))) {
|
||||||
|
|
||||||
if($client = Client::where('client_hash', $request->input('client_hash'))->first()){
|
if($client = Client::where('client_hash', $request->input('client_hash'))->first()){
|
||||||
auth()->guard('contact')->login($client->primary_contact()->first(), true);
|
|
||||||
|
$primary_contact = $client->primary_contact()->first();
|
||||||
|
|
||||||
|
if(empty($primary_contact->email))
|
||||||
|
$primary_contact->email = Str::random(6) . "@example.com"; $primary_contact->save();
|
||||||
|
|
||||||
|
auth()->guard('contact')->login($primary_contact, true);
|
||||||
return redirect()->to('client/dashboard');
|
return redirect()->to('client/dashboard');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($request->has('client_hash')) {
|
} elseif ($request->has('client_hash')) {
|
||||||
if ($client = Client::where('client_hash', $request->input('client_hash'))->first()) {
|
if ($client = Client::where('client_hash', $request->input('client_hash'))->first()) {
|
||||||
Auth::guard('contact')->login($client->primary_contact()->first(), true);
|
|
||||||
|
$primary_contact = $client->primary_contact()->first();
|
||||||
|
|
||||||
|
if(empty($primary_contact->email))
|
||||||
|
$primary_contact->email = Str::random(6) . "@example.com"; $primary_contact->save();
|
||||||
|
|
||||||
|
auth()->guard('contact')->login($primary_contact, true);
|
||||||
|
|
||||||
return redirect()->to('client/dashboard');
|
return redirect()->to('client/dashboard');
|
||||||
}
|
}
|
||||||
} elseif ($request->segment(2) && $request->segment(2) == 'magic_link' && $request->segment(3)) {
|
} elseif ($request->segment(2) && $request->segment(2) == 'magic_link' && $request->segment(3)) {
|
||||||
$contact_email = Cache::get($request->segment(3));
|
$contact_email = Cache::get($request->segment(3));
|
||||||
if($client_contact = ClientContact::where('email', $contact_email)->first()){
|
if($client_contact = ClientContact::where('email', $contact_email)->first()){
|
||||||
Auth::guard('contact')->login($client_contact, true);
|
|
||||||
|
if(empty($client_contact->email))
|
||||||
|
$client_contact->email = Str::random(6) . "@example.com"; $client_contact->save();
|
||||||
|
|
||||||
|
auth()->guard('contact')->login($client_contact, true);
|
||||||
|
|
||||||
if ($request->query('redirect') && !empty($request->query('redirect'))) {
|
if ($request->query('redirect') && !empty($request->query('redirect'))) {
|
||||||
return redirect()->to($request->query('redirect'));
|
return redirect()->to($request->query('redirect'));
|
||||||
|
@ -52,6 +52,6 @@ class ContactRegister
|
|||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
return abort(404);
|
abort(404, 'ContactRegister Middlware');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,9 +44,9 @@ class PasswordProtection
|
|||||||
else
|
else
|
||||||
$timeout = $timeout/1000;
|
$timeout = $timeout/1000;
|
||||||
|
|
||||||
if (Cache::get(auth()->user()->hashed_id.'_logged_in')) {
|
if (Cache::get(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in')) {
|
||||||
|
|
||||||
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
|
||||||
@ -68,12 +68,13 @@ class PasswordProtection
|
|||||||
//If OAuth and user also has a password set - check both
|
//If OAuth and user also has a password set - check both
|
||||||
if ($existing_user = MultiDB::hasUser($query) && auth()->user()->has_password && Hash::check(auth()->user()->password, $request->header('X-API-PASSWORD'))) {
|
if ($existing_user = MultiDB::hasUser($query) && auth()->user()->has_password && Hash::check(auth()->user()->password, $request->header('X-API-PASSWORD'))) {
|
||||||
|
|
||||||
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
elseif($existing_user = MultiDB::hasUser($query) && !auth()->user()->has_password){
|
elseif($existing_user = MultiDB::hasUser($query) && !auth()->user()->has_password){
|
||||||
|
|
||||||
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +84,7 @@ class PasswordProtection
|
|||||||
|
|
||||||
}elseif ($request->header('X-API-PASSWORD') && Hash::check($request->header('X-API-PASSWORD'), auth()->user()->password)) {
|
}elseif ($request->header('X-API-PASSWORD') && Hash::check($request->header('X-API-PASSWORD'), auth()->user()->password)) {
|
||||||
|
|
||||||
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
|
|
||||||
|
@ -34,14 +34,16 @@ class RedirectIfAuthenticated
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'user':
|
case 'user':
|
||||||
if (Auth::guard($guard)->check()) {
|
Auth::logout();
|
||||||
return redirect()->route('dashboard.index');
|
// if (Auth::guard($guard)->check()) {
|
||||||
}
|
// return redirect()->route('dashboard.index');
|
||||||
|
// }
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (Auth::guard($guard)->check()) {
|
Auth::logout();
|
||||||
return redirect('/');
|
// if (Auth::guard($guard)->check()) {
|
||||||
}
|
// return redirect('/');
|
||||||
|
// }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ class SetDb
|
|||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
|
|
||||||
$error = [
|
$error = [
|
||||||
'message' => 'Invalid Token',
|
'message' => 'Invalid Token',
|
||||||
'errors' => new stdClass,
|
'errors' => new stdClass,
|
||||||
|
@ -34,13 +34,58 @@ class SetDomainNameDb
|
|||||||
/*
|
/*
|
||||||
* Use the host name to set the active DB
|
* Use the host name to set the active DB
|
||||||
**/
|
**/
|
||||||
if ($request->getSchemeAndHttpHost() && config('ninja.db.multi_db_enabled') && ! MultiDB::findAndSetDbByDomain($request->getSchemeAndHttpHost())) {
|
|
||||||
if (request()->json) {
|
if(!config('ninja.db.multi_db_enabled'))
|
||||||
return response()->json($error, 403);
|
return $next($request);
|
||||||
} else {
|
|
||||||
abort(404);
|
|
||||||
|
if (strpos($request->getHost(), 'invoicing.co') !== false)
|
||||||
|
{
|
||||||
|
$subdomain = explode('.', $request->getHost())[0];
|
||||||
|
|
||||||
|
$query = [
|
||||||
|
'subdomain' => $subdomain,
|
||||||
|
'portal_mode' => 'subdomain',
|
||||||
|
];
|
||||||
|
|
||||||
|
if($company = MultiDB::findAndSetDbByDomain($query)){
|
||||||
|
$request->attributes->add(['account_id' => $company->account_id]);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($request->json) {
|
||||||
|
return response()->json($error, 403);
|
||||||
|
} else {
|
||||||
|
MultiDB::setDb('db-ninja-01');
|
||||||
|
nlog("I could not set the DB - defaulting to DB1");
|
||||||
|
//abort(400, 'Domain not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
$query = [
|
||||||
|
'portal_domain' => $request->getSchemeAndHttpHost(),
|
||||||
|
'portal_mode' => 'domain',
|
||||||
|
];
|
||||||
|
|
||||||
|
if($company = MultiDB::findAndSetDbByDomain($query)){
|
||||||
|
$request->attributes->add(['account_id' => $company->account_id]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($request->json) {
|
||||||
|
return response()->json($error, 403);
|
||||||
|
} else {
|
||||||
|
MultiDB::setDb('db-ninja-01');
|
||||||
|
nlog("I could not set the DB - defaulting to DB1");
|
||||||
|
//abort(400, 'Domain not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
@ -34,15 +34,10 @@ class SetEmailDb
|
|||||||
|
|
||||||
if ($request->input('email') && config('ninja.db.multi_db_enabled')) {
|
if ($request->input('email') && config('ninja.db.multi_db_enabled')) {
|
||||||
|
|
||||||
|
|
||||||
if (! MultiDB::userFindAndSetDb($request->input('email')))
|
if (! MultiDB::userFindAndSetDb($request->input('email')))
|
||||||
return response()->json($error, 400);
|
return response()->json($error, 400);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// else {
|
|
||||||
// return response()->json($error, 403);
|
|
||||||
// }
|
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ class SetInviteDb
|
|||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
$error = [
|
$error = [
|
||||||
'message' => 'Invalid URL',
|
'message' => 'I could not find the database for this object.',
|
||||||
'errors' => new stdClass,
|
'errors' => new stdClass,
|
||||||
];
|
];
|
||||||
/*
|
/*
|
||||||
@ -46,7 +46,7 @@ class SetInviteDb
|
|||||||
if (request()->json) {
|
if (request()->json) {
|
||||||
return response()->json($error, 403);
|
return response()->json($error, 403);
|
||||||
} else {
|
} else {
|
||||||
abort(404);
|
abort(404,'I could not find the database for this object.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ class TokenAuth
|
|||||||
| us to decouple a $user and their attached companies completely.
|
| us to decouple a $user and their attached companies completely.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
$user->setCompany($company_token->company);
|
|
||||||
|
|
||||||
app('queue')->createPayloadUsing(function () use ($company_token) {
|
app('queue')->createPayloadUsing(function () use ($company_token) {
|
||||||
return ['db' => $company_token->company->db];
|
return ['db' => $company_token->company->db];
|
||||||
@ -67,6 +66,7 @@ class TokenAuth
|
|||||||
|
|
||||||
//stateless, don't remember the user.
|
//stateless, don't remember the user.
|
||||||
auth()->login($user, false);
|
auth()->login($user, false);
|
||||||
|
auth()->user()->setCompany($company_token->company);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$error = [
|
$error = [
|
||||||
|
@ -40,13 +40,13 @@ class CreateAccountRequest extends Request
|
|||||||
'password' => 'required|string|min:6',
|
'password' => 'required|string|min:6',
|
||||||
'email' => 'bail|required|email:rfc,dns',
|
'email' => 'bail|required|email:rfc,dns',
|
||||||
'email' => new NewUniqueUserRule(),
|
'email' => new NewUniqueUserRule(),
|
||||||
'privacy_policy' => 'required',
|
'privacy_policy' => 'required|boolean',
|
||||||
'terms_of_service' => 'required',
|
'terms_of_service' => 'required|boolean',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function prepareForValidation()
|
protected function prepareForValidation()
|
||||||
{
|
{nlog($this->all());
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
$input['user_agent'] = request()->server('HTTP_USER_AGENT');
|
$input['user_agent'] = request()->server('HTTP_USER_AGENT');
|
||||||
|
55
app/Http/Requests/Client/AdjustClientLedgerRequest.php
Normal file
55
app/Http/Requests/Client/AdjustClientLedgerRequest.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Client;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class AdjustClientLedgerRequest extends Request
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('edit', $this->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
/* Ensure we have a client name, and that all emails are unique*/
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -53,6 +53,6 @@ class RegisterRequest extends FormRequest
|
|||||||
return $company;
|
return $company;
|
||||||
}
|
}
|
||||||
|
|
||||||
abort(404);
|
abort(404, 'Register request not found.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
app/Http/Requests/ClientPortal/Tasks/ShowTasksRequest.php
Normal file
30
app/Http/Requests/ClientPortal/Tasks/ShowTasksRequest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\ClientPortal\Tasks;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class ShowTasksRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return (bool)auth()->user('contact')->client->getSetting('enable_client_portal_tasks');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -14,8 +14,10 @@ namespace App\Http\Requests\Company;
|
|||||||
use App\DataMapper\CompanySettings;
|
use App\DataMapper\CompanySettings;
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
use App\Http\ValidationRules\Company\ValidCompanyQuantity;
|
use App\Http\ValidationRules\Company\ValidCompanyQuantity;
|
||||||
|
use App\Http\ValidationRules\Company\ValidSubdomain;
|
||||||
use App\Http\ValidationRules\ValidSettingsRule;
|
use App\Http\ValidationRules\ValidSettingsRule;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
class StoreCompanyRequest extends Request
|
class StoreCompanyRequest extends Request
|
||||||
@ -45,7 +47,13 @@ class StoreCompanyRequest extends Request
|
|||||||
if (isset($input['portal_mode']) && ($input['portal_mode'] == 'domain' || $input['portal_mode'] == 'iframe')) {
|
if (isset($input['portal_mode']) && ($input['portal_mode'] == 'domain' || $input['portal_mode'] == 'iframe')) {
|
||||||
$rules['portal_domain'] = 'sometimes|url';
|
$rules['portal_domain'] = 'sometimes|url';
|
||||||
} else {
|
} else {
|
||||||
$rules['subdomain'] = 'nullable|alpha_num';
|
|
||||||
|
if(Ninja::isHosted()){
|
||||||
|
$rules['subdomain'] = ['nullable', 'alpha_num', new ValidSubdomain($this->all())];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$rules['subdomain'] = 'nullable|alpha_num';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
@ -55,8 +63,9 @@ class StoreCompanyRequest extends Request
|
|||||||
{
|
{
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
if(array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1)
|
//https not sure i should be forcing this.
|
||||||
$input['portal_domain'] = str_replace("http:", "https:", $input['portal_domain']);
|
// if(array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1)
|
||||||
|
// $input['portal_domain'] = str_replace("http:", "https:", $input['portal_domain']);
|
||||||
|
|
||||||
if (array_key_exists('google_analytics_url', $input)) {
|
if (array_key_exists('google_analytics_url', $input)) {
|
||||||
$input['google_analytics_key'] = $input['google_analytics_url'];
|
$input['google_analytics_key'] = $input['google_analytics_url'];
|
||||||
|
@ -13,7 +13,9 @@ namespace App\Http\Requests\Company;
|
|||||||
|
|
||||||
use App\DataMapper\CompanySettings;
|
use App\DataMapper\CompanySettings;
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
|
use App\Http\ValidationRules\Company\ValidSubdomain;
|
||||||
use App\Http\ValidationRules\ValidSettingsRule;
|
use App\Http\ValidationRules\ValidSettingsRule;
|
||||||
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
class UpdateCompanyRequest extends Request
|
class UpdateCompanyRequest extends Request
|
||||||
@ -46,7 +48,12 @@ class UpdateCompanyRequest extends Request
|
|||||||
if (isset($input['portal_mode']) && ($input['portal_mode'] == 'domain' || $input['portal_mode'] == 'iframe')) {
|
if (isset($input['portal_mode']) && ($input['portal_mode'] == 'domain' || $input['portal_mode'] == 'iframe')) {
|
||||||
$rules['portal_domain'] = 'sometimes|url';
|
$rules['portal_domain'] = 'sometimes|url';
|
||||||
} else {
|
} else {
|
||||||
$rules['subdomain'] = 'nullable|alpha_num';
|
|
||||||
|
if(Ninja::isHosted()){
|
||||||
|
$rules['subdomain'] = ['nullable', 'alpha_num', new ValidSubdomain($this->all())];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$rules['subdomain'] = 'nullable|alpha_num';
|
||||||
}
|
}
|
||||||
|
|
||||||
// if($this->company->account->isPaidHostedClient()) {
|
// if($this->company->account->isPaidHostedClient()) {
|
||||||
@ -60,8 +67,8 @@ class UpdateCompanyRequest extends Request
|
|||||||
{
|
{
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
if(array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1)
|
// if(array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1)
|
||||||
$input['portal_domain'] = str_replace("http:", "https:", $input['portal_domain']);
|
// $input['portal_domain'] = str_replace("http:", "https:", $input['portal_domain']);
|
||||||
|
|
||||||
if (array_key_exists('settings', $input)) {
|
if (array_key_exists('settings', $input)) {
|
||||||
$input['settings'] = $this->filterSaveableSettings($input['settings']);
|
$input['settings'] = $this->filterSaveableSettings($input['settings']);
|
||||||
|
39
app/Http/Requests/Export/StoreExportRequest.php
Normal file
39
app/Http/Requests/Export/StoreExportRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Export;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class StoreExportRequest extends Request
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Requests/Import/ImportJsonRequest.php
Normal file
39
app/Http/Requests/Import/ImportJsonRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Import;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class ImportJsonRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
// 'import_type' => 'required',
|
||||||
|
// 'files' => 'required_without:hash|array|min:1|max:6',
|
||||||
|
// 'hash' => 'nullable|string',
|
||||||
|
// 'column_map' => 'required_with:hash|array',
|
||||||
|
// 'skip_header' => 'required_with:hash|boolean',
|
||||||
|
// 'files.*' => 'file|mimes:csv,txt',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,7 @@ class PaymentWebhookRequest extends Request
|
|||||||
|
|
||||||
public function authorize()
|
public function authorize()
|
||||||
{
|
{
|
||||||
MultiDB::findAndSetDbByCompanyKey($this->getCompany()->company_key);
|
MultiDB::findAndSetDbByCompanyKey($this->company_key);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ class PaymentWebhookRequest extends Request
|
|||||||
* @param mixed $id
|
* @param mixed $id
|
||||||
* @return null|\App\Models\CompanyGateway
|
* @return null|\App\Models\CompanyGateway
|
||||||
*/
|
*/
|
||||||
public function getCompanyGateway(): ?CompanyGateway
|
public function getCompanyGateway()
|
||||||
{
|
{
|
||||||
return CompanyGateway::findOrFail($this->decodePrimaryKey($this->company_gateway_id));
|
return CompanyGateway::findOrFail($this->decodePrimaryKey($this->company_gateway_id));
|
||||||
}
|
}
|
||||||
@ -56,13 +56,13 @@ class PaymentWebhookRequest extends Request
|
|||||||
* @param string $hash
|
* @param string $hash
|
||||||
* @return null|\App\Models\PaymentHash
|
* @return null|\App\Models\PaymentHash
|
||||||
*/
|
*/
|
||||||
public function getPaymentHash(): ?PaymentHash
|
public function getPaymentHash()
|
||||||
{
|
{
|
||||||
if ($this->query('hash')) {
|
if ($this->query('hash')) {
|
||||||
return PaymentHash::where('hash', $this->query('hash'))->firstOrFail();
|
return PaymentHash::where('hash', $this->query('hash'))->firstOrFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,7 +94,7 @@ class PaymentWebhookRequest extends Request
|
|||||||
|
|
||||||
// If none of previously done logics is correct, we'll just display
|
// If none of previously done logics is correct, we'll just display
|
||||||
// not found page.
|
// not found page.
|
||||||
abort(404);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,11 +102,14 @@ class PaymentWebhookRequest extends Request
|
|||||||
*
|
*
|
||||||
* @return null|\App\Models\Client
|
* @return null|\App\Models\Client
|
||||||
*/
|
*/
|
||||||
public function getClient(): ?Client
|
public function getClient()
|
||||||
{
|
{
|
||||||
$hash = $this->getPaymentHash();
|
$hash = $this->getPaymentHash();
|
||||||
|
|
||||||
return Client::find($hash->data->client_id)->firstOrFail();
|
if($hash)
|
||||||
|
return Client::find($hash->data->client_id)->firstOrFail();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,6 +49,9 @@ class InitializeStripeConnectRequest extends FormRequest
|
|||||||
*/
|
*/
|
||||||
public function getTokenContent()
|
public function getTokenContent()
|
||||||
{
|
{
|
||||||
|
if($this->state)
|
||||||
|
$this->token = $this->state;
|
||||||
|
|
||||||
$data = Cache::get($this->token);
|
$data = Cache::get($this->token);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
@ -45,9 +45,6 @@ class UpdateUserRequest extends Request
|
|||||||
{
|
{
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
// if (isset($input['company_user']) && ! auth()->user()->isAdmin()) {
|
|
||||||
// unset($input['company_user']);
|
|
||||||
// }
|
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ use App\Http\Requests\Request;
|
|||||||
use App\Http\ValidationRules\ValidVendorGroupSettingsRule;
|
use App\Http\ValidationRules\ValidVendorGroupSettingsRule;
|
||||||
use App\Models\Vendor;
|
use App\Models\Vendor;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class StoreVendorRequest extends Request
|
class StoreVendorRequest extends Request
|
||||||
{
|
{
|
||||||
@ -39,6 +40,9 @@ class StoreVendorRequest extends Request
|
|||||||
//$rules['settings'] = new ValidVendorGroupSettingsRule();
|
//$rules['settings'] = new ValidVendorGroupSettingsRule();
|
||||||
$rules['contacts.*.email'] = 'nullable|distinct';
|
$rules['contacts.*.email'] = 'nullable|distinct';
|
||||||
|
|
||||||
|
if (isset($this->number)) {
|
||||||
|
$rules['number'] = Rule::unique('vendors')->where('company_id', auth()->user()->company()->id);
|
||||||
|
}
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
50
app/Http/ValidationRules/Company/ValidSubdomain.php
Normal file
50
app/Http/ValidationRules/Company/ValidSubdomain.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\ValidationRules\Company;
|
||||||
|
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use Illuminate\Contracts\Validation\Rule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ValidCompanyQuantity.
|
||||||
|
*/
|
||||||
|
class ValidSubdomain implements Rule
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $attribute
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
private $input;
|
||||||
|
|
||||||
|
public function __construct($input)
|
||||||
|
{
|
||||||
|
$this->input = $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function passes($attribute, $value)
|
||||||
|
{
|
||||||
|
if(empty($input['subdomain']))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return MultiDB::checkDomainAvailable($input['subdomain']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function message()
|
||||||
|
{
|
||||||
|
return ctrans('texts.subdomain_taken');
|
||||||
|
}
|
||||||
|
}
|
@ -57,13 +57,13 @@ class InvoiceBalanceSanity implements Rule
|
|||||||
private function checkIfInvoiceBalanceIsSane() : bool
|
private function checkIfInvoiceBalanceIsSane() : bool
|
||||||
{
|
{
|
||||||
|
|
||||||
|
DB::connection(config('database.default'))->beginTransaction();
|
||||||
|
|
||||||
|
$this->invoice = Invoice::on(config('database.default'))->find($this->invoice->id);
|
||||||
$this->invoice->line_items = $this->input['line_items'];
|
$this->invoice->line_items = $this->input['line_items'];
|
||||||
|
$temp_invoice = $this->invoice->calc()->getTempEntity();
|
||||||
|
|
||||||
DB::beginTransaction();
|
DB::connection(config('database.default'))->rollBack();
|
||||||
|
|
||||||
$temp_invoice = $this->invoice->calc()->getTempEntity();
|
|
||||||
|
|
||||||
DB::rollBack();
|
|
||||||
|
|
||||||
if($temp_invoice->balance < 0){
|
if($temp_invoice->balance < 0){
|
||||||
$this->message = 'Invoice balance cannot go negative';
|
$this->message = 'Invoice balance cannot go negative';
|
||||||
@ -71,7 +71,7 @@ class InvoiceBalanceSanity implements Rule
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ use Illuminate\Contracts\Validation\Rule;
|
|||||||
*/
|
*/
|
||||||
class AttachableUser implements Rule
|
class AttachableUser implements Rule
|
||||||
{
|
{
|
||||||
|
public $message;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@ -39,7 +40,7 @@ class AttachableUser implements Rule
|
|||||||
*/
|
*/
|
||||||
public function message()
|
public function message()
|
||||||
{
|
{
|
||||||
return "Cannot add the same user to the same company";
|
return $this->message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,15 +58,22 @@ class AttachableUser implements Rule
|
|||||||
if(!$user)
|
if(!$user)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
$user_already_attached = CompanyUser::query()
|
$user_already_attached = CompanyUser::query()
|
||||||
->where('user_id', $user->id)
|
->where('user_id', $user->id)
|
||||||
->where('account_id',$user->account_id)
|
->where('account_id',$user->account_id)
|
||||||
->where('company_id', auth()->user()->company()->id)
|
->where('company_id', auth()->user()->company()->id)
|
||||||
->exists();
|
->exists();
|
||||||
|
|
||||||
if($user_already_attached)
|
//If the user is already attached or isn't link to this account - return false
|
||||||
|
if($user_already_attached) {
|
||||||
|
$this->message = ctrans('texts.user_duplicate_error');
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($user->account_id != auth()->user()->account_id){
|
||||||
|
$this->message = ctrans('texts.user_cross_linked_error');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,9 @@ class PortalComposer
|
|||||||
$view->with($this->portalData());
|
$view->with($this->portalData());
|
||||||
|
|
||||||
if (auth()->user()) {
|
if (auth()->user()) {
|
||||||
Lang::replace(Ninja::transformTranslations(auth()->user()->client->getMergedSettings()));
|
App::forgetInstance('translator');
|
||||||
|
$t = app('translator');
|
||||||
|
$t->replace(Ninja::transformTranslations(auth()->user()->client->getMergedSettings()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,9 +84,7 @@ class PortalComposer
|
|||||||
$data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar'];
|
$data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar'];
|
||||||
|
|
||||||
if (auth()->user('contact')->client->getSetting('enable_client_portal_tasks')) {
|
if (auth()->user('contact')->client->getSetting('enable_client_portal_tasks')) {
|
||||||
$data[] = ['title' => ctrans('texts.tasks'), 'url' => 'client.dashboard', 'icon' => 'clock'];
|
$data[] = ['title' => ctrans('texts.tasks'), 'url' => 'client.tasks.index', 'icon' => 'clock'];
|
||||||
|
|
||||||
// TODO: Update when 'tasks' module is available in client portal.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
@ -25,11 +25,13 @@ use App\Jobs\Util\VersionCheck;
|
|||||||
use App\Mail\Admin\AccountCreatedObject;
|
use App\Mail\Admin\AccountCreatedObject;
|
||||||
use App\Mail\Admin\VerifyUserObject;
|
use App\Mail\Admin\VerifyUserObject;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Models\Timezone;
|
||||||
use App\Notifications\Ninja\NewAccountCreated;
|
use App\Notifications\Ninja\NewAccountCreated;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Turbo124\Beacon\Facades\LightLogs;
|
use Turbo124\Beacon\Facades\LightLogs;
|
||||||
@ -40,9 +42,12 @@ class CreateAccount
|
|||||||
|
|
||||||
protected $request;
|
protected $request;
|
||||||
|
|
||||||
public function __construct(array $sp660339)
|
protected $client_ip;
|
||||||
|
|
||||||
|
public function __construct(array $sp660339, $client_ip)
|
||||||
{
|
{
|
||||||
$this->request = $sp660339;
|
$this->request = $sp660339;
|
||||||
|
$this->client_ip = $client_ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
@ -74,6 +79,7 @@ class CreateAccount
|
|||||||
|
|
||||||
$sp035a66 = CreateCompany::dispatchNow($this->request, $sp794f3f);
|
$sp035a66 = CreateCompany::dispatchNow($this->request, $sp794f3f);
|
||||||
$sp035a66->load('account');
|
$sp035a66->load('account');
|
||||||
|
$sp035a66->settings = $this->processSettings($sp035a66->settings);
|
||||||
$sp794f3f->default_company_id = $sp035a66->id;
|
$sp794f3f->default_company_id = $sp035a66->id;
|
||||||
$sp794f3f->save();
|
$sp794f3f->save();
|
||||||
|
|
||||||
@ -107,4 +113,53 @@ class CreateAccount
|
|||||||
|
|
||||||
return $sp794f3f;
|
return $sp794f3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function processSettings($settings)
|
||||||
|
{
|
||||||
|
if(Ninja::isHosted() && Cache::get('currencies') && $data = unserialize(@file_get_contents('http://www.geoplugin.net/php.gp?ip=' . $this->client_ip)))
|
||||||
|
{
|
||||||
|
|
||||||
|
$currency_code = strtolower($data['geoplugin_currencyCode']);
|
||||||
|
$country_code = strtolower($data['geoplugin_countryCode']);
|
||||||
|
|
||||||
|
$currency = Cache::get('currencies')->filter(function ($item) use ($currency_code) {
|
||||||
|
return strtolower($item->code) == $currency_code;
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if ($currency) {
|
||||||
|
$settings->currency_id = (string)$currency->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$country = Cache::get('countries')->filter(function ($item) use ($country_code) {
|
||||||
|
return strtolower($item->iso_3166_2) == $country_code || strtolower($item->iso_3166_3) == $country_code;
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if ($country) {
|
||||||
|
$settings->country_id = (string)$country->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$language = Cache::get('languages')->filter(function ($item) use ($currency_code) {
|
||||||
|
return strtolower($item->locale) == $currency_code;
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if ($language) {
|
||||||
|
$settings->language_id = (string)$language->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$timezone = Timezone::where('name', $data['geoplugin_timezone'])->first();
|
||||||
|
|
||||||
|
if($timezone) {
|
||||||
|
$settings->timezone_id = (string)$timezone->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $settings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
509
app/Jobs/Company/CompanyExport.php
Normal file
509
app/Jobs/Company/CompanyExport.php
Normal file
@ -0,0 +1,509 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Jobs\Company;
|
||||||
|
|
||||||
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
|
use App\Jobs\Util\UnlinkFile;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Mail\DownloadBackup;
|
||||||
|
use App\Mail\DownloadInvoices;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\CreditInvitation;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\VendorContact;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use ZipStream\Option\Archive;
|
||||||
|
use ZipStream\ZipStream;
|
||||||
|
|
||||||
|
class CompanyExport implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
private $export_format;
|
||||||
|
|
||||||
|
private $export_data = [];
|
||||||
|
|
||||||
|
public $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param Company $company
|
||||||
|
* @param User $user
|
||||||
|
* @param string $custom_token_name
|
||||||
|
*/
|
||||||
|
public function __construct(Company $company, User $user, $export_format = 'json')
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
$this->user = $user;
|
||||||
|
$this->export_format = $export_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return CompanyToken|null
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
$this->company = Company::where('company_key', $this->company->company_key)->first();
|
||||||
|
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
|
$this->export_data['app_version'] = config('ninja.app_version');
|
||||||
|
|
||||||
|
$this->export_data['activities'] = $this->company->all_activities->map(function ($activity){
|
||||||
|
|
||||||
|
$activity = $this->transformArrayOfKeys($activity, [
|
||||||
|
'user_id',
|
||||||
|
'company_id',
|
||||||
|
'client_id',
|
||||||
|
'client_contact_id',
|
||||||
|
'account_id',
|
||||||
|
'project_id',
|
||||||
|
'vendor_id',
|
||||||
|
'payment_id',
|
||||||
|
'invoice_id',
|
||||||
|
'credit_id',
|
||||||
|
'invitation_id',
|
||||||
|
'task_id',
|
||||||
|
'expense_id',
|
||||||
|
'token_id',
|
||||||
|
'quote_id',
|
||||||
|
'subscription_id',
|
||||||
|
'recurring_invoice_id'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $activity;
|
||||||
|
|
||||||
|
})->makeHidden(['id'])->all();
|
||||||
|
|
||||||
|
$this->export_data['backups'] = $this->company->all_activities()->with('backup')->cursor()->map(function ($activity){
|
||||||
|
|
||||||
|
$backup = $activity->backup;
|
||||||
|
|
||||||
|
if(!$backup)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$backup->activity_id = $this->encodePrimaryKey($backup->activity_id);
|
||||||
|
|
||||||
|
return $backup;
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['users'] = $this->company->users()->withTrashed()->cursor()->map(function ($user){
|
||||||
|
|
||||||
|
$user->account_id = $this->encodePrimaryKey($user->account_id);
|
||||||
|
// $user->id = $this->encodePrimaryKey($user->id);
|
||||||
|
|
||||||
|
return $user->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['client_contacts'] = $this->company->client_contacts->map(function ($client_contact){
|
||||||
|
|
||||||
|
$client_contact = $this->transformArrayOfKeys($client_contact, ['company_id', 'user_id', 'client_id']);
|
||||||
|
|
||||||
|
return $client_contact->makeVisible([
|
||||||
|
'password',
|
||||||
|
'remember_token',
|
||||||
|
'user_id',
|
||||||
|
'company_id',
|
||||||
|
'client_id',
|
||||||
|
'google_2fa_secret',
|
||||||
|
'id',
|
||||||
|
'oauth_provider_id',
|
||||||
|
'oauth_user_id',
|
||||||
|
'token',
|
||||||
|
'hashed_id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['client_gateway_tokens'] = $this->company->client_gateway_tokens->map(function ($client_gateway_token){
|
||||||
|
|
||||||
|
$client_gateway_token = $this->transformArrayOfKeys($client_gateway_token, ['company_id', 'client_id']);
|
||||||
|
|
||||||
|
return $client_gateway_token->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['clients'] = $this->company->clients->map(function ($client){
|
||||||
|
|
||||||
|
$client = $this->transformArrayOfKeys($client, ['company_id', 'user_id', 'assigned_user_id', 'group_settings_id']);
|
||||||
|
|
||||||
|
return $client->makeVisible(['id','private_notes','user_id','company_id','last_login','hashed_id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['company'] = $this->company->toArray();
|
||||||
|
|
||||||
|
$this->export_data['company_gateways'] = $this->company->company_gateways->map(function ($company_gateway){
|
||||||
|
|
||||||
|
$company_gateway = $this->transformArrayOfKeys($company_gateway, ['company_id', 'user_id']);
|
||||||
|
$company_gateway->config = decrypt($company_gateway->config);
|
||||||
|
|
||||||
|
return $company_gateway->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['company_tokens'] = $this->company->tokens->map(function ($token){
|
||||||
|
|
||||||
|
$token = $this->transformArrayOfKeys($token, ['company_id', 'account_id', 'user_id']);
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['company_ledger'] = $this->company->ledger->map(function ($ledger){
|
||||||
|
|
||||||
|
$ledger = $this->transformArrayOfKeys($ledger, ['activity_id', 'client_id', 'company_id', 'account_id', 'user_id','company_ledgerable_id']);
|
||||||
|
|
||||||
|
return $ledger;
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['company_users'] = $this->company->company_users->map(function ($company_user){
|
||||||
|
|
||||||
|
$company_user = $this->transformArrayOfKeys($company_user, ['company_id', 'account_id', 'user_id']);
|
||||||
|
|
||||||
|
return $company_user;
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['credits'] = $this->company->credits->map(function ($credit){
|
||||||
|
|
||||||
|
$credit = $this->transformBasicEntities($credit);
|
||||||
|
$credit = $this->transformArrayOfKeys($credit, ['recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id','invoice_id']);
|
||||||
|
|
||||||
|
return $credit->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['credit_invitations'] = CreditInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($credit){
|
||||||
|
|
||||||
|
$credit = $this->transformArrayOfKeys($credit, ['company_id', 'user_id', 'client_contact_id', 'credit_id']);
|
||||||
|
|
||||||
|
return $credit->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['designs'] = $this->company->user_designs->makeHidden(['id'])->all();
|
||||||
|
|
||||||
|
$this->export_data['documents'] = $this->company->all_documents->map(function ($document){
|
||||||
|
|
||||||
|
$document = $this->transformArrayOfKeys($document, ['user_id', 'assigned_user_id', 'company_id', 'project_id', 'vendor_id','documentable_id']);
|
||||||
|
$document->hashed_id = $this->encodePrimaryKey($document->id);
|
||||||
|
|
||||||
|
return $document->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['expense_categories'] = $this->company->expense_categories->map(function ($expense_category){
|
||||||
|
|
||||||
|
$expense_category = $this->transformArrayOfKeys($expense_category, ['user_id', 'company_id']);
|
||||||
|
|
||||||
|
return $expense_category->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['expenses'] = $this->company->expenses->map(function ($expense){
|
||||||
|
|
||||||
|
$expense = $this->transformBasicEntities($expense);
|
||||||
|
$expense = $this->transformArrayOfKeys($expense, ['vendor_id', 'invoice_id', 'client_id', 'category_id', 'recurring_expense_id','project_id']);
|
||||||
|
|
||||||
|
return $expense->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['group_settings'] = $this->company->group_settings->map(function ($gs){
|
||||||
|
|
||||||
|
$gs = $this->transformArrayOfKeys($gs, ['user_id', 'company_id']);
|
||||||
|
|
||||||
|
return $gs->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['invoices'] = $this->company->invoices->map(function ($invoice){
|
||||||
|
|
||||||
|
$invoice = $this->transformBasicEntities($invoice);
|
||||||
|
$invoice = $this->transformArrayOfKeys($invoice, ['recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id']);
|
||||||
|
|
||||||
|
return $invoice->makeVisible(['id',
|
||||||
|
'private_notes',
|
||||||
|
'user_id',
|
||||||
|
'client_id',
|
||||||
|
'company_id',]);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['invoice_invitations'] = InvoiceInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($invoice){
|
||||||
|
|
||||||
|
$invoice = $this->transformArrayOfKeys($invoice, ['company_id', 'user_id', 'client_contact_id', 'invoice_id']);
|
||||||
|
|
||||||
|
return $invoice->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['payment_terms'] = $this->company->user_payment_terms->map(function ($term){
|
||||||
|
|
||||||
|
$term = $this->transformArrayOfKeys($term, ['user_id', 'company_id']);
|
||||||
|
|
||||||
|
return $term;
|
||||||
|
|
||||||
|
})->makeHidden(['id'])->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['payments'] = $this->company->payments->map(function ($payment){
|
||||||
|
|
||||||
|
$payment = $this->transformBasicEntities($payment);
|
||||||
|
$payment = $this->transformArrayOfKeys($payment, ['client_id','project_id', 'vendor_id', 'client_contact_id', 'invitation_id', 'company_gateway_id']);
|
||||||
|
|
||||||
|
$payment->paymentables = $this->transformPaymentable($payment);
|
||||||
|
|
||||||
|
return $payment->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['products'] = $this->company->products->map(function ($product){
|
||||||
|
|
||||||
|
$product = $this->transformBasicEntities($product);
|
||||||
|
$product = $this->transformArrayOfKeys($product, ['vendor_id','project_id']);
|
||||||
|
|
||||||
|
return $product->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['projects'] = $this->company->projects->map(function ($project){
|
||||||
|
|
||||||
|
$project = $this->transformBasicEntities($project);
|
||||||
|
$project = $this->transformArrayOfKeys($project, ['client_id']);
|
||||||
|
|
||||||
|
return $project->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['quotes'] = $this->company->quotes->map(function ($quote){
|
||||||
|
|
||||||
|
$quote = $this->transformBasicEntities($quote);
|
||||||
|
$quote = $this->transformArrayOfKeys($quote, ['invoice_id','recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id']);
|
||||||
|
|
||||||
|
return $quote->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['quote_invitations'] = QuoteInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($quote){
|
||||||
|
|
||||||
|
$quote = $this->transformArrayOfKeys($quote, ['company_id', 'user_id', 'client_contact_id', 'quote_id']);
|
||||||
|
|
||||||
|
return $quote->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['recurring_invoices'] = $this->company->recurring_invoices->makeVisible(['id'])->map(function ($ri){
|
||||||
|
|
||||||
|
$ri = $this->transformBasicEntities($ri);
|
||||||
|
$ri = $this->transformArrayOfKeys($ri, ['client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id']);
|
||||||
|
|
||||||
|
return $ri->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['recurring_invoice_invitations'] = RecurringInvoiceInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($ri){
|
||||||
|
|
||||||
|
$ri = $this->transformArrayOfKeys($ri, ['company_id', 'user_id', 'client_contact_id', 'recurring_invoice_id']);
|
||||||
|
|
||||||
|
return $ri;
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['subscriptions'] = $this->company->subscriptions->map(function ($subscription){
|
||||||
|
|
||||||
|
$subscription = $this->transformBasicEntities($subscription);
|
||||||
|
$subscription->group_id = $this->encodePrimaryKey($subscription->group_id);
|
||||||
|
|
||||||
|
return $subscription->makeVisible([ 'id',
|
||||||
|
'user_id',
|
||||||
|
'assigned_user_id',
|
||||||
|
'company_id',
|
||||||
|
'product_ids',
|
||||||
|
'recurring_product_ids',
|
||||||
|
'group_id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['system_logs'] = $this->company->system_logs->map(function ($log){
|
||||||
|
|
||||||
|
$log->client_id = $this->encodePrimaryKey($log->client_id);
|
||||||
|
$log->company_id = $this->encodePrimaryKey($log->company_id);
|
||||||
|
|
||||||
|
return $log;
|
||||||
|
|
||||||
|
})->makeHidden(['id'])->all();
|
||||||
|
|
||||||
|
$this->export_data['tasks'] = $this->company->tasks->map(function ($task){
|
||||||
|
|
||||||
|
$task = $this->transformBasicEntities($task);
|
||||||
|
$task = $this->transformArrayOfKeys($task, ['client_id', 'invoice_id', 'project_id', 'status_id']);
|
||||||
|
|
||||||
|
return $task->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['task_statuses'] = $this->company->task_statuses->map(function ($status){
|
||||||
|
|
||||||
|
$status->id = $this->encodePrimaryKey($status->id);
|
||||||
|
$status->user_id = $this->encodePrimaryKey($status->user_id);
|
||||||
|
$status->company_id = $this->encodePrimaryKey($status->company_id);
|
||||||
|
|
||||||
|
return $status;
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['tax_rates'] = $this->company->tax_rates->map(function ($rate){
|
||||||
|
|
||||||
|
$rate->company_id = $this->encodePrimaryKey($rate->company_id);
|
||||||
|
$rate->user_id = $this->encodePrimaryKey($rate->user_id);
|
||||||
|
|
||||||
|
return $rate;
|
||||||
|
|
||||||
|
})->makeHidden(['id'])->all();
|
||||||
|
|
||||||
|
$this->export_data['vendors'] = $this->company->vendors->map(function ($vendor){
|
||||||
|
|
||||||
|
return $this->transformBasicEntities($vendor)->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
|
||||||
|
$this->export_data['vendor_contacts'] = VendorContact::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($vendor){
|
||||||
|
|
||||||
|
$vendor = $this->transformBasicEntities($vendor);
|
||||||
|
$vendor->vendor_id = $this->encodePrimaryKey($vendor->vendor_id);
|
||||||
|
|
||||||
|
return $vendor->makeVisible(['id']);
|
||||||
|
|
||||||
|
})->all();
|
||||||
|
|
||||||
|
$this->export_data['webhooks'] = $this->company->webhooks->map(function ($hook){
|
||||||
|
|
||||||
|
$hook->user_id = $this->encodePrimaryKey($hook->user_id);
|
||||||
|
$hook->company_id = $this->encodePrimaryKey($hook->company_id);
|
||||||
|
|
||||||
|
return $hook;
|
||||||
|
|
||||||
|
})->makeHidden(['id'])->all();
|
||||||
|
|
||||||
|
//write to tmp and email to owner();
|
||||||
|
|
||||||
|
$this->zipAndSend();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function transformBasicEntities($model)
|
||||||
|
{
|
||||||
|
|
||||||
|
return $this->transformArrayOfKeys($model, ['user_id', 'assigned_user_id', 'company_id']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function transformArrayOfKeys($model, $keys)
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach($keys as $key){
|
||||||
|
$model->{$key} = $this->encodePrimaryKey($model->{$key});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $model;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function transformPaymentable($payment)
|
||||||
|
{
|
||||||
|
|
||||||
|
$new_arr = [];
|
||||||
|
|
||||||
|
foreach($payment->paymentables as $paymentable)
|
||||||
|
{
|
||||||
|
|
||||||
|
$paymentable->payment_id = $this->encodePrimaryKey($paymentable->payment_id);
|
||||||
|
$paymentable->paymentable_id = $this->encodePrimaryKey($paymentable->paymentable_id);
|
||||||
|
|
||||||
|
$new_arr[] = $paymentable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new_arr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function zipAndSend()
|
||||||
|
{
|
||||||
|
|
||||||
|
$file_name = date('Y-m-d').'_'.str_replace(' ', '_', $this->company->present()->name() . '_' . $this->company->company_key .'.zip');
|
||||||
|
|
||||||
|
$zip_path = public_path('storage/backups/'.$file_name);
|
||||||
|
$zip = new \ZipArchive();
|
||||||
|
|
||||||
|
if ($zip->open($zip_path, \ZipArchive::CREATE)!==TRUE) {
|
||||||
|
nlog("cannot open {$zip_path}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$zip->addFromString("backup.json", json_encode($this->export_data));
|
||||||
|
$zip->close();
|
||||||
|
|
||||||
|
if(Ninja::isHosted()) {
|
||||||
|
Storage::disk(config('filesystems.default'))->put('backups/'.$file_name, file_get_contents($zip_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
$nmo = new NinjaMailerObject;
|
||||||
|
$nmo->mailable = new DownloadBackup(Storage::disk(config('filesystems.default'))->url('backups/'.$file_name), $this->company);
|
||||||
|
$nmo->to_user = $this->user;
|
||||||
|
$nmo->company = $this->company;
|
||||||
|
$nmo->settings = $this->company->settings;
|
||||||
|
|
||||||
|
NinjaMailerJob::dispatch($nmo);
|
||||||
|
|
||||||
|
UnlinkFile::dispatch(config('filesystems.default'), 'backups/'.$file_name)->delay(now()->addHours(1));
|
||||||
|
UnlinkFile::dispatch('public', 'backups/'.$file_name)->delay(now()->addHours(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1103
app/Jobs/Company/CompanyImport.php
Normal file
1103
app/Jobs/Company/CompanyImport.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,9 @@
|
|||||||
namespace App\Jobs\Company;
|
namespace App\Jobs\Company;
|
||||||
|
|
||||||
use App\DataMapper\CompanySettings;
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -60,6 +62,12 @@ class CreateCompany
|
|||||||
$company->subdomain = isset($this->request['subdomain']) ? $this->request['subdomain'] : '';
|
$company->subdomain = isset($this->request['subdomain']) ? $this->request['subdomain'] : '';
|
||||||
$company->custom_fields = new \stdClass;
|
$company->custom_fields = new \stdClass;
|
||||||
$company->default_password_timeout = 1800000;
|
$company->default_password_timeout = 1800000;
|
||||||
|
|
||||||
|
if(Ninja::isHosted())
|
||||||
|
$company->subdomain = MultiDB::randomSubdomainGenerator();
|
||||||
|
else
|
||||||
|
$company->subdomain = '';
|
||||||
|
|
||||||
$company->save();
|
$company->save();
|
||||||
|
|
||||||
return $company;
|
return $company;
|
||||||
|
101
app/Jobs/Cron/AutoBillCron.php
Normal file
101
app/Jobs/Cron/AutoBillCron.php
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Jobs\Cron;
|
||||||
|
|
||||||
|
use App\Jobs\RecurringInvoice\SendRecurring;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
class AutoBillCron
|
||||||
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
|
||||||
|
public $tries = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle() : void
|
||||||
|
{
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
|
/* Get all invoices where the send date is less than NOW + 30 minutes() */
|
||||||
|
nlog("Performing Autobilling ".Carbon::now()->format('Y-m-d h:i:s'));
|
||||||
|
|
||||||
|
if (! config('ninja.db.multi_db_enabled')) {
|
||||||
|
|
||||||
|
$auto_bill_partial_invoices = Invoice::whereDate('partial_due_date', '<=', now())
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('auto_bill_enabled', true)
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->with('company')
|
||||||
|
->cursor()->each(function ($invoice){
|
||||||
|
$this->runAutoBiller($invoice);
|
||||||
|
});
|
||||||
|
|
||||||
|
$auto_bill_invoices = Invoice::whereDate('due_date', '<=', now())
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('auto_bill_enabled', true)
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->with('company')
|
||||||
|
->cursor()->each(function ($invoice){
|
||||||
|
$this->runAutoBiller($invoice);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//multiDB environment, need to
|
||||||
|
foreach (MultiDB::$dbs as $db) {
|
||||||
|
MultiDB::setDB($db);
|
||||||
|
|
||||||
|
$auto_bill_partial_invoices = Invoice::whereDate('partial_due_date', '<=', now())
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('auto_bill_enabled', true)
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->with('company')
|
||||||
|
->cursor()->each(function ($invoice){
|
||||||
|
$this->runAutoBiller($invoice);
|
||||||
|
});
|
||||||
|
|
||||||
|
$auto_bill_invoices = Invoice::whereDate('due_date', '<=', now())
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('auto_bill_enabled', true)
|
||||||
|
->where('balance', '>', 0)
|
||||||
|
->with('company')
|
||||||
|
->cursor()->each(function ($invoice){
|
||||||
|
$this->runAutoBiller($invoice);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function runAutoBiller(Invoice $invoice)
|
||||||
|
{
|
||||||
|
nlog("Firing autobill for {$invoice->company_id} - {$invoice->number}");
|
||||||
|
$invoice->service()->autoBill()->save();
|
||||||
|
}
|
||||||
|
}
|
@ -64,7 +64,7 @@ class CreateEntityPdf implements ShouldQueue
|
|||||||
*
|
*
|
||||||
* @param $invitation
|
* @param $invitation
|
||||||
*/
|
*/
|
||||||
public function __construct($invitation)
|
public function __construct($invitation, $disk = 'public')
|
||||||
{
|
{
|
||||||
$this->invitation = $invitation;
|
$this->invitation = $invitation;
|
||||||
|
|
||||||
@ -86,22 +86,26 @@ class CreateEntityPdf implements ShouldQueue
|
|||||||
|
|
||||||
$this->contact = $invitation->contact;
|
$this->contact = $invitation->contact;
|
||||||
|
|
||||||
$this->disk = $disk ?? config('filesystems.default');
|
$this->disk = $disk;
|
||||||
|
|
||||||
|
// $this->disk = $disk ?? config('filesystems.default');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
/* Set the locale*/
|
|
||||||
App::setLocale($this->contact->preferredLocale());
|
|
||||||
|
|
||||||
/* Forget the singleton*/
|
/* Forget the singleton*/
|
||||||
App::forgetInstance('translator');
|
App::forgetInstance('translator');
|
||||||
|
|
||||||
/* Init a new copy of the translator*/
|
/* Init a new copy of the translator*/
|
||||||
$t = app('translator');
|
$t = app('translator');
|
||||||
|
/* Set the locale*/
|
||||||
|
App::setLocale($this->contact->preferredLocale());
|
||||||
|
|
||||||
|
// nlog($this->entity->client->getMergedSettings());
|
||||||
|
|
||||||
/* Set customized translations _NOW_ */
|
/* Set customized translations _NOW_ */
|
||||||
Lang::replace(Ninja::transformTranslations($this->entity->client->getMergedSettings()));
|
$t->replace(Ninja::transformTranslations($this->entity->client->getMergedSettings()));
|
||||||
|
|
||||||
$this->entity->service()->deletePdf();
|
$this->entity->service()->deletePdf();
|
||||||
|
|
||||||
@ -197,7 +201,7 @@ class CreateEntityPdf implements ShouldQueue
|
|||||||
catch(\Exception $e)
|
catch(\Exception $e)
|
||||||
{
|
{
|
||||||
|
|
||||||
throw new FilePermissionsFailure('Could not write the PDF, permission issues!');
|
throw new FilePermissionsFailure($e->getMessage());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,8 +213,5 @@ class CreateEntityPdf implements ShouldQueue
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
// public function failed(\Exception $exception)
|
|
||||||
// {
|
|
||||||
// nlog("help!");
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ class CSVImport implements ShouldQueue {
|
|||||||
|
|
||||||
Auth::login( $this->company->owner(), true );
|
Auth::login( $this->company->owner(), true );
|
||||||
|
|
||||||
$this->company->owner()->setCompany( $this->company );
|
auth()->user()->setCompany($this->company);
|
||||||
|
|
||||||
$this->buildMaps();
|
$this->buildMaps();
|
||||||
|
|
||||||
@ -293,10 +293,14 @@ class CSVImport implements ShouldQueue {
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$payment_repository->save(
|
/* Make sure we don't apply any payments to invoices with a Zero Amount*/
|
||||||
$payment_data,
|
if($invoice->amount > 0)
|
||||||
PaymentFactory::create( $this->company->id, $invoice->user_id, $invoice->client_id )
|
{
|
||||||
);
|
$payment_repository->save(
|
||||||
|
$payment_data,
|
||||||
|
PaymentFactory::create( $this->company->id, $invoice->user_id, $invoice->client_id )
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,23 +83,24 @@ class ZipInvoices implements ShouldQueue
|
|||||||
$zip = new ZipStream($file_name, $options);
|
$zip = new ZipStream($file_name, $options);
|
||||||
|
|
||||||
foreach ($this->invoices as $invoice) {
|
foreach ($this->invoices as $invoice) {
|
||||||
$zip->addFileFromPath(basename($invoice->pdf_file_path()), TempFile::path($invoice->pdf_file_path()));
|
//$zip->addFileFromPath(basename($invoice->pdf_file_path()), TempFile::path($invoice->pdf_file_path()));
|
||||||
|
$zip->addFileFromPath(basename($invoice->pdf_file_path()), $invoice->pdf_file_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
$zip->finish();
|
$zip->finish();
|
||||||
|
|
||||||
Storage::disk(config('filesystems.default'))->put($path.$file_name, $tempStream);
|
Storage::disk('public')->put($path.$file_name, $tempStream);
|
||||||
|
|
||||||
fclose($tempStream);
|
fclose($tempStream);
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject;
|
$nmo = new NinjaMailerObject;
|
||||||
$nmo->mailable = new DownloadInvoices(Storage::disk(config('filesystems.default'))->url($path.$file_name), $this->company);
|
$nmo->mailable = new DownloadInvoices(Storage::disk('public')->url($path.$file_name), $this->company);
|
||||||
$nmo->to_user = $this->user;
|
$nmo->to_user = $this->user;
|
||||||
$nmo->settings = $this->settings;
|
$nmo->settings = $this->settings;
|
||||||
$nmo->company = $this->company;
|
$nmo->company = $this->company;
|
||||||
|
|
||||||
NinjaMailerJob::dispatch($nmo);
|
NinjaMailerJob::dispatch($nmo);
|
||||||
|
|
||||||
UnlinkFile::dispatch(config('filesystems.default'), $path.$file_name)->delay(now()->addHours(1));
|
UnlinkFile::dispatch('public', $path.$file_name)->delay(now()->addHours(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ use App\Libraries\Google\Google;
|
|||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use App\Mail\TemplateEmail;
|
use App\Mail\TemplateEmail;
|
||||||
use App\Models\ClientContact;
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\Company;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\SystemLog;
|
use App\Models\SystemLog;
|
||||||
@ -46,30 +47,38 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash;
|
||||||
|
|
||||||
public $tries = 5; //number of retries
|
public $tries = 3; //number of retries
|
||||||
|
|
||||||
public $backoff = 5; //seconds to wait until retry
|
public $backoff = 10; //seconds to wait until retry
|
||||||
|
|
||||||
public $deleteWhenMissingModels = true;
|
public $deleteWhenMissingModels = true;
|
||||||
|
|
||||||
public $nmo;
|
public $nmo;
|
||||||
|
|
||||||
public function __construct(NinjaMailerObject $nmo)
|
public $override;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public function __construct(NinjaMailerObject $nmo, bool $override = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->nmo = $nmo;
|
$this->nmo = $nmo;
|
||||||
|
$this->override = $override;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
/*If we are migrating data we don't want to fire any emails*/
|
/*If we are migrating data we don't want to fire any emails*/
|
||||||
if ($this->nmo->company->is_disabled)
|
if ($this->nmo->company->is_disabled && !$this->override)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*Set the correct database*/
|
/*Set the correct database*/
|
||||||
MultiDB::setDb($this->nmo->company->db);
|
MultiDB::setDb($this->nmo->company->db);
|
||||||
|
|
||||||
|
/* Serializing models from other jobs wipes the primary key */
|
||||||
|
$this->company = Company::where('company_key', $this->nmo->company->company_key)->first();
|
||||||
|
|
||||||
/* Set the email driver */
|
/* Set the email driver */
|
||||||
$this->setMailDriver();
|
$this->setMailDriver();
|
||||||
|
|
||||||
@ -83,6 +92,10 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
$this->nmo->mailable->replyTo($this->nmo->settings->reply_to_email, $reply_to_name);
|
$this->nmo->mailable->replyTo($this->nmo->settings->reply_to_email, $reply_to_name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$this->nmo->mailable->replyTo($this->company->owner()->email, $this->company->owner()->present()->name());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (strlen($this->nmo->settings->bcc_email) > 1) {
|
if (strlen($this->nmo->settings->bcc_email) > 1) {
|
||||||
nlog('bcc list available');
|
nlog('bcc list available');
|
||||||
@ -93,7 +106,7 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
//send email
|
//send email
|
||||||
try {
|
try {
|
||||||
nlog("trying to send");
|
nlog("trying to send to {$this->nmo->to_user->email} ". now()->toDateTimeString());
|
||||||
|
|
||||||
Mail::to($this->nmo->to_user->email)
|
Mail::to($this->nmo->to_user->email)
|
||||||
->send($this->nmo->mailable);
|
->send($this->nmo->mailable);
|
||||||
@ -104,10 +117,12 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
nlog("error failed with {$e->getMessage()}");
|
nlog("error failed with {$e->getMessage()}");
|
||||||
// nlog($e);
|
|
||||||
|
|
||||||
if($this->nmo->entity)
|
if($this->nmo->entity)
|
||||||
$this->entityEmailFailed($e->getMessage());
|
$this->entityEmailFailed($e->getMessage());
|
||||||
|
|
||||||
|
if(Ninja::isHosted())
|
||||||
|
app('sentry')->captureException($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,9 +154,9 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
App::forgetInstance('mail.manager'); //singletons must be destroyed!
|
App::forgetInstance('mail.manager'); //singletons must be destroyed!
|
||||||
App::forgetInstance('mailer');
|
App::forgetInstance('mailer');
|
||||||
App::forgetInstance('laravelgmail');
|
App::forgetInstance('laravelgmail');
|
||||||
|
$t = app('translator');
|
||||||
/* Inject custom translations if any exist */
|
/* Inject custom translations if any exist */
|
||||||
Lang::replace(Ninja::transformTranslations($this->nmo->settings));
|
$t->replace(Ninja::transformTranslations($this->nmo->settings));
|
||||||
|
|
||||||
switch ($this->nmo->settings->email_sending_method) {
|
switch ($this->nmo->settings->email_sending_method) {
|
||||||
case 'default':
|
case 'default':
|
||||||
@ -169,7 +184,15 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
nlog("Sending via {$user->name()}");
|
nlog("Sending via {$user->name()}");
|
||||||
|
|
||||||
$google = (new Google())->init();
|
$google = (new Google())->init();
|
||||||
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
|
|
||||||
|
try{
|
||||||
|
$google->getClient()->setAccessToken(json_encode($user->oauth_user_token));
|
||||||
|
}
|
||||||
|
catch(\Exception $e) {
|
||||||
|
$this->logMailError('Gmail Token Invalid', $this->company->clients()->first());
|
||||||
|
$this->nmo->settings->email_sending_method = 'default';
|
||||||
|
return $this->setMailDriver();
|
||||||
|
}
|
||||||
|
|
||||||
if ($google->getClient()->isAccessTokenExpired()) {
|
if ($google->getClient()->isAccessTokenExpired()) {
|
||||||
$google->refreshToken($user);
|
$google->refreshToken($user);
|
||||||
@ -202,7 +225,8 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
SystemLog::CATEGORY_MAIL,
|
SystemLog::CATEGORY_MAIL,
|
||||||
SystemLog::EVENT_MAIL_SEND,
|
SystemLog::EVENT_MAIL_SEND,
|
||||||
SystemLog::TYPE_FAILURE,
|
SystemLog::TYPE_FAILURE,
|
||||||
$recipient_object
|
$recipient_object,
|
||||||
|
$this->nmo->company
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user