Merge branch 'invoiceninja:v5-develop' into v5-develop

This commit is contained in:
Kendall Arneaud 2024-07-22 20:06:24 -04:00 committed by GitHub
commit d5d9d54c1f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
188 changed files with 4213 additions and 2365 deletions

View File

@ -1 +1 @@
5.10.8 5.10.13

View File

@ -385,6 +385,9 @@ class CreateSingleAccount extends Command
}); });
$this->countryClients($company, $user);
$this->info("finished"); $this->info("finished");
} }
@ -1109,4 +1112,44 @@ class CreateSingleAccount extends Command
event(new RecurringInvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars())); event(new RecurringInvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars()));
} }
private function countryClients($company, $user)
{
Client::unguard();
Client::create([
'company_id' => $company->id,
'user_id' => $user->id,
'name' => 'Swiss Company AG',
'website' => 'https://www.testcompany.ch',
'private_notes' => 'These are some private notes about the test client.',
'balance' => 0,
'paid_to_date' => 0,
'vat_number' => '654321987',
'id_number' => 'CH9300762011623852957', // Sample Swiss IBAN
'custom_value1' => '2024-07-22 10:00:00',
'custom_value2' => 'blue',
'custom_value3' => 'sampleword',
'custom_value4' => 'test@example.com',
'address1' => '123',
'address2' => 'Test Street 45',
'city' => 'Zurich',
'state' => 'Zurich',
'postal_code' => '8001',
'country_id' => '756', // Switzerland
'shipping_address1' => '123',
'shipping_address2' => 'Test Street 45',
'shipping_city' => 'Zurich',
'shipping_state' => 'Zurich',
'shipping_postal_code' => '8001',
'shipping_country_id' => '756', // Switzerland
'settings' => ClientSettings::Defaults(),
'client_hash' => \Illuminate\Support\Str::random(32),
'routing_id' => '',
]);
}
} }

View File

@ -97,11 +97,6 @@ class Handler extends ExceptionHandler
{ {
if (Ninja::isHosted()) { if (Ninja::isHosted()) {
// if($exception instanceof ThrottleRequestsException && class_exists(\Modules\Admin\Events\ThrottledExceptionRaised::class)) {
// $uri = urldecode(request()->getRequestUri());
// event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip()));
// }
Integration::configureScope(function (Scope $scope): void { Integration::configureScope(function (Scope $scope): void {
$name = 'hosted@invoiceninja.com'; $name = 'hosted@invoiceninja.com';

View File

@ -57,6 +57,7 @@ class ActivityExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
/** @var \App\Models\Activity $resource */
$row = $this->buildActivityRow($resource); $row = $this->buildActivityRow($resource);
return $this->processMetaData($row, $resource); return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
@ -128,6 +129,9 @@ class ActivityExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($entity) { ->each(function ($entity) {
/** @var \App\Models\Activity $entity */
$this->buildRow($entity); $this->buildRow($entity);
}); });

View File

@ -102,6 +102,8 @@ class ClientExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($client) { ->map(function ($client) {
/** @var \App\Models\Client $client */
$row = $this->buildRow($client); $row = $this->buildRow($client);
return $this->processMetaData($row, $client); return $this->processMetaData($row, $client);
})->toArray(); })->toArray();
@ -154,6 +156,8 @@ class ClientExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($client) { ->each(function ($client) {
/** @var \App\Models\Client $client */
$this->csv->insertOne($this->buildRow($client)); $this->csv->insertOne($this->buildRow($client));
}); });

View File

@ -82,6 +82,7 @@ class ContactExport extends BaseExport
$this->csv->insertOne($this->buildHeader()); $this->csv->insertOne($this->buildHeader());
$query->cursor()->each(function ($contact) { $query->cursor()->each(function ($contact) {
/** @var \App\Models\ClientContact $contact */
$this->csv->insertOne($this->buildRow($contact)); $this->csv->insertOne($this->buildRow($contact));
}); });
@ -101,6 +102,7 @@ class ContactExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($contact) { ->map(function ($contact) {
/** @var \App\Models\ClientContact $contact */
$row = $this->buildRow($contact); $row = $this->buildRow($contact);
return $this->processMetaData($row, $contact); return $this->processMetaData($row, $contact);
})->toArray(); })->toArray();

View File

@ -52,6 +52,8 @@ class CreditExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($credit) { ->map(function ($credit) {
/** @var \App\Models\Credit $credit */
$row = $this->buildRow($credit); $row = $this->buildRow($credit);
return $this->processMetaData($row, $credit); return $this->processMetaData($row, $credit);
})->toArray(); })->toArray();
@ -139,6 +141,7 @@ class CreditExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($credit) { ->each(function ($credit) {
/** @var \App\Models\Credit $credit */
$this->csv->insertOne($this->buildRow($credit)); $this->csv->insertOne($this->buildRow($credit));
}); });

View File

@ -54,6 +54,8 @@ class DocumentExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($document) { ->map(function ($document) {
/** @var \App\Models\Document $document */
$row = $this->buildRow($document); $row = $this->buildRow($document);
return $this->processMetaData($row, $document); return $this->processMetaData($row, $document);
})->toArray(); })->toArray();
@ -99,6 +101,7 @@ class DocumentExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($entity) { ->each(function ($entity) {
/** @var mixed $entity */
$this->csv->insertOne($this->buildRow($entity)); $this->csv->insertOne($this->buildRow($entity));
}); });

View File

@ -52,6 +52,8 @@ class ExpenseExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
/** @var \App\Models\Expense $resource */
$row = $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource); return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
@ -132,6 +134,8 @@ class ExpenseExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($expense) { ->each(function ($expense) {
/** @var \App\Models\Expense $expense */
$this->csv->insertOne($this->buildRow($expense)); $this->csv->insertOne($this->buildRow($expense));
}); });

View File

@ -99,6 +99,8 @@ class InvoiceExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
/** @var \App\Models\Invoice $resource */
$row = $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource); return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
@ -119,6 +121,8 @@ class InvoiceExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($invoice) { ->each(function ($invoice) {
/** @var \App\Models\Invoice $invoice */
$this->csv->insertOne($this->buildRow($invoice)); $this->csv->insertOne($this->buildRow($invoice));
}); });

View File

@ -113,6 +113,8 @@ class InvoiceItemExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($resource) { ->each(function ($resource) {
/** @var \App\Models\Invoice $resource */
$this->iterateItems($resource); $this->iterateItems($resource);
foreach($this->storage_array as $row) { foreach($this->storage_array as $row) {
@ -141,6 +143,8 @@ class InvoiceItemExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($invoice) { ->each(function ($invoice) {
/** @var \App\Models\Invoice $invoice */
$this->iterateItems($invoice); $this->iterateItems($invoice);
}); });

View File

@ -92,6 +92,8 @@ class PaymentExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
/** @var \App\Models\Payment $resource */
$row = $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource); return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
@ -112,6 +114,8 @@ class PaymentExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($entity) { ->each(function ($entity) {
/** @var \App\Models\Payment $entity */
$this->csv->insertOne($this->buildRow($entity)); $this->csv->insertOne($this->buildRow($entity));
}); });

View File

@ -51,6 +51,8 @@ class ProductExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
/** @var \App\Models\Product $resource */
$row = $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource); return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
@ -103,7 +105,9 @@ class ProductExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($entity) { ->each(function ($entity) {
$this->csv->insertOne($this->buildRow($entity));
/** @var \App\Models\Product $entity */
$this->csv->insertOne($this->buildRow($entity));
}); });
return $this->csv->toString(); return $this->csv->toString();

View File

@ -98,6 +98,8 @@ class PurchaseOrderExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
/** @var \App\Models\PurchaseOrder $resource */
$row = $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource); return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
@ -119,7 +121,9 @@ class PurchaseOrderExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($purchase_order) { ->each(function ($purchase_order) {
$this->csv->insertOne($this->buildRow($purchase_order));
/** @var \App\Models\PurchaseOrder $purchase_order */
$this->csv->insertOne($this->buildRow($purchase_order));
}); });
return $this->csv->toString(); return $this->csv->toString();

View File

@ -101,13 +101,15 @@ class PurchaseOrderItemExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($resource) { ->each(function ($resource) {
$this->iterateItems($resource);
/** @var \App\Models\PurchaseOrder $resource */
$this->iterateItems($resource);
foreach($this->storage_array as $row) { foreach($this->storage_array as $row) {
$this->storage_item_array[] = $this->processItemMetaData($row, $resource); $this->storage_item_array[] = $this->processItemMetaData($row, $resource);
} }
$this->storage_array = []; $this->storage_array = [];
}); });
@ -127,7 +129,9 @@ class PurchaseOrderItemExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($purchase_order) { ->each(function ($purchase_order) {
$this->iterateItems($purchase_order);
/** @var \App\Models\PurchaseOrder $purchase_order */
$this->iterateItems($purchase_order);
}); });
$this->csv->insertAll($this->storage_array); $this->csv->insertAll($this->storage_array);

View File

@ -103,6 +103,8 @@ class QuoteExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
/** @var \App\Models\Quote $resource */
$row = $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource); return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
@ -125,6 +127,8 @@ class QuoteExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($quote) { ->each(function ($quote) {
/** @var \App\Models\Quote $quote */
$this->csv->insertOne($this->buildRow($quote)); $this->csv->insertOne($this->buildRow($quote));
}); });

View File

