mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge branch 'v5-develop' of https://github.com/invoiceninja/invoiceninja into feature-inbound-email-expenses
This commit is contained in:
commit
b13e54f49b
1
.env.ci
1
.env.ci
@ -24,3 +24,4 @@ PHANTOMJS_PDF_GENERATION=false
|
|||||||
CACHE_DRIVER=redis
|
CACHE_DRIVER=redis
|
||||||
QUEUE_CONNECTION=redis
|
QUEUE_CONNECTION=redis
|
||||||
SESSION_DRIVER=redis
|
SESSION_DRIVER=redis
|
||||||
|
PDF_GENERATOR=hosted_ninja
|
@ -1 +1 @@
|
|||||||
5.9.6
|
5.9.9
|
@ -176,6 +176,7 @@ class BackupUpdate extends Command
|
|||||||
try {
|
try {
|
||||||
$doc_bin = $document->getFile();
|
$doc_bin = $document->getFile();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: BackupUpdate::" . $e->getMessage());
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,8 +185,6 @@ class BackupUpdate extends Command
|
|||||||
|
|
||||||
$document->disk = $this->option('disk');
|
$document->disk = $this->option('disk');
|
||||||
$document->saveQuietly();
|
$document->saveQuietly();
|
||||||
|
|
||||||
nlog("Documents - Moving {$document->url} to {$this->option('disk')}");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -199,8 +198,6 @@ class BackupUpdate extends Command
|
|||||||
|
|
||||||
if ($backup_bin) {
|
if ($backup_bin) {
|
||||||
Storage::disk($this->option('disk'))->put($backup->filename, $backup_bin);
|
Storage::disk($this->option('disk'))->put($backup->filename, $backup_bin);
|
||||||
|
|
||||||
nlog("Backups - Moving {$backup->filename} to {$this->option('disk')}");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -121,28 +121,6 @@ class CreateAccount extends Command
|
|||||||
(new CreateCompanyTaskStatuses($company, $user))->handle();
|
(new CreateCompanyTaskStatuses($company, $user))->handle();
|
||||||
(new VersionCheck())->handle();
|
(new VersionCheck())->handle();
|
||||||
|
|
||||||
$this->warmCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function warmCache()
|
|
||||||
{
|
|
||||||
/* Warm up the cache !*/
|
|
||||||
$cached_tables = config('ninja.cached_tables');
|
|
||||||
|
|
||||||
foreach ($cached_tables as $name => $class) {
|
|
||||||
if ($name == 'payment_terms') {
|
|
||||||
$orderBy = 'num_days';
|
|
||||||
} elseif ($name == 'fonts') {
|
|
||||||
$orderBy = 'sort_order';
|
|
||||||
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) {
|
|
||||||
$orderBy = 'name';
|
|
||||||
} else {
|
|
||||||
$orderBy = 'id';
|
|
||||||
}
|
|
||||||
$tableData = $class::orderBy($orderBy)->get();
|
|
||||||
if ($tableData->count()) {
|
|
||||||
Cache::forever($name, $tableData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -97,10 +97,6 @@ class CreateSingleAccount extends Command
|
|||||||
$this->count = 5;
|
$this->count = 5;
|
||||||
$this->gateway = $this->argument('gateway');
|
$this->gateway = $this->argument('gateway');
|
||||||
|
|
||||||
$this->info('Warming up cache');
|
|
||||||
|
|
||||||
$this->warmCache();
|
|
||||||
|
|
||||||
$this->createSmallAccount();
|
$this->createSmallAccount();
|
||||||
|
|
||||||
|
|
||||||
@ -774,32 +770,6 @@ class CreateSingleAccount extends Command
|
|||||||
return $line_items;
|
return $line_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function warmCache()
|
|
||||||
{
|
|
||||||
/* Warm up the cache !*/
|
|
||||||
$cached_tables = config('ninja.cached_tables');
|
|
||||||
|
|
||||||
foreach ($cached_tables as $name => $class) {
|
|
||||||
// check that the table exists in case the migration is pending
|
|
||||||
if (! Schema::hasTable((new $class())->getTable())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($name == 'payment_terms') {
|
|
||||||
$orderBy = 'num_days';
|
|
||||||
} elseif ($name == 'fonts') {
|
|
||||||
$orderBy = 'sort_order';
|
|
||||||
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) {
|
|
||||||
$orderBy = 'name';
|
|
||||||
} else {
|
|
||||||
$orderBy = 'id';
|
|
||||||
}
|
|
||||||
$tableData = $class::orderBy($orderBy)->get();
|
|
||||||
if ($tableData->count()) {
|
|
||||||
Cache::forever($name, $tableData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createGateways($company, $user)
|
private function createGateways($company, $user)
|
||||||
{
|
{
|
||||||
if (config('ninja.testvars.stripe') && ($this->gateway == 'all' || $this->gateway == 'stripe')) {
|
if (config('ninja.testvars.stripe') && ($this->gateway == 'all' || $this->gateway == 'stripe')) {
|
||||||
|
@ -86,8 +86,6 @@ class CreateTestData extends Command
|
|||||||
|
|
||||||
$this->info('Warming up cache');
|
$this->info('Warming up cache');
|
||||||
|
|
||||||
$this->warmCache();
|
|
||||||
|
|
||||||
$this->createSmallAccount();
|
$this->createSmallAccount();
|
||||||
$this->createMediumAccount();
|
$this->createMediumAccount();
|
||||||
$this->createLargeAccount();
|
$this->createLargeAccount();
|
||||||
@ -673,31 +671,4 @@ class CreateTestData extends Command
|
|||||||
return $line_items;
|
return $line_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function warmCache()
|
|
||||||
{
|
|
||||||
/* Warm up the cache !*/
|
|
||||||
$cached_tables = config('ninja.cached_tables');
|
|
||||||
|
|
||||||
foreach ($cached_tables as $name => $class) {
|
|
||||||
if (! Cache::has($name)) {
|
|
||||||
// check that the table exists in case the migration is pending
|
|
||||||
if (! Schema::hasTable((new $class())->getTable())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($name == 'payment_terms') {
|
|
||||||
$orderBy = 'num_days';
|
|
||||||
} elseif ($name == 'fonts') {
|
|
||||||
$orderBy = 'sort_order';
|
|
||||||
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) {
|
|
||||||
$orderBy = 'name';
|
|
||||||
} else {
|
|
||||||
$orderBy = 'id';
|
|
||||||
}
|
|
||||||
$tableData = $class::orderBy($orderBy)->get();
|
|
||||||
if ($tableData->count()) {
|
|
||||||
Cache::forever($name, $tableData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -84,15 +84,13 @@ class DemoMode extends Command
|
|||||||
|
|
||||||
$this->invoice_repo = new InvoiceRepository();
|
$this->invoice_repo = new InvoiceRepository();
|
||||||
|
|
||||||
$cached_tables = config('ninja.cached_tables');
|
|
||||||
|
|
||||||
$this->info('Migrating');
|
$this->info('Migrating');
|
||||||
Artisan::call('migrate:fresh --force');
|
Artisan::call('migrate:fresh --force');
|
||||||
|
|
||||||
$this->info('Seeding');
|
$this->info('Seeding');
|
||||||
Artisan::call('db:seed --force');
|
|
||||||
|
|
||||||
$this->buildCache(true);
|
Artisan::call('db:seed --force');
|
||||||
|
Artisan::call('cache:clear');
|
||||||
|
|
||||||
$this->info('Seeding Random Data');
|
$this->info('Seeding Random Data');
|
||||||
$this->createSmallAccount();
|
$this->createSmallAccount();
|
||||||
@ -623,31 +621,4 @@ class DemoMode extends Command
|
|||||||
return $line_items;
|
return $line_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function warmCache()
|
|
||||||
{
|
|
||||||
/* Warm up the cache !*/
|
|
||||||
$cached_tables = config('ninja.cached_tables');
|
|
||||||
|
|
||||||
foreach ($cached_tables as $name => $class) {
|
|
||||||
if (! Cache::has($name)) {
|
|
||||||
// check that the table exists in case the migration is pending
|
|
||||||
if (! Schema::hasTable((new $class())->getTable())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($name == 'payment_terms') {
|
|
||||||
$orderBy = 'num_days';
|
|
||||||
} elseif ($name == 'fonts') {
|
|
||||||
$orderBy = 'sort_order';
|
|
||||||
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) {
|
|
||||||
$orderBy = 'name';
|
|
||||||
} else {
|
|
||||||
$orderBy = 'id';
|
|
||||||
}
|
|
||||||
$tableData = $class::orderBy($orderBy)->get();
|
|
||||||
if ($tableData->count()) {
|
|
||||||
Cache::forever($name, $tableData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,6 @@ class HostedMigrations extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$this->buildCache();
|
|
||||||
|
|
||||||
if (! MultiDB::userFindAndSetDb($this->option('email'))) {
|
if (! MultiDB::userFindAndSetDb($this->option('email'))) {
|
||||||
$this->info('Could not find a user with that email address');
|
$this->info('Could not find a user with that email address');
|
||||||
|
@ -75,8 +75,6 @@ class ImportMigrations extends Command
|
|||||||
{
|
{
|
||||||
$this->faker = Factory::create();
|
$this->faker = Factory::create();
|
||||||
|
|
||||||
$this->buildCache();
|
|
||||||
|
|
||||||
$path = $this->option('path') ?? public_path('storage/migrations/import');
|
$path = $this->option('path') ?? public_path('storage/migrations/import');
|
||||||
|
|
||||||
$directory = new DirectoryIterator($path);
|
$directory = new DirectoryIterator($path);
|
||||||
|
@ -86,8 +86,7 @@ class PostUpdate extends Command
|
|||||||
|
|
||||||
info('queue restarted');
|
info('queue restarted');
|
||||||
|
|
||||||
$this->buildCache(true);
|
Artisan::call('cache:clear');
|
||||||
|
|
||||||
VersionCheck::dispatch();
|
VersionCheck::dispatch();
|
||||||
|
|
||||||
info('Sent for version check');
|
info('Sent for version check');
|
||||||
|
@ -27,6 +27,7 @@ use App\Jobs\Ninja\TaskScheduler;
|
|||||||
use App\Jobs\Quote\QuoteCheckExpired;
|
use App\Jobs\Quote\QuoteCheckExpired;
|
||||||
use App\Jobs\Subscription\CleanStaleInvoiceOrder;
|
use App\Jobs\Subscription\CleanStaleInvoiceOrder;
|
||||||
use App\Jobs\Util\DiskCleanup;
|
use App\Jobs\Util\DiskCleanup;
|
||||||
|
use App\Jobs\Util\QuoteReminderJob;
|
||||||
use App\Jobs\Util\ReminderJob;
|
use App\Jobs\Util\ReminderJob;
|
||||||
use App\Jobs\Util\SchedulerCheck;
|
use App\Jobs\Util\SchedulerCheck;
|
||||||
use App\Jobs\Util\UpdateExchangeRates;
|
use App\Jobs\Util\UpdateExchangeRates;
|
||||||
@ -55,6 +56,9 @@ class Kernel extends ConsoleKernel
|
|||||||
/* Send reminders */
|
/* Send reminders */
|
||||||
$schedule->job(new ReminderJob())->hourly()->withoutOverlapping()->name('reminder-job')->onOneServer();
|
$schedule->job(new ReminderJob())->hourly()->withoutOverlapping()->name('reminder-job')->onOneServer();
|
||||||
|
|
||||||
|
/* Send quote reminders */
|
||||||
|
$schedule->job(new QuoteReminderJob())->hourly()->withoutOverlapping()->name('quote-reminder-job')->onOneServer();
|
||||||
|
|
||||||
/* Sends recurring invoices*/
|
/* Sends recurring invoices*/
|
||||||
$schedule->job(new RecurringInvoicesCron())->hourly()->withoutOverlapping()->name('recurring-invoice-job')->onOneServer();
|
$schedule->job(new RecurringInvoicesCron())->hourly()->withoutOverlapping()->name('recurring-invoice-job')->onOneServer();
|
||||||
|
|
||||||
|
@ -507,7 +507,25 @@ class CompanySettings extends BaseSettings
|
|||||||
|
|
||||||
public int $task_round_to_nearest = 1;
|
public int $task_round_to_nearest = 1;
|
||||||
|
|
||||||
|
/** quote reminders */
|
||||||
|
public $email_quote_template_reminder1 = '';
|
||||||
|
public $email_quote_subject_reminder1 = '';
|
||||||
|
public $enable_quote_reminder1 = false;
|
||||||
|
public $quote_num_days_reminder1 = 0;
|
||||||
|
public $quote_schedule_reminder1 = ''; //before_valid_until_date,after_valid_until_date,after_quote_date
|
||||||
|
public $quote_late_fee_amount1 = 0;
|
||||||
|
public $quote_late_fee_percent1 = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static $casts = [
|
public static $casts = [
|
||||||
|
'enable_quote_reminder1' => 'bool',
|
||||||
|
'quote_num_days_reminder1' => 'int',
|
||||||
|
'quote_schedule_reminder1' => 'string',
|
||||||
|
'quote_late_fee_amount1' => 'float',
|
||||||
|
'quote_late_fee_percent1' => 'float',
|
||||||
|
'email_quote_template_reminder1' => 'string',
|
||||||
|
'email_quote_subject_reminder1' => 'string',
|
||||||
'task_round_up' => 'bool',
|
'task_round_up' => 'bool',
|
||||||
'task_round_to_nearest' => 'int',
|
'task_round_to_nearest' => 'int',
|
||||||
'e_quote_type' => 'string',
|
'e_quote_type' => 'string',
|
||||||
@ -962,6 +980,7 @@ class CompanySettings extends BaseSettings
|
|||||||
'$invoice.due_date',
|
'$invoice.due_date',
|
||||||
'$invoice.total',
|
'$invoice.total',
|
||||||
'$invoice.balance_due',
|
'$invoice.balance_due',
|
||||||
|
'$invoice.project',
|
||||||
],
|
],
|
||||||
'quote_details' => [
|
'quote_details' => [
|
||||||
'$quote.number',
|
'$quote.number',
|
||||||
@ -969,6 +988,7 @@ class CompanySettings extends BaseSettings
|
|||||||
'$quote.date',
|
'$quote.date',
|
||||||
'$quote.valid_until',
|
'$quote.valid_until',
|
||||||
'$quote.total',
|
'$quote.total',
|
||||||
|
'$quote.project',
|
||||||
],
|
],
|
||||||
'credit_details' => [
|
'credit_details' => [
|
||||||
'$credit.number',
|
'$credit.number',
|
||||||
|
@ -115,12 +115,32 @@ class EmailTemplateDefaults
|
|||||||
case 'email_vendor_notification_body':
|
case 'email_vendor_notification_body':
|
||||||
return self::emailVendorNotificationBody();
|
return self::emailVendorNotificationBody();
|
||||||
|
|
||||||
|
case 'email_quote_template_reminder1':
|
||||||
|
return self::emailQuoteReminder1Body();
|
||||||
|
|
||||||
|
case 'email_quote_subject_reminder1':
|
||||||
|
return self::emailQuoteReminder1Subject();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return self::emailInvoiceTemplate();
|
return self::emailInvoiceTemplate();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function emailQuoteReminder1Subject()
|
||||||
|
{
|
||||||
|
return ctrans('texts.quote_reminder_subject', ['quote' => '$number', 'company' => '$company.name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function emailQuoteReminder1Body()
|
||||||
|
{
|
||||||
|
|
||||||
|
$invoice_message = '<p>$client<br><br>'.self::transformText('quote_reminder_message').'</p><div class="center">$view_button</div>';
|
||||||
|
|
||||||
|
return $invoice_message;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static function emailVendorNotificationSubject()
|
public static function emailVendorNotificationSubject()
|
||||||
{
|
{
|
||||||
return self::transformText('vendor_notification_subject');
|
return self::transformText('vendor_notification_subject');
|
||||||
|
@ -220,6 +220,7 @@ class BaseRule implements RuleInterface
|
|||||||
try {
|
try {
|
||||||
$this->invoice->saveQuietly();
|
$this->invoice->saveQuietly();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: BaseRule::" . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -261,7 +262,7 @@ class BaseRule implements RuleInterface
|
|||||||
return $this->client->state;
|
return $this->client->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
return USStates::getState(strlen($this->client->postal_code) > 1 ? $this->client->postal_code : $this->client->shipping_postal_code);
|
return USStates::getState(strlen($this->client->postal_code ?? '') > 1 ? $this->client->postal_code : $this->client->shipping_postal_code);
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return 'CA';
|
return 'CA';
|
||||||
|
@ -34006,7 +34006,7 @@ class USStates
|
|||||||
'WA', 'WA', 'WA', 'WA', 'WA', 'WA', 'WA', 'AK', 'AK', 'AK', 'AK', 'AK'
|
'WA', 'WA', 'WA', 'WA', 'WA', 'WA', 'WA', 'AK', 'AK', 'AK', 'AK', 'AK'
|
||||||
];
|
];
|
||||||
|
|
||||||
$prefix = substr($zip, 0, 3);
|
$prefix = substr(($zip ?? ''), 0, 3);
|
||||||
$index = intval($prefix);
|
$index = intval($prefix);
|
||||||
/* converts prefix to integer */
|
/* converts prefix to integer */
|
||||||
return $zip_by_state[$index] == "--" ? false : $zip_by_state[$index];
|
return $zip_by_state[$index] == "--" ? false : $zip_by_state[$index];
|
||||||
|
28
app/Events/Quote/QuoteReminderWasEmailed.php
Normal file
28
app/Events/Quote/QuoteReminderWasEmailed.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Quote Ninja (https://Quoteninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/Quoteninja/Quoteninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024. Quote Ninja LLC (https://Quoteninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Events\Quote;
|
||||||
|
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class QuoteReminderWasEmailed.
|
||||||
|
*/
|
||||||
|
class QuoteReminderWasEmailed
|
||||||
|
{
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public function __construct(public QuoteInvitation $invitation, public Company $company, public array $event_vars, public string $template)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
44
app/Exceptions/DuplicatePaymentException.php
Normal file
44
app/Exceptions/DuplicatePaymentException.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class DuplicatePaymentException extends Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Report the exception.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function report()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the exception into an HTTP response.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return JsonResponse
|
||||||
|
*/
|
||||||
|
public function render($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Duplicate request',
|
||||||
|
], 400);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -31,11 +31,11 @@ class QuoteExport extends BaseExport
|
|||||||
|
|
||||||
private Decorator $decorator;
|
private Decorator $decorator;
|
||||||
|
|
||||||
private array $decorate_keys = [
|
// private array $decorate_keys = [
|
||||||
'client',
|
// 'client',
|
||||||
'currency',
|
// 'currency',
|
||||||
'invoice',
|
// 'invoice',
|
||||||
];
|
// ];
|
||||||
|
|
||||||
public function __construct(Company $company, array $input)
|
public function __construct(Company $company, array $input)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ class TaskExport extends BaseExport
|
|||||||
|
|
||||||
public string $date_key = 'created_at';
|
public string $date_key = 'created_at';
|
||||||
|
|
||||||
private string $date_format = 'YYYY-MM-DD';
|
private string $date_format = 'Y-m-d';
|
||||||
|
|
||||||
public Writer $csv;
|
public Writer $csv;
|
||||||
|
|
||||||
@ -180,13 +180,7 @@ class TaskExport extends BaseExport
|
|||||||
|
|
||||||
$logs = json_decode($task->time_log, 1);
|
$logs = json_decode($task->time_log, 1);
|
||||||
|
|
||||||
$date_format_default = 'Y-m-d';
|
$date_format_default = $this->date_format;
|
||||||
|
|
||||||
$date_format = DateFormat::find($task->company->settings->date_format_id);
|
|
||||||
|
|
||||||
if ($date_format) {
|
|
||||||
$date_format_default = $date_format->format;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($logs as $key => $item) {
|
foreach ($logs as $key => $item) {
|
||||||
if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) {
|
if (in_array('task.start_date', $this->input['report_keys']) || in_array('start_date', $this->input['report_keys'])) {
|
||||||
@ -236,7 +230,7 @@ class TaskExport extends BaseExport
|
|||||||
*/
|
*/
|
||||||
protected function addTaskStatusFilter(Builder $query, string $status): Builder
|
protected function addTaskStatusFilter(Builder $query, string $status): Builder
|
||||||
{
|
{
|
||||||
|
/** @var array $status_parameters */
|
||||||
$status_parameters = explode(',', $status);
|
$status_parameters = explode(',', $status);
|
||||||
|
|
||||||
if (in_array('all', $status_parameters) || count($status_parameters) == 0) {
|
if (in_array('all', $status_parameters) || count($status_parameters) == 0) {
|
||||||
|
@ -171,16 +171,16 @@ class VendorExport extends BaseExport
|
|||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function calculateStatus($vendor)
|
// private function calculateStatus($vendor)
|
||||||
{
|
// {
|
||||||
if ($vendor->is_deleted) {
|
// if ($vendor->is_deleted) {
|
||||||
return ctrans('texts.deleted');
|
// return ctrans('texts.deleted');
|
||||||
}
|
// }
|
||||||
|
|
||||||
if ($vendor->deleted_at) {
|
// if ($vendor->deleted_at) {
|
||||||
return ctrans('texts.archived');
|
// return ctrans('texts.archived');
|
||||||
}
|
// }
|
||||||
|
|
||||||
return ctrans('texts.active');
|
// return ctrans('texts.active');
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -82,11 +82,15 @@ class RecurringExpenseToExpenseFactory
|
|||||||
} else {
|
} else {
|
||||||
$locale = $recurring_expense->company->locale();
|
$locale = $recurring_expense->company->locale();
|
||||||
|
|
||||||
$date_formats = Cache::get('date_formats');
|
//@deprecated
|
||||||
|
// $date_formats = Cache::get('date_formats');
|
||||||
|
|
||||||
$date_format = $date_formats->filter(function ($item) use ($recurring_expense) {
|
/** @var \Illuminate\Support\Collection<\App\Models\DateFormat> */
|
||||||
|
$date_formats = app('date_formats');
|
||||||
|
|
||||||
|
$date_format = $date_formats->first(function ($item) use ($recurring_expense) {
|
||||||
return $item->id == $recurring_expense->company->settings->date_format_id;
|
return $item->id == $recurring_expense->company->settings->date_format_id;
|
||||||
})->first()->format;
|
})->format;
|
||||||
}
|
}
|
||||||
|
|
||||||
Carbon::setLocale($locale);
|
Carbon::setLocale($locale);
|
||||||
@ -144,7 +148,7 @@ class RecurringExpenseToExpenseFactory
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Str::contains($match, '|')) {
|
// if (Str::contains($match, '|')) {
|
||||||
$parts = explode('|', $match); // [ '[MONTH', 'MONTH+2]' ]
|
$parts = explode('|', $match); // [ '[MONTH', 'MONTH+2]' ]
|
||||||
|
|
||||||
$left = substr($parts[0], 1); // 'MONTH'
|
$left = substr($parts[0], 1); // 'MONTH'
|
||||||
@ -182,7 +186,7 @@ class RecurringExpenseToExpenseFactory
|
|||||||
$value,
|
$value,
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second case with more common calculations.
|
// Second case with more common calculations.
|
||||||
|
@ -79,7 +79,7 @@ class ExpenseFilters extends QueryFilters
|
|||||||
$this->builder->where(function ($query) use ($status_parameters) {
|
$this->builder->where(function ($query) use ($status_parameters) {
|
||||||
if (in_array('logged', $status_parameters)) {
|
if (in_array('logged', $status_parameters)) {
|
||||||
$query->orWhere(function ($query) {
|
$query->orWhere(function ($query) {
|
||||||
$query->where('amount', '>', 0)
|
$query->where('amount', '>=', 0)
|
||||||
->whereNull('invoice_id')
|
->whereNull('invoice_id')
|
||||||
->whereNull('payment_date')
|
->whereNull('payment_date')
|
||||||
->where('should_be_invoiced', false);
|
->where('should_be_invoiced', false);
|
||||||
|
@ -271,6 +271,7 @@ class InvoiceFilters extends QueryFilters
|
|||||||
if (count($parts) != 2) {
|
if (count($parts) != 2) {
|
||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
$start_date = Carbon::parse($parts[0]);
|
$start_date = Carbon::parse($parts[0]);
|
||||||
@ -281,7 +282,6 @@ class InvoiceFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,7 +307,6 @@ class InvoiceFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -204,7 +204,6 @@ class PaymentFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,6 +133,10 @@ class RecurringInvoiceFilters extends QueryFilters
|
|||||||
return $this->builder->orderByRaw("REGEXP_REPLACE(number,'[^0-9]+','')+0 " . $dir);
|
return $this->builder->orderByRaw("REGEXP_REPLACE(number,'[^0-9]+','')+0 " . $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($sort_col[0] == 'status_id'){
|
||||||
|
return $this->builder->orderBy('status_id', $dir)->orderBy('last_sent_date', $dir);
|
||||||
|
}
|
||||||
|
|
||||||
if($sort_col[0] == 'next_send_datetime') {
|
if($sort_col[0] == 'next_send_datetime') {
|
||||||
$sort_col[0] = 'next_send_date';
|
$sort_col[0] = 'next_send_date';
|
||||||
}
|
}
|
||||||
@ -162,9 +166,10 @@ class RecurringInvoiceFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var array $key_parameters */
|
||||||
$key_parameters = explode(',', $value);
|
$key_parameters = explode(',', $value);
|
||||||
|
|
||||||
if (count($key_parameters)) {
|
if (count($key_parameters) > 0) {
|
||||||
return $this->builder->where(function ($query) use ($key_parameters) {
|
return $this->builder->where(function ($query) use ($key_parameters) {
|
||||||
foreach ($key_parameters as $key) {
|
foreach ($key_parameters as $key) {
|
||||||
$query->orWhereJsonContains('line_items', ['product_key' => $key]);
|
$query->orWhereJsonContains('line_items', ['product_key' => $key]);
|
||||||
@ -183,6 +188,7 @@ class RecurringInvoiceFilters extends QueryFilters
|
|||||||
*/
|
*/
|
||||||
public function next_send_between(string $range = ''): Builder
|
public function next_send_between(string $range = ''): Builder
|
||||||
{
|
{
|
||||||
|
/** @var array $parts */
|
||||||
$parts = explode('|', $range);
|
$parts = explode('|', $range);
|
||||||
|
|
||||||
if (!isset($parts[0]) || !isset($parts[1])) {
|
if (!isset($parts[0]) || !isset($parts[1])) {
|
||||||
|
@ -175,6 +175,7 @@ class TaskFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var array $status_parameters */
|
||||||
$status_parameters = explode(',', $value);
|
$status_parameters = explode(',', $value);
|
||||||
|
|
||||||
if(count($status_parameters) >= 1) {
|
if(count($status_parameters) >= 1) {
|
||||||
|
@ -156,21 +156,15 @@ class TransactionTransformer implements BankRevenueInterface
|
|||||||
private function convertCurrency(string $code)
|
private function convertCurrency(string $code)
|
||||||
{
|
{
|
||||||
|
|
||||||
$currencies = Cache::get('currencies');
|
$currencies = app('currencies');
|
||||||
|
|
||||||
if (!$currencies) {
|
$currency = $currencies->first(function ($item) use ($code) {
|
||||||
$this->buildCache(true);
|
/** @var \App\Models\Currency $item */
|
||||||
}
|
|
||||||
|
|
||||||
$currency = $currencies->filter(function ($item) use ($code) {
|
|
||||||
return $item->code == $code;
|
return $item->code == $code;
|
||||||
})->first();
|
});
|
||||||
|
|
||||||
if ($currency) {
|
/** @var \App\Models\Currency $currency */
|
||||||
return $currency->id;
|
return $currency ? $currency->id : 1; //@phpstan-ignore-line
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +186,7 @@ class TransactionTransformer implements BankRevenueInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Carbon::createFromFormat("d-m-Y", $input)->setTimezone($timezone_name)->format($date_format_default) ?? $input;
|
return Carbon::createFromFormat("d-m-Y", $input)->setTimezone($timezone_name)->format($date_format_default);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return $input;
|
return $input;
|
||||||
}
|
}
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Invoice Ninja (https://invoiceninja.com).
|
|
||||||
*
|
|
||||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
|
||||||
*
|
|
||||||
* @license https://www.elastic.co/licensing/elastic-license
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Helpers\Bank\Yodlee\DTO;
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Spatie\LaravelData\Attributes\MapInputName;
|
|
||||||
use Spatie\LaravelData\Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* [
|
|
||||||
"account": [
|
|
||||||
[
|
|
||||||
"CONTAINER": "bank",
|
|
||||||
"providerAccountId": 1005,
|
|
||||||
"accountName": "Business Acct",
|
|
||||||
"accountStatus": "ACTIVE",
|
|
||||||
"accountNumber": "1011",
|
|
||||||
"aggregationSource": "USER",
|
|
||||||
"isAsset": true,
|
|
||||||
"balance": [
|
|
||||||
"currency": "AUD",
|
|
||||||
"amount": 304.98,
|
|
||||||
],
|
|
||||||
"id": 10139315,
|
|
||||||
"includeInNetWorth": true,
|
|
||||||
"providerId": "3857",
|
|
||||||
"providerName": "Bank",
|
|
||||||
"isManual": false,
|
|
||||||
"availableBalance": {#2966
|
|
||||||
"currency": "AUD",
|
|
||||||
"amount": 304.98,
|
|
||||||
],
|
|
||||||
"currentBalance": [
|
|
||||||
"currency": "AUD",
|
|
||||||
"amount": 3044.98,
|
|
||||||
],
|
|
||||||
"accountType": "CHECKING",
|
|
||||||
"displayedName": "after David",
|
|
||||||
"createdDate": "2023-01-10T08:29:07Z",
|
|
||||||
"classification": "SMALL_BUSINESS",
|
|
||||||
"lastUpdated": "2023-08-01T23:50:13Z",
|
|
||||||
"nickname": "Business ",
|
|
||||||
"bankTransferCode": [
|
|
||||||
[
|
|
||||||
"id": "062",
|
|
||||||
"type": "BSB",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
"dataset": [
|
|
||||||
[
|
|
||||||
"name": "BASIC_AGG_DATA",
|
|
||||||
"additionalStatus": "AVAILABLE_DATA_RETRIEVED",
|
|
||||||
"updateEligibility": "ALLOW_UPDATE",
|
|
||||||
"lastUpdated": "2023-08-01T23:49:53Z",
|
|
||||||
"lastUpdateAttempt": "2023-08-01T23:49:53Z",
|
|
||||||
"nextUpdateScheduled": "2023-08-03T14:45:14Z",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
*/
|
|
||||||
class AccountSummary extends Data
|
|
||||||
{
|
|
||||||
public ?int $id;
|
|
||||||
|
|
||||||
#[MapInputName('CONTAINER')]
|
|
||||||
public ?string $account_type = '';
|
|
||||||
|
|
||||||
#[MapInputName('accountName')]
|
|
||||||
public ?string $account_name = '';
|
|
||||||
|
|
||||||
#[MapInputName('accountStatus')]
|
|
||||||
public ?string $account_status = '';
|
|
||||||
|
|
||||||
#[MapInputName('accountNumber')]
|
|
||||||
public ?string $account_number = '';
|
|
||||||
|
|
||||||
#[MapInputName('providerAccountId')]
|
|
||||||
public int $provider_account_id;
|
|
||||||
|
|
||||||
#[MapInputName('providerId')]
|
|
||||||
public ?string $provider_id = '';
|
|
||||||
|
|
||||||
#[MapInputName('providerName')]
|
|
||||||
public ?string $provider_name = '';
|
|
||||||
|
|
||||||
public ?string $nickname = '';
|
|
||||||
|
|
||||||
public ?float $current_balance = 0;
|
|
||||||
public ?string $account_currency = '';
|
|
||||||
|
|
||||||
public static function prepareForPipeline(Collection $properties): Collection
|
|
||||||
{
|
|
||||||
|
|
||||||
$properties->put('current_balance', $properties['currentBalance']['amount'] ?? 0);
|
|
||||||
$properties->put('account_currency', $properties['currentBalance']['currency'] ?? 0);
|
|
||||||
|
|
||||||
return $properties;
|
|
||||||
}
|
|
||||||
}
|
|
@ -171,20 +171,16 @@ class IncomeTransformer implements BankRevenueInterface
|
|||||||
|
|
||||||
private function convertCurrency(string $code)
|
private function convertCurrency(string $code)
|
||||||
{
|
{
|
||||||
$currencies = Cache::get('currencies');
|
|
||||||
|
|
||||||
if (! $currencies) {
|
$currencies = app('currencies');
|
||||||
$this->buildCache(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$currency = $currencies->filter(function ($item) use ($code) {
|
$currency = $currencies->first(function ($item) use ($code) {
|
||||||
|
/** @var \App\Models\Currency $item */
|
||||||
return $item->code == $code;
|
return $item->code == $code;
|
||||||
})->first();
|
});
|
||||||
|
|
||||||
if ($currency) {
|
/** @var \App\Models\Currency $currency */
|
||||||
return $currency->id;
|
return $currency ? $currency->id : 1; //@phpstan-ignore-line
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,15 +26,15 @@ use BaconQrCode\Writer;
|
|||||||
*/
|
*/
|
||||||
class EpcQrGenerator
|
class EpcQrGenerator
|
||||||
{
|
{
|
||||||
private array $sepa = [
|
// private array $sepa = [
|
||||||
'serviceTag' => 'BCD',
|
// 'serviceTag' => 'BCD',
|
||||||
'version' => 2,
|
// 'version' => 2,
|
||||||
'characterSet' => 1,
|
// 'characterSet' => 1,
|
||||||
'identification' => 'SCT',
|
// 'identification' => 'SCT',
|
||||||
'bic' => '',
|
// 'bic' => '',
|
||||||
'purpose' => '',
|
// 'purpose' => '',
|
||||||
|
|
||||||
];
|
// ];
|
||||||
|
|
||||||
public function __construct(protected Company $company, protected Invoice|RecurringInvoice $invoice, protected float $amount)
|
public function __construct(protected Company $company, protected Invoice|RecurringInvoice $invoice, protected float $amount)
|
||||||
{
|
{
|
||||||
@ -61,12 +61,6 @@ class EpcQrGenerator
|
|||||||
} catch(\Throwable $e) {
|
} catch(\Throwable $e) {
|
||||||
nlog("EPC QR failure => ".$e->getMessage());
|
nlog("EPC QR failure => ".$e->getMessage());
|
||||||
return '';
|
return '';
|
||||||
} catch(\Exception $e) {
|
|
||||||
nlog("EPC QR failure => ".$e->getMessage());
|
|
||||||
return '';
|
|
||||||
} catch(InvalidArgumentException $e) {
|
|
||||||
nlog("EPC QR failure => ".$e->getMessage());
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ class InvoiceItemSum
|
|||||||
use Discounter;
|
use Discounter;
|
||||||
use Taxer;
|
use Taxer;
|
||||||
|
|
||||||
|
//@phpstan-ignore-next-line
|
||||||
private array $eu_tax_jurisdictions = [
|
private array $eu_tax_jurisdictions = [
|
||||||
'AT', // Austria
|
'AT', // Austria
|
||||||
'BE', // Belgium
|
'BE', // Belgium
|
||||||
@ -170,7 +171,7 @@ class InvoiceItemSum
|
|||||||
private function shouldCalculateTax(): self
|
private function shouldCalculateTax(): self
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!$this->invoice->company?->calculate_taxes || $this->invoice->company->account->isFreeHostedClient()) {
|
if (!$this->invoice->company?->calculate_taxes || $this->invoice->company->account->isFreeHostedClient()) { //@phpstan-ignore-line
|
||||||
$this->calc_tax = false;
|
$this->calc_tax = false;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -331,7 +332,7 @@ class InvoiceItemSum
|
|||||||
|
|
||||||
public function setLineTotal($total)
|
public function setLineTotal($total)
|
||||||
{
|
{
|
||||||
$this->item->line_total = $total;
|
$this->item->line_total = (float) $total;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class InvoiceItemSumInclusive
|
|||||||
use Discounter;
|
use Discounter;
|
||||||
use Taxer;
|
use Taxer;
|
||||||
|
|
||||||
|
//@phpstan-ignore-next-line
|
||||||
private array $eu_tax_jurisdictions = [
|
private array $eu_tax_jurisdictions = [
|
||||||
'AT', // Austria
|
'AT', // Austria
|
||||||
'BE', // Belgium
|
'BE', // Belgium
|
||||||
@ -98,6 +98,7 @@ class InvoiceItemSumInclusive
|
|||||||
|
|
||||||
private $total_taxes;
|
private $total_taxes;
|
||||||
|
|
||||||
|
/** @phpstan-ignore-next-line */
|
||||||
private $item;
|
private $item;
|
||||||
|
|
||||||
private $line_items;
|
private $line_items;
|
||||||
@ -399,7 +400,7 @@ class InvoiceItemSumInclusive
|
|||||||
private function shouldCalculateTax(): self
|
private function shouldCalculateTax(): self
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!$this->invoice->company?->calculate_taxes || $this->invoice->company->account->isFreeHostedClient()) {
|
if (!$this->invoice->company?->calculate_taxes || $this->invoice->company->account->isFreeHostedClient()) {//@phpstan-ignore-line
|
||||||
$this->calc_tax = false;
|
$this->calc_tax = false;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ class ProRata
|
|||||||
*/
|
*/
|
||||||
public function refund(float $amount, Carbon $from_date, Carbon $to_date, int $frequency): float
|
public function refund(float $amount, Carbon $from_date, Carbon $to_date, int $frequency): float
|
||||||
{
|
{
|
||||||
$days = $from_date->copy()->diffInDays($to_date);
|
$days = intval(abs($from_date->copy()->diffInDays($to_date)));
|
||||||
$days_in_frequency = $this->getDaysInFrequency($frequency);
|
$days_in_frequency = $this->getDaysInFrequency($frequency);
|
||||||
|
|
||||||
return round((($days / $days_in_frequency) * $amount), 2);
|
return round((($days / $days_in_frequency) * $amount), 2);
|
||||||
@ -48,7 +48,7 @@ class ProRata
|
|||||||
*/
|
*/
|
||||||
public function charge(float $amount, Carbon $from_date, Carbon $to_date, int $frequency): float
|
public function charge(float $amount, Carbon $from_date, Carbon $to_date, int $frequency): float
|
||||||
{
|
{
|
||||||
$days = $from_date->copy()->diffInDays($to_date);
|
$days = intval(abs($from_date->copy()->diffInDays($to_date)));
|
||||||
$days_in_frequency = $this->getDaysInFrequency($frequency);
|
$days_in_frequency = $this->getDaysInFrequency($frequency);
|
||||||
|
|
||||||
return round((($days / $days_in_frequency) * $amount), 2);
|
return round((($days / $days_in_frequency) * $amount), 2);
|
||||||
@ -58,21 +58,21 @@ class ProRata
|
|||||||
* Prepares the line items of an invoice
|
* Prepares the line items of an invoice
|
||||||
* to be pro rata refunded.
|
* to be pro rata refunded.
|
||||||
*
|
*
|
||||||
* @param Invoice $invoice
|
* @param ?Invoice $invoice
|
||||||
* @param bool $is_credit
|
* @param bool $is_credit
|
||||||
* @return array
|
* @return array
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function refundItems(Invoice $invoice, $is_credit = false): array
|
public function refundItems(?Invoice $invoice, $is_credit = false): array
|
||||||
{
|
{
|
||||||
if (! $invoice) {
|
if (! $invoice) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var \App\Models\RecurringInvoice $recurring_invoice **/
|
/** @var \App\Models\RecurringInvoice $recurring_invoice **/
|
||||||
$recurring_invoice = RecurringInvoice::find($invoice->recurring_id)->first();
|
$recurring_invoice = RecurringInvoice::find($invoice->recurring_id);
|
||||||
|
|
||||||
if (! $recurring_invoice) {
|
if (! $recurring_invoice) { // @phpstan-ignore-line
|
||||||
throw new \Exception("Invoice isn't attached to a recurring invoice");
|
throw new \Exception("Invoice isn't attached to a recurring invoice");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,23 +107,23 @@ class ProRata
|
|||||||
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
||||||
return 14;
|
return 14;
|
||||||
case RecurringInvoice::FREQUENCY_FOUR_WEEKS:
|
case RecurringInvoice::FREQUENCY_FOUR_WEEKS:
|
||||||
return now()->diffInDays(now()->addWeeks(4));
|
return intval(abs(now()->diffInDays(now()->addWeeks(4))));
|
||||||
case RecurringInvoice::FREQUENCY_MONTHLY:
|
case RecurringInvoice::FREQUENCY_MONTHLY:
|
||||||
return now()->diffInDays(now()->addMonthNoOverflow());
|
return intval(abs(now()->diffInDays(now()->addMonthNoOverflow())));
|
||||||
case RecurringInvoice::FREQUENCY_TWO_MONTHS:
|
case RecurringInvoice::FREQUENCY_TWO_MONTHS:
|
||||||
return now()->diffInDays(now()->addMonthsNoOverflow(2));
|
return intval(abs(now()->diffInDays(now()->addMonthsNoOverflow(2))));
|
||||||
case RecurringInvoice::FREQUENCY_THREE_MONTHS:
|
case RecurringInvoice::FREQUENCY_THREE_MONTHS:
|
||||||
return now()->diffInDays(now()->addMonthsNoOverflow(3));
|
return intval(abs(now()->diffInDays(now()->addMonthsNoOverflow(3))));
|
||||||
case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
|
case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
|
||||||
return now()->diffInDays(now()->addMonthsNoOverflow(4));
|
return intval(abs(now()->diffInDays(now()->addMonthsNoOverflow(4))));
|
||||||
case RecurringInvoice::FREQUENCY_SIX_MONTHS:
|
case RecurringInvoice::FREQUENCY_SIX_MONTHS:
|
||||||
return now()->diffInDays(now()->addMonthsNoOverflow(6));
|
return intval(abs(now()->diffInDays(now()->addMonthsNoOverflow(6))));
|
||||||
case RecurringInvoice::FREQUENCY_ANNUALLY:
|
case RecurringInvoice::FREQUENCY_ANNUALLY:
|
||||||
return now()->diffInDays(now()->addYear());
|
return intval(abs(now()->diffInDays(now()->addYear())));
|
||||||
case RecurringInvoice::FREQUENCY_TWO_YEARS:
|
case RecurringInvoice::FREQUENCY_TWO_YEARS:
|
||||||
return now()->diffInDays(now()->addYears(2));
|
return intval(abs(now()->diffInDays(now()->addYears(2))));
|
||||||
case RecurringInvoice::FREQUENCY_THREE_YEARS:
|
case RecurringInvoice::FREQUENCY_THREE_YEARS:
|
||||||
return now()->diffInDays(now()->addYears(3));
|
return intval(abs(now()->diffInDays(now()->addYears(3))));
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -11,19 +11,31 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
|
|
||||||
use App\Http\Requests\Activity\ShowActivityRequest;
|
|
||||||
use App\Models\Activity;
|
|
||||||
use App\Transformers\ActivityTransformer;
|
|
||||||
use App\Utils\HostedPDF\NinjaPdf;
|
|
||||||
use App\Utils\Ninja;
|
|
||||||
use App\Utils\PhantomJS\Phantom;
|
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use App\Utils\Traits\Pdf\PageNumbering;
|
|
||||||
use App\Utils\Traits\Pdf\PdfMaker;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Activity;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\PhantomJS\Phantom;
|
||||||
|
use App\Utils\HostedPDF\NinjaPdf;
|
||||||
|
use App\Utils\Traits\Pdf\PdfMaker;
|
||||||
|
use App\Utils\Traits\Pdf\PageNumbering;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use App\Transformers\ActivityTransformer;
|
||||||
|
use App\Http\Requests\Activity\StoreNoteRequest;
|
||||||
|
use App\Http\Requests\Activity\ShowActivityRequest;
|
||||||
|
use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
|
||||||
|
use App\Models\Credit;
|
||||||
|
use App\Models\Expense;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\PurchaseOrder;
|
||||||
|
use App\Models\Quote;
|
||||||
|
use App\Models\RecurringExpense;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Models\Task;
|
||||||
|
use App\Models\Vendor;
|
||||||
|
|
||||||
class ActivityController extends BaseController
|
class ActivityController extends BaseController
|
||||||
{
|
{
|
||||||
@ -177,4 +189,89 @@ class ActivityController extends BaseController
|
|||||||
echo $pdf;
|
echo $pdf;
|
||||||
}, $filename, ['Content-Type' => 'application/pdf']);
|
}, $filename, ['Content-Type' => 'application/pdf']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function note(StoreNoteRequest $request)
|
||||||
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$entity = $request->getEntity();
|
||||||
|
|
||||||
|
$activity = new Activity();
|
||||||
|
$activity->account_id = $user->account_id;
|
||||||
|
$activity->company_id = $user->company()->id;
|
||||||
|
$activity->notes = $request->notes;
|
||||||
|
$activity->user_id = $user->id;
|
||||||
|
$activity->ip = $request->ip();
|
||||||
|
$activity->activity_type_id = Activity::USER_NOTE;
|
||||||
|
|
||||||
|
switch (get_class($entity)) {
|
||||||
|
case Invoice::class:
|
||||||
|
$activity->invoice_id = $entity->id;
|
||||||
|
$activity->client_id = $entity->client_id;
|
||||||
|
$activity->project_id = $entity->project_id;
|
||||||
|
$activity->vendor_id = $entity->vendor_id;
|
||||||
|
break;
|
||||||
|
case Credit::class:
|
||||||
|
$activity->credit_id = $entity->id;
|
||||||
|
$activity->client_id = $entity->client_id;
|
||||||
|
$activity->project_id = $entity->project_id;
|
||||||
|
$activity->vendor_id = $entity->vendor_id;
|
||||||
|
$activity->invoice_id = $entity->invoice_id;
|
||||||
|
break;
|
||||||
|
case Client::class:
|
||||||
|
$activity->client_id = $entity->id;
|
||||||
|
break;
|
||||||
|
case Quote::class:
|
||||||
|
$activity->quote_id = $entity->id;
|
||||||
|
$activity->client_id = $entity->client_id;
|
||||||
|
$activity->project_id = $entity->project_id;
|
||||||
|
$activity->vendor_id = $entity->vendor_id;
|
||||||
|
break;
|
||||||
|
case RecurringInvoice::class:
|
||||||
|
$activity->recurring_invoice_id = $entity->id;
|
||||||
|
$activity->client_id = $entity->client_id;
|
||||||
|
break;
|
||||||
|
case Expense::class:
|
||||||
|
$activity->expense_id = $entity->id;
|
||||||
|
$activity->client_id = $entity->client_id;
|
||||||
|
$activity->project_id = $entity->project_id;
|
||||||
|
$activity->vendor_id = $entity->vendor_id;
|
||||||
|
break;
|
||||||
|
case RecurringExpense::class:
|
||||||
|
$activity->recurring_expense_id = $entity->id;
|
||||||
|
$activity->expense_id = $entity->id;
|
||||||
|
$activity->client_id = $entity->client_id;
|
||||||
|
$activity->project_id = $entity->project_id;
|
||||||
|
$activity->vendor_id = $entity->vendor_id;
|
||||||
|
break;
|
||||||
|
case Vendor::class:
|
||||||
|
$activity->vendor_id = $entity->id;
|
||||||
|
break;
|
||||||
|
case PurchaseOrder::class:
|
||||||
|
$activity->purchase_order_id = $entity->id;
|
||||||
|
$activity->expense_id = $entity->id;
|
||||||
|
$activity->client_id = $entity->client_id;
|
||||||
|
$activity->project_id = $entity->project_id;
|
||||||
|
$activity->vendor_id = $entity->vendor_id;
|
||||||
|
case Task::class:
|
||||||
|
$activity->task_id = $entity->id;
|
||||||
|
$activity->expense_id = $entity->id;
|
||||||
|
$activity->client_id = $entity->client_id;
|
||||||
|
$activity->project_id = $entity->project_id;
|
||||||
|
$activity->vendor_id = $entity->vendor_id;
|
||||||
|
case Payment::class:
|
||||||
|
$activity->payment_id = $entity->id;
|
||||||
|
$activity->expense_id = $entity->id;
|
||||||
|
$activity->client_id = $entity->client_id;
|
||||||
|
$activity->project_id = $entity->project_id;
|
||||||
|
default:
|
||||||
|
# code...
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$activity->save();
|
||||||
|
|
||||||
|
return $this->itemResponse($activity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ class ContactForgotPasswordController extends Controller
|
|||||||
})->first();
|
})->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = false;
|
// $response = false;
|
||||||
|
|
||||||
if ($contact) {
|
if ($contact) {
|
||||||
/* Update all instances of the client */
|
/* Update all instances of the client */
|
||||||
@ -131,16 +131,16 @@ class ContactForgotPasswordController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->ajax()) {
|
if ($request->ajax()) {
|
||||||
if ($response == Password::RESET_THROTTLED) {
|
if ($response == Password::RESET_THROTTLED) { // @phpstan-ignore-line
|
||||||
return response()->json(['message' => ctrans('passwords.throttled'), 'status' => false], 429);
|
return response()->json(['message' => ctrans('passwords.throttled'), 'status' => false], 429);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response == Password::RESET_LINK_SENT
|
return $response == Password::RESET_LINK_SENT // @phpstan-ignore-line
|
||||||
? 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response == Password::RESET_LINK_SENT
|
return $response == Password::RESET_LINK_SENT // @phpstan-ignore-line
|
||||||
? $this->sendResetLinkResponse($request, $response)
|
? $this->sendResetLinkResponse($request, $response)
|
||||||
: $this->sendResetLinkFailedResponse($request, $response);
|
: $this->sendResetLinkFailedResponse($request, $response);
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ class ContactLoginController extends Controller
|
|||||||
$company = Company::where('company_key', $company_key)->first();
|
$company = Company::where('company_key', $company_key)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var \App\Models\Company $company **/
|
/** @var ?\App\Models\Company $company **/
|
||||||
if ($company) {
|
if ($company) {
|
||||||
$account = $company->account;
|
$account = $company->account;
|
||||||
} elseif (! $company && strpos($request->getHost(), config('ninja.app_domain')) !== false) {
|
} elseif (! $company && strpos($request->getHost(), config('ninja.app_domain')) !== false) {
|
||||||
|
@ -137,8 +137,8 @@ class ResetPasswordController extends Controller
|
|||||||
return redirect('/#/login');
|
return redirect('/#/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect($this->redirectPath())
|
// return redirect($this->redirectPath())
|
||||||
->with('status', trans($response));
|
// ->with('status', trans($response));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Bank;
|
namespace App\Http\Controllers\Bank;
|
||||||
|
|
||||||
use App\Helpers\Bank\Yodlee\DTO\AccountSummary;
|
|
||||||
use App\Helpers\Bank\Yodlee\Yodlee;
|
use App\Helpers\Bank\Yodlee\Yodlee;
|
||||||
use App\Http\Controllers\BaseController;
|
use App\Http\Controllers\BaseController;
|
||||||
use App\Http\Requests\Yodlee\YodleeAdminRequest;
|
use App\Http\Requests\Yodlee\YodleeAdminRequest;
|
||||||
@ -301,8 +300,6 @@ class YodleeController extends BaseController
|
|||||||
|
|
||||||
$summary = $yodlee->getAccountSummary($account_number);
|
$summary = $yodlee->getAccountSummary($account_number);
|
||||||
|
|
||||||
//@todo remove laravel-data
|
|
||||||
// $transformed_summary = AccountSummary::from($summary[0]);
|
|
||||||
$transformed_summary = $this->transformSummary($summary[0]);
|
$transformed_summary = $this->transformSummary($summary[0]);
|
||||||
|
|
||||||
return response()->json($transformed_summary, 200);
|
return response()->json($transformed_summary, 200);
|
||||||
|
@ -270,7 +270,7 @@ class BankIntegrationController extends BaseController
|
|||||||
|
|
||||||
$nordigen = new Nordigen();
|
$nordigen = new Nordigen();
|
||||||
|
|
||||||
BankIntegration::where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->whereNotNull('nordigen_account_id')->each(function (BankIntegration $bank_integration) use ($nordigen) {
|
BankIntegration::where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->where('account_id', $user->account_id)->whereNotNull('nordigen_account_id')->each(function (BankIntegration $bank_integration) use ($nordigen) {
|
||||||
$is_account_active = $nordigen->isAccountActive($bank_integration->nordigen_account_id);
|
$is_account_active = $nordigen->isAccountActive($bank_integration->nordigen_account_id);
|
||||||
$account = $nordigen->getAccount($bank_integration->nordigen_account_id);
|
$account = $nordigen->getAccount($bank_integration->nordigen_account_id);
|
||||||
|
|
||||||
|
@ -1035,7 +1035,7 @@ class BaseController extends Controller
|
|||||||
|
|
||||||
$resource = new Item($item, $transformer, $this->entity_type);
|
$resource = new Item($item, $transformer, $this->entity_type);
|
||||||
|
|
||||||
/** @var \App\Models\User $user */
|
/** @var ?\App\Models\User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
if ($user && request()->include_static) {
|
if ($user && request()->include_static) {
|
||||||
@ -1158,8 +1158,6 @@ class BaseController extends Controller
|
|||||||
|
|
||||||
$data['path'] = $this->setBuild();
|
$data['path'] = $this->setBuild();
|
||||||
|
|
||||||
$this->buildCache();
|
|
||||||
|
|
||||||
if (Ninja::isSelfHost() && $account->set_react_as_default_ap) {
|
if (Ninja::isSelfHost() && $account->set_react_as_default_ap) {
|
||||||
return response()->view('react.index', $data)->header('X-Frame-Options', 'SAMEORIGIN', false);
|
return response()->view('react.index', $data)->header('X-Frame-Options', 'SAMEORIGIN', false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,7 +20,6 @@ use Illuminate\Http\Request;
|
|||||||
*/
|
*/
|
||||||
class BrevoController extends BaseController
|
class BrevoController extends BaseController
|
||||||
{
|
{
|
||||||
private $invitation;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -141,7 +141,7 @@ class ClientController extends BaseController
|
|||||||
return $request->disallowUpdate();
|
return $request->disallowUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var \App\Models\User $user */
|
/** @var ?\App\Models\User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
$client = $this->client_repo->save($request->all(), $client);
|
$client = $this->client_repo->save($request->all(), $client);
|
||||||
@ -426,7 +426,7 @@ class ClientController extends BaseController
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
/** @var \Postmark\Models\DynamicResponseModel $response */
|
/** @var ?\Postmark\Models\DynamicResponseModel $response */
|
||||||
$response = $postmark->activateBounce((int)$bounce_id);
|
$response = $postmark->activateBounce((int)$bounce_id);
|
||||||
|
|
||||||
if($response && $response?->Message == 'OK' && !$response->Bounce->Inactive && $response->Bounce->Email) {
|
if($response && $response?->Message == 'OK' && !$response->Bounce->Inactive && $response->Bounce->Email) {
|
||||||
|
@ -146,6 +146,7 @@ class InvitationController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function fireEntityViewedEvent($invitation, $entity_string)
|
private function fireEntityViewedEvent($invitation, $entity_string)
|
||||||
{
|
{
|
||||||
switch ($entity_string) {
|
switch ($entity_string) {
|
||||||
|
@ -97,12 +97,12 @@ class InvoiceController extends Controller
|
|||||||
|
|
||||||
$invitation = false;
|
$invitation = false;
|
||||||
|
|
||||||
match($data['entity_type'] ?? false) {
|
match($data['entity_type'] ?? 'invoice') {
|
||||||
'invoice' => $invitation = InvoiceInvitation::withTrashed()->find($data['invitation_id']),
|
'invoice' => $invitation = InvoiceInvitation::withTrashed()->find($data['invitation_id']),
|
||||||
'quote' => $invitation = QuoteInvitation::withTrashed()->find($data['invitation_id']),
|
'quote' => $invitation = QuoteInvitation::withTrashed()->find($data['invitation_id']),
|
||||||
'credit' => $invitation = CreditInvitation::withTrashed()->find($data['invitation_id']),
|
'credit' => $invitation = CreditInvitation::withTrashed()->find($data['invitation_id']),
|
||||||
'recurring_invoice' => $invitation = RecurringInvoiceInvitation::withTrashed()->find($data['invitation_id']),
|
'recurring_invoice' => $invitation = RecurringInvoiceInvitation::withTrashed()->find($data['invitation_id']),
|
||||||
false => $invitation = false,
|
default => $invitation = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (! $invitation) {
|
if (! $invitation) {
|
||||||
|
@ -77,6 +77,7 @@ class PaymentController extends Controller
|
|||||||
'EUR' => $data = $bt->formatDataforEur($payment_intent),
|
'EUR' => $data = $bt->formatDataforEur($payment_intent),
|
||||||
'JPY' => $data = $bt->formatDataforJp($payment_intent),
|
'JPY' => $data = $bt->formatDataforJp($payment_intent),
|
||||||
'GBP' => $data = $bt->formatDataforUk($payment_intent),
|
'GBP' => $data = $bt->formatDataforUk($payment_intent),
|
||||||
|
default => $data = $bt->formatDataforUk($payment_intent),
|
||||||
};
|
};
|
||||||
|
|
||||||
$gateway = $stripe;
|
$gateway = $stripe;
|
||||||
|
@ -90,15 +90,20 @@ class SubscriptionPurchaseController extends Controller
|
|||||||
* Set locale for incoming request.
|
* Set locale for incoming request.
|
||||||
*
|
*
|
||||||
* @param string $locale
|
* @param string $locale
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function setLocale(string $locale): void
|
private function setLocale(string $locale): string
|
||||||
{
|
{
|
||||||
$record = Cache::get('languages')->filter(function ($item) use ($locale) {
|
|
||||||
return $item->locale == $locale;
|
|
||||||
})->first();
|
|
||||||
|
|
||||||
if ($record) {
|
/** @var \Illuminate\Support\Collection<\App\Models\Language> */
|
||||||
App::setLocale($record->locale);
|
$languages = app('languages');
|
||||||
}
|
|
||||||
|
$record = $languages->first(function ($item) use ($locale) {
|
||||||
|
/** @var \App\Models\Language $item */
|
||||||
|
return $item->locale == $locale;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $record ? $record->locale : 'en';
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -693,7 +693,7 @@ class CompanyController extends BaseController
|
|||||||
public function updateOriginTaxData(DefaultCompanyRequest $request, Company $company)
|
public function updateOriginTaxData(DefaultCompanyRequest $request, Company $company)
|
||||||
{
|
{
|
||||||
|
|
||||||
if($company->settings->country_id == "840" && !$company?->account->isFreeHostedClient()) {
|
if($company->settings->country_id == "840" && !$company->account->isFreeHostedClient()) {
|
||||||
try {
|
try {
|
||||||
(new CompanyTaxRate($company))->handle();
|
(new CompanyTaxRate($company))->handle();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
@ -119,8 +119,6 @@ class CompanyUserController extends BaseController
|
|||||||
|
|
||||||
if (! $company_user) {
|
if (! $company_user) {
|
||||||
throw new ModelNotFoundException(ctrans('texts.company_user_not_found'));
|
throw new ModelNotFoundException(ctrans('texts.company_user_not_found'));
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($auth_user->isAdmin()) {
|
if ($auth_user->isAdmin()) {
|
||||||
@ -152,7 +150,6 @@ class CompanyUserController extends BaseController
|
|||||||
|
|
||||||
if (! $company_user) {
|
if (! $company_user) {
|
||||||
throw new ModelNotFoundException(ctrans('texts.company_user_not_found'));
|
throw new ModelNotFoundException(ctrans('texts.company_user_not_found'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->entity_type = User::class;
|
$this->entity_type = User::class;
|
||||||
|
@ -594,13 +594,11 @@ class CreditController extends BaseController
|
|||||||
$credit->service()->markPaid()->save();
|
$credit->service()->markPaid()->save();
|
||||||
|
|
||||||
return $this->itemResponse($credit);
|
return $this->itemResponse($credit);
|
||||||
break;
|
|
||||||
|
|
||||||
case 'clone_to_credit':
|
case 'clone_to_credit':
|
||||||
$credit = CloneCreditFactory::create($credit, auth()->user()->id);
|
$credit = CloneCreditFactory::create($credit, auth()->user()->id);
|
||||||
|
|
||||||
return $this->itemResponse($credit);
|
return $this->itemResponse($credit);
|
||||||
break;
|
|
||||||
case 'history':
|
case 'history':
|
||||||
// code...
|
// code...
|
||||||
break;
|
break;
|
||||||
@ -617,7 +615,7 @@ class CreditController extends BaseController
|
|||||||
return response()->streamDownload(function () use ($file) {
|
return response()->streamDownload(function () use ($file) {
|
||||||
echo $file;
|
echo $file;
|
||||||
}, $credit->numberFormatter() . '.pdf', ['Content-Type' => 'application/pdf']);
|
}, $credit->numberFormatter() . '.pdf', ['Content-Type' => 'application/pdf']);
|
||||||
break;
|
|
||||||
case 'archive':
|
case 'archive':
|
||||||
$this->credit_repository->archive($credit);
|
$this->credit_repository->archive($credit);
|
||||||
|
|
||||||
@ -655,7 +653,6 @@ class CreditController extends BaseController
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
|
return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,19 +139,19 @@ class EmailController extends BaseController
|
|||||||
return $this->itemResponse($entity_obj->fresh());
|
return $this->itemResponse($entity_obj->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function sendPurchaseOrder($entity_obj, $data, $template)
|
// private function sendPurchaseOrder($entity_obj, $data, $template)
|
||||||
{
|
// {
|
||||||
$this->entity_type = PurchaseOrder::class;
|
// $this->entity_type = PurchaseOrder::class;
|
||||||
|
|
||||||
$this->entity_transformer = PurchaseOrderTransformer::class;
|
// $this->entity_transformer = PurchaseOrderTransformer::class;
|
||||||
|
|
||||||
$data['template'] = $template;
|
// $data['template'] = $template;
|
||||||
|
|
||||||
PurchaseOrderEmail::dispatch($entity_obj, $entity_obj->company, $data);
|
// PurchaseOrderEmail::dispatch($entity_obj, $entity_obj->company, $data);
|
||||||
$entity_obj->sendEvent(Webhook::EVENT_SENT_PURCHASE_ORDER, "vendor");
|
// $entity_obj->sendEvent(Webhook::EVENT_SENT_PURCHASE_ORDER, "vendor");
|
||||||
|
|
||||||
return $this->itemResponse($entity_obj);
|
// return $this->itemResponse($entity_obj);
|
||||||
}
|
// }
|
||||||
|
|
||||||
private function resolveClass(string $entity): string
|
private function resolveClass(string $entity): string
|
||||||
{
|
{
|
||||||
|
@ -19,10 +19,12 @@ use App\Http\Requests\Expense\BulkExpenseRequest;
|
|||||||
use App\Http\Requests\Expense\CreateExpenseRequest;
|
use App\Http\Requests\Expense\CreateExpenseRequest;
|
||||||
use App\Http\Requests\Expense\DestroyExpenseRequest;
|
use App\Http\Requests\Expense\DestroyExpenseRequest;
|
||||||
use App\Http\Requests\Expense\EditExpenseRequest;
|
use App\Http\Requests\Expense\EditExpenseRequest;
|
||||||
|
use App\Http\Requests\Expense\EDocumentRequest;
|
||||||
use App\Http\Requests\Expense\ShowExpenseRequest;
|
use App\Http\Requests\Expense\ShowExpenseRequest;
|
||||||
use App\Http\Requests\Expense\StoreExpenseRequest;
|
use App\Http\Requests\Expense\StoreExpenseRequest;
|
||||||
use App\Http\Requests\Expense\UpdateExpenseRequest;
|
use App\Http\Requests\Expense\UpdateExpenseRequest;
|
||||||
use App\Http\Requests\Expense\UploadExpenseRequest;
|
use App\Http\Requests\Expense\UploadExpenseRequest;
|
||||||
|
use App\Jobs\EDocument\ImportEDocument;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\Expense;
|
use App\Models\Expense;
|
||||||
use App\Repositories\ExpenseRepository;
|
use App\Repositories\ExpenseRepository;
|
||||||
@ -581,4 +583,15 @@ class ExpenseController extends BaseController
|
|||||||
|
|
||||||
return $this->itemResponse($expense->fresh());
|
return $this->itemResponse($expense->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function edocument(EDocumentRequest $request): string
|
||||||
|
{
|
||||||
|
if ($request->hasFile("documents")) {
|
||||||
|
return (new ImportEDocument($request->file("documents")[0]->get(), $request->file("documents")[0]->getClientOriginalName()))->handle();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "No file found";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,186 +280,172 @@ class MigrationController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app()->environment() === 'local') {
|
foreach ($companies as $company) {
|
||||||
}
|
if (! is_array($company)) {
|
||||||
|
continue;
|
||||||
try {
|
|
||||||
return response()->json([
|
|
||||||
'_id' => Str::uuid(),
|
|
||||||
'method' => config('queue.default'),
|
|
||||||
'started_at' => now(),
|
|
||||||
], 200);
|
|
||||||
} finally {
|
|
||||||
// Controller logic here
|
|
||||||
|
|
||||||
foreach ($companies as $company) {
|
|
||||||
if (! is_array($company)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$company = (array) $company;
|
|
||||||
|
|
||||||
$user = auth()->user();
|
|
||||||
|
|
||||||
$company_count = $user->account->companies()->count();
|
|
||||||
$fresh_company = false;
|
|
||||||
|
|
||||||
// Look for possible existing company (based on company keys).
|
|
||||||
$existing_company = Company::query()->whereRaw('BINARY `company_key` = ?', [$company['company_key']])->first();
|
|
||||||
|
|
||||||
App::forgetInstance('translator');
|
|
||||||
$t = app('translator');
|
|
||||||
$t->replace(Ninja::transformTranslations($user->account->companies()->first()->settings));
|
|
||||||
App::setLocale($user->account->companies()->first()->getLocale());
|
|
||||||
|
|
||||||
if (! $existing_company && $company_count >= 10) {
|
|
||||||
$nmo = new NinjaMailerObject();
|
|
||||||
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
|
|
||||||
$nmo->company = $user->account->companies()->first();
|
|
||||||
$nmo->settings = $user->account->companies()->first()->settings;
|
|
||||||
$nmo->to_user = $user;
|
|
||||||
|
|
||||||
if(!$this->silent_migration) {
|
|
||||||
NinjaMailerJob::dispatch($nmo, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
} elseif ($existing_company && $company_count > 10) {
|
|
||||||
$nmo = new NinjaMailerObject();
|
|
||||||
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
|
|
||||||
$nmo->company = $user->account->companies()->first();
|
|
||||||
$nmo->settings = $user->account->companies()->first()->settings;
|
|
||||||
$nmo->to_user = $user;
|
|
||||||
|
|
||||||
if(!$this->silent_migration) {
|
|
||||||
NinjaMailerJob::dispatch($nmo, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$checks = [
|
|
||||||
'existing_company' => $existing_company ? (bool) 1 : false,
|
|
||||||
'force' => array_key_exists('force', $company) ? (bool) $company['force'] : false,
|
|
||||||
];
|
|
||||||
|
|
||||||
// If there's existing company and ** no ** force is provided - skip migration.
|
|
||||||
if ($checks['existing_company'] == true && $checks['force'] == false) {
|
|
||||||
nlog('Migrating: Existing company without force. (CASE_01)');
|
|
||||||
|
|
||||||
$nmo = new NinjaMailerObject();
|
|
||||||
$nmo->mailable = new ExistingMigration($existing_company);
|
|
||||||
$nmo->company = $user->account->companies()->first();
|
|
||||||
$nmo->settings = $user->account->companies()->first();
|
|
||||||
$nmo->to_user = $user;
|
|
||||||
|
|
||||||
if(!$this->silent_migration) {
|
|
||||||
NinjaMailerJob::dispatch($nmo, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'_id' => Str::uuid(),
|
|
||||||
'method' => config('queue.default'),
|
|
||||||
'started_at' => now(),
|
|
||||||
], 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's existing company and force ** is provided ** - purge the company and migrate again.
|
|
||||||
if ($checks['existing_company'] == true && $checks['force'] == true) {
|
|
||||||
nlog('purging the existing company here');
|
|
||||||
$this->purgeCompanyWithForceFlag($existing_company);
|
|
||||||
|
|
||||||
$account = auth()->user()->account;
|
|
||||||
$fresh_company = (new ImportMigrations())->getCompany($account);
|
|
||||||
$fresh_company->is_disabled = true;
|
|
||||||
$fresh_company->save();
|
|
||||||
|
|
||||||
$account->default_company_id = $fresh_company->id;
|
|
||||||
$account->save();
|
|
||||||
|
|
||||||
$fresh_company_token = new CompanyToken();
|
|
||||||
$fresh_company_token->user_id = $user->id;
|
|
||||||
$fresh_company_token->company_id = $fresh_company->id;
|
|
||||||
$fresh_company_token->account_id = $account->id;
|
|
||||||
$fresh_company_token->name = $request->token_name ?? Str::random(12);
|
|
||||||
$fresh_company_token->token = $request->token ?? Str::random(64);
|
|
||||||
$fresh_company_token->is_system = true;
|
|
||||||
$fresh_company_token->save();
|
|
||||||
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user->companies()->attach($fresh_company->id, [
|
|
||||||
'account_id' => $account->id,
|
|
||||||
'is_owner' => 1,
|
|
||||||
'is_admin' => 1,
|
|
||||||
'is_locked' => 0,
|
|
||||||
'notifications' => CompanySettings::notificationDefaults(),
|
|
||||||
'permissions' => '',
|
|
||||||
'settings' => null,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's no existing company migrate just normally.
|
|
||||||
if ($checks['existing_company'] == false) {
|
|
||||||
nlog('creating fresh company');
|
|
||||||
|
|
||||||
$account = auth()->user()->account;
|
|
||||||
$fresh_company = (new ImportMigrations())->getCompany($account);
|
|
||||||
|
|
||||||
$fresh_company->is_disabled = true;
|
|
||||||
$fresh_company->save();
|
|
||||||
|
|
||||||
$fresh_company_token = new CompanyToken();
|
|
||||||
$fresh_company_token->user_id = $user->id;
|
|
||||||
$fresh_company_token->company_id = $fresh_company->id;
|
|
||||||
$fresh_company_token->account_id = $account->id;
|
|
||||||
$fresh_company_token->name = $request->token_name ?? Str::random(12);
|
|
||||||
$fresh_company_token->token = $request->token ?? Str::random(64);
|
|
||||||
$fresh_company_token->is_system = true;
|
|
||||||
|
|
||||||
$fresh_company_token->save();
|
|
||||||
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user->companies()->attach($fresh_company->id, [
|
|
||||||
'account_id' => $account->id,
|
|
||||||
'is_owner' => 1,
|
|
||||||
'is_admin' => 1,
|
|
||||||
'is_locked' => 0,
|
|
||||||
'notifications' => CompanySettings::notificationDefaults(),
|
|
||||||
'permissions' => '',
|
|
||||||
'settings' => null,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$migration_file = $request->file($company['company_index'])
|
|
||||||
->storeAs(
|
|
||||||
'migrations',
|
|
||||||
$request->file($company['company_index'])->getClientOriginalName(),
|
|
||||||
'public'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (app()->environment() == 'testing') {
|
|
||||||
nlog('environment is testing = bailing out now');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nlog('starting migration job');
|
|
||||||
nlog($migration_file);
|
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
|
||||||
StartMigration::dispatch($migration_file, $user, $fresh_company, $this->silent_migration)->onQueue('migration');
|
|
||||||
} else {
|
|
||||||
StartMigration::dispatch($migration_file, $user, $fresh_company, $this->silent_migration);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
$company = (array) $company;
|
||||||
'_id' => Str::uuid(),
|
|
||||||
'method' => config('queue.default'),
|
|
||||||
'started_at' => now(),
|
|
||||||
], 200);
|
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$company_count = $user->account->companies()->count();
|
||||||
|
$fresh_company = false;
|
||||||
|
|
||||||
|
// Look for possible existing company (based on company keys).
|
||||||
|
$existing_company = Company::query()->whereRaw('BINARY `company_key` = ?', [$company['company_key']])->first();
|
||||||
|
|
||||||
|
App::forgetInstance('translator');
|
||||||
|
$t = app('translator');
|
||||||
|
$t->replace(Ninja::transformTranslations($user->account->companies()->first()->settings));
|
||||||
|
App::setLocale($user->account->companies()->first()->getLocale());
|
||||||
|
|
||||||
|
if (! $existing_company && $company_count >= 10) {
|
||||||
|
$nmo = new NinjaMailerObject();
|
||||||
|
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
|
||||||
|
$nmo->company = $user->account->companies()->first();
|
||||||
|
$nmo->settings = $user->account->companies()->first()->settings;
|
||||||
|
$nmo->to_user = $user;
|
||||||
|
|
||||||
|
if(!$this->silent_migration) {
|
||||||
|
NinjaMailerJob::dispatch($nmo, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
} elseif ($existing_company && $company_count > 10) {
|
||||||
|
$nmo = new NinjaMailerObject();
|
||||||
|
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
|
||||||
|
$nmo->company = $user->account->companies()->first();
|
||||||
|
$nmo->settings = $user->account->companies()->first()->settings;
|
||||||
|
$nmo->to_user = $user;
|
||||||
|
|
||||||
|
if(!$this->silent_migration) {
|
||||||
|
NinjaMailerJob::dispatch($nmo, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$checks = [
|
||||||
|
'existing_company' => $existing_company ? (bool) 1 : false,
|
||||||
|
'force' => array_key_exists('force', $company) ? (bool) $company['force'] : false,
|
||||||
|
];
|
||||||
|
|
||||||
|
// If there's existing company and ** no ** force is provided - skip migration.
|
||||||
|
if ($checks['existing_company'] == true && $checks['force'] == false) {
|
||||||
|
nlog('Migrating: Existing company without force. (CASE_01)');
|
||||||
|
|
||||||
|
$nmo = new NinjaMailerObject();
|
||||||
|
$nmo->mailable = new ExistingMigration($existing_company);
|
||||||
|
$nmo->company = $user->account->companies()->first();
|
||||||
|
$nmo->settings = $user->account->companies()->first();
|
||||||
|
$nmo->to_user = $user;
|
||||||
|
|
||||||
|
if(!$this->silent_migration) {
|
||||||
|
NinjaMailerJob::dispatch($nmo, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'_id' => Str::uuid(),
|
||||||
|
'method' => config('queue.default'),
|
||||||
|
'started_at' => now(),
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's existing company and force ** is provided ** - purge the company and migrate again.
|
||||||
|
if ($checks['existing_company'] == true && $checks['force'] == true) {
|
||||||
|
nlog('purging the existing company here');
|
||||||
|
$this->purgeCompanyWithForceFlag($existing_company);
|
||||||
|
|
||||||
|
$account = auth()->user()->account;
|
||||||
|
$fresh_company = (new ImportMigrations())->getCompany($account);
|
||||||
|
$fresh_company->is_disabled = true;
|
||||||
|
$fresh_company->save();
|
||||||
|
|
||||||
|
$account->default_company_id = $fresh_company->id;
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
$fresh_company_token = new CompanyToken();
|
||||||
|
$fresh_company_token->user_id = $user->id;
|
||||||
|
$fresh_company_token->company_id = $fresh_company->id;
|
||||||
|
$fresh_company_token->account_id = $account->id;
|
||||||
|
$fresh_company_token->name = $request->token_name ?? Str::random(12);
|
||||||
|
$fresh_company_token->token = $request->token ?? Str::random(64);
|
||||||
|
$fresh_company_token->is_system = true;
|
||||||
|
$fresh_company_token->save();
|
||||||
|
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user->companies()->attach($fresh_company->id, [
|
||||||
|
'account_id' => $account->id,
|
||||||
|
'is_owner' => 1,
|
||||||
|
'is_admin' => 1,
|
||||||
|
'is_locked' => 0,
|
||||||
|
'notifications' => CompanySettings::notificationDefaults(),
|
||||||
|
'permissions' => '',
|
||||||
|
'settings' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's no existing company migrate just normally.
|
||||||
|
if ($checks['existing_company'] == false) {
|
||||||
|
nlog('creating fresh company');
|
||||||
|
|
||||||
|
$account = auth()->user()->account;
|
||||||
|
$fresh_company = (new ImportMigrations())->getCompany($account);
|
||||||
|
|
||||||
|
$fresh_company->is_disabled = true;
|
||||||
|
$fresh_company->save();
|
||||||
|
|
||||||
|
$fresh_company_token = new CompanyToken();
|
||||||
|
$fresh_company_token->user_id = $user->id;
|
||||||
|
$fresh_company_token->company_id = $fresh_company->id;
|
||||||
|
$fresh_company_token->account_id = $account->id;
|
||||||
|
$fresh_company_token->name = $request->token_name ?? Str::random(12);
|
||||||
|
$fresh_company_token->token = $request->token ?? Str::random(64);
|
||||||
|
$fresh_company_token->is_system = true;
|
||||||
|
|
||||||
|
$fresh_company_token->save();
|
||||||
|
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user->companies()->attach($fresh_company->id, [
|
||||||
|
'account_id' => $account->id,
|
||||||
|
'is_owner' => 1,
|
||||||
|
'is_admin' => 1,
|
||||||
|
'is_locked' => 0,
|
||||||
|
'notifications' => CompanySettings::notificationDefaults(),
|
||||||
|
'permissions' => '',
|
||||||
|
'settings' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$migration_file = $request->file($company['company_index'])
|
||||||
|
->storeAs(
|
||||||
|
'migrations',
|
||||||
|
$request->file($company['company_index'])->getClientOriginalName(),
|
||||||
|
'public'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (app()->environment() == 'testing') {
|
||||||
|
nlog('environment is testing = bailing out now');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlog('starting migration job');
|
||||||
|
nlog($migration_file);
|
||||||
|
|
||||||
|
if (Ninja::isHosted()) {
|
||||||
|
StartMigration::dispatch($migration_file, $user, $fresh_company, $this->silent_migration)->onQueue('migration');
|
||||||
|
} else {
|
||||||
|
StartMigration::dispatch($migration_file, $user, $fresh_company, $this->silent_migration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'_id' => Str::uuid(),
|
||||||
|
'method' => config('queue.default'),
|
||||||
|
'started_at' => now(),
|
||||||
|
], 200);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,6 @@ use Illuminate\Support\Str;
|
|||||||
|
|
||||||
class OneTimeTokenController extends BaseController
|
class OneTimeTokenController extends BaseController
|
||||||
{
|
{
|
||||||
private $contexts = [
|
|
||||||
];
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,6 @@ use Illuminate\Http\Request;
|
|||||||
*/
|
*/
|
||||||
class PostMarkController extends BaseController
|
class PostMarkController extends BaseController
|
||||||
{
|
{
|
||||||
private $invitation;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -219,139 +219,6 @@ class PreviewPurchaseOrderController extends BaseController
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function livex(PreviewPurchaseOrderRequest $request)
|
|
||||||
{
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = auth()->user();
|
|
||||||
$company = $user->company();
|
|
||||||
$file_path = (new PreviewPdf('<html></html>', $company))->handle();
|
|
||||||
$response = Response::make($file_path, 200);
|
|
||||||
$response->header('Content-Type', 'application/pdf');
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
|
|
||||||
MultiDB::setDb($company->db);
|
|
||||||
|
|
||||||
$repo = new PurchaseOrderRepository();
|
|
||||||
$entity_obj = PurchaseOrderFactory::create($company->id, $user->id);
|
|
||||||
$class = PurchaseOrder::class;
|
|
||||||
|
|
||||||
try {
|
|
||||||
DB::connection(config('database.default'))->beginTransaction();
|
|
||||||
|
|
||||||
if ($request->has('entity_id')) {
|
|
||||||
/** @var \App\Models\PurchaseOrder|\Illuminate\Contracts\Database\Eloquent\Builder $entity_obj **/
|
|
||||||
$entity_obj = \App\Models\PurchaseOrder::on(config('database.default'))
|
|
||||||
->with('vendor.company')
|
|
||||||
->where('id', $this->decodePrimaryKey($request->input('entity_id')))
|
|
||||||
->where('company_id', $company->id)
|
|
||||||
->withTrashed()
|
|
||||||
->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
$entity_obj = $repo->save($request->all(), $entity_obj);
|
|
||||||
|
|
||||||
if (!$request->has('entity_id')) {
|
|
||||||
$entity_obj->service()->fillDefaults()->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
App::forgetInstance('translator');
|
|
||||||
$t = app('translator');
|
|
||||||
App::setLocale($entity_obj->company->locale());
|
|
||||||
$t->replace(Ninja::transformTranslations($entity_obj->company->settings));
|
|
||||||
|
|
||||||
$html = new VendorHtmlEngine($entity_obj->invitations()->first());
|
|
||||||
|
|
||||||
/** @var \App\Models\Design $design */
|
|
||||||
$design = \App\Models\Design::withTrashed()->find($entity_obj->design_id);
|
|
||||||
|
|
||||||
/* Catch all in case migration doesn't pass back a valid design */
|
|
||||||
if (!$design) {
|
|
||||||
$design = \App\Models\Design::find(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($design->is_custom) {
|
|
||||||
$options = [
|
|
||||||
'custom_partials' => json_decode(json_encode($design->design), true)
|
|
||||||
];
|
|
||||||
$template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options);
|
|
||||||
} else {
|
|
||||||
$template = new PdfMakerDesign(strtolower($design->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
$variables = $html->generateLabelsAndValues();
|
|
||||||
|
|
||||||
$state = [
|
|
||||||
'template' => $template->elements([
|
|
||||||
'client' => null,
|
|
||||||
'vendor' => $entity_obj->vendor,
|
|
||||||
'entity' => $entity_obj,
|
|
||||||
'pdf_variables' => (array) $entity_obj->company->settings->pdf_variables,
|
|
||||||
'variables' => $html->generateLabelsAndValues(),
|
|
||||||
'$product' => $design->design->product,
|
|
||||||
]),
|
|
||||||
'variables' => $html->generateLabelsAndValues(),
|
|
||||||
'options' => [
|
|
||||||
'client' => null,
|
|
||||||
'vendor' => $entity_obj->vendor,
|
|
||||||
'purchase_orders' => [$entity_obj],
|
|
||||||
'variables' => $html->generateLabelsAndValues(),
|
|
||||||
],
|
|
||||||
'process_markdown' => $entity_obj->company->markdown_enabled,
|
|
||||||
];
|
|
||||||
|
|
||||||
$maker = new PdfMaker($state);
|
|
||||||
|
|
||||||
$maker
|
|
||||||
->design($template)
|
|
||||||
->build();
|
|
||||||
|
|
||||||
DB::connection(config('database.default'))->rollBack();
|
|
||||||
|
|
||||||
if (request()->query('html') == 'true') {
|
|
||||||
return $maker->getCompiledHTML();
|
|
||||||
}
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
DB::connection(config('database.default'))->rollBack();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = auth()->user();
|
|
||||||
|
|
||||||
//if phantom js...... inject here..
|
|
||||||
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
|
||||||
return (new Phantom())->convertHtmlToPdf($maker->getCompiledHTML(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') {
|
|
||||||
$pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
|
|
||||||
|
|
||||||
$numbered_pdf = $this->pageNumbering($pdf, $user->company());
|
|
||||||
|
|
||||||
if ($numbered_pdf) {
|
|
||||||
$pdf = $numbered_pdf;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $pdf;
|
|
||||||
}
|
|
||||||
|
|
||||||
$file_path = (new PreviewPdf($maker->getCompiledHTML(true), $company))->handle();
|
|
||||||
|
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
|
||||||
LightLogs::create(new LivePreview())
|
|
||||||
->increment()
|
|
||||||
->batch();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$response = Response::make($file_path, 200);
|
|
||||||
$response->header('Content-Type', 'application/pdf');
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function blankEntity()
|
private function blankEntity()
|
||||||
{
|
{
|
||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\User $user */
|
||||||
|
@ -25,7 +25,6 @@ class ProtectedDownloadController extends BaseController
|
|||||||
|
|
||||||
if (!$hashed_path) {
|
if (!$hashed_path) {
|
||||||
throw new SystemError('File no longer available', 404);
|
throw new SystemError('File no longer available', 404);
|
||||||
abort(404, 'File no longer available');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($hashed_path) {
|
return response()->streamDownload(function () use ($hashed_path) {
|
||||||
|
@ -495,7 +495,7 @@ class PurchaseOrderController extends BaseController
|
|||||||
|
|
||||||
$purchase_orders = PurchaseOrder::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()->get();
|
$purchase_orders = PurchaseOrder::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()->get();
|
||||||
|
|
||||||
if (! $purchase_orders) {
|
if ($purchase_orders->count() == 0) {
|
||||||
return response()->json(['message' => 'No Purchase Orders Found']);
|
return response()->json(['message' => 'No Purchase Orders Found']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,7 +717,7 @@ class PurchaseOrderController extends BaseController
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
|
return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,7 +787,6 @@ class QuoteController extends BaseController
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
|
return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,8 +112,7 @@ class SelfUpdateController extends BaseController
|
|||||||
Artisan::call('view:clear');
|
Artisan::call('view:clear');
|
||||||
Artisan::call('migrate', ['--force' => true]);
|
Artisan::call('migrate', ['--force' => true]);
|
||||||
Artisan::call('config:clear');
|
Artisan::call('config:clear');
|
||||||
|
Artisan::call('cache:clear');
|
||||||
$this->buildCache(true);
|
|
||||||
|
|
||||||
$this->runModelChecks();
|
$this->runModelChecks();
|
||||||
|
|
||||||
|
@ -159,8 +159,6 @@ class SetupController extends Controller
|
|||||||
|
|
||||||
(new VersionCheck())->handle();
|
(new VersionCheck())->handle();
|
||||||
|
|
||||||
$this->buildCache(true);
|
|
||||||
|
|
||||||
return redirect('/');
|
return redirect('/');
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
@ -234,24 +232,6 @@ class SetupController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function testPhantom()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$key = config('ninja.phantomjs_key');
|
|
||||||
$url = 'https://www.invoiceninja.org/';
|
|
||||||
|
|
||||||
$phantom_url = "https://phantomjscloud.com/api/browser/v2/{$key}/?request=%7Burl:%22{$url}%22,renderType:%22pdf%22%7D";
|
|
||||||
$pdf = CurlUtils::get($phantom_url);
|
|
||||||
|
|
||||||
Storage::disk(config('filesystems.default'))->put('test.pdf', $pdf);
|
|
||||||
Storage::disk('local')->put('test.pdf', $pdf);
|
|
||||||
|
|
||||||
return response(['url' => Storage::disk('local')->url('test.pdf')], 200);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return response([], 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function clearCompiledCache()
|
public function clearCompiledCache()
|
||||||
{
|
{
|
||||||
$cacheCompiled = base_path('bootstrap/cache/compiled.php');
|
$cacheCompiled = base_path('bootstrap/cache/compiled.php');
|
||||||
@ -305,8 +285,7 @@ class SetupController extends Controller
|
|||||||
|
|
||||||
Artisan::call('migrate', ['--force' => true]);
|
Artisan::call('migrate', ['--force' => true]);
|
||||||
Artisan::call('db:seed', ['--force' => true]);
|
Artisan::call('db:seed', ['--force' => true]);
|
||||||
|
Artisan::call('cache:clear');
|
||||||
$this->buildCache(true);
|
|
||||||
|
|
||||||
(new SchedulerCheck())->handle();
|
(new SchedulerCheck())->handle();
|
||||||
|
|
||||||
|
@ -141,6 +141,7 @@ class StripeConnectController extends BaseController
|
|||||||
$company_gateway->save();
|
$company_gateway->save();
|
||||||
}
|
}
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: StripeConnectController::" . $e->getMessage());
|
||||||
nlog("could not harvest stripe company name");
|
nlog("could not harvest stripe company name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ class PasswordProtection
|
|||||||
return $next($request);
|
return $next($request);
|
||||||
} elseif(strlen(auth()->user()->oauth_provider_id) > 2 && !auth()->user()->company()->oauth_password_required) {
|
} elseif(strlen(auth()->user()->oauth_provider_id) > 2 && !auth()->user()->company()->oauth_password_required) {
|
||||||
return $next($request);
|
return $next($request);
|
||||||
} elseif ($request->header('X-API-OAUTH-PASSWORD') && strlen($request->header('X-API-OAUTH-PASSWORD')) >= 1) {
|
} elseif ($request->header('X-API-OAUTH-PASSWORD') && strlen($request->header('X-API-OAUTH-PASSWORD')) > 1) {
|
||||||
//user is attempting to reauth with OAuth - check the token value
|
//user is attempting to reauth with OAuth - check the token value
|
||||||
//todo expand this to include all OAuth providers
|
//todo expand this to include all OAuth providers
|
||||||
if (auth()->user()->oauth_provider_id == 'google') {
|
if (auth()->user()->oauth_provider_id == 'google') {
|
||||||
@ -93,6 +93,7 @@ class PasswordProtection
|
|||||||
try {
|
try {
|
||||||
$payload = json_decode(base64_decode(str_replace('_', '/', str_replace('-', '+', explode('.', request()->header('X-API-OAUTH-PASSWORD'))[1]))));
|
$payload = json_decode(base64_decode(str_replace('_', '/', str_replace('-', '+', explode('.', request()->header('X-API-OAUTH-PASSWORD'))[1]))));
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: PasswordProtection::" . $e->getMessage());
|
||||||
nlog("could not decode microsoft response");
|
nlog("could not decode microsoft response");
|
||||||
return response()->json(['message' => 'Could not decode the response from Microsoft'], 412);
|
return response()->json(['message' => 'Could not decode the response from Microsoft'], 412);
|
||||||
}
|
}
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Invoice Ninja (https://invoiceninja.com).
|
|
||||||
*
|
|
||||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
|
||||||
*
|
|
||||||
* @license https://www.elastic.co/licensing/elastic-license
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use App\DataMapper\EmailTemplateDefaults;
|
|
||||||
use Closure;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class StartupCheck.
|
|
||||||
*/
|
|
||||||
class StartupCheck
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
* @deprecated
|
|
||||||
* @param Request $request
|
|
||||||
* @param Closure $next
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function handle(Request $request, Closure $next)
|
|
||||||
{
|
|
||||||
// $start = microtime(true);
|
|
||||||
|
|
||||||
/* Make sure our cache is built */
|
|
||||||
$cached_tables = config('ninja.cached_tables');
|
|
||||||
|
|
||||||
foreach ($cached_tables as $name => $class) {
|
|
||||||
if ($request->has('clear_cache') || ! Cache::has($name)) {
|
|
||||||
// check that the table exists in case the migration is pending
|
|
||||||
if (! Schema::hasTable((new $class())->getTable())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($name == 'payment_terms') {
|
|
||||||
$orderBy = 'num_days';
|
|
||||||
} elseif ($name == 'fonts') {
|
|
||||||
$orderBy = 'sort_order';
|
|
||||||
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries', 'banks'])) {
|
|
||||||
$orderBy = 'name';
|
|
||||||
} else {
|
|
||||||
$orderBy = 'id';
|
|
||||||
}
|
|
||||||
$tableData = $class::orderBy($orderBy)->get();
|
|
||||||
if ($tableData->count()) {
|
|
||||||
Cache::forever($name, $tableData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Build template cache*/
|
|
||||||
if ($request->has('clear_cache') || ! Cache::has('templates')) {
|
|
||||||
$this->buildTemplates();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildTemplates($name = 'templates')
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'invoice' => [
|
|
||||||
'subject' => EmailTemplateDefaults::emailInvoiceSubject(),
|
|
||||||
'body' => EmailTemplateDefaults::emailInvoiceTemplate(),
|
|
||||||
],
|
|
||||||
'quote' => [
|
|
||||||
'subject' => EmailTemplateDefaults::emailQuoteSubject(),
|
|
||||||
'body' => EmailTemplateDefaults::emailQuoteTemplate(),
|
|
||||||
],
|
|
||||||
'payment' => [
|
|
||||||
'subject' => EmailTemplateDefaults::emailPaymentSubject(),
|
|
||||||
'body' => EmailTemplateDefaults::emailPaymentTemplate(),
|
|
||||||
],
|
|
||||||
'reminder1' => [
|
|
||||||
'subject' => EmailTemplateDefaults::emailReminder1Subject(),
|
|
||||||
'body' => EmailTemplateDefaults::emailReminder1Template(),
|
|
||||||
],
|
|
||||||
'reminder2' => [
|
|
||||||
'subject' => EmailTemplateDefaults::emailReminder2Subject(),
|
|
||||||
'body' => EmailTemplateDefaults::emailReminder2Template(),
|
|
||||||
],
|
|
||||||
'reminder3' => [
|
|
||||||
'subject' => EmailTemplateDefaults::emailReminder3Subject(),
|
|
||||||
'body' => EmailTemplateDefaults::emailReminder3Template(),
|
|
||||||
],
|
|
||||||
'reminder_endless' => [
|
|
||||||
'subject' => EmailTemplateDefaults::emailReminderEndlessSubject(),
|
|
||||||
'body' => EmailTemplateDefaults::emailReminderEndlessTemplate(),
|
|
||||||
],
|
|
||||||
'statement' => [
|
|
||||||
'subject' => EmailTemplateDefaults::emailStatementSubject(),
|
|
||||||
'body' => EmailTemplateDefaults::emailStatementTemplate(),
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
Cache::forever($name, $data);
|
|
||||||
}
|
|
||||||
}
|
|
79
app/Http/Requests/Activity/StoreNoteRequest.php
Normal file
79
app/Http/Requests/Activity/StoreNoteRequest.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Activity;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class StoreNoteRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return $this->checkAuthority();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$rules = [
|
||||||
|
'entity' => 'required|bail|in:invoices,quotes,credits,recurring_invoices,clients,vendors,credits,payments,projects,tasks,expenses,recurring_expenses,bank_transactions,purchase_orders',
|
||||||
|
'entity_id' => ['required','bail', Rule::exists($this->entity, 'id')->where('company_id', $user->company()->id)],
|
||||||
|
'notes' => 'required|bail',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
if(isset($input['entity_id']) && $input['entity_id'] != null) {
|
||||||
|
$input['entity_id'] = $this->decodePrimaryKey($input['entity_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkAuthority(): bool
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->error_message = ctrans('texts.authorization_failure');
|
||||||
|
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$entity = $this->getEntity();
|
||||||
|
|
||||||
|
return $user->isAdmin() || $user->can('view', $entity);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEntity()
|
||||||
|
{
|
||||||
|
if(!$this->entity)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
$class = "\\App\\Models\\".ucfirst(Str::camel(rtrim($this->entity, 's')));
|
||||||
|
return $class::withTrashed()->find(is_string($this->entity_id) ? $this->decodePrimaryKey($this->entity_id) : $this->entity_id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -51,9 +51,9 @@ class StoreBankTransactionRuleRequest extends Request
|
|||||||
'applies_to' => 'bail|sometimes|string',
|
'applies_to' => 'bail|sometimes|string',
|
||||||
];
|
];
|
||||||
|
|
||||||
$rules['category_id'] = 'bail|sometimes|exists:expense_categories,id,company_id,'.$user->company()->id.',is_deleted,0';
|
$rules['category_id'] = 'bail|sometimes|nullable|exists:expense_categories,id,company_id,'.$user->company()->id.',is_deleted,0';
|
||||||
$rules['vendor_id'] = 'bail|sometimes|exists:vendors,id,company_id,'.$user->company()->id.',is_deleted,0';
|
$rules['vendor_id'] = 'bail|sometimes|nullable|exists:vendors,id,company_id,'.$user->company()->id.',is_deleted,0';
|
||||||
$rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.$user->company()->id.',is_deleted,0';
|
$rules['client_id'] = 'bail|sometimes|nullable|exists:clients,id,company_id,'.$user->company()->id.',is_deleted,0';
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
@ -185,48 +185,44 @@ class StoreClientRequest extends Request
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLanguageId($language_code)
|
private function getLanguageId(string $language_code)
|
||||||
{
|
{
|
||||||
$languages = Cache::get('languages');
|
/** @var \Illuminate\Support\Collection<\App\Models\Language> */
|
||||||
|
$languages = app('languages');
|
||||||
|
|
||||||
$language = $languages->filter(function ($item) use ($language_code) {
|
$language = $languages->first(function ($item) use ($language_code) {
|
||||||
return $item->locale == $language_code;
|
return $item->locale == $language_code;
|
||||||
})->first();
|
});
|
||||||
|
|
||||||
if ($language) {
|
return $language ? (string)$language->id : '';
|
||||||
return (string) $language->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getCountryCode($country_code)
|
private function getCountryCode(string $country_code)
|
||||||
{
|
{
|
||||||
$countries = Cache::get('countries');
|
|
||||||
|
|
||||||
$country = $countries->filter(function ($item) use ($country_code) {
|
/** @var \Illuminate\Support\Collection<\App\Models\Country> */
|
||||||
|
$countries = app('countries');
|
||||||
|
|
||||||
|
$country = $countries->first(function ($item) use ($country_code) {
|
||||||
return $item->iso_3166_2 == $country_code || $item->iso_3166_3 == $country_code;
|
return $item->iso_3166_2 == $country_code || $item->iso_3166_3 == $country_code;
|
||||||
})->first();
|
});
|
||||||
|
|
||||||
if ($country) {
|
return $country ? (string) $country->id : '';
|
||||||
return (string) $country->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getCurrencyCode($code)
|
private function getCurrencyCode($code)
|
||||||
{
|
{
|
||||||
$currencies = Cache::get('currencies');
|
|
||||||
|
|
||||||
$currency = $currencies->filter(function ($item) use ($code) {
|
/** @var \Illuminate\Support\Collection<\App\Models\Currency> */
|
||||||
|
$currencies = app('currencies');
|
||||||
|
|
||||||
|
$currency = $currencies->first(function ($item) use ($code) {
|
||||||
return $item->code == $code;
|
return $item->code == $code;
|
||||||
})->first();
|
});
|
||||||
|
|
||||||
if ($currency) {
|
return $currency ? (string)$currency->id : '';
|
||||||
return (string) $currency->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,32 +139,28 @@ class UpdateClientRequest extends Request
|
|||||||
|
|
||||||
private function getCountryCode($country_code)
|
private function getCountryCode($country_code)
|
||||||
{
|
{
|
||||||
$countries = Cache::get('countries');
|
|
||||||
|
|
||||||
$country = $countries->filter(function ($item) use ($country_code) {
|
/** @var \Illuminate\Support\Collection<\App\Models\Country> */
|
||||||
|
$countries = app('countries');
|
||||||
|
|
||||||
|
$country = $countries->first(function ($item) use ($country_code) {
|
||||||
return $item->iso_3166_2 == $country_code || $item->iso_3166_3 == $country_code;
|
return $item->iso_3166_2 == $country_code || $item->iso_3166_3 == $country_code;
|
||||||
})->first();
|
});
|
||||||
|
|
||||||
if ($country) {
|
return $country ? (string) $country->id : '';
|
||||||
return (string) $country->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getLanguageId($language_code)
|
private function getLanguageId($language_code)
|
||||||
{
|
{
|
||||||
$languages = Cache::get('languages');
|
|
||||||
|
|
||||||
$language = $languages->filter(function ($item) use ($language_code) {
|
/** @var \Illuminate\Support\Collection<\App\Models\Language> */
|
||||||
|
$languages = app('languages');
|
||||||
|
|
||||||
|
$language = $languages->first(function ($item) use ($language_code) {
|
||||||
return $item->locale == $language_code;
|
return $item->locale == $language_code;
|
||||||
})->first();
|
});
|
||||||
|
|
||||||
if ($language) {
|
return $language ? (string) $language->id : '';
|
||||||
return (string) $language->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,6 +65,7 @@ class UpdateCompanyRequest extends Request
|
|||||||
$rules['smtp_local_domain'] = 'sometimes|string|nullable';
|
$rules['smtp_local_domain'] = 'sometimes|string|nullable';
|
||||||
// $rules['smtp_verify_peer'] = 'sometimes|string';
|
// $rules['smtp_verify_peer'] = 'sometimes|string';
|
||||||
|
|
||||||
|
// $rules['e_invoice'] = ['sometimes','nullable', new ValidScheme()];
|
||||||
|
|
||||||
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'] = 'bail|nullable|sometimes|url';
|
$rules['portal_domain'] = 'bail|nullable|sometimes|url';
|
||||||
@ -120,11 +121,6 @@ class UpdateCompanyRequest extends Request
|
|||||||
$input['smtp_verify_peer'] == 'true' ? true : false;
|
$input['smtp_verify_peer'] == 'true' ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if(isset($input['e_invoice'])){
|
|
||||||
// nlog("am i set?");
|
|
||||||
// $r = FatturaElettronica::validate($input['e_invoice']);
|
|
||||||
// }
|
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
43
app/Http/Requests/Expense/EDocumentRequest.php
Normal file
43
app/Http/Requests/Expense/EDocumentRequest.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Expense;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class EDocumentRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
/** @var User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
return $user->isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
if ($this->file('documents') && is_array($this->file('documents'))) {
|
||||||
|
$rules['documents.*'] = $this->fileValidation();
|
||||||
|
} elseif ($this->file('documents')) {
|
||||||
|
$rules['documents'] = $this->fileValidation();
|
||||||
|
}
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareForValidation()
|
||||||
|
{
|
||||||
|
$input = $this->all();
|
||||||
|
|
||||||
|
$this->replace($input);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests\Payment;
|
namespace App\Http\Requests\Payment;
|
||||||
|
|
||||||
|
use App\Exceptions\DuplicatePaymentException;
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
use App\Http\ValidationRules\Credit\CreditsSumRule;
|
use App\Http\ValidationRules\Credit\CreditsSumRule;
|
||||||
use App\Http\ValidationRules\Credit\ValidCreditsRules;
|
use App\Http\ValidationRules\Credit\ValidCreditsRules;
|
||||||
@ -79,6 +80,11 @@ class StorePaymentRequest extends Request
|
|||||||
/** @var \App\Models\User $user */
|
/** @var \App\Models\User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if(\Illuminate\Support\Facades\Cache::has($this->ip()."|".$this->input('amount', 0)."|".$this->input('client_id', '')."|".$user->company()->company_key))
|
||||||
|
throw new DuplicatePaymentException('Duplicate request.', 429);
|
||||||
|
|
||||||
|
\Illuminate\Support\Facades\Cache::put(($this->ip()."|".$this->input('amount', 0)."|".$this->input('client_id', '')."|".$user->company()->company_key), true, 1);
|
||||||
|
|
||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
$invoices_total = 0;
|
$invoices_total = 0;
|
||||||
@ -130,7 +136,7 @@ class StorePaymentRequest extends Request
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! isset($input['idempotency_key'])) {
|
if (! isset($input['idempotency_key'])) {
|
||||||
$input['idempotency_key'] = substr(sha1(json_encode($input)).time()."{$input['date']}{$input['amount']}{$user->id}", 0, 64);
|
$input['idempotency_key'] = substr(time()."{$input['date']}{$input['amount']}{$credits_total}{$this->client_id}{$user->company()->company_key}", 0, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
|
@ -89,6 +89,7 @@ class PreviewInvoiceRequest extends Request
|
|||||||
{
|
{
|
||||||
$invitation = false;
|
$invitation = false;
|
||||||
|
|
||||||
|
/** @phpstan-ignore-next-line */
|
||||||
if(! $this->entity_id ?? false) {
|
if(! $this->entity_id ?? false) {
|
||||||
return $this->stubInvitation();
|
return $this->stubInvitation();
|
||||||
}
|
}
|
||||||
@ -98,6 +99,7 @@ class PreviewInvoiceRequest extends Request
|
|||||||
'quote' => $invitation = QuoteInvitation::withTrashed()->where('quote_id', $this->entity_id)->first(),
|
'quote' => $invitation = QuoteInvitation::withTrashed()->where('quote_id', $this->entity_id)->first(),
|
||||||
'credit' => $invitation = CreditInvitation::withTrashed()->where('credit_id', $this->entity_id)->first(),
|
'credit' => $invitation = CreditInvitation::withTrashed()->where('credit_id', $this->entity_id)->first(),
|
||||||
'recurring_invoice' => $invitation = RecurringInvoiceInvitation::withTrashed()->where('recurring_invoice_id', $this->entity_id)->first(),
|
'recurring_invoice' => $invitation = RecurringInvoiceInvitation::withTrashed()->where('recurring_invoice_id', $this->entity_id)->first(),
|
||||||
|
default => $invitation = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if($invitation) {
|
if($invitation) {
|
||||||
|
@ -24,7 +24,6 @@ class PreviewPurchaseOrderRequest extends Request
|
|||||||
use CleanLineItems;
|
use CleanLineItems;
|
||||||
|
|
||||||
private ?Vendor $vendor = null;
|
private ?Vendor $vendor = null;
|
||||||
private string $entity_plural = '';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Determine if the user is authorized to make this request.
|
||||||
@ -72,7 +71,7 @@ class PreviewPurchaseOrderRequest extends Request
|
|||||||
{
|
{
|
||||||
$invitation = false;
|
$invitation = false;
|
||||||
|
|
||||||
if(! $this->entity_id ?? false) {
|
if(! isset($this->entity_id)) {
|
||||||
return $this->stubInvitation();
|
return $this->stubInvitation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,12 +129,5 @@ class PreviewPurchaseOrderRequest extends Request
|
|||||||
return $entity;
|
return $entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function convertEntityPlural(string $entity): self
|
|
||||||
{
|
|
||||||
|
|
||||||
$this->entity_plural = 'purchase_orders';
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -155,23 +155,27 @@ class StoreShopClientRequest extends Request
|
|||||||
|
|
||||||
private function getCountryCode($country_code)
|
private function getCountryCode($country_code)
|
||||||
{
|
{
|
||||||
$countries = Cache::get('countries');
|
|
||||||
|
|
||||||
$country = $countries->filter(function ($item) use ($country_code) {
|
/** @var \Illuminate\Support\Collection<\App\Models\Country> */
|
||||||
|
$countries = app('countries');
|
||||||
|
|
||||||
|
$country = $countries->first(function ($item) use ($country_code) {
|
||||||
return $item->iso_3166_2 == $country_code || $item->iso_3166_3 == $country_code;
|
return $item->iso_3166_2 == $country_code || $item->iso_3166_3 == $country_code;
|
||||||
})->first();
|
});
|
||||||
|
|
||||||
return (string) $country->id;
|
return $country ? (string) $country->id : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getCurrencyCode($code)
|
private function getCurrencyCode($code)
|
||||||
{
|
{
|
||||||
$currencies = Cache::get('currencies');
|
|
||||||
|
|
||||||
$currency = $currencies->filter(function ($item) use ($code) {
|
/** @var \Illuminate\Support\Collection<\App\Models\Country> */
|
||||||
|
$currencies = app('currencies');
|
||||||
|
|
||||||
|
$currency = $currencies->first(function ($item) use ($code) {
|
||||||
return $item->code == $code;
|
return $item->code == $code;
|
||||||
})->first();
|
});
|
||||||
|
|
||||||
return (string) $currency->id;
|
return $currency ? (string) $currency->id : '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ use App\Http\Requests\Request;
|
|||||||
|
|
||||||
class DisconnectUserMailerRequest extends Request
|
class DisconnectUserMailerRequest extends Request
|
||||||
{
|
{
|
||||||
private bool $phone_has_changed = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Determine if the user is authorized to make this request.
|
||||||
|
62
app/Http/ValidationRules/EInvoice/ValidScheme.php
Normal file
62
app/Http/ValidationRules/EInvoice/ValidScheme.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*1`
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\ValidationRules\EInvoice;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use InvoiceNinja\EInvoice\EInvoice;
|
||||||
|
use Illuminate\Validation\Validator;
|
||||||
|
use InvoiceNinja\EInvoice\Models\Peppol\Invoice;
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Contracts\Validation\ValidatorAwareRule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class BlackListRule.
|
||||||
|
*/
|
||||||
|
class ValidScheme implements ValidationRule, ValidatorAwareRule
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The validator instance.
|
||||||
|
*
|
||||||
|
* @var Validator
|
||||||
|
*/
|
||||||
|
protected $validator;
|
||||||
|
|
||||||
|
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||||
|
{
|
||||||
|
|
||||||
|
$r = new EInvoice();
|
||||||
|
$errors = $r->validateRequest($value['Invoice'], Invoice::class);
|
||||||
|
|
||||||
|
foreach ($errors as $key => $msg) {
|
||||||
|
|
||||||
|
$this->validator->errors()->add(
|
||||||
|
"e_invoice.{$key}",
|
||||||
|
"{$key} - {$msg}"
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current validator.
|
||||||
|
*/
|
||||||
|
public function setValidator(Validator $validator): static
|
||||||
|
{
|
||||||
|
$this->validator = $validator;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -119,17 +119,18 @@ class BaseTransformer
|
|||||||
{
|
{
|
||||||
$code = array_key_exists($key, $data) ? $data[$key] : false;
|
$code = array_key_exists($key, $data) ? $data[$key] : false;
|
||||||
|
|
||||||
$currencies = Cache::get('currencies');
|
if(!$code)
|
||||||
|
return $this->company->settings->currency_id;
|
||||||
|
|
||||||
$currency = $currencies
|
/** @var \Illuminate\Support\Collection<\App\Models\Currency> */
|
||||||
->filter(function ($item) use ($code) {
|
$currencies = app('currencies');
|
||||||
return $item->code == $code;
|
|
||||||
})
|
$currency = $currencies->first(function ($item) use ($code) {
|
||||||
->first();
|
return $item->code == $code;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $currency ? (string) $currency->id : $this->company->settings->currency_id;
|
||||||
|
|
||||||
return $currency
|
|
||||||
? $currency->id
|
|
||||||
: $this->company->settings->currency_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFrequency($frequency = RecurringInvoice::FREQUENCY_MONTHLY): int
|
public function getFrequency($frequency = RecurringInvoice::FREQUENCY_MONTHLY): int
|
||||||
@ -653,12 +654,11 @@ class BaseTransformer
|
|||||||
/**
|
/**
|
||||||
* @param $name
|
* @param $name
|
||||||
*
|
*
|
||||||
* @return int|null
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getExpenseCategoryId($name)
|
public function getExpenseCategoryId($name)
|
||||||
{
|
{
|
||||||
/** @var \App\Models\ExpenseCategory $ec */
|
/** @var ?\App\Models\ExpenseCategory $ec */
|
||||||
|
|
||||||
$ec = ExpenseCategory::query()->where('company_id', $this->company->id)
|
$ec = ExpenseCategory::query()->where('company_id', $this->company->id)
|
||||||
->where('is_deleted', false)
|
->where('is_deleted', false)
|
||||||
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
->whereRaw("LOWER(REPLACE(`name`, ' ' ,'')) = ?", [
|
||||||
@ -674,7 +674,7 @@ class BaseTransformer
|
|||||||
$ec->name = $name;
|
$ec->name = $name;
|
||||||
$ec->save();
|
$ec->save();
|
||||||
|
|
||||||
return $ec ? $ec->id : null;
|
return $ec->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOrCreateExpenseCategry($name)
|
public function getOrCreateExpenseCategry($name)
|
||||||
|
@ -70,16 +70,18 @@ class ClientTransformer extends BaseTransformer
|
|||||||
'custom_value2' => $this->getString($data, 'client.custom_value2'),
|
'custom_value2' => $this->getString($data, 'client.custom_value2'),
|
||||||
'custom_value3' => $this->getString($data, 'client.custom_value3'),
|
'custom_value3' => $this->getString($data, 'client.custom_value3'),
|
||||||
'custom_value4' => $this->getString($data, 'client.custom_value4'),
|
'custom_value4' => $this->getString($data, 'client.custom_value4'),
|
||||||
'balance' => preg_replace(
|
// 'balance' => preg_replace(
|
||||||
'/[^0-9,.]+/',
|
// '/[^0-9,.]+/',
|
||||||
'',
|
// '',
|
||||||
$this->getFloat($data, 'client.balance')
|
// $this->getFloat($data, 'client.balance')
|
||||||
),
|
// ),
|
||||||
'paid_to_date' => preg_replace(
|
// 'paid_to_date' => preg_replace(
|
||||||
'/[^0-9,.]+/',
|
// '/[^0-9,.]+/',
|
||||||
'',
|
// '',
|
||||||
$this->getFloat($data, 'client.paid_to_date')
|
// $this->getFloat($data, 'client.paid_to_date')
|
||||||
),
|
// ),
|
||||||
|
'paid_to_date' => 0,
|
||||||
|
'balance' => 0,
|
||||||
'credit_balance' => 0,
|
'credit_balance' => 0,
|
||||||
'settings' => $settings,
|
'settings' => $settings,
|
||||||
'client_hash' => Str::random(40),
|
'client_hash' => Str::random(40),
|
||||||
|
@ -277,7 +277,7 @@ class InvoiceTransformer extends BaseTransformer
|
|||||||
if($key == 0) {
|
if($key == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
/** @var array $row */
|
||||||
if(is_array($row[5])) {
|
if(is_array($row[5])) {
|
||||||
$csv = str_getcsv($row[5][0], ";");
|
$csv = str_getcsv($row[5][0], ";");
|
||||||
$row[5] = array_combine(explode(",", $csv[0]), explode(",", $csv[1]));
|
$row[5] = array_combine(explode(",", $csv[0]), explode(",", $csv[1]));
|
||||||
|
@ -50,7 +50,7 @@ class InvoiceTransformer extends BaseTransformer
|
|||||||
'client_id' => $this->getClient($customer_name = $this->getString($invoice_data, $customer_key), null),
|
'client_id' => $this->getClient($customer_name = $this->getString($invoice_data, $customer_key), null),
|
||||||
'number' => $invoice_number = $this->getString($invoice_data, 'Invoice Number'),
|
'number' => $invoice_number = $this->getString($invoice_data, 'Invoice Number'),
|
||||||
'date' => $this->parseDate($invoice_data[$date_key]) ?: now()->format('Y-m-d'), //27-01-2022
|
'date' => $this->parseDate($invoice_data[$date_key]) ?: now()->format('Y-m-d'), //27-01-2022
|
||||||
'currency_id' => $this->getCurrencyByCode($invoice_data, 'Currency'),
|
// 'currency_id' => $this->getCurrencyByCode($invoice_data, 'Currency'),
|
||||||
'status_id' => Invoice::STATUS_SENT,
|
'status_id' => Invoice::STATUS_SENT,
|
||||||
'due_date' => array_key_exists('Due Date', $invoice_data) ? $this->parseDate($invoice_data['Due Date']) : null,
|
'due_date' => array_key_exists('Due Date', $invoice_data) ? $this->parseDate($invoice_data['Due Date']) : null,
|
||||||
];
|
];
|
||||||
|
@ -126,13 +126,12 @@ class MatchBankTransactions implements ShouldQueue
|
|||||||
{
|
{
|
||||||
$collection = collect();
|
$collection = collect();
|
||||||
|
|
||||||
|
/** @array $invoices */
|
||||||
$invoices = explode(",", $invoice_hashed_ids);
|
$invoices = explode(",", $invoice_hashed_ids);
|
||||||
|
|
||||||
if (count($invoices) >= 1) {
|
foreach ($invoices as $invoice) {
|
||||||
foreach ($invoices as $invoice) {
|
if (is_string($invoice) && strlen($invoice) > 1) {
|
||||||
if (is_string($invoice) && strlen($invoice) > 1) {
|
$collection->push($this->decodePrimaryKey($invoice));
|
||||||
$collection->push($this->decodePrimaryKey($invoice));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +188,7 @@ class MatchBankTransactions implements ShouldQueue
|
|||||||
private function coalesceExpenses($expense): string
|
private function coalesceExpenses($expense): string
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!$this->bt->expense_id || strlen($this->bt->expense_id) < 1) {
|
if (!$this->bt->expense_id || strlen($this->bt->expense_id ?? '') < 2) {
|
||||||
return $expense;
|
return $expense;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,11 +232,12 @@ class MatchBankTransactions implements ShouldQueue
|
|||||||
$_invoices = Invoice::query()
|
$_invoices = Invoice::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->where('company_id', $this->bt->company_id)
|
->where('company_id', $this->bt->company_id)
|
||||||
->whereIn('id', $this->getInvoices($input['invoice_ids']));
|
->whereIn('id', $this->getInvoices($input['invoice_ids']))
|
||||||
|
->get();
|
||||||
|
|
||||||
$amount = $this->bt->amount;
|
$amount = $this->bt->amount;
|
||||||
|
|
||||||
if ($_invoices && $this->checkPayable($_invoices)) {
|
if ($_invoices->count() >0 && $this->checkPayable($_invoices)) {
|
||||||
$this->createPayment($_invoices, $amount);
|
$this->createPayment($_invoices, $amount);
|
||||||
|
|
||||||
$this->bts->push($this->bt->id);
|
$this->bts->push($this->bt->id);
|
||||||
@ -312,8 +312,11 @@ class MatchBankTransactions implements ShouldQueue
|
|||||||
if ($_amount) {
|
if ($_amount) {
|
||||||
$this->attachable_invoices[] = ['id' => $this->invoice->id, 'amount' => $_amount];
|
$this->attachable_invoices[] = ['id' => $this->invoice->id, 'amount' => $_amount];
|
||||||
|
|
||||||
|
$this->invoice->next_send_date = null;
|
||||||
|
|
||||||
$this->invoice
|
$this->invoice
|
||||||
->service()
|
->service()
|
||||||
|
->applyNumber()
|
||||||
->setExchangeRate()
|
->setExchangeRate()
|
||||||
->updateBalance($_amount * -1)
|
->updateBalance($_amount * -1)
|
||||||
->updatePaidToDate($_amount)
|
->updatePaidToDate($_amount)
|
||||||
@ -323,6 +326,7 @@ class MatchBankTransactions implements ShouldQueue
|
|||||||
});
|
});
|
||||||
}, 2);
|
}, 2);
|
||||||
|
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
if (!$this->invoice) {
|
if (!$this->invoice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -355,7 +359,7 @@ class MatchBankTransactions implements ShouldQueue
|
|||||||
$this->setExchangeRate($payment);
|
$this->setExchangeRate($payment);
|
||||||
|
|
||||||
/* Create a payment relationship to the invoice entity */
|
/* Create a payment relationship to the invoice entity */
|
||||||
foreach ($this->attachable_invoices as $attachable_invoice) {
|
foreach ($this->attachable_invoices as $attachable_invoice) { // @phpstan-ignore-line
|
||||||
$payment->invoices()->attach($attachable_invoice['id'], [
|
$payment->invoices()->attach($attachable_invoice['id'], [
|
||||||
'amount' => $attachable_invoice['amount'],
|
'amount' => $attachable_invoice['amount'],
|
||||||
]);
|
]);
|
||||||
@ -363,14 +367,6 @@ class MatchBankTransactions implements ShouldQueue
|
|||||||
|
|
||||||
event('eloquent.created: App\Models\Payment', $payment);
|
event('eloquent.created: App\Models\Payment', $payment);
|
||||||
|
|
||||||
$this->invoice->next_send_date = null;
|
|
||||||
|
|
||||||
$this->invoice
|
|
||||||
->service()
|
|
||||||
->applyNumber()
|
|
||||||
->deletePdf()
|
|
||||||
->save();
|
|
||||||
|
|
||||||
$payment->ledger()
|
$payment->ledger()
|
||||||
->updatePaymentBalance($amount * -1);
|
->updatePaymentBalance($amount * -1);
|
||||||
|
|
||||||
@ -389,7 +385,13 @@ class MatchBankTransactions implements ShouldQueue
|
|||||||
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||||
event(new InvoiceWasPaid($this->invoice, $payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
event(new InvoiceWasPaid($this->invoice, $payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||||
|
|
||||||
$this->bt->invoice_ids = $invoices->get()->pluck('hashed_id')->implode(',');
|
$hashed_keys = [];
|
||||||
|
|
||||||
|
foreach($this->attachable_invoices as $attachable_invoice){ //@phpstan-ignore-line
|
||||||
|
$hashed_keys[] = $this->encodePrimaryKey($attachable_invoice['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->bt->invoice_ids = implode(",", $hashed_keys);
|
||||||
$this->bt->status_id = BankTransaction::STATUS_CONVERTED;
|
$this->bt->status_id = BankTransaction::STATUS_CONVERTED;
|
||||||
$this->bt->payment_id = $payment->id;
|
$this->bt->payment_id = $payment->id;
|
||||||
$this->bt->save();
|
$this->bt->save();
|
||||||
|
@ -70,6 +70,7 @@ class UpdateTaxData implements ShouldQueue
|
|||||||
|
|
||||||
|
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: UpdateTaxData::" . $e->getMessage());
|
||||||
nlog("problem getting tax data => ".$e->getMessage());
|
nlog("problem getting tax data => ".$e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1205,6 +1205,7 @@ class CompanyImport implements ShouldQueue
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var string $storage_url */
|
||||||
$storage_url = (object)$this->getObject('storage_url', true);
|
$storage_url = (object)$this->getObject('storage_url', true);
|
||||||
|
|
||||||
if (!Storage::exists($document->url) && is_string($storage_url)) {
|
if (!Storage::exists($document->url) && is_string($storage_url)) {
|
||||||
@ -1351,45 +1352,31 @@ class CompanyImport implements ShouldQueue
|
|||||||
switch ($type) {
|
switch ($type) {
|
||||||
case Company::class:
|
case Company::class:
|
||||||
return $this->company->id;
|
return $this->company->id;
|
||||||
break;
|
|
||||||
case Client::class:
|
case Client::class:
|
||||||
return $this->transformId('clients', $id);
|
return $this->transformId('clients', $id);
|
||||||
break;
|
|
||||||
case ClientContact::class:
|
case ClientContact::class:
|
||||||
return $this->transformId('client_contacts', $id);
|
return $this->transformId('client_contacts', $id);
|
||||||
break;
|
|
||||||
case Credit::class:
|
case Credit::class:
|
||||||
return $this->transformId('credits', $id);
|
return $this->transformId('credits', $id);
|
||||||
break;
|
|
||||||
case Expense::class:
|
case Expense::class:
|
||||||
return $this->transformId('expenses', $id);
|
return $this->transformId('expenses', $id);
|
||||||
break;
|
|
||||||
case 'invoices':
|
case 'invoices':
|
||||||
return $this->transformId('invoices', $id);
|
return $this->transformId('invoices', $id);
|
||||||
break;
|
|
||||||
case Payment::class:
|
case Payment::class:
|
||||||
return $this->transformId('payments', $id);
|
return $this->transformId('payments', $id);
|
||||||
break;
|
|
||||||
case Project::class:
|
case Project::class:
|
||||||
return $this->transformId('projects', $id);
|
return $this->transformId('projects', $id);
|
||||||
break;
|
|
||||||
case Product::class:
|
case Product::class:
|
||||||
return $this->transformId('products', $id);
|
return $this->transformId('products', $id);
|
||||||
break;
|
|
||||||
case Quote::class:
|
case Quote::class:
|
||||||
return $this->transformId('quotes', $id);
|
return $this->transformId('quotes', $id);
|
||||||
break;
|
|
||||||
case RecurringInvoice::class:
|
case RecurringInvoice::class:
|
||||||
return $this->transformId('recurring_invoices', $id);
|
return $this->transformId('recurring_invoices', $id);
|
||||||
break;
|
|
||||||
case Company::class:
|
case Company::class:
|
||||||
return $this->transformId('clients', $id);
|
return $this->transformId('clients', $id);
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1420,10 +1407,10 @@ class CompanyImport implements ShouldQueue
|
|||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'invoices':
|
case 'invoices':
|
||||||
return $this->transformId('invoices', $id);
|
return $this->transformId('invoices', $id);
|
||||||
break;
|
|
||||||
case Credit::class:
|
case Credit::class:
|
||||||
return $this->transformId('credits', $id);
|
return $this->transformId('credits', $id);
|
||||||
break;
|
|
||||||
case Payment::class:
|
case Payment::class:
|
||||||
return $this->transformId('payments', $id);
|
return $this->transformId('payments', $id);
|
||||||
default:
|
default:
|
||||||
|
@ -61,6 +61,7 @@ class CompanyTaxRate implements ShouldQueue
|
|||||||
try {
|
try {
|
||||||
$calculated_state = USStates::getState($this->company->settings->postal_code);
|
$calculated_state = USStates::getState($this->company->settings->postal_code);
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: CompanyTaxRate::" . $e->getMessage());
|
||||||
nlog("could not calculate state from postal code => {$this->company->settings->postal_code} or from state {$this->company->settings->state}");
|
nlog("could not calculate state from postal code => {$this->company->settings->postal_code} or from state {$this->company->settings->state}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +123,7 @@ class CreateCompany
|
|||||||
|
|
||||||
}
|
}
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: CreateCompany::" . $e->getMessage());
|
||||||
nlog("Could not resolve country => {$e->getMessage()}");
|
nlog("Could not resolve country => {$e->getMessage()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +157,7 @@ class CreateCompany
|
|||||||
return $company;
|
return $company;
|
||||||
|
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: CreateCompany::" . $e->getMessage());
|
||||||
nlog("SETUP: could not complete setup for Spanish Locale");
|
nlog("SETUP: could not complete setup for Spanish Locale");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,6 +191,7 @@ class CreateCompany
|
|||||||
|
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
|
nlog("Exception:: CreateCompany::" . $e->getMessage());
|
||||||
nlog("SETUP: could not complete setup for South African Locale");
|
nlog("SETUP: could not complete setup for South African Locale");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,6 +225,7 @@ class CreateCompany
|
|||||||
|
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
|
nlog("Exception:: CreateCompany::" . $e->getMessage());
|
||||||
nlog("SETUP: could not complete setup for Australian Locale");
|
nlog("SETUP: could not complete setup for Australian Locale");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,9 +65,9 @@ class SubscriptionCron
|
|||||||
//Requires the crons to be updated and set to hourly @ 00:01
|
//Requires the crons to be updated and set to hourly @ 00:01
|
||||||
private function timezoneAware()
|
private function timezoneAware()
|
||||||
{
|
{
|
||||||
$grouped_company_ids =
|
|
||||||
|
|
||||||
Invoice::select('company_id')
|
Invoice::query()
|
||||||
|
->with('company')
|
||||||
->where('is_deleted', 0)
|
->where('is_deleted', 0)
|
||||||
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
->where('balance', '>', 0)
|
->where('balance', '>', 0)
|
||||||
@ -77,10 +77,11 @@ class SubscriptionCron
|
|||||||
->whereNotNull('subscription_id')
|
->whereNotNull('subscription_id')
|
||||||
->groupBy('company_id')
|
->groupBy('company_id')
|
||||||
->cursor()
|
->cursor()
|
||||||
->each(function ($company_id) {
|
->each(function ($invoice) {
|
||||||
|
|
||||||
/** @var \App\Models\Company $company */
|
/** @var \App\Models\Company $company */
|
||||||
$company = Company::find($company_id);
|
// $company = Company::find($invoice->company_id);
|
||||||
|
$company = $invoice->company;
|
||||||
|
|
||||||
$timezone_now = now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway');
|
$timezone_now = now()->setTimezone($company->timezone()->name ?? 'Pacific/Midway');
|
||||||
|
|
||||||
|
64
app/Jobs/EDocument/ImportEDocument.php
Normal file
64
app/Jobs/EDocument/ImportEDocument.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Jobs\EDocument;
|
||||||
|
|
||||||
|
use App\Models\Expense;
|
||||||
|
use App\Services\EDocument\Imports\ZugferdEDocument;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class ImportEDocument implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
use InteractsWithQueue;
|
||||||
|
use Queueable;
|
||||||
|
use SerializesModels;
|
||||||
|
|
||||||
|
public $deleteWhenMissingModels = true;
|
||||||
|
private string $file_name;
|
||||||
|
private readonly string $file_content;
|
||||||
|
|
||||||
|
public function __construct(string $file_content, string $file_name)
|
||||||
|
{
|
||||||
|
$this->file_content = $file_content;
|
||||||
|
$this->file_name = $file_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return Expense
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function handle(): Expense
|
||||||
|
{
|
||||||
|
if (str_contains($this->file_name, ".xml")){
|
||||||
|
switch (true) {
|
||||||
|
case stristr($this->file_content, "urn:cen.eu:en16931:2017"):
|
||||||
|
case stristr($this->file_content, "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0"):
|
||||||
|
case stristr($this->file_content, "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_2.1"):
|
||||||
|
case stristr($this->file_content, "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_2.0"):
|
||||||
|
return (new ZugferdEDocument($this->file_content, $this->file_name))->run();
|
||||||
|
default:
|
||||||
|
throw new Exception("E-Invoice standard not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Exception("File type not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -40,7 +40,7 @@ class CreateRawPdf
|
|||||||
|
|
||||||
public Invoice | Credit | Quote | RecurringInvoice | PurchaseOrder $entity;
|
public Invoice | Credit | Quote | RecurringInvoice | PurchaseOrder $entity;
|
||||||
|
|
||||||
public $company;
|
public \App\Models\Company $company;
|
||||||
|
|
||||||
public $contact;
|
public $contact;
|
||||||
|
|
||||||
@ -55,6 +55,7 @@ class CreateRawPdf
|
|||||||
{
|
{
|
||||||
|
|
||||||
$this->invitation = $invitation;
|
$this->invitation = $invitation;
|
||||||
|
$this->company = $invitation->company;
|
||||||
|
|
||||||
if ($invitation instanceof InvoiceInvitation) {
|
if ($invitation instanceof InvoiceInvitation) {
|
||||||
$this->entity = $invitation->invoice;
|
$this->entity = $invitation->invoice;
|
||||||
@ -110,12 +111,22 @@ class CreateRawPdf
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$pdf = $ps->boot()->getPdf();
|
$pdf = $ps->boot()->getPdf();
|
||||||
} catch (\Exception) {
|
} catch (\Exception $e) {
|
||||||
|
echo "EXCEPTION::".PHP_EOL;
|
||||||
|
echo $e->getMessage().PHP_EOL;
|
||||||
throw new FilePermissionsFailure('Unable to generate the raw PDF');
|
throw new FilePermissionsFailure('Unable to generate the raw PDF');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->entity_string == "invoice" && $this->entity->client->getSetting("merge_e_invoice_to_pdf")) {
|
if ($this->entity_string == "invoice" && $this->entity->client->getSetting("merge_e_invoice_to_pdf")) {
|
||||||
$pdf = (new MergeEDocument($this->entity, $pdf))->handle();
|
$pdf = (new MergeEDocument($this->entity, $pdf))->handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$merge_docs = isset($this->entity->client) ? $this->entity->client->getSetting('embed_documents') : $this->company->getSetting('embed_documents');
|
||||||
|
|
||||||
|
if($merge_docs && ($this->entity->documents()->where('is_public', true)->count() > 0 || $this->company->documents()->where('is_public', true)->count() > 0)) {
|
||||||
|
$pdf = $this->entity->documentMerge($pdf);
|
||||||
|
}
|
||||||
|
|
||||||
return $pdf;
|
return $pdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ class CreateUbl implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* @param $item
|
* @param $item
|
||||||
* @param $invoice_total
|
* @param $invoice_total
|
||||||
* @return float|int
|
* @return float
|
||||||
*/
|
*/
|
||||||
private function getItemTaxable($item, $invoice_total)
|
private function getItemTaxable($item, $invoice_total)
|
||||||
{
|
{
|
||||||
|
@ -71,6 +71,7 @@ class AdjustEmailQuota implements ShouldQueue
|
|||||||
try {
|
try {
|
||||||
LightLogs::create(new EmailCount($email_count, $account->key))->send(); // this runs syncronously
|
LightLogs::create(new EmailCount($email_count, $account->key))->send(); // this runs syncronously
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: AdjustEmailQuota::" . $e->getMessage());
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,7 @@ class BankTransactionSync implements ShouldQueue
|
|||||||
try {
|
try {
|
||||||
(new ProcessBankTransactionsNordigen($bank_integration))->handle();
|
(new ProcessBankTransactionsNordigen($bank_integration))->handle();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: BankTransactioSync::" . $e->getMessage());
|
||||||
sleep(20);
|
sleep(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ class RefundCancelledAccount implements ShouldQueue
|
|||||||
$end_date = Carbon::parse($plan_expires);
|
$end_date = Carbon::parse($plan_expires);
|
||||||
$now = Carbon::now();
|
$now = Carbon::now();
|
||||||
|
|
||||||
$days_left = $now->diffInDays($end_date);
|
$days_left = intval(abs($now->diffInDays($end_date)));
|
||||||
|
|
||||||
$pro_rata_ratio = $days_left / 365;
|
$pro_rata_ratio = $days_left / 365;
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class TaskScheduler implements ShouldQueue
|
|||||||
//@var \App\Models\Schedule $scheduler
|
//@var \App\Models\Schedule $scheduler
|
||||||
$scheduler->service()->runTask();
|
$scheduler->service()->runTask();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
nlog($e->getMessage());
|
nlog("Exception:: TaskScheduler:: Doing job {$scheduler->name}" . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -89,6 +89,7 @@ class TaskScheduler implements ShouldQueue
|
|||||||
/** @var \App\Models\Scheduler $scheduler */
|
/** @var \App\Models\Scheduler $scheduler */
|
||||||
$scheduler->service()->runTask();
|
$scheduler->service()->runTask();
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
nlog("Exception:: TaskScheduler::" . $e->getMessage());
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ class CleanStaleInvoiceOrder implements ShouldQueue
|
|||||||
Invoice::query()
|
Invoice::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->where('status_id', Invoice::STATUS_SENT)
|
->where('status_id', Invoice::STATUS_SENT)
|
||||||
->where('created_at', '<', now()->subMinutes(30))
|
->where('updated_at', '<', now()->subHour())
|
||||||
->where('balance', '>', 0)
|
->where('balance', '>', 0)
|
||||||
->whereJsonContains('line_items', ['type_id' => '3'])
|
->whereJsonContains('line_items', ['type_id' => '3'])
|
||||||
->cursor()
|
->cursor()
|
||||||
@ -88,7 +88,7 @@ class CleanStaleInvoiceOrder implements ShouldQueue
|
|||||||
Invoice::query()
|
Invoice::query()
|
||||||
->withTrashed()
|
->withTrashed()
|
||||||
->where('status_id', Invoice::STATUS_SENT)
|
->where('status_id', Invoice::STATUS_SENT)
|
||||||
->where('created_at', '<', now()->subMinutes(30))
|
->where('updated_at', '<', now()->subHour())
|
||||||
->where('balance', '>', 0)
|
->where('balance', '>', 0)
|
||||||
->whereJsonContains('line_items', ['type_id' => '3'])
|
->whereJsonContains('line_items', ['type_id' => '3'])
|
||||||
->cursor()
|
->cursor()
|
||||||
|
71
app/Jobs/Task/TaskAssigned.php
Normal file
71
app/Jobs/Task/TaskAssigned.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Jobs\Task;
|
||||||
|
|
||||||
|
use App\Models\Task;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Services\Email\Email;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use App\Services\Email\EmailObject;
|
||||||
|
use Illuminate\Mail\Mailables\Address;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use App\Utils\Traits\Notifications\UserNotifies;
|
||||||
|
|
||||||
|
class TaskAssigned implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
use InteractsWithQueue;
|
||||||
|
use Queueable;
|
||||||
|
use SerializesModels;
|
||||||
|
use UserNotifies;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct(private Task $task, private string $db)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
MultiDB::setDb($this->db);
|
||||||
|
|
||||||
|
$company_user = $this->task->assignedCompanyUser();
|
||||||
|
|
||||||
|
if($this->findEntityAssignedNotification($company_user, 'task'))
|
||||||
|
{
|
||||||
|
$mo = new EmailObject();
|
||||||
|
$mo->subject = ctrans('texts.task_assigned_subject', ['task' => $this->task->number, 'date' => now()->setTimeZone($this->task->company->timezone()->name)->format($this->task->company->date_format()) ]);
|
||||||
|
$mo->body = ctrans('texts.task_assigned_body',['task' => $this->task->number, 'description' => $this->task->description ?? '', 'client' => $this->task->client ? $this->task->client->present()->name() : ' ']);
|
||||||
|
$mo->text_body = ctrans('texts.task_assigned_body',['task' => $this->task->number, 'description' => $this->task->description ?? '', 'client' => $this->task->client ? $this->task->client->present()->name() : ' ']);
|
||||||
|
$mo->company_key = $this->task->company->company_key;
|
||||||
|
$mo->html_template = 'email.template.generic';
|
||||||
|
$mo->to = [new Address($this->task->assigned_user->email, $this->task->assigned_user->present()->name())];
|
||||||
|
$mo->email_template_body = 'task_assigned_body';
|
||||||
|
$mo->email_template_subject = 'task_assigned_subject';
|
||||||
|
|
||||||
|
(new Email($mo, $this->task->company))->handle();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function failed($exception = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -56,7 +56,7 @@ class VerifyPhone implements ShouldQueue
|
|||||||
|
|
||||||
$twilio = new \Twilio\Rest\Client($sid, $token);
|
$twilio = new \Twilio\Rest\Client($sid, $token);
|
||||||
|
|
||||||
$country = $this->user->account?->companies()?->first()?->country();
|
$country = $this->user->account?->companies()?->first()?->country(); //@phpstan-ignore-line
|
||||||
|
|
||||||
if (!$country || strlen($this->user->phone) < 2) {
|
if (!$country || strlen($this->user->phone) < 2) {
|
||||||
return;
|
return;
|
||||||
@ -73,7 +73,7 @@ class VerifyPhone implements ShouldQueue
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($phone_number && strlen($phone_number->phoneNumber) > 1) {
|
if ($phone_number && strlen($phone_number->phoneNumber) > 1) { //@phpstan-ignore-line
|
||||||
$this->user->phone = $phone_number->phoneNumber;
|
$this->user->phone = $phone_number->phoneNumber;
|
||||||
$this->user->verified_phone_number = true;
|
$this->user->verified_phone_number = true;
|
||||||
$this->user->save();
|
$this->user->save();
|
||||||
|
@ -1455,30 +1455,23 @@ class Import implements ShouldQueue
|
|||||||
switch ($status_id) {
|
switch ($status_id) {
|
||||||
case 1:
|
case 1:
|
||||||
return $payment;
|
return $payment;
|
||||||
break;
|
|
||||||
case 2:
|
case 2:
|
||||||
return $payment->service()->deletePayment();
|
return $payment->service()->deletePayment();
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
return $payment->service()->deletePayment();
|
return $payment->service()->deletePayment();
|
||||||
break;
|
|
||||||
case 4:
|
case 4:
|
||||||
return $payment;
|
return $payment;
|
||||||
break;
|
|
||||||
case 5:
|
case 5:
|
||||||
$payment->status_id = Payment::STATUS_PARTIALLY_REFUNDED;
|
$payment->status_id = Payment::STATUS_PARTIALLY_REFUNDED;
|
||||||
$payment->save();
|
$payment->save();
|
||||||
return $payment;
|
return $payment;
|
||||||
break;
|
|
||||||
case 6:
|
case 6:
|
||||||
$payment->status_id = Payment::STATUS_REFUNDED;
|
$payment->status_id = Payment::STATUS_REFUNDED;
|
||||||
$payment->save();
|
$payment->save();
|
||||||
return $payment;
|
return $payment;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return $payment;
|
return $payment;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
323
app/Jobs/Util/QuoteReminderJob.php
Normal file
323
app/Jobs/Util/QuoteReminderJob.php
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use App\Models\Quote;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Webhook;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use App\DataMapper\InvoiceItem;
|
||||||
|
use App\Factory\InvoiceFactory;
|
||||||
|
use App\Jobs\Entity\EmailEntity;
|
||||||
|
use App\Utils\Traits\MakesDates;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use App\Utils\Traits\MakesReminders;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use App\Events\Quote\QuoteReminderWasEmailed;
|
||||||
|
|
||||||
|
class QuoteReminderJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
use InteractsWithQueue;
|
||||||
|
use Queueable;
|
||||||
|
use SerializesModels;
|
||||||
|
use MakesReminders;
|
||||||
|
use MakesDates;
|
||||||
|
|
||||||
|
public $tries = 1;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
|
Auth::logout();
|
||||||
|
|
||||||
|
if (! config('ninja.db.multi_db_enabled')) {
|
||||||
|
nrlog("Sending quote reminders on ".now()->format('Y-m-d h:i:s'));
|
||||||
|
|
||||||
|
Quote::query()
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT])
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('next_send_date', '<=', now()->toDateTimeString())
|
||||||
|
->whereHas('client', function ($query) {
|
||||||
|
$query->where('is_deleted', 0)
|
||||||
|
->where('deleted_at', null);
|
||||||
|
})
|
||||||
|
->whereHas('company', function ($query) {
|
||||||
|
$query->where('is_disabled', 0);
|
||||||
|
})
|
||||||
|
->with('invitations')->chunk(50, function ($quotes) {
|
||||||
|
foreach ($quotes as $quote) {
|
||||||
|
$this->sendReminderForQuote($quote);
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
//multiDB environment, need to
|
||||||
|
|
||||||
|
foreach (MultiDB::$dbs as $db) {
|
||||||
|
MultiDB::setDB($db);
|
||||||
|
|
||||||
|
nrlog("Sending quote reminders on db {$db} ".now()->format('Y-m-d h:i:s'));
|
||||||
|
|
||||||
|
Quote::query()
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT])
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('next_send_date', '<=', now()->toDateTimeString())
|
||||||
|
->whereHas('client', function ($query) {
|
||||||
|
$query->where('is_deleted', 0)
|
||||||
|
->where('deleted_at', null);
|
||||||
|
})
|
||||||
|
->whereHas('company', function ($query) {
|
||||||
|
$query->where('is_disabled', 0);
|
||||||
|
})
|
||||||
|
->with('invitations')->chunk(50, function ($quotes) {
|
||||||
|
|
||||||
|
foreach ($quotes as $quote) {
|
||||||
|
$this->sendReminderForQuote($quote);
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendReminderForQuote(Quote $quote)
|
||||||
|
{
|
||||||
|
App::forgetInstance('translator');
|
||||||
|
$t = app('translator');
|
||||||
|
$t->replace(Ninja::transformTranslations($quote->client->getMergedSettings()));
|
||||||
|
App::setLocale($quote->client->locale());
|
||||||
|
|
||||||
|
if ($quote->isPayable()) {
|
||||||
|
//Attempts to prevent duplicates from sending
|
||||||
|
if ($quote->reminder_last_sent && Carbon::parse($quote->reminder_last_sent)->startOfDay()->eq(now()->startOfDay())) {
|
||||||
|
nrlog("caught a duplicate reminder for quote {$quote->number}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$reminder_template = $quote->calculateTemplate('invoice');
|
||||||
|
nrlog("#{$quote->number} => reminder template = {$reminder_template}");
|
||||||
|
$quote->service()->touchReminder($reminder_template)->save();
|
||||||
|
$fees = $this->calcLateFee($quote, $reminder_template);
|
||||||
|
|
||||||
|
if($quote->isLocked()) {
|
||||||
|
return $this->addFeeToNewQuote($quote, $reminder_template, $fees);
|
||||||
|
}
|
||||||
|
|
||||||
|
$quote = $this->setLateFee($quote, $fees[0], $fees[1]);
|
||||||
|
|
||||||
|
//20-04-2022 fixes for endless reminders - generic template naming was wrong
|
||||||
|
$enabled_reminder = 'enable_'.$reminder_template;
|
||||||
|
if ($reminder_template == 'endless_reminder') {
|
||||||
|
$enabled_reminder = 'enable_reminder_endless';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($reminder_template, ['reminder1', 'reminder2', 'reminder3', 'reminder_endless', 'endless_reminder']) &&
|
||||||
|
$quote->client->getSetting($enabled_reminder) &&
|
||||||
|
$quote->client->getSetting('send_reminders') &&
|
||||||
|
(Ninja::isSelfHost() || $quote->company->account->isPaidHostedClient())) {
|
||||||
|
$quote->invitations->each(function ($invitation) use ($quote, $reminder_template) {
|
||||||
|
if ($invitation->contact && !$invitation->contact->trashed() && $invitation->contact->email) {
|
||||||
|
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
|
||||||
|
nrlog("Firing reminder email for invoice {$quote->number} - {$reminder_template}");
|
||||||
|
$quote->entityEmailEvent($invitation, $reminder_template);
|
||||||
|
$quote->sendEvent(Webhook::EVENT_REMIND_INVOICE, "client");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$quote->service()->setReminder()->save();
|
||||||
|
} else {
|
||||||
|
$quote->next_send_date = null;
|
||||||
|
$quote->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addFeeToNewQuote(Quote $over_due_quote, string $reminder_template, array $fees)
|
||||||
|
{
|
||||||
|
|
||||||
|
$amount = $fees[0];
|
||||||
|
$percent = $fees[1];
|
||||||
|
|
||||||
|
$quote = false;
|
||||||
|
|
||||||
|
//2024-06-07 this early return prevented any reminders from sending for users who enabled lock_invoices.
|
||||||
|
if ($amount > 0 || $percent > 0) {
|
||||||
|
// return;
|
||||||
|
|
||||||
|
$fee = $amount;
|
||||||
|
|
||||||
|
if ($over_due_quote->partial > 0) {
|
||||||
|
$fee += round($over_due_quote->partial * $percent / 100, 2);
|
||||||
|
} else {
|
||||||
|
$fee += round($over_due_quote->balance * $percent / 100, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \App\Models\Invoice $quote */
|
||||||
|
$quote = InvoiceFactory::create($over_due_quote->company_id, $over_due_quote->user_id);
|
||||||
|
$quote->client_id = $over_due_quote->client_id;
|
||||||
|
$quote->date = now()->format('Y-m-d');
|
||||||
|
$quote->due_date = now()->format('Y-m-d');
|
||||||
|
|
||||||
|
$quote_item = new InvoiceItem();
|
||||||
|
$quote_item->type_id = '5';
|
||||||
|
$quote_item->product_key = trans('texts.fee');
|
||||||
|
$quote_item->notes = ctrans('texts.late_fee_added_locked_invoice', ['invoice' => $over_due_quote->number, 'date' => $this->translateDate(now()->startOfDay(), $over_due_invoice->client->date_format(), $over_due_invoice->client->locale())]);
|
||||||
|
$quote_item->quantity = 1;
|
||||||
|
$quote_item->cost = $fee;
|
||||||
|
|
||||||
|
$quote_items = [];
|
||||||
|
$quote_items[] = $quote_item;
|
||||||
|
|
||||||
|
$quote->line_items = $quote_items;
|
||||||
|
|
||||||
|
/**Refresh Invoice values*/
|
||||||
|
$quote = $quote->calc()->getInvoice();
|
||||||
|
$quote->service()
|
||||||
|
->createInvitations()
|
||||||
|
->applyNumber()
|
||||||
|
->markSent()
|
||||||
|
->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$quote) {
|
||||||
|
$quote = $over_due_quote;
|
||||||
|
}
|
||||||
|
|
||||||
|
$enabled_reminder = 'enable_'.$reminder_template;
|
||||||
|
// if ($reminder_template == 'endless_reminder') {
|
||||||
|
// $enabled_reminder = 'enable_reminder_endless';
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (in_array($reminder_template, ['reminder1', 'reminder2', 'reminder3', 'reminder_endless', 'endless_reminder']) &&
|
||||||
|
$quote->client->getSetting($enabled_reminder) &&
|
||||||
|
$quote->client->getSetting('send_reminders') &&
|
||||||
|
(Ninja::isSelfHost() || $quote->company->account->isPaidHostedClient())) {
|
||||||
|
$quote->invitations->each(function ($invitation) use ($quote, $reminder_template) {
|
||||||
|
if ($invitation->contact && !$invitation->contact->trashed() && $invitation->contact->email) {
|
||||||
|
EmailEntity::dispatch($invitation, $invitation->company, $reminder_template);
|
||||||
|
nrlog("Firing reminder email for qipte {$quote->number} - {$reminder_template}");
|
||||||
|
event(new QuoteReminderWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template));
|
||||||
|
$quote->sendEvent(Webhook::EVENT_REMIND_QUOTE, "client");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$quote->service()->setReminder()->save();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the late if - if any - and rebuilds the invoice
|
||||||
|
*
|
||||||
|
* @param Invoice $quote
|
||||||
|
* @param string $template
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function calcLateFee($quote, $template): array
|
||||||
|
{
|
||||||
|
$late_fee_amount = 0;
|
||||||
|
$late_fee_percent = 0;
|
||||||
|
|
||||||
|
switch ($template) {
|
||||||
|
case 'reminder1':
|
||||||
|
$late_fee_amount = $quote->client->getSetting('late_fee_amount1');
|
||||||
|
$late_fee_percent = $quote->client->getSetting('late_fee_percent1');
|
||||||
|
break;
|
||||||
|
case 'reminder2':
|
||||||
|
$late_fee_amount = $quote->client->getSetting('late_fee_amount2');
|
||||||
|
$late_fee_percent = $quote->client->getSetting('late_fee_percent2');
|
||||||
|
break;
|
||||||
|
case 'reminder3':
|
||||||
|
$late_fee_amount = $quote->client->getSetting('late_fee_amount3');
|
||||||
|
$late_fee_percent = $quote->client->getSetting('late_fee_percent3');
|
||||||
|
break;
|
||||||
|
case 'endless_reminder':
|
||||||
|
$late_fee_amount = $quote->client->getSetting('late_fee_endless_amount');
|
||||||
|
$late_fee_percent = $quote->client->getSetting('late_fee_endless_percent');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$late_fee_amount = 0;
|
||||||
|
$late_fee_percent = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$late_fee_amount, $late_fee_percent];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the late fee to the invoice line items
|
||||||
|
*
|
||||||
|
* @param Invoice $quote
|
||||||
|
* @param float $amount The fee amount
|
||||||
|
* @param float $percent The fee percentage amount
|
||||||
|
*
|
||||||
|
* @return Invoice
|
||||||
|
*/
|
||||||
|
private function setLateFee($quote, $amount, $percent): Invoice
|
||||||
|
{
|
||||||
|
|
||||||
|
$temp_invoice_balance = $quote->balance;
|
||||||
|
|
||||||
|
if ($amount <= 0 && $percent <= 0) {
|
||||||
|
return $quote;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fee = $amount;
|
||||||
|
|
||||||
|
if ($quote->partial > 0) {
|
||||||
|
$fee += round($quote->partial * $percent / 100, 2);
|
||||||
|
} else {
|
||||||
|
$fee += round($quote->balance * $percent / 100, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$quote_item = new InvoiceItem();
|
||||||
|
$quote_item->type_id = '5';
|
||||||
|
$quote_item->product_key = trans('texts.fee');
|
||||||
|
$quote_item->notes = ctrans('texts.late_fee_added', ['date' => $this->translateDate(now()->startOfDay(), $quote->client->date_format(), $quote->client->locale())]);
|
||||||
|
$quote_item->quantity = 1;
|
||||||
|
$quote_item->cost = $fee;
|
||||||
|
|
||||||
|
$quote_items = $quote->line_items;
|
||||||
|
$quote_items[] = $quote_item;
|
||||||
|
|
||||||
|
$quote->line_items = $quote_items;
|
||||||
|
|
||||||
|
/**Refresh Invoice values*/
|
||||||
|
$quote = $quote->calc()->getInvoice();
|
||||||
|
|
||||||
|
$quote->ledger()->updateInvoiceBalance($quote->balance - $temp_invoice_balance, "Late Fee Adjustment for invoice {$quote->number}");
|
||||||
|
$quote->client->service()->calculateBalance();
|
||||||
|
|
||||||
|
return $quote;
|
||||||
|
}
|
||||||
|
}
|
12
app/Jobs/Vendor/CreatePurchaseOrderPdf.php
vendored
12
app/Jobs/Vendor/CreatePurchaseOrderPdf.php
vendored
@ -100,18 +100,6 @@ class CreatePurchaseOrderPdf implements ShouldQueue
|
|||||||
|
|
||||||
return $ps->boot()->getPdf();
|
return $ps->boot()->getPdf();
|
||||||
|
|
||||||
|
|
||||||
$pdf = $this->rawPdf();
|
|
||||||
|
|
||||||
if ($pdf) {
|
|
||||||
try {
|
|
||||||
Storage::disk($this->disk)->put($this->file_path, $pdf);
|
|
||||||
} catch(\Exception $e) {
|
|
||||||
throw new FilePermissionsFailure($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->file_path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rawPdf()
|
public function rawPdf()
|
||||||
|
@ -477,6 +477,23 @@ class MultiDB
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function findUserByReferralCode(string $referral_code): ?User
|
||||||
|
{
|
||||||
|
$current_db = config('database.default');
|
||||||
|
|
||||||
|
foreach (self::$dbs as $db) {
|
||||||
|
if ($user = User::on($db)->where('referral_code', $referral_code)->first()) {
|
||||||
|
self::setDb($db);
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::setDB($current_db);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static function findAndSetDbByClientId($client_id): ?Client
|
public static function findAndSetDbByClientId($client_id): ?Client
|
||||||
{
|
{
|
||||||
$current_db = config('database.default');
|
$current_db = config('database.default');
|
||||||
@ -587,7 +604,7 @@ class MultiDB
|
|||||||
|
|
||||||
$current_db = config('database.default');
|
$current_db = config('database.default');
|
||||||
|
|
||||||
if (SMSNumbers::hasNumber($phone)) {
|
if (SMSNumbers::hasNumber($phone)) { // @phpstan-ignore-line
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,6 @@ class OAuth
|
|||||||
return $this;
|
return $this;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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