@ -104,6 +104,8 @@ class QuoteItemExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($resource) { ->each(function ($resource) {
/** @var \App\Models\Quote $resource */
$this->iterateItems($resource); $this->iterateItems($resource);
foreach($this->storage_array as $row) { foreach($this->storage_array as $row) {
@ -134,6 +136,8 @@ class QuoteItemExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($quote) { ->each(function ($quote) {
/** @var \App\Models\Quote $quote */
$this->iterateItems($quote); $this->iterateItems($quote);
}); });

View File

@ -93,6 +93,8 @@ class RecurringInvoiceExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($invoice) { ->each(function ($invoice) {
/** @var \App\Models\RecurringInvoice $invoice */
$this->csv->insertOne($this->buildRow($invoice)); $this->csv->insertOne($this->buildRow($invoice));
}); });
@ -112,6 +114,8 @@ class RecurringInvoiceExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
/** @var \App\Models\RecurringInvoice $resource */
$row = $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource); return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();

View File

@ -106,7 +106,9 @@ class TaskExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($entity) { ->each(function ($entity) {
$this->buildRow($entity);
/** @var \App\Models\Task $entity*/
$this->buildRow($entity);
}); });
$this->csv->insertAll($this->storage_array); $this->csv->insertAll($this->storage_array);
@ -128,6 +130,7 @@ class TaskExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($resource) { ->each(function ($resource) {
/** @var \App\Models\Task $resource*/
$this->buildRow($resource); $this->buildRow($resource);
foreach($this->storage_array as $row) { foreach($this->storage_array as $row) {
@ -161,7 +164,7 @@ class TaskExport extends BaseExport
} }
if (is_null($task->time_log) || (is_array(json_decode($task->time_log, 1)) && count(json_decode($task->time_log, 1)) == 0)) { if (is_null($task->time_log) || (is_array(json_decode($task->time_log, true)) && count(json_decode($task->time_log, true)) == 0)) {
$this->storage_array[] = $entity; $this->storage_array[] = $entity;
} else { } else {
$this->iterateLogs($task, $entity); $this->iterateLogs($task, $entity);
@ -178,7 +181,7 @@ class TaskExport extends BaseExport
$timezone_name = $timezone->name; $timezone_name = $timezone->name;
} }
$logs = json_decode($task->time_log, 1); $logs = json_decode($task->time_log, true);
$date_format_default = $this->date_format; $date_format_default = $this->date_format;

View File

@ -90,6 +90,8 @@ class VendorExport extends BaseExport
$report = $query->cursor() $report = $query->cursor()
->map(function ($resource) { ->map(function ($resource) {
/** @var \App\Models\Vendor $resource */
$row = $this->buildRow($resource); $row = $this->buildRow($resource);
return $this->processMetaData($row, $resource); return $this->processMetaData($row, $resource);
})->toArray(); })->toArray();
@ -107,7 +109,9 @@ class VendorExport extends BaseExport
$query->cursor() $query->cursor()
->each(function ($vendor) { ->each(function ($vendor) {
$this->csv->insertOne($this->buildRow($vendor));
/** @var \App\Models\Vendor $vendor */
$this->csv->insertOne($this->buildRow($vendor));
}); });
return $this->csv->toString(); return $this->csv->toString();

View File

@ -48,7 +48,7 @@ class TaskDecorator extends Decorator implements DecoratorInterface
$timezone_name = $timezone->name; $timezone_name = $timezone->name;
} }
$logs = json_decode($task->time_log, 1); $logs = json_decode($task->time_log, true);
$date_format_default = 'Y-m-d'; $date_format_default = 'Y-m-d';
@ -77,7 +77,7 @@ class TaskDecorator extends Decorator implements DecoratorInterface
$timezone_name = $timezone->name; $timezone_name = $timezone->name;
} }
$logs = json_decode($task->time_log, 1); $logs = json_decode($task->time_log, true);
$date_format_default = 'Y-m-d'; $date_format_default = 'Y-m-d';

View File

@ -175,7 +175,7 @@ class RecurringExpenseToExpenseFactory
$_value = explode($_operation, $right); // [MONTHYEAR, 4] $_value = explode($_operation, $right); // [MONTHYEAR, 4]
$_right = Carbon::createFromDate(now()->year, now()->month)->addMonths($_value[1])->translatedFormat('F Y'); $_right = Carbon::createFromDate(now()->year, now()->month)->addMonths($_value[1])->translatedFormat('F Y'); //@phpstan-ignore-line
} }
$replacement = sprintf('%s to %s', $_left, $_right); $replacement = sprintf('%s to %s', $_left, $_right);

View File

@ -97,7 +97,8 @@ class CreditFilters extends QueryFilters
$q->where('first_name', 'like', '%'.$filter.'%') $q->where('first_name', 'like', '%'.$filter.'%')
->orWhere('last_name', 'like', '%'.$filter.'%') ->orWhere('last_name', 'like', '%'.$filter.'%')
->orWhere('email', 'like', '%'.$filter.'%'); ->orWhere('email', 'like', '%'.$filter.'%');
}); })
->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']);
}); });
} }

View File

@ -124,7 +124,8 @@ class InvoiceFilters extends QueryFilters
$q->where('first_name', 'like', '%'.$filter.'%') $q->where('first_name', 'like', '%'.$filter.'%')
->orWhere('last_name', 'like', '%'.$filter.'%') ->orWhere('last_name', 'like', '%'.$filter.'%')
->orWhere('email', 'like', '%'.$filter.'%'); ->orWhere('email', 'like', '%'.$filter.'%');
}); })
->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']);
}); });
} }

View File

@ -45,7 +45,8 @@ class QuoteFilters extends QueryFilters
$q->where('first_name', 'like', '%'.$filter.'%') $q->where('first_name', 'like', '%'.$filter.'%')
->orWhere('last_name', 'like', '%'.$filter.'%') ->orWhere('last_name', 'like', '%'.$filter.'%')
->orWhere('email', 'like', '%'.$filter.'%'); ->orWhere('email', 'like', '%'.$filter.'%');
}); })
->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']);
}); });
} }

View File

@ -48,7 +48,8 @@ class RecurringInvoiceFilters extends QueryFilters
$q->where('first_name', 'like', '%'.$filter.'%') $q->where('first_name', 'like', '%'.$filter.'%')
->orWhere('last_name', 'like', '%'.$filter.'%') ->orWhere('last_name', 'like', '%'.$filter.'%')
->orWhere('email', 'like', '%'.$filter.'%'); ->orWhere('email', 'like', '%'.$filter.'%');
}); })
->orWhereRaw("JSON_UNQUOTE(JSON_EXTRACT(line_items, '$[*].notes')) LIKE ?", ['%'.$filter.'%']);
}); });
} }

View File

@ -27,7 +27,7 @@ function nlog($output, $context = []): void
} }
if (gettype($output) == 'object') { if (gettype($output) == 'object') {
$output = print_r($output, 1); $output = print_r($output, true);
} }
// $trace = debug_backtrace(); // $trace = debug_backtrace();
@ -53,7 +53,7 @@ function nrlog($output, $context = []): void
} }
if (gettype($output) == 'object') { if (gettype($output) == 'object') {
$output = print_r($output, 1); $output = print_r($output, true);
} }
// $trace = debug_backtrace(); // $trace = debug_backtrace();

View File

@ -411,7 +411,7 @@ class InvoiceItemSumInclusive
$this->rule = new $class(); $this->rule = new $class();
if($this->rule->regionWithNoTaxCoverage($this->client->country->iso_3166_2)) { if($this->rule->regionWithNoTaxCoverage($this->client->country->iso_3166_2 ?? false)) {
return $this; return $this;
} }

View File

@ -31,7 +31,7 @@ class GmailTransport extends AbstractTransport
protected function doSend(SentMessage $message): void protected function doSend(SentMessage $message): void
{ {
nlog("In Do Send"); nlog("In Do Send");
$message = MessageConverter::toEmail($message->getOriginalMessage()); $message = MessageConverter::toEmail($message->getOriginalMessage()); //@phpstan-ignore-line
/** @phpstan-ignore-next-line **/ /** @phpstan-ignore-next-line **/
$token = $message->getHeaders()->get('gmailtoken')->getValue(); // @phpstan-ignore-line $token = $message->getHeaders()->get('gmailtoken')->getValue(); // @phpstan-ignore-line

View File

@ -25,7 +25,8 @@ class Office365MailTransport extends AbstractTransport
protected function doSend(SentMessage $message): void protected function doSend(SentMessage $message): void
{ {
$symfony_message = MessageConverter::toEmail($message->getOriginalMessage()); $symfony_message = MessageConverter::toEmail($message->getOriginalMessage()); //@phpstan-ignore-line
$graph = new Graph(); $graph = new Graph();

View File

@ -376,6 +376,7 @@ class LoginController extends BaseController
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
/** @var Builder $cu */
$cu = CompanyUser::query()->where('user_id', $user->id); $cu = CompanyUser::query()->where('user_id', $user->id);
if ($cu->count() == 0) { if ($cu->count() == 0) {
@ -398,18 +399,15 @@ class LoginController extends BaseController
$truth->setCompany($set_company); $truth->setCompany($set_company);
//21-03-2024 //21-03-2024
$cu->each(function ($cu) { $cu->each(function ($cu) {
if(CompanyToken::where('company_id', $cu->company_id)->where('user_id', $cu->user_id)->where('is_system', true)->doesntExist()) { /** @var \App\Models\CompanyUser $cu */
if(CompanyToken::query()->where('company_id', $cu->company_id)->where('user_id', $cu->user_id)->where('is_system', true)->doesntExist()) {
(new CreateCompanyToken($cu->company, $cu->user, request()->server('HTTP_USER_AGENT')))->handle(); (new CreateCompanyToken($cu->company, $cu->user, request()->server('HTTP_USER_AGENT')))->handle();
} }
}); });
// $user->account->companies->each(function ($company) use ($user) {
// if ($company->tokens()->where('user_id',$user->id)->where('is_system', true)->count() == 0) {
// (new CreateCompanyToken($company, $user, request()->server('HTTP_USER_AGENT')))->handle();
// }
// });
$truth->setCompanyToken(CompanyToken::where('user_id', $user->id)->where('company_id', $set_company->id)->where('is_system', true)->first()); $truth->setCompanyToken(CompanyToken::where('user_id', $user->id)->where('company_id', $set_company->id)->where('is_system', true)->first());
return CompanyUser::query()->where('user_id', $user->id); return CompanyUser::query()->where('user_id', $user->id);

View File

@ -97,7 +97,7 @@ class YodleeController extends BaseController
} }
$company->account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->each(function ($bank_integration) use ($company) { // TODO: filter to yodlee only $company->account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->each(function ($bank_integration) use ($company) { // TODO: filter to yodlee only
ProcessBankTransactionsYodlee::dispatch($company->account->id, $bank_integration); ProcessBankTransactionsYodlee::dispatch($company->account->bank_integration_account_id, $bank_integration);
}); });
} }

View File

@ -197,6 +197,7 @@ class BankIntegrationController extends BaseController
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
/** @var \App\Models\Account $user_account */
$user_account = $user->account; $user_account = $user->account;
$this->refreshAccountsYodlee($user); $this->refreshAccountsYodlee($user);
@ -210,12 +211,14 @@ class BankIntegrationController extends BaseController
// Processing transactions for each bank account // Processing transactions for each bank account
if (Ninja::isHosted() && $user->account->bank_integration_account_id) { if (Ninja::isHosted() && $user->account->bank_integration_account_id) {
$user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->each(function ($bank_integration) use ($user_account) { $user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->each(function ($bank_integration) use ($user_account) {
ProcessBankTransactionsYodlee::dispatch($user_account->id, $bank_integration); /** @var \App\Models\BankIntegration $bank_integration */
ProcessBankTransactionsYodlee::dispatch($user_account->bank_integration_account_id, $bank_integration);
}); });
} }
if (config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key') && (Ninja::isSelfHost() || (Ninja::isHosted() && $user_account->isEnterprisePaidClient()))) { if (config('ninja.nordigen.secret_id') && config('ninja.nordigen.secret_key') && (Ninja::isSelfHost() || (Ninja::isHosted() && $user_account->isEnterprisePaidClient()))) {
$user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->each(function ($bank_integration) { $user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->each(function ($bank_integration) {
/** @var \App\Models\BankIntegration $bank_integration */
ProcessBankTransactionsNordigen::dispatch($bank_integration); ProcessBankTransactionsNordigen::dispatch($bank_integration);
}); });
} }
@ -345,7 +348,7 @@ class BankIntegrationController extends BaseController
if (Ninja::isHosted() && $account->isPaid() && $account->plan == 'enterprise') { if (Ninja::isHosted() && $account->isPaid() && $account->plan == 'enterprise') {
$account->bank_integrations()->where('integration_type', BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->cursor()->each(function ($bank_integration) use ($account) { $account->bank_integrations()->where('integration_type', BankIntegration::INTEGRATION_TYPE_YODLEE)->where('auto_sync', true)->cursor()->each(function ($bank_integration) use ($account) {
(new ProcessBankTransactionsYodlee($account->id, $bank_integration))->handle(); (new ProcessBankTransactionsYodlee($account->bank_integration_account_id, $bank_integration))->handle();
}); });
} }

View File

@ -654,7 +654,7 @@ class BaseController extends Controller
/** /**
* Passes back the miniloaded data response * Passes back the miniloaded data response
* *
* @param Builder $query * @param mixed $query
* *
*/ */
protected function timeConstrainedResponse($query) protected function timeConstrainedResponse($query)
@ -895,11 +895,7 @@ class BaseController extends Controller
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
} }
// else { return $this->response($this->manager->createData($resource)->toArray()); //@phpstan-ignore-line
// $resource = new Collection($query, $transformer, $this->entity_type);
// }
return $this->response($this->manager->createData($resource)->toArray());
} }
/** /**

View File

@ -209,7 +209,7 @@ class PaymentController extends Controller
if (property_exists($payment_hash->data, 'billing_context')) { if (property_exists($payment_hash->data, 'billing_context')) {
$billing_subscription = \App\Models\Subscription::find($this->decodePrimaryKey($payment_hash->data->billing_context->subscription_id)); $billing_subscription = \App\Models\Subscription::find($this->decodePrimaryKey($payment_hash->data->billing_context->subscription_id));
/** @var \App\Models\Subscription $billing_subscription */
return (new SubscriptionService($billing_subscription))->completePurchase($payment_hash); return (new SubscriptionService($billing_subscription))->completePurchase($payment_hash);
} }

View File

@ -183,7 +183,7 @@ class DocumentController extends BaseController
} }
if ($action == 'download') { if ($action == 'download') {
ZipDocuments::dispatch($documents->pluck('id'), $user->company(), auth()->user()); ZipDocuments::dispatch($documents->pluck('id'), $user->company(), auth()->user()); //@phpstan-ignore-line
return response()->json(['message' => ctrans('texts.sent_message')], 200); return response()->json(['message' => ctrans('texts.sent_message')], 200);
} }

View File

@ -267,7 +267,7 @@ class MigrationController extends BaseController
if ($request->companies) { if ($request->companies) {
//handle Laravel 5.5 UniHTTP //handle Laravel 5.5 UniHTTP
$companies = json_decode($request->companies, 1); $companies = json_decode($request->companies, true);
} else { } else {
//handle Laravel 6 Guzzle //handle Laravel 6 Guzzle
$companies = []; $companies = [];
@ -275,7 +275,7 @@ class MigrationController extends BaseController
foreach ($request->all() as $input) { foreach ($request->all() as $input) {
if ($input instanceof UploadedFile) { if ($input instanceof UploadedFile) {
} else { } else {
$companies[] = json_decode($input, 1); $companies[] = json_decode($input, true);
} }
} }
} }

View File

@ -24,8 +24,9 @@ class PaymentNotificationWebhookController extends Controller
public function __invoke(PaymentNotificationWebhookRequest $request, string $company_key, string $company_gateway_id, string $client_hash) public function __invoke(PaymentNotificationWebhookRequest $request, string $company_key, string $company_gateway_id, string $client_hash)
{ {
/** @var \App\Models\CompanyGateway $company_gateway */ /** @var \App\Models\CompanyGateway $company_gateway */
$company_gateway = CompanyGateway::find($this->decodePrimaryKey($company_gateway_id)); $company_gateway = CompanyGateway::find($this->decodePrimaryKey($company_gateway_id));
/** @var \App\Models\Client $client */
$client = Client::find($this->decodePrimaryKey($client_hash)); $client = Client::find($this->decodePrimaryKey($client_hash));
return $company_gateway return $company_gateway

View File

@ -125,7 +125,7 @@ class PreviewController extends BaseController
$response = Response::make($pdf, 200); $response = Response::make($pdf, 200);
$response->header('Content-Type', 'application/pdf'); $response->header('Content-Type', 'application/pdf');
$response->header('Server-Timing', microtime(true) - $start); $response->header('Server-Timing', (string) (microtime(true) - $start));
return $response; return $response;
} }
@ -288,7 +288,7 @@ class PreviewController extends BaseController
/** @var \App\Models\Company $company */ /** @var \App\Models\Company $company */
$company = $user->company(); $company = $user->company();
$design_object = json_decode(json_encode(request()->input('design')), 1); $design_object = json_decode(json_encode(request()->input('design')), true);
$ts = (new TemplateService()); $ts = (new TemplateService());

View File

@ -145,8 +145,8 @@ class SetupController extends Controller
Artisan::call('config:clear'); Artisan::call('config:clear');
Artisan::call('key:generate', ['--force' => true]); Artisan::call('key:generate', ['--force' => true]);
Artisan::call('migrate', ['--force' => true]); Artisan::call('migrate', ['--force' => true]);
Artisan::call('db:seed', ['--force' => true]); Artisan::call('db:seed', ['--force' => true]);
Artisan::call('config:clear'); Artisan::call('config:clear');

View File

@ -11,13 +11,14 @@
namespace App\Http\Requests\Client; namespace App\Http\Requests\Client;
use App\DataMapper\CompanySettings;
use App\Http\Requests\Request; use App\Http\Requests\Request;
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
use App\Utils\Traits\ChecksEntityStatus;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Support\Facades\Cache;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use App\DataMapper\CompanySettings;
use Illuminate\Support\Facades\Cache;
use App\Utils\Traits\ChecksEntityStatus;
use App\Http\ValidationRules\EInvoice\ValidClientScheme;
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
class UpdateClientRequest extends Request class UpdateClientRequest extends Request
{ {
@ -66,6 +67,8 @@ class UpdateClientRequest extends Request
$rules['id_number'] = ['sometimes', 'bail', 'nullable', Rule::unique('clients')->where('company_id', $user->company()->id)->ignore($this->client->id)]; $rules['id_number'] = ['sometimes', 'bail', 'nullable', Rule::unique('clients')->where('company_id', $user->company()->id)->ignore($this->client->id)];
$rules['number'] = ['sometimes', 'bail', Rule::unique('clients')->where('company_id', $user->company()->id)->ignore($this->client->id)]; $rules['number'] = ['sometimes', 'bail', Rule::unique('clients')->where('company_id', $user->company()->id)->ignore($this->client->id)];
$rules['e_invoice'] = ['sometimes','nullable', new ValidClientScheme()];
$rules['settings'] = new ValidClientGroupSettingsRule(); $rules['settings'] = new ValidClientGroupSettingsRule();
$rules['contacts'] = 'array'; $rules['contacts'] = 'array';
$rules['contacts.*.email'] = 'bail|nullable|distinct|sometimes|email'; $rules['contacts.*.email'] = 'bail|nullable|distinct|sometimes|email';

View File

@ -29,7 +29,7 @@ class CreatePaymentMethodRequest extends FormRequest
$available_methods = []; $available_methods = [];
collect($client->service()->getPaymentMethods(-1)) collect($client->service()->getPaymentMethods(-1))
->filter(function ($method) use (&$available_methods) { ->filter(function ($method) use (&$available_methods) { //@phpstan-ignore-line
$available_methods[] = $method['gateway_type_id']; $available_methods[] = $method['gateway_type_id'];
}); });

View File

@ -48,7 +48,7 @@ class StoreCompanyGatewayRequest extends Request
{ {
$input = $this->all(); $input = $this->all();
if ($gateway = Gateway::where('key', $input['gateway_key'])->first()) { if ($gateway = Gateway::query()->where('key', $input['gateway_key'])->first()) {
$default_gateway_fields = json_decode($gateway->fields); $default_gateway_fields = json_decode($gateway->fields);
/*Force gateway properties */ /*Force gateway properties */

View File

@ -48,7 +48,7 @@ class UpdateCompanyGatewayRequest extends Request
/*Force gateway properties */ /*Force gateway properties */
if (isset($input['config']) && is_object(json_decode($input['config'])) && array_key_exists('gateway_key', $input)) { if (isset($input['config']) && is_object(json_decode($input['config'])) && array_key_exists('gateway_key', $input)) {
$gateway = Gateway::where('key', $input['gateway_key'])->first(); $gateway = Gateway::query()->where('key', $input['gateway_key'])->first();
$default_gateway_fields = json_decode($gateway->fields); $default_gateway_fields = json_decode($gateway->fields);
foreach (json_decode($input['config']) as $key => $value) { foreach (json_decode($input['config']) as $key => $value) {

View File

@ -94,7 +94,7 @@ class SendEmailRequest extends Request
$this->entity_plural = Str::plural($input['entity']) ?? ''; $this->entity_plural = Str::plural($input['entity']) ?? '';
if (isset($input['entity'])) { if (isset($input['entity']) && in_array($input['entity'], ['invoice','quote','credit','recurring_invoice','purchase_order','payment'])) {
$input['entity'] = "App\Models\\".ucfirst(Str::camel($input['entity'])); $input['entity'] = "App\Models\\".ucfirst(Str::camel($input['entity']));
} }

View File

@ -46,7 +46,7 @@ class StorePaymentRequest extends Request
$rules = [ $rules = [
'client_id' => ['bail','required',Rule::exists('clients', 'id')->where('company_id', $user->company()->id)->where('is_deleted', 0)], 'client_id' => ['bail','required',Rule::exists('clients', 'id')->where('company_id', $user->company()->id)->where('is_deleted', 0)],
'invoices' => ['bail','sometimes', 'nullable', 'array', new ValidPayableInvoicesRule()], 'invoices' => ['bail', 'sometimes', 'nullable', 'array', new ValidPayableInvoicesRule()],
'invoices.*.amount' => ['bail','required'], 'invoices.*.amount' => ['bail','required'],
'invoices.*.invoice_id' => ['bail','required','distinct', new ValidInvoicesRules($this->all()),Rule::exists('invoices', 'id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)], 'invoices.*.invoice_id' => ['bail','required','distinct', new ValidInvoicesRules($this->all()),Rule::exists('invoices', 'id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],
'credits.*.credit_id' => ['bail','required','distinct', new ValidCreditsRules($this->all()),Rule::exists('credits', 'id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)], 'credits.*.credit_id' => ['bail','required','distinct', new ValidCreditsRules($this->all()),Rule::exists('credits', 'id')->where('company_id', $user->company()->id)->where('client_id', $this->client_id)],

View File

@ -34,7 +34,10 @@ class BulkRecurringExpenseRequest extends Request
return false; return false;
} }
return auth()->user()->can(auth()->user()->isAdmin(), RecurringExpense::class); /** @var \App\Models\User $user */
$user = auth()->user();
return $user->can('edit', RecurringExpense::class);
} }
/** /**

View File

@ -69,7 +69,7 @@ class StoreTaskRequest extends Request
foreach ($values as $k) { foreach ($values as $k) {
if (!is_int($k[0]) || !is_int($k[1])) { if (!is_int($k[0]) || !is_int($k[1])) {
return $fail('The '.$attribute.' - '.print_r($k, 1).' is invalid. Unix timestamps only.'); return $fail('The '.$attribute.' - '.print_r($k, true).' is invalid. Unix timestamps only.');
} }
} }

View File

@ -75,7 +75,7 @@ class UpdateTaskRequest extends Request
foreach ($values as $k) { foreach ($values as $k) {
if (!is_int($k[0]) || !is_int($k[1])) { if (!is_int($k[0]) || !is_int($k[1])) {
return $fail('The '.$attribute.' - '.print_r($k, 1).' is invalid. Unix timestamps only.'); return $fail('The '.$attribute.' - '.print_r($k, true).' is invalid. Unix timestamps only.');
} }
} }

View File

@ -34,7 +34,11 @@ class BulkVendorRequest extends Request
return false; return false;
} }
return auth()->user()->can(auth()->user()->isAdmin(), Vendor::class); /** @var \App\Models\User $user */
$user = auth()->user();
return $user->can('edit', Vendor::class);
} }
/** /**

View File

@ -0,0 +1,63 @@
<?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 App\Services\EDocument\Standards\Validation\Peppol\ClientLevel;
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 ValidClientScheme.
*/
class ValidClientScheme implements ValidationRule, ValidatorAwareRule
{
/**
* The validator instance.
*
* @var Validator
*/
protected $validator;
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if(isset($value['Invoice']))
{
$r = new EInvoice();
$errors = $r->validateRequest($value['Invoice'], ClientLevel::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;
}
}

View File

@ -35,18 +35,21 @@ class ValidCompanyScheme implements ValidationRule, ValidatorAwareRule
public function validate(string $attribute, mixed $value, Closure $fail): void public function validate(string $attribute, mixed $value, Closure $fail): void
{ {
$r = new EInvoice(); if(isset($value['Invoice']))
$errors = $r->validateRequest($value['Invoice'], CompanyLevel::class); {
$r = new EInvoice();
foreach ($errors as $key => $msg) { $errors = $r->validateRequest($value['Invoice'], CompanyLevel::class);
foreach ($errors as $key => $msg) {
$this->validator->errors()->add( $this->validator->errors()->add(
"e_invoice.{$key}", "e_invoice.{$key}",
"{$key} - {$msg}" "{$key} - {$msg}"
); );
}
} }
} }
/** /**

View File

@ -85,11 +85,12 @@ class ValidInvoicesRules implements Rule
//catch here nothing to do - we need this to prevent the last elseif triggering //catch here nothing to do - we need this to prevent the last elseif triggering
} elseif ($inv->status_id == Invoice::STATUS_DRAFT && floatval($invoice['amount']) > floatval($inv->amount)) { } elseif ($inv->status_id == Invoice::STATUS_DRAFT && floatval($invoice['amount']) > floatval($inv->amount)) {
$this->error_msg = 'Amount cannot be greater than invoice balance'; $this->error_msg = 'Amount cannot be greater than invoice balance';
return false; return false;
} elseif (floatval($invoice['amount']) > floatval($inv->balance)) { } elseif (floatval($invoice['amount']) > floatval($inv->balance)) {
$this->error_msg = ctrans('texts.amount_greater_than_balance_v5'); $this->error_msg = ctrans('texts.amount_greater_than_balance_v5');
return false;
} elseif($inv->is_deleted){
$this->error_msg = 'One or more invoices in this request have since been deleted';
return false; return false;
} }
} }

View File

@ -35,7 +35,7 @@ class ValidPayableInvoicesRule implements Rule
$invoices = []; $invoices = [];
if (is_array($value)) { if (is_array($value)) {
$invoices = Invoice::query()->whereIn('id', array_column($value, 'invoice_id'))->company()->get(); $invoices = Invoice::query()->withTrashed()->whereIn('id', array_column($value, 'invoice_id'))->company()->get();
} }
foreach ($invoices as $invoice) { foreach ($invoices as $invoice) {

View File

@ -31,7 +31,10 @@ class ProductMap
12 => 'product.custom_value2', 12 => 'product.custom_value2',
13 => 'product.custom_value3', 13 => 'product.custom_value3',
14 => 'product.custom_value4', 14 => 'product.custom_value4',
15 => 'product.image_url' 15 => 'product.image_url',
16 => 'product.in_stock_quantity',
17 => 'product.tax_category',
18 => 'product.max_quantity',
]; ];
} }
@ -54,6 +57,9 @@ class ProductMap
13 => 'texts.custom_value', 13 => 'texts.custom_value',
14 => 'texts.custom_value', 14 => 'texts.custom_value',
15 => 'texts.image_url', 15 => 'texts.image_url',
16 => 'texts.in_stock_quantity',
17 => 'texts.tax_category',
18 => 'texts.max_quantity',
]; ];
} }
} }

View File

@ -42,7 +42,7 @@ class ExpenseTransformer extends BaseTransformer
'client_id' => isset($data['expense.client']) 'client_id' => isset($data['expense.client'])
? $this->getClientId($data['expense.client']) ? $this->getClientId($data['expense.client'])
: null, : null,
'date' => strlen($this->getString($data, 'expense.date') > 1) ? $this->parseDate($data['expense.date']) : now()->format('Y-m-d'), 'date' => strlen($this->getString($data, 'expense.date')) > 1 ? $this->parseDate($data['expense.date']) : now()->format('Y-m-d'),
'public_notes' => $this->getString($data, 'expense.public_notes'), 'public_notes' => $this->getString($data, 'expense.public_notes'),
'private_notes' => $this->getString($data, 'expense.private_notes'), 'private_notes' => $this->getString($data, 'expense.private_notes'),
'category_id' => isset($data['expense.category']) 'category_id' => isset($data['expense.category'])

View File

@ -43,6 +43,7 @@ class ProductTransformer extends BaseTransformer
'custom_value3' => $this->getString($data, 'product.custom_value3'), 'custom_value3' => $this->getString($data, 'product.custom_value3'),
'custom_value4' => $this->getString($data, 'product.custom_value4'), 'custom_value4' => $this->getString($data, 'product.custom_value4'),
'product_image' => $this->getString($data, 'product.image_url'), 'product_image' => $this->getString($data, 'product.image_url'),
'in_stock_quantity' => $this->getFloat($data, 'product.in_stock_quantity'),
]; ];
} }
} }

View File

@ -448,6 +448,6 @@ class MatchBankTransactions implements ShouldQueue
public function middleware() public function middleware()
{ {
return [new WithoutOverlapping($this->company_id)]; return [new WithoutOverlapping($this->company->account->bank_integration_account_id)];
} }
} }

View File

@ -35,10 +35,6 @@ class ProcessBankTransactionsYodlee implements ShouldQueue
use Queueable; use Queueable;
use SerializesModels; use SerializesModels;
private string $bank_integration_account_id;
private BankIntegration $bank_integration;
private ?string $from_date; private ?string $from_date;
private bool $stop_loop = true; private bool $stop_loop = true;
@ -50,10 +46,8 @@ class ProcessBankTransactionsYodlee implements ShouldQueue
/** /**
* Create a new job instance. * Create a new job instance.
*/ */
public function __construct(string $bank_integration_account_id, BankIntegration $bank_integration) public function __construct(private string $bank_integration_account_id, private BankIntegration $bank_integration)
{ {
$this->bank_integration_account_id = $bank_integration_account_id;
$this->bank_integration = $bank_integration;
$this->from_date = $bank_integration->from_date; $this->from_date = $bank_integration->from_date;
$this->company = $this->bank_integration->company; $this->company = $this->bank_integration->company;
} }

View File

@ -93,8 +93,7 @@ class ProcessBrevoWebhook implements ShouldQueue
{ {
MultiDB::findAndSetDbByCompanyKey($this->request['tags'][0]); MultiDB::findAndSetDbByCompanyKey($this->request['tags'][0]);
/** @phpstan-ignore-next-line */ $this->company = Company::query()->where('company_key', $this->request['tags'][0])->first();
$this->company = Company::where('company_key', $this->request['tags'][0])->first();
$this->invitation = $this->discoverInvitation($this->request['message-id']); $this->invitation = $this->discoverInvitation($this->request['message-id']);

View File

@ -58,7 +58,7 @@ class CheckVat implements ShouldQueue
public function middleware() public function middleware()
{ {
return [new WithoutOverlapping($this->client->id)]; return [new WithoutOverlapping($this->client->client_hash)];
} }
} }

View File

@ -108,7 +108,8 @@ class CompanyExport implements ShouldQueue
$this->export_data['users'] = $this->company->users()->withTrashed()->cursor()->map(function ($user) { $this->export_data['users'] = $this->company->users()->withTrashed()->cursor()->map(function ($user) {
$user->account_id = $this->encodePrimaryKey($user->account_id); /** @var \App\Models\User $user */
$user->account_id = $this->encodePrimaryKey($user->account_id); //@phpstan-ignore-line
return $user; return $user;
})->all(); })->all();

View File

@ -94,7 +94,7 @@ class CompanyTaxRate implements ShouldQueue
public function middleware() public function middleware()
{ {
return [new WithoutOverlapping($this->company->id)]; return [new WithoutOverlapping($this->company->company_key)];
} }
public function failed($e) public function failed($e)

View File

@ -65,7 +65,7 @@ class AutoBillCron
$auto_bill_partial_invoices->chunk(400, function ($invoices) { $auto_bill_partial_invoices->chunk(400, function ($invoices) {
foreach ($invoices as $invoice) { foreach ($invoices as $invoice) {
AutoBill::dispatch($invoice->id, false); AutoBill::dispatch($invoice->id, null);
} }
sleep(2); sleep(2);
@ -87,7 +87,7 @@ class AutoBillCron
$auto_bill_invoices->chunk(400, function ($invoices) { $auto_bill_invoices->chunk(400, function ($invoices) {
foreach ($invoices as $invoice) { foreach ($invoices as $invoice) {
AutoBill::dispatch($invoice->id, false); AutoBill::dispatch($invoice->id, null);
} }
sleep(2); sleep(2);

View File

@ -47,10 +47,12 @@ class CopyDocs implements ShouldQueue
{ {
MultiDB::setDb($this->db); MultiDB::setDb($this->db);
Document::whereIn('id', $this->document_ids) Document::query()
->whereIn('id', $this->document_ids)
->where('company_id', $this->entity->company_id) ->where('company_id', $this->entity->company_id)
->each(function ($document) { ->each(function ($document) {
/** @var \App\Models\Document $document */
$file = $document->getFile(); $file = $document->getFile();
$extension = pathinfo($document->name, PATHINFO_EXTENSION); $extension = pathinfo($document->name, PATHINFO_EXTENSION);

View File

@ -63,7 +63,7 @@ class CreateUbl implements ShouldQueue
// invoice // invoice
$ubl_invoice->setId($invoice->number); $ubl_invoice->setId($invoice->number);
$ubl_invoice->setIssueDate(date_create($invoice->date)); $ubl_invoice->setIssueDate(date_create($invoice->date));
$ubl_invoice->setInvoiceTypeCode($invoice->amount < 0 ? self::INVOICE_TYPE_CREDIT : self::INVOICE_TYPE_STANDARD); $ubl_invoice->setInvoiceTypeCode($invoice->amount < 0 ? (string)self::INVOICE_TYPE_CREDIT : (string)self::INVOICE_TYPE_STANDARD);
$supplier_party = $this->createParty($company, $invoice->user); $supplier_party = $this->createParty($company, $invoice->user);
$ubl_invoice->setAccountingSupplierParty($supplier_party); $ubl_invoice->setAccountingSupplierParty($supplier_party);

View File

@ -75,6 +75,6 @@ class ClientLedgerBalanceUpdate implements ShouldQueue
public function middleware() public function middleware()
{ {
return [(new WithoutOverlapping($this->client->id))->dontRelease()]; return [(new WithoutOverlapping($this->client->client_hash))->dontRelease()];
} }
} }

View File

@ -94,7 +94,7 @@ class ProcessMailgunWebhook implements ShouldQueue
} }
MultiDB::findAndSetDbByCompanyKey($this->request['event-data']['tags'][0]); MultiDB::findAndSetDbByCompanyKey($this->request['event-data']['tags'][0]);
$company = Company::where('company_key', $this->request['event-data']['tags'][0])->first(); $company = Company::query()->where('company_key', $this->request['event-data']['tags'][0])->first();
if ($company && $this->request['event-data']['event'] == 'complained' && config('ninja.notification.slack')) { if ($company && $this->request['event-data']['event'] == 'complained' && config('ninja.notification.slack')) {
$company->notification(new EmailSpamNotification($company))->ninja(); $company->notification(new EmailSpamNotification($company))->ninja();

View File

@ -87,7 +87,7 @@ class ProcessPostmarkWebhook implements ShouldQueue
public function handle() public function handle()
{ {
MultiDB::findAndSetDbByCompanyKey($this->request['Tag']); MultiDB::findAndSetDbByCompanyKey($this->request['Tag']);
$this->company = Company::where('company_key', $this->request['Tag'])->first(); /** @phpstan-ignore-line */ $this->company = Company::query()->where('company_key', $this->request['Tag'])->first(); /** @phpstan-ignore-line */
$this->invitation = $this->discoverInvitation($this->request['MessageID']); $this->invitation = $this->discoverInvitation($this->request['MessageID']);

View File

@ -140,6 +140,6 @@ class UpdateOrCreateProduct implements ShouldQueue
public function failed($exception = null) public function failed($exception = null)
{ {
info('update create failed with = '); info('update create failed with = ');
info(print_r($exception->getMessage(), 1)); nlog($exception->getMessage());
} }
} }

View File

@ -202,6 +202,6 @@ class SendRecurring implements ShouldQueue
LightLogs::create($job_failure) LightLogs::create($job_failure)
->send(); ->send();
nlog(print_r($exception->getMessage(), 1)); nlog($exception->getMessage());
} }
} }

View File

@ -212,7 +212,7 @@ class Import implements ShouldQueue
$user->setCompany($this->company); $user->setCompany($this->company);
$array = json_decode(file_get_contents($this->file_path), 1); $array = json_decode(file_get_contents($this->file_path), true);
$data = $array['data']; $data = $array['data'];
foreach ($this->available_imports as $import) { foreach ($this->available_imports as $import) {
@ -253,7 +253,7 @@ class Import implements ShouldQueue
$this->setInitialCompanyLedgerBalances(); $this->setInitialCompanyLedgerBalances();
// $this->fixClientBalances(); // $this->fixClientBalances();
$check_data = (new CheckCompanyData($this->company, md5(time())))->handle(); $check_data = (new CheckCompanyData($this->company, md5(time())))->handle(); //@phpstan-ignore-line
// if(Ninja::isHosted() && array_key_exists('ninja_tokens', $data)) // if(Ninja::isHosted() && array_key_exists('ninja_tokens', $data))
$this->processNinjaTokens($data['ninja_tokens']); $this->processNinjaTokens($data['ninja_tokens']);
@ -1545,7 +1545,6 @@ class Import implements ShouldQueue
$file_path, $file_path,
$file_name, $file_name,
$file_info, $file_info,
filesize($file_path),
0, 0,
false false
); );
@ -2010,7 +2009,7 @@ class Import implements ShouldQueue
public function transformId($resource, string $old): int public function transformId($resource, string $old): int
{ {
if (! array_key_exists($resource, $this->ids)) { if (! array_key_exists($resource, $this->ids)) {
info(print_r($resource, 1)); nlog($resource);
throw new Exception("Resource {$resource} not available."); throw new Exception("Resource {$resource} not available.");
} }
@ -2067,11 +2066,10 @@ class Import implements ShouldQueue
LightLogs::create($job_failure) LightLogs::create($job_failure)
->queue(); ->queue();
nlog(print_r($exception->getMessage(), 1)); nlog($exception->getMessage());
// if (Ninja::isHosted()) {
app('sentry')->captureException($exception); app('sentry')->captureException($exception);
// }
} }

View File

@ -168,6 +168,6 @@ class StartMigration implements ShouldQueue
public function failed($exception = null) public function failed($exception = null)
{ {
info(print_r($exception->getMessage(), 1)); nlog($exception->getMessage());
} }
} }

View File

@ -38,7 +38,7 @@ class UploadAvatar implements ShouldQueue
public function handle(): ?string public function handle(): ?string
{ {
$tmp_file = sha1(time()).'.png'; $tmp_file = sha1(time()).'.png'; //@phpstan-ignore-line
$im = imagecreatefromstring(file_get_contents($this->file)); $im = imagecreatefromstring(file_get_contents($this->file));
imagealphablending($im, false); imagealphablending($im, false);

View File

@ -94,7 +94,7 @@ class VersionCheck implements ShouldQueue
Client::doesntHave('contacts') Client::doesntHave('contacts')
->cursor() ->cursor()
->each(function (Client $client) { ->each(function (Client $client) { //@phpstan-ignore-line
$new_contact = ClientContactFactory::create($client->company_id, $client->user_id); $new_contact = ClientContactFactory::create($client->company_id, $client->user_id);
$new_contact->client_id = $client->id; $new_contact->client_id = $client->id;
@ -107,7 +107,7 @@ class VersionCheck implements ShouldQueue
Vendor::doesntHave('contacts') Vendor::doesntHave('contacts')
->cursor() ->cursor()
->each(function (Vendor $vendor) { ->each(function (Vendor $vendor) { //@phpstan-ignore-line
$new_contact = VendorContactFactory::create($vendor->company_id, $vendor->user_id); $new_contact = VendorContactFactory::create($vendor->company_id, $vendor->user_id);
$new_contact->vendor_id = $vendor->id; $new_contact->vendor_id = $vendor->id;

View File

@ -199,7 +199,7 @@ class CreatePurchaseOrderPdf implements ShouldQueue
} }
} }
} catch (\Exception $e) { } catch (\Exception $e) {
nlog(print_r($e->getMessage(), 1)); nlog($e->getMessage());
} }
if (config('ninja.log_pdf_html')) { if (config('ninja.log_pdf_html')) {

View File

@ -58,7 +58,7 @@ class Apple
'bid' => $this->bundle_id, 'bid' => $this->bundle_id,
]; ];
$jwt = JWT::encode($payload, $this->private_key, $this->alg, $header); $jwt = JWT::encode($payload, $this->private_key, $this->alg, null, $header);
$decoded = JWT::decode($jwt, new Key($this->private_key, $this->alg)); $decoded = JWT::decode($jwt, new Key($this->private_key, $this->alg));

View File

@ -46,7 +46,7 @@ class MailSentListener implements ShouldQueue
try { try {
$message_id = $event->sent->getMessageId(); $message_id = $event->sent->getMessageId();
$message = MessageConverter::toEmail($event->sent->getOriginalMessage()); $message = MessageConverter::toEmail($event->sent->getOriginalMessage()); //@phpstan-ignore-line
if (!$message->getHeaders()->get('x-invitation')) { if (!$message->getHeaders()->get('x-invitation')) {
return; return;

View File

@ -39,7 +39,7 @@ class StripeConnectFailed extends Mailable
return new Envelope( return new Envelope(
subject: "Stripe Connect not configured, please login and connect.", subject: "Stripe Connect not configured, please login and connect.",
from: config('ninja.contact.email'), from: config('ninja.contact.email'),
to: $this->user->email, to: $this->user->email, //@phpstan-ignore-line
); );
} }

View File

@ -24,12 +24,17 @@ class TemplateEmail extends Mailable
{ {
private $build_email; private $build_email;
private $client;
/** @var \App\Models\Client $client */
private $client;
/** @var \App\Models\ClientContact | \App\Models\VendorContact $contact */
private $contact; private $contact;
/** @var \App\Models\Company $company */
private $company; private $company;
/** @var \App\Models\InvoiceInvitation | \App\Models\QuoteInvitation | \App\Models\CreditInvitation | \App\Models\PurchaseOrderInvitation | \App\Models\RecurringInvoiceInvitation | null $invitation */
private $invitation; private $invitation;
public function __construct($build_email, ClientContact $contact, $invitation = null) public function __construct($build_email, ClientContact $contact, $invitation = null)
@ -158,7 +163,7 @@ class TemplateEmail extends Mailable
return $this; return $this;
} }
if ($this->invitation->invoice && $settings->ubl_email_attachment && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->invitation->invoice && $settings->ubl_email_attachment && !$this->invitation->invoice->client->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$ubl_string = (new CreateUbl($this->invitation->invoice))->handle(); $ubl_string = (new CreateUbl($this->invitation->invoice))->handle();
if ($ubl_string) { if ($ubl_string) {
@ -167,8 +172,8 @@ class TemplateEmail extends Mailable
} }
if ($this->invitation->invoice) { if ($this->invitation->invoice) { //@phpstan-ignore-line
if ($this->invitation->invoice->client->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->invitation->invoice->client->getSetting('enable_e_invoice') && $this->invitation->invoice->client->getSetting('ubl_email_attachment') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$xml_string = $this->invitation->invoice->service()->getEInvoice($this->invitation->contact); $xml_string = $this->invitation->invoice->service()->getEInvoice($this->invitation->contact);
if ($xml_string) { if ($xml_string) {
@ -176,8 +181,8 @@ class TemplateEmail extends Mailable
} }
} }
} elseif ($this->invitation->credit) { } elseif ($this->invitation->credit) {//@phpstan-ignore-line
if ($this->invitation->credit->client->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->invitation->credit->client->getSetting('enable_e_invoice') && $this->invitation->invoice->client->getSetting('ubl_email_attachment') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$xml_string = $this->invitation->credit->service()->getECredit($this->invitation->contact); $xml_string = $this->invitation->credit->service()->getECredit($this->invitation->contact);
if ($xml_string) { if ($xml_string) {
@ -185,8 +190,8 @@ class TemplateEmail extends Mailable
} }
} }
} elseif ($this->invitation->quote) { } elseif ($this->invitation->quote) {//@phpstan-ignore-line
if ($this->invitation->quote->client->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->invitation->quote->client->getSetting('enable_e_invoice') && $this->invitation->invoice->client->getSetting('ubl_email_attachment') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$xml_string = $this->invitation->quote->service()->getEQuote($this->invitation->contact); $xml_string = $this->invitation->quote->service()->getEQuote($this->invitation->contact);
if ($xml_string) { if ($xml_string) {
@ -195,7 +200,7 @@ class TemplateEmail extends Mailable
} }
} elseif ($this->invitation->purchase_order) { } elseif ($this->invitation->purchase_order) {
if ($this->invitation->purchase_order->vendor->getSetting('enable_e_invoice') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { if ($this->invitation->purchase_order->vendor->getSetting('enable_e_invoice') && $this->invitation->invoice->client->getSetting('ubl_email_attachment') && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$xml_string = $this->invitation->purchase_order->service()->getEPurchaseOrder($this->invitation->contact); $xml_string = $this->invitation->purchase_order->service()->getEPurchaseOrder($this->invitation->contact);
if ($xml_string) { if ($xml_string) {

View File

@ -431,11 +431,11 @@ class Activity extends StaticModel
} }
if($this->client) { if($this->client) {
$replacements['client'] = ['label' => $this?->client?->present()->name() ?? '', 'hashed_id' => $this->client->hashed_id ?? '']; $replacements['client'] = ['label' => $this->client?->present()->name() ?? '', 'hashed_id' => $this->client->hashed_id ?? ''];
} }
if($this->vendor) { if($this->vendor) {
$replacements['vendor'] = ['label' => $this?->vendor?->present()->name() ?? '', 'hashed_id' => $this->vendor->hashed_id ?? '']; $replacements['vendor'] = ['label' => $this->vendor?->present()->name() ?? '', 'hashed_id' => $this->vendor->hashed_id ?? ''];
} }
if($this->activity_type_id == 4 && $this->recurring_invoice) { if($this->activity_type_id == 4 && $this->recurring_invoice) {
@ -449,10 +449,41 @@ class Activity extends StaticModel
$replacements['created_at'] = $this->created_at ?? ''; $replacements['created_at'] = $this->created_at ?? '';
$replacements['ip'] = $this->ip ?? ''; $replacements['ip'] = $this->ip ?? '';
if($this->activity_type_id == 141)
$replacements = $this->harvestNoteEntities($replacements);
return $replacements; return $replacements;
} }
private function harvestNoteEntities(array $replacements): array
{
$entities = [
':invoice',
':quote',
':credit',
':payment',
':task',
':expense',
':purchase_order',
':recurring_invoice',
':recurring_expense',
':client',
];
foreach($entities as $entity)
{
$entity_key = substr($entity, 1);
if($this?->{$entity_key})
$replacements = array_merge($replacements, $this->matchVar($entity));
}
return $replacements;
}
private function matchVar(string $variable) private function matchVar(string $variable)
{ {
$system = ctrans('texts.system'); $system = ctrans('texts.system');

View File

@ -61,7 +61,7 @@ class Backup extends BaseModel
} }
$path = $client_or_vendor->backup_path().'/'; $path = $client_or_vendor->backup_path().'/';
$filename = now()->format('Y_m_d').'_'.md5(time()).'.html'; $filename = now()->format('Y_m_d').'_'.md5(time()).'.html'; //@phpstan-ignore-line
$file_path = $path.$filename; $file_path = $path.$filename;
Storage::disk(config('filesystems.default'))->put($file_path, $html); Storage::disk(config('filesystems.default'))->put($file_path, $html);

View File

@ -38,7 +38,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property string|null $participant * @property string|null $participant
* @property string|null $participant_name * @property string|null $participant_name
* @property string $invoice_ids * @property string $invoice_ids
* @property int|null $expense_id * @property string|null $expense_id
* @property int|null $vendor_id * @property int|null $vendor_id
* @property int $status_id * @property int $status_id
* @property bool $is_deleted * @property bool $is_deleted

View File

@ -573,7 +573,7 @@ class Client extends BaseModel implements HasLocalePreference
if ($pm['gateway_type_id'] == GatewayType::BACS) { if ($pm['gateway_type_id'] == GatewayType::BACS) {
$cg = CompanyGateway::query()->find($pm['company_gateway_id']); $cg = CompanyGateway::query()->find($pm['company_gateway_id']);
if ($cg && ! property_exists($cg->fees_and_limits, GatewayType::BACS)) { if ($cg && ! property_exists($cg->fees_and_limits, GatewayType::BACS)) { //@phpstan-ignore-line
$fees_and_limits = $cg->fees_and_limits; $fees_and_limits = $cg->fees_and_limits;
$fees_and_limits->{GatewayType::BACS} = new FeesAndLimits(); $fees_and_limits->{GatewayType::BACS} = new FeesAndLimits();
$cg->fees_and_limits = $fees_and_limits; $cg->fees_and_limits = $fees_and_limits;
@ -597,7 +597,7 @@ class Client extends BaseModel implements HasLocalePreference
if ($pm['gateway_type_id'] == GatewayType::ACSS) { if ($pm['gateway_type_id'] == GatewayType::ACSS) {
$cg = CompanyGateway::query()->find($pm['company_gateway_id']); $cg = CompanyGateway::query()->find($pm['company_gateway_id']);
if ($cg && ! property_exists($cg->fees_and_limits, GatewayType::ACSS)) { if ($cg && ! property_exists($cg->fees_and_limits, GatewayType::ACSS)) { //@phpstan-ignore-line
$fees_and_limits = $cg->fees_and_limits; $fees_and_limits = $cg->fees_and_limits;
$fees_and_limits->{GatewayType::ACSS} = new FeesAndLimits(); $fees_and_limits->{GatewayType::ACSS} = new FeesAndLimits();
$cg->fees_and_limits = $fees_and_limits; $cg->fees_and_limits = $fees_and_limits;
@ -624,7 +624,7 @@ class Client extends BaseModel implements HasLocalePreference
if ($pm['gateway_type_id'] == GatewayType::BANK_TRANSFER) { if ($pm['gateway_type_id'] == GatewayType::BANK_TRANSFER) {
$cg = CompanyGateway::query()->find($pm['company_gateway_id']); $cg = CompanyGateway::query()->find($pm['company_gateway_id']);
if ($cg && ! property_exists($cg->fees_and_limits, GatewayType::BANK_TRANSFER)) { if ($cg && ! property_exists($cg->fees_and_limits, GatewayType::BANK_TRANSFER)) { //@phpstan-ignore-line
$fees_and_limits = $cg->fees_and_limits; $fees_and_limits = $cg->fees_and_limits;
$fees_and_limits->{GatewayType::BANK_TRANSFER} = new FeesAndLimits(); $fees_and_limits->{GatewayType::BANK_TRANSFER} = new FeesAndLimits();
$cg->fees_and_limits = $fees_and_limits; $cg->fees_and_limits = $fees_and_limits;
@ -822,6 +822,20 @@ class Client extends BaseModel implements HasLocalePreference
} }
public function utc_offset(): int
{
$offset = 0;
$timezone = $this->timezone();
date_default_timezone_set('GMT');
$date = new \DateTime("now", new \DateTimeZone($timezone->name));
$offset = $date->getOffset();
return $offset;
}
public function timezone_offset(): int public function timezone_offset(): int
{ {
$offset = 0; $offset = 0;

View File

@ -59,7 +59,7 @@ class DateFormat extends StaticModel
*/ */
public function __toString() public function __toString()
{ {
$date = mktime(0, 0, 0, 12, 31, date('Y')); $date = mktime(0, 0, 0, 12, 31, date('Y')); //@phpstan-ignore-line
return date($this->format, $date); return date($this->format, $date);
} }

View File

@ -32,7 +32,7 @@ class DatetimeFormat extends StaticModel
*/ */
public function __toString() public function __toString()
{ {
$date = mktime(0, 0, 0, 12, 31, date('Y')); $date = mktime(0, 0, 0, 12, 31, date('Y')); //@phpstan-ignore-line
return date($this->format, $date); return date($this->format, $date);
} }

View File

@ -245,9 +245,9 @@ class Document extends BaseModel
try { try {
$file = base64_encode($image); $file = base64_encode($image);
$img = new \Imagick(); $img = new \Imagick(); //@phpstan-ignore-line
$img->readImageBlob($file); $img->readImageBlob($file);
$img->setImageCompression(true); $img->setImageCompression(true); //@phpstan-ignore-line
$img->setImageCompressionQuality(40); $img->setImageCompressionQuality(40);
return $img->getImageBlob(); return $img->getImageBlob();

View File

@ -24,7 +24,7 @@ namespace App\Models;
* @property string|null $site_url * @property string|null $site_url
* @property bool $is_offsite * @property bool $is_offsite
* @property bool $is_secure * @property bool $is_secure
* @property object|null $fields * @property object|null|string $fields
* @property string $default_gateway_type_id * @property string $default_gateway_type_id
* @property int|null $created_at * @property int|null $created_at
* @property int|null $updated_at * @property int|null $updated_at

View File

@ -371,6 +371,14 @@ class Invoice extends BaseModel
return $this->hasOne(Task::class); return $this->hasOne(Task::class);
} }
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne<Quote>
*/
public function quote(): \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(Quote::class);
}
public function expenses(): \Illuminate\Database\Eloquent\Relations\HasMany public function expenses(): \Illuminate\Database\Eloquent\Relations\HasMany
{ {
return $this->hasMany(Expense::class); return $this->hasMany(Expense::class);
@ -423,7 +431,9 @@ class Invoice extends BaseModel
public function isPayable(): bool public function isPayable(): bool
{ {
if ($this->status_id == self::STATUS_DRAFT && $this->is_deleted == false) { if($this->is_deleted)
return false;
elseif ($this->status_id == self::STATUS_DRAFT && $this->is_deleted == false) {
return true; return true;
} elseif ($this->status_id == self::STATUS_SENT && $this->is_deleted == false) { } elseif ($this->status_id == self::STATUS_SENT && $this->is_deleted == false) {
return true; return true;

View File

@ -375,6 +375,7 @@ class BaseDriver extends AbstractPaymentDriver
// To access campaign data => Cache::get(CAMPAIGN_HASH) // To access campaign data => Cache::get(CAMPAIGN_HASH)
// To access utm data => session()->get('utm-' . CAMPAIGN_HASH); // To access utm data => session()->get('utm-' . CAMPAIGN_HASH);
/** @var \App\Models\Subscription $billing_subscription */
(new SubscriptionService($billing_subscription))->completePurchase($this->payment_hash); (new SubscriptionService($billing_subscription))->completePurchase($this->payment_hash);
} }

View File

@ -83,7 +83,7 @@ class CreditCard
if ($this->braintree->company_gateway->getConfigField('merchantAccountId')) { if ($this->braintree->company_gateway->getConfigField('merchantAccountId')) {
/** https://developer.paypal.com/braintree/docs/reference/request/client-token/generate#merchant_account_id */ /** https://developer.paypal.com/braintree/docs/reference/request/client-token/generate#merchant_account_id */
$data['client_token'] = $this->braintree->gateway->clientToken()->generate([ $data['client_token'] = $this->braintree->gateway->clientToken()->generate([ //@phpstan-ignore-line
'merchantAccountId' => $this->braintree->company_gateway->getConfigField('merchantAccountId'), 'merchantAccountId' => $this->braintree->company_gateway->getConfigField('merchantAccountId'),
]); ]);
} }
@ -118,7 +118,7 @@ class CreditCard
$token = $this->getPaymentToken($request->all(), $customer->id); $token = $this->getPaymentToken($request->all(), $customer->id);
$data = [ $data = [
'amount' => $this->braintree->payment_hash->data->amount_with_fee, 'amount' => $this->braintree->payment_hash->data->amount_with_fee, //@phpstan-ignore-line
'paymentMethodToken' => $token, 'paymentMethodToken' => $token,
'deviceData' => $state['client-data'], 'deviceData' => $state['client-data'],
'options' => [ 'options' => [

View File

@ -387,7 +387,7 @@ class BraintreePaymentDriver extends BaseDriver
foreach($cards as $card) { foreach($cards as $card) {
if($this->getToken($card->token, $card->customerId) || Carbon::createFromDate($card->expirationYear, $card->expirationMonth, '1')->lt(now())) { if($this->getToken($card->token, $card->customerId) || Carbon::createFromDate($card->expirationYear, $card->expirationMonth, '1')->lt(now())) { //@phpstan-ignore-line
continue; continue;
} }

View File

@ -592,7 +592,7 @@ class CheckoutComPaymentDriver extends BaseDriver
foreach($customer['instruments'] as $card) { foreach($customer['instruments'] as $card) {
if( if(
$card['type'] != 'card' || $card['type'] != 'card' ||
Carbon::createFromDate($card['expiry_year'], $card['expiry_month'], '1')->lt(now()) || Carbon::createFromDate($card['expiry_year'], $card['expiry_month'], '1')->lt(now()) || //@phpstan-ignore-line
$this->getToken($card['id'], $customer['id']) $this->getToken($card['id'], $customer['id'])
) { ) {
continue; continue;

View File

@ -525,61 +525,74 @@ class PayPalBasePaymentDriver extends BaseDriver
$this->init(); $this->init();
PayPalWebhook::dispatch($request->all(), $request->headers->all(), $this->access_token); PayPalWebhook::dispatch($request->all(), $request->headers->all(), $this->access_token);
} }
public function createNinjaPayment($request, $response) public function createNinjaPayment($request, $response)
{ {
$data = [ if(isset($response['purchase_units'][0]['payments']['captures'][0]['status']) && in_array($response['purchase_units'][0]['payments']['captures'][0]['status'], ['COMPLETED', 'PENDING']))
'payment_type' => $this->getPaymentMethod($request->gateway_type_id), {
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => GatewayType::PAYPAL,
];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); $payment_status = $response['purchase_units'][0]['payments']['captures'][0]['status'] == 'COMPLETED' ? \App\Models\Payment::STATUS_COMPLETED : \App\Models\Payment::STATUS_PENDING;
if ($request->has('store_card') && $request->input('store_card') === true) { $data = [
$payment_source = $response->json()['payment_source'] ?? false; 'payment_type' => $this->getPaymentMethod($request->gateway_type_id),
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => GatewayType::PAYPAL,
];
if(isset($payment_source['card']) && ($payment_source['card']['attributes']['vault']['status'] ?? false) && $payment_source['card']['attributes']['vault']['status'] == 'VAULTED') { $payment = $this->createPayment($data, $payment_status);
$last4 = $payment_source['card']['last_digits']; if ($request->has('store_card') && $request->input('store_card') === true) {
$expiry = $payment_source['card']['expiry']; //'2025-01' $payment_source = $response->json()['payment_source'] ?? false;
$expiry_meta = explode('-', $expiry);
$brand = $payment_source['card']['brand'];
$payment_meta = new \stdClass(); if(isset($payment_source['card']) && ($payment_source['card']['attributes']['vault']['status'] ?? false) && $payment_source['card']['attributes']['vault']['status'] == 'VAULTED') {
$payment_meta->exp_month = $expiry_meta[1] ?? '';
$payment_meta->exp_year = $expiry_meta[0] ?? $expiry;
$payment_meta->brand = $brand;
$payment_meta->last4 = $last4;
$payment_meta->type = GatewayType::CREDIT_CARD;
$token = $payment_source['card']['attributes']['vault']['id']; // 09f28652d01257021 $last4 = $payment_source['card']['last_digits'];
$gateway_customer_reference = $payment_source['card']['attributes']['vault']['customer']['id']; //rbTHnLsZqE; $expiry = $payment_source['card']['expiry']; //'2025-01'
$expiry_meta = explode('-', $expiry);
$brand = $payment_source['card']['brand'];
$data['token'] = $token; $payment_meta = new \stdClass();
$data['payment_method_id'] = GatewayType::PAYPAL_ADVANCED_CARDS; $payment_meta->exp_month = $expiry_meta[1] ?? '';
$data['payment_meta'] = $payment_meta; $payment_meta->exp_year = $expiry_meta[0] ?? $expiry;
$payment_meta->brand = $brand;
$payment_meta->last4 = $last4;
$payment_meta->type = GatewayType::CREDIT_CARD;
$additional['gateway_customer_reference'] = $gateway_customer_reference; $token = $payment_source['card']['attributes']['vault']['id']; // 09f28652d01257021
$gateway_customer_reference = $payment_source['card']['attributes']['vault']['customer']['id']; //rbTHnLsZqE;
$this->storeGatewayToken($data, $additional); $data['token'] = $token;
$data['payment_method_id'] = GatewayType::PAYPAL_ADVANCED_CARDS;
$data['payment_meta'] = $payment_meta;
$additional['gateway_customer_reference'] = $gateway_customer_reference;
$this->storeGatewayToken($data, $additional);
}
} }
SystemLogger::dispatch(
['response' => $response->json(), 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL,
$this->client,
$this->client->company,
);
return response()->json(['redirect' => route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)], false)]);
} }
SystemLogger::dispatch( SystemLogger::dispatch($response, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_PAYPAL, $this->client, $this->client->company);
['response' => $response->json(), 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE, $error = isset($response['purchase_units'][0]['payments']['captures'][0]['status_details'][0]) ? $response['purchase_units'][0]['payments']['captures'][0]['status_details'][0] : $response['purchase_units'][0]['payments']['captures'][0]['status'];
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL, return response()->json(['message' => $error], 400);
$this->client,
$this->client->company,
);
return response()->json(['redirect' => route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)], false)]);
} }

View File

@ -297,8 +297,7 @@ class PayPalWebhook implements ShouldQueue
$gateway = CompanyGateway::query() $gateway = CompanyGateway::query()
->where('company_id', $company->id) ->where('company_id', $company->id)
->where('gateway_key', $this->gateway_key) ->where('gateway_key', $this->gateway_key)
->cursor() ->first(function ($cg) use ($merchant_id) { //@phpstan-ignore-line
->first(function ($cg) use ($merchant_id) {
$config = $cg->getConfig(); $config = $cg->getConfig();
if($config->merchantId == $merchant_id) { if($config->merchantId == $merchant_id) {

View File

@ -306,7 +306,6 @@ class PayPalPPCPPaymentDriver extends PayPalBasePaymentDriver
* *
* @param mixed $request * @param mixed $request
* @param array $response * @param array $response
* @return void
*/ */
public function processTokenPayment($request, array $response) public function processTokenPayment($request, array $response)
{ {
@ -362,26 +361,32 @@ class PayPalPPCPPaymentDriver extends PayPalBasePaymentDriver
} }
$response = $r->json(); $response = $r->json();
if(isset($response['purchase_units'][0]['payments']['captures'][0]['status']) && $response['purchase_units'][0]['payments']['captures'][0]['status'] == 'COMPLETED')
{
$data = [ $data = [
'payment_type' => $this->getPaymentMethod($request->gateway_type_id), 'payment_type' => $this->getPaymentMethod($request->gateway_type_id),
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'], 'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'], 'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => $this->gateway_type_id, 'gateway_type_id' => $this->gateway_type_id,
]; ];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch( SystemLogger::dispatch(
['response' => $response, 'data' => $data], ['response' => $response, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL_PPCP, SystemLog::TYPE_PAYPAL_PPCP,
$this->client, $this->client,
$this->client->company, $this->client->company,
); );
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
}
return response()->json(['message' => 'Error processing token payment'], 400);
} }
@ -431,26 +436,36 @@ class PayPalPPCPPaymentDriver extends PayPalBasePaymentDriver
} }
$response = $r->json(); $response = $r->json();
if(isset($response['purchase_units'][0]['payments']['captures'][0]['status']) && $response['purchase_units'][0]['payments']['captures'][0]['status'] == 'COMPLETED')
{
$data = [ $data = [
'payment_type' => $this->getPaymentMethod((string)$cgt->gateway_type_id), 'payment_type' => $this->getPaymentMethod((string)$cgt->gateway_type_id),
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'], 'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'], 'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => $this->gateway_type_id, 'gateway_type_id' => $this->gateway_type_id,
]; ];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch( SystemLogger::dispatch(
['response' => $response, 'data' => $data], ['response' => $response, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL_PPCP, SystemLog::TYPE_PAYPAL_PPCP,
$this->client, $this->client,
$this->client->company, $this->client->company,
); );
}
$this->processInternallyFailedPayment($this, new \Exception('Auto billing failed.', 400));
SystemLogger::dispatch($response, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_PAYPAL, $this->client, $this->client->company);
} }
} }

View File

@ -288,8 +288,6 @@ class PayPalRestPaymentDriver extends PayPalBasePaymentDriver
$orderId = $this->createOrder($data); $orderId = $this->createOrder($data);
// $r = $this->gatewayRequest("/v2/checkout/orders/{$orderId}", 'get', ['body' => '']);
try { try {
$r = $this->gatewayRequest("/v2/checkout/orders/{$orderId}", 'get', ['body' => '']); $r = $this->gatewayRequest("/v2/checkout/orders/{$orderId}", 'get', ['body' => '']);
@ -318,25 +316,31 @@ class PayPalRestPaymentDriver extends PayPalBasePaymentDriver
$response = $r->json(); $response = $r->json();
$data = [ if(isset($response['purchase_units'][0]['payments']['captures'][0]['status']) && $response['purchase_units'][0]['payments']['captures'][0]['status'] == 'COMPLETED')
'payment_type' => $this->getPaymentMethod($request->gateway_type_id), {
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'], $data = [
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'], 'payment_type' => $this->getPaymentMethod($request->gateway_type_id),
'gateway_type_id' => $this->gateway_type_id, 'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
]; 'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => $this->gateway_type_id,
];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch( SystemLogger::dispatch(
['response' => $response, 'data' => $data], ['response' => $response, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL, SystemLog::TYPE_PAYPAL,
$this->client, $this->client,
$this->client->company, $this->client->company,
); );
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
}
return response()->json(['message' => 'Error processing token payment'], 400);
} }
@ -387,24 +391,32 @@ class PayPalRestPaymentDriver extends PayPalBasePaymentDriver
$response = $r->json(); $response = $r->json();
$data = [ if(isset($response['purchase_units'][0]['payments']['captures'][0]['status']) && $response['purchase_units'][0]['payments']['captures'][0]['status'] == 'COMPLETED')
'payment_type' => $this->getPaymentMethod((string)$cgt->gateway_type_id), {
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => $this->gateway_type_id,
];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); $data = [
'payment_type' => $this->getPaymentMethod((string)$cgt->gateway_type_id),
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => $this->gateway_type_id,
];
SystemLogger::dispatch( $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
['response' => $response, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL_PPCP,
$this->client,
$this->client->company,
);
SystemLogger::dispatch(
['response' => $response, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL_PPCP,
$this->client,
$this->client->company,
);
}
$this->processInternallyFailedPayment($this, new \Exception('Auto billing failed.', 400));
SystemLogger::dispatch($response, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_PAYPAL, $this->client, $this->client->company);
} }
} }

View File

@ -188,7 +188,7 @@ class SquarePaymentDriver extends BaseDriver
} else { } else {
/** @var \Square\Models\Error $error */ /** @var \Square\Models\Error $error */
$error = end($apiResponse->getErrors()); $error = end($apiResponse->getErrors()); //@phpstan-ignore-line
$data = [ $data = [
'transaction_reference' => $payment->transaction_reference, 'transaction_reference' => $payment->transaction_reference,

View File

@ -267,6 +267,7 @@ class ACSS
$gateway_response = json_decode($request->gateway_response); $gateway_response = json_decode($request->gateway_response);
/** @var \App\Models\ClientGatewayToken $cgt */
$cgt = ClientGatewayToken::find($this->decodePrimaryKey($request->token)); $cgt = ClientGatewayToken::find($this->decodePrimaryKey($request->token));
/** @var \Stripe\PaymentIntent $intent */ /** @var \Stripe\PaymentIntent $intent */

View File

@ -208,7 +208,7 @@ class ImportCustomers
if (! $cgt) { if (! $cgt) {
nlog('customer '.$searchResults->data[0]->id.' does not exist.'); nlog('customer '.$searchResults->data[0]->id.' does not exist.');
$this->update_payment_methods->updateMethods($searchResults->data[0], $client); $this->update_payment_methods->updateMethods($searchResults->data[0], $client); //@phpstan-ignore-line
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More