From c6e249bb67edb6ffb21c7ad1fe820017dbdf9419 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 25 Jun 2023 14:34:50 +1000 Subject: [PATCH 01/47] Minor fixes for bank transaction processing --- app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php b/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php index 42c0e9bf5895..43d337c5577d 100644 --- a/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php +++ b/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php @@ -127,9 +127,12 @@ class IncomeTransformer implements BankRevenueInterface foreach ($transaction->transaction as $transaction) { //do not store duplicate / pending transactions - if (property_exists($transaction, 'status') && $transaction->status == 'PENDING') { + if (property_exists($transaction, 'status') && $transaction->status == 'PENDING') + continue; + + //some object do no store amounts ignore these + if(!property_exists($transaction, 'amount')) continue; - } $data[] = $this->transformTransaction($transaction); } From fdc67cd5fb027c01ab26c11044c28e88bf25697f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 25 Jun 2023 14:35:58 +1000 Subject: [PATCH 02/47] Handle unavailable properties in Yodlee response --- app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php b/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php index 43d337c5577d..48966aa20382 100644 --- a/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php +++ b/app/Helpers/Bank/Yodlee/Transformer/IncomeTransformer.php @@ -151,7 +151,7 @@ class IncomeTransformer implements BankRevenueInterface 'category_type' => $transaction->categoryType, 'date' => $transaction->date, 'bank_account_id' => $transaction->accountId, - 'description' => $transaction->description->original, + 'description' => $transaction?->description?->original ?? '', 'base_type' => property_exists($transaction, 'baseType') ? $transaction->baseType : $this->calculateBaseType($transaction), ]; } From 0fea51ba53ede1f4ec95b8ba9d882af1873083ca Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 25 Jun 2023 14:44:38 +1000 Subject: [PATCH 03/47] improve resiliency of bank transaction processing --- app/Jobs/Bank/ProcessBankTransactions.php | 31 ++++++-- .../Ninja/GenericNinjaAdminNotification.php | 71 +++++++++++++++++++ 2 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 app/Notifications/Ninja/GenericNinjaAdminNotification.php diff --git a/app/Jobs/Bank/ProcessBankTransactions.php b/app/Jobs/Bank/ProcessBankTransactions.php index 9cd35817a17b..019f93dc333b 100644 --- a/app/Jobs/Bank/ProcessBankTransactions.php +++ b/app/Jobs/Bank/ProcessBankTransactions.php @@ -11,17 +11,19 @@ namespace App\Jobs\Bank; -use App\Helpers\Bank\Yodlee\Yodlee; +use App\Models\Company; use App\Libraries\MultiDB; +use Illuminate\Bus\Queueable; use App\Models\BankIntegration; use App\Models\BankTransaction; -use App\Models\Company; +use App\Helpers\Bank\Yodlee\Yodlee; +use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\InteractsWithQueue; use App\Services\Bank\BankMatchingService; -use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Events\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\Middleware\WithoutOverlapping; +use App\Notifications\Ninja\GenericNinjaAdminNotification; class ProcessBankTransactions implements ShouldQueue { @@ -70,6 +72,14 @@ class ProcessBankTransactions implements ShouldQueue $this->processTransactions(); } catch(\Exception $e) { nlog("{$this->bank_integration_account_id} - exited abnormally => ". $e->getMessage()); + + $content = [ + "Processing transactions for account: {$this->bank_integration->account->key} failed", + "Exception Details => ", + $e->getMessage(), + ]; + + $this->bank_integration->account->company->notification(new GenericNinjaAdminNotification($content))->ninja(); return; } } while ($this->stop_loop); @@ -152,4 +162,15 @@ class ProcessBankTransactions implements ShouldQueue $this->bank_integration->save(); } } + + + public function middleware() + { + return [new WithoutOverlapping($this->bank_integration_account_id)]; + } + + public function backoff() + { + return [rand(10, 15), rand(30, 40), rand(60, 79), rand(160, 200), rand(3000, 5000)]; + } } diff --git a/app/Notifications/Ninja/GenericNinjaAdminNotification.php b/app/Notifications/Ninja/GenericNinjaAdminNotification.php new file mode 100644 index 000000000000..7b40141aa22a --- /dev/null +++ b/app/Notifications/Ninja/GenericNinjaAdminNotification.php @@ -0,0 +1,71 @@ +message_array as $message) { + $content .= $message . "\n"; + } + + return (new SlackMessage) + ->success() + ->from(ctrans('texts.notification_bot')) + ->image('https://app.invoiceninja.com/favicon.png') + ->content($content); + } +} From 6b78cd7a63b177f760c8123eee921f190d5ffb83 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 25 Jun 2023 16:54:36 +1000 Subject: [PATCH 04/47] Fixes for PDF Previews --- app/Jobs/Util/WebhookSingle.php | 4 +++- app/Services/Pdf/PdfBuilder.php | 2 +- app/Services/Pdf/PdfMock.php | 14 ++++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/Jobs/Util/WebhookSingle.php b/app/Jobs/Util/WebhookSingle.php index ca6185a5c3dd..26f79e992250 100644 --- a/app/Jobs/Util/WebhookSingle.php +++ b/app/Jobs/Util/WebhookSingle.php @@ -122,7 +122,9 @@ class WebhookSingle implements ShouldQueue $client = new Client(['headers' => array_merge($base_headers, $headers)]); try { - $response = $client->{$subscription->rest_method}($subscription->target_url, [ + $verb = $subscription->rest_method ?? 'post'; + + $response = $client->{$verb}($subscription->target_url, [ RequestOptions::JSON => $data, // or 'json' => [...] ]); diff --git a/app/Services/Pdf/PdfBuilder.php b/app/Services/Pdf/PdfBuilder.php index 39775948626a..78d8d38fb2a9 100644 --- a/app/Services/Pdf/PdfBuilder.php +++ b/app/Services/Pdf/PdfBuilder.php @@ -653,7 +653,7 @@ class PdfBuilder $data[$key][$table_type.".{$_table_type}4"] = strlen($item->custom_value4) >= 1 ? $helpers->formatCustomFieldValue($this->service->company->custom_fields, "{$_table_type}4", $item->custom_value4, $this->service->config->currency_entity) : ''; if ($item->quantity > 0 || $item->cost > 0) { - $data[$key][$table_type.'.quantity'] = $this->service->config->formatMoney($item->quantity); + $data[$key][$table_type.'.quantity'] = $item->quantity; $data[$key][$table_type.'.unit_cost'] = $this->service->config->formatMoney($item->cost); diff --git a/app/Services/Pdf/PdfMock.php b/app/Services/Pdf/PdfMock.php index 8c569ed0323f..06a572c0680d 100644 --- a/app/Services/Pdf/PdfMock.php +++ b/app/Services/Pdf/PdfMock.php @@ -232,6 +232,9 @@ class PdfMock '$secondary_font_url' => 'https://fonts.googleapis.com/css2?family=Roboto&display=swap', '$contact.signature' => '', '$company_logo_size' => $this->settings->company_logo_size ?: '65%', + '$product.tax_rate1' => ctrans('texts.tax'), + '$product.tax_rate2' => ctrans('texts.tax'), + '$product.tax_rate3' => ctrans('texts.tax'), '$product.tax_name1' => '', '$product.tax_name2' => '', '$product.tax_name3' => '', @@ -688,8 +691,11 @@ class PdfMock '$net_subtotal_label' => ctrans('texts.net_subtotal'), '$credit.total_label' => ctrans('texts.total'), '$quote.amount_label' => ctrans('texts.amount'), - '$description_label' => ctrans('texts.description'), + '$product.tax_rate1_label' => ctrans('texts.tax'), + '$product.tax_rate2_label' => ctrans('texts.tax'), + '$product.tax_rate3_label' => ctrans('texts.tax'), '$product.tax_label' => ctrans('texts.tax'), + '$description_label' => ctrans('texts.description'), '$your_entity_label' => ctrans("texts.your_{$this->entity_string}"), '$view_button_label' => ctrans('texts.view'), '$status_logo_label' => ctrans('texts.logo'), @@ -782,9 +788,9 @@ class PdfMock '$amount_label' => ctrans('texts.amount'), '$notes_label' => ctrans('texts.notes'), '$terms_label' => ctrans('texts.terms'), - 'tax_rate1_label' => ctrans('texts.tax_rate1'), - 'tax_rate2_label' => ctrans('texts.tax_rate2'), - 'tax_rate3_label' => ctrans('texts.tax_rate3'), + '$tax_rate1_label' => ctrans('texts.tax_rate1'), + '$tax_rate2_label' => ctrans('texts.tax_rate2'), + '$tax_rate3_label' => ctrans('texts.tax_rate3'), '$phone_label' => ctrans('texts.phone'), '$email_label' => ctrans('texts.email'), '$taxes_label' => ctrans('texts.taxes'), From 9363a3f7b60b2c99e500a74438f21e11b889e955 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 25 Jun 2023 19:04:06 +1000 Subject: [PATCH 05/47] Fixes for imports --- app/Jobs/Util/Import.php | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index bae27f44c5c0..ceedd63d0c3e 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -135,6 +135,7 @@ class Import implements ShouldQueue 'recurring_expenses', 'tasks', 'documents', + 'activities', ]; /** @@ -1776,6 +1777,75 @@ class Import implements ShouldQueue $data = null; } + private function processActivities(array $data): void + { + Activity::where('company_id', $this->company->id)->cursor()->each(function ($a){ + $a->forceDelete(); + }); + + Activity::unguard(); + + foreach ($data as $resource) { + $modified = $resource; + + $modified['company_id'] = $this->company->id; + $modified['user_id'] = $this->processUserId($resource); + +try { + if (isset($modified['client_id'])) { + $modified['client_id'] = $this->transformId('clients', $resource['client_id']); + } + + if (isset($modified['invoice_id'])) { + $modified['invoice_id'] = $this->transformId('invoices', $resource['invoice_id']); + } + + if (isset($modified['quote_id'])) { + $modified['quote_id'] = $this->transformId('quotes', $resource['quote_id']); + } + + if (isset($modified['recurring_invoice_id'])) { + $modified['recurring_invoice_id'] = $this->transformId('recurring_invoices', $resource['recurring_invoice_id']); + } + + if (isset($modified['payment_id'])) { + $modified['payment_id'] = $this->transformId('payments', $resource['payment_id']); + } + + if (isset($modified['credit_id'])) { + $modified['credit_id'] = $this->transformId('credits', $resource['credit_id']); + } + + if (isset($modified['expense_id'])) { + $modified['expense_id'] = $this->transformId('expenses', $resource['expense_id']); + } + + if (isset($modified['task_id'])) { + $modified['task_id'] = $this->transformId('tasks', $resource['task_id']); + } + + if (isset($modified['client_contact_id'])) { + $modified['client_contact_id'] = $this->transformId('client_contacts', $resource['client_contact_id']); + } + + $act = Activity::make($modified); + + $act->save(['timestamps' => false]); +} +catch (\Exception $e) { + +nlog("could not import activity: {$e->getMessage()}"); + +} + + } + + + Activity::reguard(); + + } + + private function processExpenses(array $data) :void { Expense::unguard(); From 5cbded2ee19fb2b971304d8f83810e193a2f1f0d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 25 Jun 2023 20:09:45 +1000 Subject: [PATCH 06/47] Accept activities for import --- app/Exceptions/Handler.php | 2 +- app/Jobs/Util/Import.php | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index c551b6d38306..506213d57797 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -105,7 +105,7 @@ class Handler extends ExceptionHandler 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())); + // event(new \Modules\Admin\Events\ThrottledExceptionRaised(auth()->user()?->account?->key, $uri, request()->ip())); } Integration::configureScope(function (Scope $scope): void { diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index ceedd63d0c3e..b04d4c24670d 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -304,7 +304,7 @@ class Import implements ShouldQueue if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) { $client->paid_to_date = $total_invoice_payments; - $client->save(); + $client->saveQuietly(); } }); } @@ -320,12 +320,12 @@ class Import implements ShouldQueue $company_ledger->notes = 'Migrated Client Balance'; $company_ledger->balance = $invoice_balances; $company_ledger->activity_id = Activity::CREATE_CLIENT; - $company_ledger->save(); + $company_ledger->saveQuietly(); $client->company_ledger()->save($company_ledger); $client->balance = $invoice_balances; - $client->save(); + $client->saveQuietly(); }); } @@ -1781,6 +1781,7 @@ class Import implements ShouldQueue { Activity::where('company_id', $this->company->id)->cursor()->each(function ($a){ $a->forceDelete(); + nlog("deleting {$a->id}"); }); Activity::unguard(); @@ -1828,6 +1829,8 @@ try { $modified['client_contact_id'] = $this->transformId('client_contacts', $resource['client_contact_id']); } + $modified['updated_at'] = $modified['created_at']; + $act = Activity::make($modified); $act->save(['timestamps' => false]); From 3c297f1e937303baaa684f57ba7f3ba5ab3f1c43 Mon Sep 17 00:00:00 2001 From: Luiz Amaral Date: Sun, 25 Jun 2023 13:26:03 +0200 Subject: [PATCH 07/47] Add :MONTHYEAR keyword to recurring expenses --- app/Factory/RecurringExpenseToExpenseFactory.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/Factory/RecurringExpenseToExpenseFactory.php b/app/Factory/RecurringExpenseToExpenseFactory.php index 98c2a7beee6f..82ea9224f75a 100644 --- a/app/Factory/RecurringExpenseToExpenseFactory.php +++ b/app/Factory/RecurringExpenseToExpenseFactory.php @@ -95,6 +95,11 @@ class RecurringExpenseToExpenseFactory $replacements = [ 'literal' => [ + ':MONTHYEAR' => \sprintf( + '%s %s', + Carbon::createFromDate(now()->year, now()->month)->translatedFormat('F'), + now()->year, + ), ':MONTH' => Carbon::createFromDate(now()->year, now()->month)->translatedFormat('F'), ':YEAR' => now()->year, ':QUARTER' => 'Q'.now()->quarter, @@ -240,6 +245,17 @@ class RecurringExpenseToExpenseFactory $output = \Carbon\Carbon::create()->month($output)->translatedFormat('F'); } + if ($matches->keys()->first() == ':MONTHYEAR') { + + $final_date = now()->addMonths($output-now()->month); + + $output = \sprintf( + '%s %s', + $final_date->translatedFormat('F'), + $final_date->year, + ); + } + $value = preg_replace( $target, $output, From e97b96d9f6becea86b2d221555f83d05f5b88917 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Jun 2023 08:56:56 +1000 Subject: [PATCH 08/47] Update texts --- lang/en/texts.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/en/texts.php b/lang/en/texts.php index aa92fb260bf5..8d7f8c01f0be 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -3863,7 +3863,7 @@ $LANG = array( 'notification_credit_viewed' => 'The following client :client viewed Credit :credit for :amount.', 'reset_password_text' => 'Enter your email to reset your password.', 'password_reset' => 'Password reset', - 'account_login_text' => 'Welcome back! Glad to see you.', + 'account_login_text' => 'Welcome! Glad to see you.', 'request_cancellation' => 'Request cancellation', 'delete_payment_method' => 'Delete Payment Method', 'about_to_delete_payment_method' => 'You are about to delete the payment method.', From 966f6b5ea9868ee79bac9ff99b6c7d7062117834 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Jun 2023 11:02:09 +1000 Subject: [PATCH 09/47] Fixes for tax provider checks --- app/Jobs/Util/ReminderJob.php | 2 +- app/Services/Tax/Providers/ZipTax.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index c7955d3f40e7..e11234f6785c 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -126,7 +126,7 @@ class ReminderJob implements ShouldQueue } $reminder_template = $invoice->calculateTemplate('invoice'); - nlog("reminder template = {$reminder_template}"); + // nlog("reminder template = {$reminder_template}"); $invoice->service()->touchReminder($reminder_template)->save(); $fees = $this->calcLateFee($invoice, $reminder_template); diff --git a/app/Services/Tax/Providers/ZipTax.php b/app/Services/Tax/Providers/ZipTax.php index 0cc0dd1a5524..dad7ef0768fc 100644 --- a/app/Services/Tax/Providers/ZipTax.php +++ b/app/Services/Tax/Providers/ZipTax.php @@ -69,7 +69,7 @@ class ZipTax implements TaxProviderInterface private function parseResponse($response) { - if(isset($response['rCode']) && $response['rCode'] == 100) + if(isset($response['rCode']) && $response['rCode'] == 100 && isset($response['results']['0'])) return $response['results']['0']; if(isset($response['rCode']) && class_exists(\Modules\Admin\Events\TaxProviderException::class)) From 6424ed5a4bb8e136abd185492e23d6c3a38a2c4f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Jun 2023 12:56:57 +1000 Subject: [PATCH 10/47] Stubs for supporting date ranges into charts --- app/Http/Requests/Chart/ShowChartRequest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Http/Requests/Chart/ShowChartRequest.php b/app/Http/Requests/Chart/ShowChartRequest.php index 83754f2a86e0..0293513d2555 100644 --- a/app/Http/Requests/Chart/ShowChartRequest.php +++ b/app/Http/Requests/Chart/ShowChartRequest.php @@ -28,8 +28,9 @@ class ShowChartRequest extends Request public function rules() { return [ - 'start_date' => 'date', - 'end_date' => 'date', + 'date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom', + 'start_date' => 'bail|sometimes|date', + 'end_date' => 'bail|sometimes|date', ]; } From 81d6dbe865b28d9b1776c028c37114f30e5f0700 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Jun 2023 15:14:58 +1000 Subject: [PATCH 11/47] Fixes for date range calculations --- app/Http/Controllers/ChartController.php | 2 +- app/Http/Requests/Chart/ShowChartRequest.php | 24 ++++++++++++++++---- app/Services/Chart/ChartService.php | 4 ++++ app/Services/Scheduler/EmailReport.php | 3 ++- app/Utils/Traits/MakesDates.php | 8 +++---- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/ChartController.php b/app/Http/Controllers/ChartController.php index 85b387d30202..69669159c68f 100644 --- a/app/Http/Controllers/ChartController.php +++ b/app/Http/Controllers/ChartController.php @@ -61,7 +61,7 @@ class ChartController extends BaseController /** @var \App\Models\User auth()->user() */ $user = auth()->user(); $cs = new ChartService($user->company(), $user, $user->isAdmin()); - + return response()->json($cs->chart_summary($request->input('start_date'), $request->input('end_date')), 200); } diff --git a/app/Http/Requests/Chart/ShowChartRequest.php b/app/Http/Requests/Chart/ShowChartRequest.php index 0293513d2555..f33766eec2a6 100644 --- a/app/Http/Requests/Chart/ShowChartRequest.php +++ b/app/Http/Requests/Chart/ShowChartRequest.php @@ -12,9 +12,12 @@ namespace App\Http\Requests\Chart; use App\Http\Requests\Request; +use App\Utils\Traits\MakesDates; class ShowChartRequest extends Request { + use MakesDates; + /** * Determine if the user is authorized to make this request. * @@ -22,7 +25,10 @@ class ShowChartRequest extends Request */ public function authorize() : bool { - return auth()->user()->isAdmin(); + /**@var \App\Models\User auth()->user */ + $user = auth()->user(); + + return $user->isAdmin(); } public function rules() @@ -38,14 +44,22 @@ class ShowChartRequest extends Request { $input = $this->all(); - if (! array_key_exists('start_date', $input)) { - $input['start_date'] = now()->subDays(20); + if(isset($input['date_range'])) { + $dates = $this->calculateStartAndEndDates($input); + $input['start_date'] = $dates[0]; + $input['end_date'] = $dates[1]; } - if (! array_key_exists('end_date', $input)) { - $input['end_date'] = now(); + if (! isset($input['start_date'])) { + $input['start_date'] = now()->subDays(20)->format('Y-m-d'); } + if (! isset($input['end_date'])) { + $input['end_date'] = now()->format('Y-m-d'); + } + + nlog($input); + $this->replace($input); } } diff --git a/app/Services/Chart/ChartService.php b/app/Services/Chart/ChartService.php index c9a8be50eda7..e69f513f84d0 100644 --- a/app/Services/Chart/ChartService.php +++ b/app/Services/Chart/ChartService.php @@ -76,6 +76,8 @@ class ChartService $currencies = $this->getCurrencyCodes(); $data = []; + $data['start_date'] = $start_date; + $data['end_date'] = $end_date; foreach ($currencies as $key => $value) { $data[$key]['invoices'] = $this->getInvoiceChartQuery($start_date, $end_date, $key); @@ -96,6 +98,8 @@ class ChartService $data = []; $data['currencies'] = $this->getCurrencyCodes(); + $data['start_date'] = $start_date; + $data['end_date'] = $end_date; $revenue = $this->getRevenue($start_date, $end_date); $outstanding = $this->getOutstanding($start_date, $end_date); diff --git a/app/Services/Scheduler/EmailReport.php b/app/Services/Scheduler/EmailReport.php index ce76e54fad04..f1def5d9b61c 100644 --- a/app/Services/Scheduler/EmailReport.php +++ b/app/Services/Scheduler/EmailReport.php @@ -58,7 +58,8 @@ class EmailReport public function run() { - $start_end_dates = $this->calculateStartAndEndDates(); + $start_end_dates = $this->calculateStartAndEndDates($this->scheduler->parameters); + $data = []; $data = [ diff --git a/app/Utils/Traits/MakesDates.php b/app/Utils/Traits/MakesDates.php index f63977932db2..caea8e926d64 100644 --- a/app/Utils/Traits/MakesDates.php +++ b/app/Utils/Traits/MakesDates.php @@ -119,9 +119,9 @@ trait MakesDates * * @return array [$start_date, $end_date]; */ - public function calculateStartAndEndDates(): array + public function calculateStartAndEndDates(array $data): array { - return match ($this->scheduler->parameters['date_range']) { + return match ($data['date_range']) { EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], EmailStatement::LAST30 => [now()->startOfDay()->subDays(30)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], EmailStatement::LAST365 => [now()->startOfDay()->subDays(365)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], @@ -131,9 +131,9 @@ trait MakesDates EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')], EmailStatement::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')], EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')], - EmailStatement::CUSTOM_RANGE => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']], + EmailStatement::CUSTOM_RANGE => [$data['start_date'], $data['end_date']], default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')], }; } -} +} \ No newline at end of file From a37773b3a23fdd3b6d719366a83e823eee97fbc4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Jun 2023 15:23:48 +1000 Subject: [PATCH 12/47] Minor fixes --- app/Services/Chart/ChartService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Services/Chart/ChartService.php b/app/Services/Chart/ChartService.php index e69f513f84d0..3378c998aeec 100644 --- a/app/Services/Chart/ChartService.php +++ b/app/Services/Chart/ChartService.php @@ -98,6 +98,7 @@ class ChartService $data = []; $data['currencies'] = $this->getCurrencyCodes(); + $data['start_date'] = $start_date; $data['end_date'] = $end_date; From 2385bf8ad256bb1cf13313885535941c6a3100ab Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Jun 2023 21:05:15 +1000 Subject: [PATCH 13/47] Catch Quote Exceptions --- app/DataMapper/Tax/US/Rule.php | 3 --- app/Exceptions/QuoteConversion.php | 41 +++++++++++++++++++++++++++++ app/Jobs/Util/Import.php | 2 +- app/Services/Quote/QuoteService.php | 14 +++++----- tests/Feature/QuoteTest.php | 34 +++++++++++++++++------- 5 files changed, 74 insertions(+), 20 deletions(-) create mode 100644 app/Exceptions/QuoteConversion.php diff --git a/app/DataMapper/Tax/US/Rule.php b/app/DataMapper/Tax/US/Rule.php index fbfb5b78b323..59cd75943ca5 100644 --- a/app/DataMapper/Tax/US/Rule.php +++ b/app/DataMapper/Tax/US/Rule.php @@ -165,9 +165,6 @@ class Rule extends BaseRule implements RuleInterface $this->tax_rate1 = 0; $this->tax_name1 = ''; - // $this->tax_rate1 = $this->invoice->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate; - // $this->tax_name1 = "Sales Tax"; - return $this; } diff --git a/app/Exceptions/QuoteConversion.php b/app/Exceptions/QuoteConversion.php new file mode 100644 index 000000000000..a4812f4c1bdb --- /dev/null +++ b/app/Exceptions/QuoteConversion.php @@ -0,0 +1,41 @@ +json(['message' => 'This quote has already been converted. Cannot convert again.'], 400); + } +} diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index b04d4c24670d..674b4e7c0579 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -182,7 +182,7 @@ class Import implements ShouldQueue public function middleware() { - return [(new WithoutOverlapping($this->user->account_id))]; + return [(new WithoutOverlapping($this->company->company_key))]; } /** diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index 56ab95d8eb38..fe6189106c47 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -11,14 +11,14 @@ namespace App\Services\Quote; -use App\Events\Quote\QuoteWasApproved; -use App\Jobs\Entity\CreateEntityPdf; -use App\Jobs\Util\UnlinkFile; -use App\Models\Invoice; -use App\Models\Quote; -use App\Repositories\QuoteRepository; use App\Utils\Ninja; +use App\Models\Quote; +use App\Jobs\Util\UnlinkFile; use App\Utils\Traits\MakesHash; +use App\Exceptions\QuoteConversion; +use App\Jobs\Entity\CreateEntityPdf; +use App\Repositories\QuoteRepository; +use App\Events\Quote\QuoteWasApproved; class QuoteService { @@ -43,7 +43,7 @@ class QuoteService public function convert() :self { if ($this->quote->invoice_id) { - return $this; + throw new QuoteConversion(); } $convert_quote = (new ConvertQuote($this->quote->client))->run($this->quote); diff --git a/tests/Feature/QuoteTest.php b/tests/Feature/QuoteTest.php index c324f05f8c30..320a4f1149d0 100644 --- a/tests/Feature/QuoteTest.php +++ b/tests/Feature/QuoteTest.php @@ -11,16 +11,17 @@ namespace Tests\Feature; -use App\Models\ClientContact; -use App\Models\Project; -use App\Models\Quote; -use App\Utils\Traits\MakesHash; -use Illuminate\Database\Eloquent\Model; -use Illuminate\Foundation\Testing\DatabaseTransactions; -use Illuminate\Routing\Middleware\ThrottleRequests; -use Illuminate\Support\Facades\Session; -use Tests\MockAccountData; use Tests\TestCase; +use App\Models\Quote; +use App\Models\Project; +use Tests\MockAccountData; +use App\Models\ClientContact; +use App\Utils\Traits\MakesHash; +use App\Exceptions\QuoteConversion; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Session; +use Illuminate\Routing\Middleware\ThrottleRequests; +use Illuminate\Foundation\Testing\DatabaseTransactions; /** * @test @@ -32,6 +33,8 @@ class QuoteTest extends TestCase use DatabaseTransactions; use MockAccountData; + public $faker; + protected function setUp() :void { parent::setUp(); @@ -49,6 +52,19 @@ class QuoteTest extends TestCase ); } + public function testQuoteConversion() + { + $invoice = $this->quote->service()->convertToInvoice(); + + $this->assertInstanceOf('\App\Models\Invoice', $invoice); + + $this->expectException(QuoteConversion::class); + + $invoice = $this->quote->service()->convertToInvoice(); + + + } + public function testQuoteDownloadPDF() { $i = $this->quote->invitations->first(); From 5f1267d49527bb25d356d7fe55cb88b85b455215 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Jun 2023 22:50:26 +1000 Subject: [PATCH 14/47] Improve activities --- app/Http/Controllers/ActivityController.php | 65 ++++++++++--------- app/Http/Requests/Chart/ShowChartRequest.php | 2 - .../Activity/PaymentCreatedActivity.php | 5 ++ app/Models/Activity.php | 6 +- 4 files changed, 41 insertions(+), 37 deletions(-) diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php index 9bb69c13f15c..ac850442125e 100644 --- a/app/Http/Controllers/ActivityController.php +++ b/app/Http/Controllers/ActivityController.php @@ -92,46 +92,47 @@ class ActivityController extends BaseController ->company() ->take($default_activities); - if ($request->has('react')) { + // if ($request->has('react')) { - /** @var \App\Models\User auth()->user() */ - $user = auth()->user(); + // /** @var \App\Models\User auth()->user() */ + // $user = auth()->user(); - if (!$user->isAdmin()) { - $activities->where('user_id', auth()->user()->id); - } + // if (!$user->isAdmin()) { + // $activities->where('user_id', auth()->user()->id); + // } - $system = ctrans('texts.system'); + // $system = ctrans('texts.system'); - $data = $activities->cursor()->map(function ($activity) { + // $data = $activities->cursor()->map(function ($activity) { - $arr = - [ - 'client' => $activity->client ? $activity->client : '', - 'contact' => $activity->client ? $activity->contact : '', - 'quote' => $activity->quote ? $activity->quote : '', - 'user' => $activity->user ? $activity->user : '', - 'expense' => $activity->expense ? $activity->expense : '', - 'invoice' => $activity->invoice ? $activity->invoice : '', - 'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice : '', - 'payment' => $activity->payment ? $activity->payment : '', - 'credit' => $activity->credit ? $activity->credit : '', - 'task' => $activity->task ? $activity->task : '', - 'vendor' => $activity->vendor ? $activity->vendor : '', - 'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '', - 'subscription' => $activity->subscription ? $activity->subscription : '', - 'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '', - 'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '', - ]; + // $arr = + // [ + // 'client' => $activity->client ? $activity->client : '', + // 'contact' => $activity->client ? $activity->contact : '', + // 'quote' => $activity->quote ? $activity->quote : '', + // 'user' => $activity->user ? $activity->user : '', + // 'expense' => $activity->expense ? $activity->expense : '', + // 'invoice' => $activity->invoice ? $activity->invoice : '', + // 'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice : '', + // 'payment' => $activity->payment ? $activity->payment : '', + // 'credit' => $activity->credit ? $activity->credit : '', + // 'task' => $activity->task ? $activity->task : '', + // 'vendor' => $activity->vendor ? $activity->vendor : '', + // 'purchase_order' => $activity->purchase_order ? $activity->purchase_order : '', + // 'subscription' => $activity->subscription ? $activity->subscription : '', + // 'vendor_contact' => $activity->vendor_contact ? $activity->vendor_contact : '', + // 'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '', + // ]; - $activity_array = $activity->toArray(); + // $activity_array = $activity->toArray(); - return array_merge($arr, $activity_array); - }); + // return array_merge($arr, $activity_array); + // }); - return response()->json(['data' => $data->toArray()], 200); - } - elseif($request->has('reactv2')) { + // return response()->json(['data' => $data->toArray()], 200); + // } + // else + if($request->has('reactv2')) { /** @var \App\Models\User auth()->user() */ $user = auth()->user(); diff --git a/app/Http/Requests/Chart/ShowChartRequest.php b/app/Http/Requests/Chart/ShowChartRequest.php index f33766eec2a6..f7b4f63ba7e0 100644 --- a/app/Http/Requests/Chart/ShowChartRequest.php +++ b/app/Http/Requests/Chart/ShowChartRequest.php @@ -58,8 +58,6 @@ class ShowChartRequest extends Request $input['end_date'] = now()->format('Y-m-d'); } - nlog($input); - $this->replace($input); } } diff --git a/app/Listeners/Activity/PaymentCreatedActivity.php b/app/Listeners/Activity/PaymentCreatedActivity.php index adbacbdd88e0..859f04ec057d 100644 --- a/app/Listeners/Activity/PaymentCreatedActivity.php +++ b/app/Listeners/Activity/PaymentCreatedActivity.php @@ -42,6 +42,10 @@ class PaymentCreatedActivity implements ShouldQueue MultiDB::setDb($event->company->db); $payment = $event->payment; + $invoice_id = null; + + if($payment->invoices()->exists()) + $invoice_id = $payment->invoices->first()->id; $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->payment->user_id; @@ -50,6 +54,7 @@ class PaymentCreatedActivity implements ShouldQueue $fields = new stdClass; $fields->payment_id = $payment->id; + $fields->invoice_id = $invoice_id; $fields->client_id = $payment->client_id; $fields->user_id = $user_id; $fields->company_id = $payment->company_id; diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 679373fa0363..d0edf254e2c9 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -515,9 +515,8 @@ class Activity extends StaticModel { $system = ctrans('texts.system'); - return match($variable) { - ':invoice' => $translation = [substr($variable, 1) => [ 'label' => $this?->invoice?->number ?? '', 'hashed_id' => $this->invoice?->hashed_id ?? '']], - ':contact' => $translation = $this->resolveContact(), + match($variable) { + ':invoice' => $translation = [substr($variable, 1) => [ 'label' => $this?->invoice?->number ?? '', 'hashed_id' => $this->invoice?->hashed_id ?? '']], ':user' => $translation = [substr($variable, 1) => [ 'label' => $this?->user?->present()->name() ?? $system, 'hashed_id' => $this->user->hashed_id ?? '']], ':quote' => $translation = [substr($variable, 1) => [ 'label' => $this?->quote?->number ?? '', 'hashed_id' => $this->quote->hashed_id ?? '']], ':credit' => $translation = [substr($variable, 1) => [ 'label' => $this?->credit?->number ?? '', 'hashed_id' => $this->credit->hashed_id ?? '']], @@ -531,6 +530,7 @@ class Activity extends StaticModel ':payment_amount' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->amount, $this?->payment?->client) ?? '', 'hashed_id' => '']], ':adjustment' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->refunded, $this?->payment?->client) ?? '', 'hashed_id' => '']], ':ip' => $translation = [ 'ip' => $this->ip ?? ''], + ':contact' => $translation = $this->resolveContact(), default => $translation = [], }; From 5c835a1fc73d314f1cc3bfa9fbe3f9c628a41132 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 26 Jun 2023 23:42:30 +1000 Subject: [PATCH 15/47] Fixes for credit paymentables --- app/Listeners/Activity/PaymentCreatedActivity.php | 12 +++++------- app/Repositories/PaymentRepository.php | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/app/Listeners/Activity/PaymentCreatedActivity.php b/app/Listeners/Activity/PaymentCreatedActivity.php index 859f04ec057d..ff0c0abd0889 100644 --- a/app/Listeners/Activity/PaymentCreatedActivity.php +++ b/app/Listeners/Activity/PaymentCreatedActivity.php @@ -38,19 +38,18 @@ class PaymentCreatedActivity implements ShouldQueue * @return void */ public function handle($event) - { + { + MultiDB::setDb($event->company->db); $payment = $event->payment; $invoice_id = null; if($payment->invoices()->exists()) - $invoice_id = $payment->invoices->first()->id; + $invoice_id = $payment->invoices()->first()->id; $user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->payment->user_id; - $invoices = $payment->invoices; - $fields = new stdClass; $fields->payment_id = $payment->id; @@ -60,8 +59,7 @@ class PaymentCreatedActivity implements ShouldQueue $fields->company_id = $payment->company_id; $fields->activity_type_id = Activity::CREATE_PAYMENT; - if (count($invoices) == 0) { - $this->activity_repo->save($fields, $payment, $event->event_vars); - } + $this->activity_repo->save($fields, $payment, $event->event_vars); + } } diff --git a/app/Repositories/PaymentRepository.php b/app/Repositories/PaymentRepository.php index 0b4be3c46880..073f04fd7cec 100644 --- a/app/Repositories/PaymentRepository.php +++ b/app/Repositories/PaymentRepository.php @@ -185,7 +185,7 @@ class PaymentRepository extends BaseRepository $paymentable->payment_id = $payment->id; $paymentable->paymentable_id = $credit->id; $paymentable->paymentable_type = Credit::class; - $paymentable->amount = $paid_invoice['amount']; + $paymentable->amount = $paid_credit['amount']; $paymentable->save(); $credit = $credit->service()->markSent()->save(); From 7dbacd43062e9ad53c2b18482f69ddd80e8a3ca3 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 27 Jun 2023 15:13:20 +1000 Subject: [PATCH 16/47] Add expense categories --- app/Transformers/ExpenseTransformer.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/app/Transformers/ExpenseTransformer.php b/app/Transformers/ExpenseTransformer.php index f703da58058a..404e71a2f319 100644 --- a/app/Transformers/ExpenseTransformer.php +++ b/app/Transformers/ExpenseTransformer.php @@ -11,12 +11,14 @@ namespace App\Transformers; -use App\Models\Document; -use App\Models\Expense; use App\Models\Vendor; +use App\Models\Expense; +use App\Models\Document; +use App\Models\ExpenseCategory; use App\Utils\Traits\MakesHash; -use Illuminate\Database\Eloquent\SoftDeletes; use League\Fractal\Resource\Item; +use Illuminate\Database\Eloquent\SoftDeletes; +use App\Transformers\ExpenseCategoryTransformer; /** * class ExpenseTransformer. @@ -36,6 +38,7 @@ class ExpenseTransformer extends EntityTransformer protected $availableIncludes = [ 'client', 'vendor', + 'category', ]; public function includeDocuments(Expense $expense) @@ -56,6 +59,17 @@ class ExpenseTransformer extends EntityTransformer return $this->includeItem($expense->client, $transformer, Client::class); } + public function includeCategory(Expense $expense): ?Item + { + $transformer = new ExpenseCategoryTransformer($this->serializer); + + if (!$expense->category) { + return null; + } + + return $this->includeItem($expense->category, $transformer, ExpenseCategory::class); + } + public function includeVendor(Expense $expense): ?Item { $transformer = new VendorTransformer($this->serializer); From d944351a865dbe4e3d4573de316edd0cf213f0c2 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 27 Jun 2023 16:48:26 +1000 Subject: [PATCH 17/47] Fixes for processing bank transactions --- app/Jobs/Bank/ProcessBankTransactions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Jobs/Bank/ProcessBankTransactions.php b/app/Jobs/Bank/ProcessBankTransactions.php index 019f93dc333b..469ba5c98e49 100644 --- a/app/Jobs/Bank/ProcessBankTransactions.php +++ b/app/Jobs/Bank/ProcessBankTransactions.php @@ -79,7 +79,7 @@ class ProcessBankTransactions implements ShouldQueue $e->getMessage(), ]; - $this->bank_integration->account->company->notification(new GenericNinjaAdminNotification($content))->ninja(); + $this->bank_integration->company->notification(new GenericNinjaAdminNotification($content))->ninja(); return; } } while ($this->stop_loop); From 1ecce29e5670300e6320ffa5804fb05a9ab307fb Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 27 Jun 2023 21:26:34 +1000 Subject: [PATCH 18/47] Invoice filter for expenses --- app/Filters/ExpenseFilters.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/Filters/ExpenseFilters.php b/app/Filters/ExpenseFilters.php index d589362a63b7..a1012afe7ad8 100644 --- a/app/Filters/ExpenseFilters.php +++ b/app/Filters/ExpenseFilters.php @@ -106,6 +106,15 @@ class ExpenseFilters extends QueryFilters return $this->builder; } + public function has_invoices(string $value = ''): Builder + { + if ($value == 'true') { + return $this->builder->whereNotNull('invoice_id')->select('expenses.invoice_id'); + } + + return $this->builder; + } + /** * Returns a list of expenses that can be matched to bank transactions */ From 356834b6288704a7f15b3d314c211482eba9d8f0 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 27 Jun 2023 21:31:21 +1000 Subject: [PATCH 19/47] Invoice filters for expense --- app/Filters/ExpenseFilters.php | 2 +- app/Models/Expense.php | 5 +++++ app/Transformers/ExpenseTransformer.php | 13 +++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/Filters/ExpenseFilters.php b/app/Filters/ExpenseFilters.php index a1012afe7ad8..325606b30664 100644 --- a/app/Filters/ExpenseFilters.php +++ b/app/Filters/ExpenseFilters.php @@ -109,7 +109,7 @@ class ExpenseFilters extends QueryFilters public function has_invoices(string $value = ''): Builder { if ($value == 'true') { - return $this->builder->whereNotNull('invoice_id')->select('expenses.invoice_id'); + return $this->builder->whereNotNull('invoice_id'); } return $this->builder; diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 648e1d5635e9..00a16129fc9f 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -225,6 +225,11 @@ class Expense extends BaseModel return $this->belongsTo(Company::class); } + public function invoice() + { + return $this->belongsTo(Invoice::class); + } + public function vendor() { return $this->belongsTo(Vendor::class); diff --git a/app/Transformers/ExpenseTransformer.php b/app/Transformers/ExpenseTransformer.php index 404e71a2f319..7fb5c8826638 100644 --- a/app/Transformers/ExpenseTransformer.php +++ b/app/Transformers/ExpenseTransformer.php @@ -13,6 +13,7 @@ namespace App\Transformers; use App\Models\Vendor; use App\Models\Expense; +use App\Models\Invoice; use App\Models\Document; use App\Models\ExpenseCategory; use App\Utils\Traits\MakesHash; @@ -39,6 +40,7 @@ class ExpenseTransformer extends EntityTransformer 'client', 'vendor', 'category', + 'invoice', ]; public function includeDocuments(Expense $expense) @@ -59,6 +61,17 @@ class ExpenseTransformer extends EntityTransformer return $this->includeItem($expense->client, $transformer, Client::class); } + public function includeInvoice(Expense $expense): ?Item + { + $transformer = new InvoiceTransformer($this->serializer); + + if (!$expense->invoice) { + return null; + } + + return $this->includeItem($expense->invoice, $transformer, Invoice::class); + } + public function includeCategory(Expense $expense): ?Item { $transformer = new ExpenseCategoryTransformer($this->serializer); From b2308360566c6c50519f67f9d76f3c52746da9c2 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 27 Jun 2023 21:40:28 +1000 Subject: [PATCH 20/47] Minor fixes for expenses --- app/Filters/ExpenseFilters.php | 6 ++++++ tests/Feature/ExpenseApiTest.php | 2 ++ 2 files changed, 8 insertions(+) diff --git a/app/Filters/ExpenseFilters.php b/app/Filters/ExpenseFilters.php index 325606b30664..847964af994e 100644 --- a/app/Filters/ExpenseFilters.php +++ b/app/Filters/ExpenseFilters.php @@ -106,6 +106,12 @@ class ExpenseFilters extends QueryFilters return $this->builder; } + /** + * Filter expenses that only have invoices + * + * @param string $value + * @return Builder + */ public function has_invoices(string $value = ''): Builder { if ($value == 'true') { diff --git a/tests/Feature/ExpenseApiTest.php b/tests/Feature/ExpenseApiTest.php index 2e9b1405479f..ef6fadf3d019 100644 --- a/tests/Feature/ExpenseApiTest.php +++ b/tests/Feature/ExpenseApiTest.php @@ -31,6 +31,8 @@ class ExpenseApiTest extends TestCase use DatabaseTransactions; use MockAccountData; + public $faker; + protected function setUp() :void { parent::setUp(); From 9e7f269a0e6395c5db6b58f547130475fc38cf13 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 27 Jun 2023 22:25:24 +1000 Subject: [PATCH 21/47] Fixes for filtering --- app/Filters/ExpenseFilters.php | 12 ++++++++++-- phpstan.neon | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/Filters/ExpenseFilters.php b/app/Filters/ExpenseFilters.php index 847964af994e..922db6c8fd0b 100644 --- a/app/Filters/ExpenseFilters.php +++ b/app/Filters/ExpenseFilters.php @@ -114,8 +114,16 @@ class ExpenseFilters extends QueryFilters */ public function has_invoices(string $value = ''): Builder { - if ($value == 'true') { - return $this->builder->whereNotNull('invoice_id'); + $split = explode(",", $value); + + if (is_array($split) && in_array($split[0], ['client', 'project'])) { + + $search_key = $split[0] == 'client' ? 'client_id' : 'project_id'; + + return $this->builder->whereNotNull('invoice_id') + ->whereHas('invoice', function ($query) use ($search_key, $split){ + $query->where($search_key, $this->decodePrimaryKey($split[1])); + }); } return $this->builder; diff --git a/phpstan.neon b/phpstan.neon index 8bbf3a89f08a..4fcf09b7dab7 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -7,7 +7,7 @@ parameters: - '#Call to an undefined method .*badMethod\(\)#' - '#Call to an undefined method Illuminate\Database\Eloquent\Builder::exclude#' parallel: - maximumNumberOfProcesses: 8 + maximumNumberOfProcesses: 1 level: 4 paths: - 'app/' From 1f757cf9e3772f37998f40085699d280db448342 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 28 Jun 2023 09:45:24 +1000 Subject: [PATCH 22/47] Fixes for token billing with PayTrace --- app/PaymentDrivers/PayTrace/CreditCard.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/PaymentDrivers/PayTrace/CreditCard.php b/app/PaymentDrivers/PayTrace/CreditCard.php index a07f17e5ea4e..79de7603c75d 100644 --- a/app/PaymentDrivers/PayTrace/CreditCard.php +++ b/app/PaymentDrivers/PayTrace/CreditCard.php @@ -177,6 +177,7 @@ class CreditCard 'customer_id' => $token, 'integrator_id' => $this->paytrace->company_gateway->getConfigField('integratorId'), 'amount' => $request->input('amount_with_fee'), + 'invoice_id' => $this->harvestInvoiceId(), ]; $response = $this->paytrace->gatewayRequest('/v1/transactions/sale/by_customer', $data); From feb44618127c2ef26ef556a3692db1962074d1b6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 28 Jun 2023 09:57:03 +1000 Subject: [PATCH 23/47] improve error handling with EWay --- app/PaymentDrivers/Eway/CreditCard.php | 36 +++++++------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/app/PaymentDrivers/Eway/CreditCard.php b/app/PaymentDrivers/Eway/CreditCard.php index f93057719b34..969aa3ec670b 100644 --- a/app/PaymentDrivers/Eway/CreditCard.php +++ b/app/PaymentDrivers/Eway/CreditCard.php @@ -70,12 +70,17 @@ class CreditCard $response = $this->eway_driver->init()->eway->createCustomer(\Eway\Rapid\Enum\ApiMethod::DIRECT, $transaction); - $response_status = ErrorCode::getStatus($response->ResponseMessage); + if(property_exists($response, 'ResponseMessage')) + $response_status = ErrorCode::getStatus($response->ResponseMessage); if (! $response_status['success']) { + $this->eway_driver->sendFailureMail($response_status['message']); - throw new PaymentFailed($response_status['message'], 400); + $this->logResponse($response); + + + throw new PaymentFailed($response_status['message'] ?? 'Unknown response from gateway, please contact you merchant.', 400); } //success @@ -94,6 +99,8 @@ class CreditCard $token = $this->eway_driver->storeGatewayToken($cgt, []); + $this->logResponse($response); + return $token; } @@ -135,7 +142,7 @@ class CreditCard $amount = array_sum(array_column($this->eway_driver->payment_hash->invoices(), 'amount')) + $this->eway_driver->payment_hash->fee_total; - $description = "Invoices: {$invoice_numbers} for {$amount} for client {$this->eway_driver->client->present()->name()}"; + // $description = "Invoices: {$invoice_numbers} for {$amount} for client {$this->eway_driver->client->present()->name()}"; $transaction = [ 'Payment' => [ @@ -152,29 +159,6 @@ class CreditCard $this->logResponse($response); - // if(!$response || !property_exists($response, 'ResponseMessage')) - // throw new PaymentFailed('The gateway did not return a valid response. Please check your gateway credentials.', 400); - - // $response_status = ErrorCode::getStatus($response->ResponseMessage); - - // if(!$response_status['success']){ - - // if($response->getErrors()) - // { - // $message = false; - - // foreach ($response->getErrors() as $error) { - // $message = \Eway\Rapid::getMessage($error); - // } - - // $return_message = $message ?: $response_status['message']; - // } - - // $this->eway_driver->sendFailureMail($response_status['message']); - - // throw new PaymentFailed($response_status['message'], 400); - // } - if ($response->TransactionStatus) { $payment = $this->storePayment($response); } else { From 7c695a8de2b27bda26d61132aa5463878dac0ea7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 28 Jun 2023 20:06:15 +1000 Subject: [PATCH 24/47] Add billing country for paytrace --- app/Models/Client.php | 4 ++-- app/PaymentDrivers/PayTrace/CreditCard.php | 1 + app/Transformers/ExpenseTransformer.php | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/Models/Client.php b/app/Models/Client.php index 5a4ec88f74b1..959243ccb768 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -544,9 +544,9 @@ class Client extends BaseModel implements HasLocalePreference return $this->settings->{$setting}; } elseif (is_bool($this->settings->{$setting})) { return $this->settings->{$setting}; - } elseif (is_int($this->settings->{$setting})) { //10-08-2022 integer client values are not being passed back! This resolves it. + } elseif (is_int($this->settings->{$setting})) { return $this->settings->{$setting}; - } elseif(is_float($this->settings->{$setting})) { //10-08-2022 integer client values are not being passed back! This resolves it. + } elseif(is_float($this->settings->{$setting})) { return $this->settings->{$setting}; } } diff --git a/app/PaymentDrivers/PayTrace/CreditCard.php b/app/PaymentDrivers/PayTrace/CreditCard.php index 79de7603c75d..720d5f0b02be 100644 --- a/app/PaymentDrivers/PayTrace/CreditCard.php +++ b/app/PaymentDrivers/PayTrace/CreditCard.php @@ -123,6 +123,7 @@ class CreditCard 'city' => $this->paytrace->client->city, 'state' => $this->paytrace->client->state, 'zip' => $this->paytrace->client->postal_code, + 'country' => $this->paytrace->client->country->iso_3166_2 ]; return $data; diff --git a/app/Transformers/ExpenseTransformer.php b/app/Transformers/ExpenseTransformer.php index 7fb5c8826638..48a3ed7c4a7d 100644 --- a/app/Transformers/ExpenseTransformer.php +++ b/app/Transformers/ExpenseTransformer.php @@ -14,12 +14,12 @@ namespace App\Transformers; use App\Models\Vendor; use App\Models\Expense; use App\Models\Invoice; -use App\Models\Document; use App\Models\ExpenseCategory; +use App\Transformers\ExpenseCategoryTransformer; +use App\Models\Document; use App\Utils\Traits\MakesHash; use League\Fractal\Resource\Item; use Illuminate\Database\Eloquent\SoftDeletes; -use App\Transformers\ExpenseCategoryTransformer; /** * class ExpenseTransformer. From eb44584fe8f47bb0372aef5c531b0a5c1e972695 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 29 Jun 2023 13:57:16 +1000 Subject: [PATCH 25/47] Fixes for tax calculations --- app/DataMapper/Tax/US/Rule.php | 3 +++ app/Filters/ExpenseFilters.php | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/DataMapper/Tax/US/Rule.php b/app/DataMapper/Tax/US/Rule.php index 59cd75943ca5..497585a5bef5 100644 --- a/app/DataMapper/Tax/US/Rule.php +++ b/app/DataMapper/Tax/US/Rule.php @@ -117,6 +117,9 @@ class Rule extends BaseRule implements RuleInterface if(in_array($this->tax_data?->txbService,['Y','L'])) { $this->default($item); } + else { + $this->taxExempt($item); + } return $this; } diff --git a/app/Filters/ExpenseFilters.php b/app/Filters/ExpenseFilters.php index 922db6c8fd0b..6260c1b04b3c 100644 --- a/app/Filters/ExpenseFilters.php +++ b/app/Filters/ExpenseFilters.php @@ -120,10 +120,10 @@ class ExpenseFilters extends QueryFilters $search_key = $split[0] == 'client' ? 'client_id' : 'project_id'; - return $this->builder->whereNotNull('invoice_id') - ->whereHas('invoice', function ($query) use ($search_key, $split){ - $query->where($search_key, $this->decodePrimaryKey($split[1])); - }); + return $this->builder->whereHas('invoice', function ($query) use ($search_key, $split){ + $query->where($search_key, $this->decodePrimaryKey($split[1])) + ->whereIn('status_id', [\App\Models\Invoice::STATUS_DRAFT, \App\Models\Invoice::STATUS_SENT, \App\Models\Invoice::STATUS_PARTIAL]); + }); } return $this->builder; From 8ae74490bd9b2759f55b152f9de5de9f00d2b0a4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 29 Jun 2023 14:02:02 +1000 Subject: [PATCH 26/47] Fixes for tax calculations --- app/DataMapper/Tax/US/Rule.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/DataMapper/Tax/US/Rule.php b/app/DataMapper/Tax/US/Rule.php index 497585a5bef5..469d16c74a6f 100644 --- a/app/DataMapper/Tax/US/Rule.php +++ b/app/DataMapper/Tax/US/Rule.php @@ -48,7 +48,6 @@ class Rule extends BaseRule implements RuleInterface { $this->tax_rate1 = $item->tax_rate1; - $this->tax_name1 = $item->tax_name1; return $this; From 095748b3ddd28139bcd47985fc66e8229fec32d3 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 29 Jun 2023 14:46:48 +1000 Subject: [PATCH 27/47] Add origin tax data --- app/Transformers/CompanyTransformer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Transformers/CompanyTransformer.php b/app/Transformers/CompanyTransformer.php index 0d6241ca8c17..32f4966ba1b6 100644 --- a/app/Transformers/CompanyTransformer.php +++ b/app/Transformers/CompanyTransformer.php @@ -203,6 +203,7 @@ class CompanyTransformer extends EntityTransformer 'has_e_invoice_certificate_passphrase' => $company->e_invoice_certificate_passphrase ? true : false, 'invoice_task_project_header' => (bool) $company->invoice_task_project_header, 'invoice_task_item_description' => (bool) $company->invoice_task_item_description, + 'origin_tax_data' => $company->origin_tax_data ?: new \stdClass, ]; } From 0db0efd104398302697c7679d8e5748f5b399ece Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 29 Jun 2023 16:38:33 +1000 Subject: [PATCH 28/47] Fixes for download/view --- app/Jobs/Util/Import.php | 150 ++++++++++++++++++++++----------------- routes/client.php | 2 +- 2 files changed, 84 insertions(+), 68 deletions(-) diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index 674b4e7c0579..b45f3ead4cfa 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -11,85 +11,89 @@ namespace App\Jobs\Util; -use App\DataMapper\Analytics\MigrationFailure; -use App\DataMapper\CompanySettings; -use App\Exceptions\ClientHostedMigrationException; -use App\Exceptions\MigrationValidatorFailed; -use App\Exceptions\ResourceDependencyMissing; +use Exception; +use App\Models\Task; +use App\Models\User; +use App\Utils\Ninja; +use App\Models\Quote; +use App\Models\Client; +use App\Models\Credit; +use App\Models\Vendor; +use App\Models\Company; +use App\Models\Expense; +use App\Models\Invoice; +use App\Models\Payment; +use App\Models\Product; +use App\Models\Project; +use App\Models\TaxRate; +use App\Models\Activity; +use App\Models\Document; +use App\Libraries\MultiDB; +use App\Models\TaskStatus; +use App\Models\PaymentTerm; +use Illuminate\Support\Str; +use App\Factory\UserFactory; +use App\Factory\QuoteFactory; +use App\Models\ClientContact; +use Illuminate\Bus\Queueable; use App\Factory\ClientFactory; -use App\Factory\CompanyLedgerFactory; use App\Factory\CreditFactory; +use App\Factory\VendorFactory; +use App\Models\CompanyGateway; +use Illuminate\Support\Carbon; use App\Factory\InvoiceFactory; use App\Factory\PaymentFactory; use App\Factory\ProductFactory; -use App\Factory\QuoteFactory; -use App\Factory\RecurringInvoiceFactory; use App\Factory\TaxRateFactory; -use App\Factory\UserFactory; -use App\Factory\VendorFactory; -use App\Http\Requests\Company\UpdateCompanyRequest; -use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule; -use App\Http\ValidationRules\ValidUserForCompany; -use App\Jobs\Company\CreateCompanyToken; -use App\Jobs\Mail\NinjaMailerJob; -use App\Jobs\Mail\NinjaMailerObject; -use App\Jobs\Ninja\CheckCompanyData; -use App\Libraries\MultiDB; -use App\Mail\Migration\StripeConnectMigration; -use App\Mail\MigrationCompleted; -use App\Models\Activity; -use App\Models\Client; -use App\Models\ClientContact; -use App\Models\ClientGatewayToken; -use App\Models\Company; -use App\Models\CompanyGateway; -use App\Models\Credit; -use App\Models\Document; -use App\Models\Expense; +use App\Jobs\Util\VersionCheck; use App\Models\ExpenseCategory; -use App\Models\Invoice; -use App\Models\Payment; -use App\Models\PaymentTerm; -use App\Models\Product; -use App\Models\Project; -use App\Models\Quote; +use App\Utils\Traits\MakesHash; +use App\Mail\MigrationCompleted; use App\Models\RecurringExpense; use App\Models\RecurringInvoice; -use App\Models\Task; -use App\Models\TaskStatus; -use App\Models\TaxRate; -use App\Models\User; -use App\Models\Vendor; -use App\Repositories\ClientContactRepository; -use App\Repositories\ClientRepository; -use App\Repositories\CompanyRepository; -use App\Repositories\CreditRepository; -use App\Repositories\Migration\InvoiceMigrationRepository; -use App\Repositories\Migration\PaymentMigrationRepository; -use App\Repositories\ProductRepository; -use App\Repositories\UserRepository; -use App\Repositories\VendorContactRepository; -use App\Repositories\VendorRepository; -use App\Utils\Ninja; -use App\Utils\Traits\CleanLineItems; -use App\Utils\Traits\CompanyGatewayFeesAndLimitsSaver; -use App\Utils\Traits\MakesHash; -use App\Utils\Traits\SavesDocuments; use App\Utils\Traits\Uploadable; -use Exception; -use Illuminate\Bus\Queueable; +use App\Jobs\Mail\NinjaMailerJob; +use Illuminate\Http\UploadedFile; +use App\Models\ClientGatewayToken; +use Illuminate\Support\Facades\DB; +use App\DataMapper\CompanySettings; +use Illuminate\Support\Facades\App; +use App\Jobs\Mail\NinjaMailerObject; +use App\Jobs\Ninja\CheckCompanyData; +use App\Repositories\UserRepository; +use App\Utils\Traits\CleanLineItems; +use App\Utils\Traits\SavesDocuments; +use Illuminate\Support\Facades\Mail; +use App\Factory\CompanyLedgerFactory; +use App\Repositories\ClientRepository; +use App\Repositories\CreditRepository; +use App\Repositories\VendorRepository; +use Illuminate\Queue\SerializesModels; +use Turbo124\Beacon\Facades\LightLogs; +use App\Repositories\CompanyRepository; +use App\Repositories\ProductRepository; +use App\Factory\RecurringInvoiceFactory; +use App\Jobs\Company\CreateCompanyToken; +use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Support\Facades\Validator; +use Modules\Admin\Jobs\Account\NinjaUser; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Http\UploadedFile; -use Illuminate\Queue\InteractsWithQueue; +use App\DataMapper\ClientRegistrationFields; +use App\Exceptions\MigrationValidatorFailed; +use App\Exceptions\ResourceDependencyMissing; +use App\Repositories\ClientContactRepository; +use App\Repositories\VendorContactRepository; +use App\DataMapper\Analytics\MigrationFailure; +use App\Mail\Migration\StripeConnectMigration; +use App\Http\ValidationRules\ValidUserForCompany; +use App\Exceptions\ClientHostedMigrationException; +use App\Http\Requests\Company\UpdateCompanyRequest; use Illuminate\Queue\Middleware\WithoutOverlapping; -use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Carbon; -use Illuminate\Support\Facades\App; -use Illuminate\Support\Facades\Mail; -use Illuminate\Support\Facades\Validator; -use Illuminate\Support\Str; -use Turbo124\Beacon\Facades\LightLogs; +use App\Utils\Traits\CompanyGatewayFeesAndLimitsSaver; +use App\Repositories\Migration\InvoiceMigrationRepository; +use App\Repositories\Migration\PaymentMigrationRepository; +use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule; class Import implements ShouldQueue { @@ -1505,7 +1509,19 @@ class Import implements ShouldQueue false ); - $this->saveDocument($uploaded_file, $entity, $is_public = true); + // $this->saveDocument($uploaded_file, $entity, $is_public = true); + + $document = (new \App\Jobs\Util\UploadFile( + $uploaded_file, + \App\Jobs\Util\UploadFile::DOCUMENT, + $this->user, + $this->company, + $entity, + null, + true + ))->handle(); + + } catch(\Exception $e) { //do nothing, gracefully :) } diff --git a/routes/client.php b/routes/client.php index 0a95a333c600..f708f64113a5 100644 --- a/routes/client.php +++ b/routes/client.php @@ -40,7 +40,7 @@ Route::get('tmp_pdf/{hash}', [App\Http\Controllers\ClientPortal\TempRouteControl Route::get('client/key_login/{contact_key}', [App\Http\Controllers\ClientPortal\ContactHashLoginController::class, 'login'])->name('client.contact_login')->middleware(['domain_db','contact_key_login']); Route::get('client/magic_link/{magic_link}', [App\Http\Controllers\ClientPortal\ContactHashLoginController::class, 'magicLink'])->name('client.contact_magic_link')->middleware(['domain_db','contact_key_login']); -Route::get('documents/{document_hash}', [App\Http\Controllers\ClientPortal\DocumentController::class, 'publicDownload'])->name('documents.public_download')->middleware(['domain_db','token_auth']); +Route::get('documents/{document_hash}', [App\Http\Controllers\ClientPortal\DocumentController::class, 'publicDownload'])->name('documents.public_download')->middleware(['api_db','token_auth']); Route::get('error', [App\Http\Controllers\ClientPortal\ContactHashLoginController::class, 'errorPage'])->name('client.error'); Route::get('client/payment/{contact_key}/{payment_id}', [App\Http\Controllers\ClientPortal\InvitationController::class, 'paymentRouter'])->middleware(['domain_db','contact_key_login']); Route::get('client/ninja/{contact_key}/{company_key}', [App\Http\Controllers\ClientPortal\NinjaPlanController::class, 'index'])->name('client.ninja_contact_login')->middleware(['domain_db']); From 0b0128fb41473e0e3538ff1a6770c59eb94fed99 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 29 Jun 2023 16:52:51 +1000 Subject: [PATCH 29/47] Ensure we search trashed statuses --- app/Repositories/TaskStatusRepository.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Repositories/TaskStatusRepository.php b/app/Repositories/TaskStatusRepository.php index 4cadccd4d645..c3702136056c 100644 --- a/app/Repositories/TaskStatusRepository.php +++ b/app/Repositories/TaskStatusRepository.php @@ -38,13 +38,15 @@ class TaskStatusRepository extends BaseRepository public function archive($task_status) { - $task_status = TaskStatus::where('id', $task_status->id) + $task_status = TaskStatus::withTrashed() + ->where('id', $task_status->id) ->where('company_id', $task_status->company_id) ->first(); $new_status = $task_status ? $task_status->id : null; - Task::where('status_id', $task_status->id) + Task::withTrashed() + ->where('status_id', $task_status->id) ->where('company_id', $task_status->company_id) ->update(['status_id' => $new_status]); From 974aabe87e496477a5824d741dd2692181fefd00 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 08:54:33 +1000 Subject: [PATCH 30/47] Add column checks prior to drops --- app/Services/Subscription/SubscriptionService.php | 4 +++- .../migrations/2023_04_27_045639_add_kmher_language.php | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 955e567f62f1..32df7b7468af 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -821,13 +821,15 @@ class SubscriptionService $invoice->is_proforma = false; $invoice->save(); + // 29-06-2023 handle webhooks for payment intent - user may not be present. + $context = [ 'context' => 'change_plan', 'recurring_invoice' => $recurring_invoice->hashed_id, 'invoice' => $this->encodePrimaryKey($payment_hash->fee_invoice_id), 'client' => $recurring_invoice->client->hashed_id, 'subscription' => $this->subscription->hashed_id, - 'contact' => auth()->guard('contact')->user()->hashed_id, + 'contact' => auth()->guard('contact')->user()?->hashed_id ?? $recurring_invoice->client->contacts()->first()->hashed_id, 'account_key' => $recurring_invoice->client->custom_value2, ]; diff --git a/database/migrations/2023_04_27_045639_add_kmher_language.php b/database/migrations/2023_04_27_045639_add_kmher_language.php index 9d2d7a994f95..69e7fb433cb3 100644 --- a/database/migrations/2023_04_27_045639_add_kmher_language.php +++ b/database/migrations/2023_04_27_045639_add_kmher_language.php @@ -25,9 +25,12 @@ return new class extends Migration Language::create(['id' => 38, 'name' => 'Khmer', 'locale' => 'km_KH']); } - Schema::table('companies', function (Blueprint $table) { - $table->dropColumn('enable_e_invoice'); - }); + if (Schema::hasColumn('companies', 'enable_e_invoice')) + { + Schema::table('companies', function (Blueprint $table) { + $table->dropColumn('enable_e_invoice'); + }); + } Company::query()->cursor()->each(function ($company){ $company->tax_data = new TaxModel(); From 5b4232f7e312f27bd3627798238b96b0e6dcc8b5 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 09:14:00 +1000 Subject: [PATCH 31/47] Improvements for disk handling --- app/Services/Email/EmailDefaults.php | 3 --- app/Services/Invoice/InvoiceService.php | 16 +++++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/Services/Email/EmailDefaults.php b/app/Services/Email/EmailDefaults.php index d17ebd8b41f5..9d225c4cc310 100644 --- a/app/Services/Email/EmailDefaults.php +++ b/app/Services/Email/EmailDefaults.php @@ -307,9 +307,6 @@ class EmailDefaults $xinvoice_path = $this->email->email_object->entity->service()->getEInvoice(); - // $xinvoice_path = (new CreateEInvoice($this->email->email_object->entity, true, stream_get_meta_data($tempfile)['uri']))->handle(); - // $this->email->email_object->attachments = array_merge($this->email->email_object->attachments, [['file' => base64_encode($pdf), 'name' => $this->email->email_object->entity->numberFormatter().'.pdf']]); - if(Storage::disk(config('filesystems.default'))->exists($xinvoice_path)) $this->email->email_object->attachments = array_merge($this->email->email_object->attachments, [['file' => base64_encode(Storage::get($xinvoice_path)), 'name' => explode(".", $this->email->email_object->entity->getFileName('xml'))[0]."-xinvoice.xml"]]); diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index f0dc04a88a26..e0a98b604cef 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -115,7 +115,6 @@ class InvoiceService */ public function applyPayment(Payment $payment, float $payment_amount) { - // $this->deletePdf(); $this->invoice = $this->markSent()->save(); $this->invoice = (new ApplyPayment($this->invoice, $payment, $payment_amount))->run(); @@ -348,13 +347,15 @@ class InvoiceService { $this->invoice->load('invitations'); + //30-06-2023 $this->invoice->invitations->each(function ($invitation) { try { - if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { + // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf'); - } + // } - if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { + // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { + if (Ninja::isHosted()) { Storage::disk('public')->delete($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf'); } } catch (\Exception $e) { @@ -371,11 +372,12 @@ class InvoiceService $this->invoice->invitations->each(function ($invitation) { try { - if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) { + // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) { Storage::disk(config('filesystems.default'))->delete($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml")); - } + // } - if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) { + // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml"))) { + if (Ninja::isHosted()) { Storage::disk('public')->delete($this->invoice->client->e_invoice_filepath($invitation).$this->invoice->getFileName("xml")); } } catch (\Exception $e) { From d009eb48b9ecd5c005f07c8716bb358e3cffc35f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 10:26:26 +1000 Subject: [PATCH 32/47] Working on refactor for displaying PDFs --- app/Models/BaseModel.php | 36 ++++++++++++++++--- app/Models/Invoice.php | 4 ++- .../PurchaseOrder/GetPurchaseOrderPdf.php | 2 +- .../invoices/show-fullscreen.blade.php | 4 +-- .../purchase_orders/show-fullscreen.blade.php | 2 ++ 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index e33453092eeb..f0b787f3372a 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -11,15 +11,17 @@ namespace App\Models; +use Illuminate\Support\Str; +use Illuminate\Support\Carbon; +use App\Utils\Traits\MakesHash; +use App\Jobs\Entity\CreateRawPdf; use App\Jobs\Util\WebhookHandler; use App\Models\Traits\Excludable; -use App\Utils\Traits\MakesHash; +use Illuminate\Database\Eloquent\Model; +use App\Jobs\Vendor\CreatePurchaseOrderPdf; use App\Utils\Traits\UserSessionAttributes; use Illuminate\Database\Eloquent\Factories\HasFactory; -use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; -use Illuminate\Support\Carbon; -use Illuminate\Support\Str; /** * Class BaseModel @@ -255,4 +257,30 @@ class BaseModel extends Model WebhookHandler::dispatch($event_id, $this, $this->company, $additional_data); } } + + /** + * Returns the base64 encoded PDF string of the entity + */ + public function fullscreenPdfViewer($invitation = null): string + { + + if (! $invitation) { + if ($this->invitations()->exists()) { + $invitation = $this->invitations()->first(); + } else { + $this->service()->createInvitations(); + $invitation = $this->invitations()->first(); + } + } + + if (! $invitation) { + throw new \Exception('Hard fail, could not create an invitation - is there a valid contact?'); + } + + if($this instanceof \App\Models\PurchaseOrder) + return "data:application/pdf;base64,".base64_encode((new CreatePurchaseOrderPdf($invitation, $invitation->company->db))->rawPdf()); + + return "data:application/pdf;base64,".base64_encode((new CreateRawPdf($invitation, $invitation->company->db))->handle()); + + } } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index dfdf67c2691a..e4d09b6a24b4 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -14,6 +14,7 @@ namespace App\Models; use App\Utils\Ninja; use Illuminate\Support\Carbon; use App\Utils\Traits\MakesDates; +use App\Jobs\Entity\CreateRawPdf; use App\Helpers\Invoice\InvoiceSum; use App\Jobs\Entity\CreateEntityPdf; use App\Utils\Traits\MakesReminders; @@ -682,7 +683,8 @@ class Invoice extends BaseModel } public function pdf_file_path($invitation = null, string $type = 'path', bool $portal = false) - { + {return "data:application/pdf;base64,".base64_encode((new CreateRawPdf($invitation, $invitation->company->db))->handle()); + if (! $invitation) { if ($this->invitations()->exists()) { $invitation = $this->invitations()->first(); diff --git a/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php b/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php index dde550a269c7..2f7a56c9ee56 100644 --- a/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php +++ b/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php @@ -19,7 +19,7 @@ use Illuminate\Support\Facades\Storage; class GetPurchaseOrderPdf extends AbstractService { - public function __construct(PurchaseOrder $purchase_order, VendorContact $contact = null) + public function __construct(public PurchaseOrder $purchase_order, public VendorContact $contact = null) { $this->purchase_order = $purchase_order; diff --git a/resources/views/portal/ninja2020/invoices/show-fullscreen.blade.php b/resources/views/portal/ninja2020/invoices/show-fullscreen.blade.php index d15cebda832d..8de82110754e 100644 --- a/resources/views/portal/ninja2020/invoices/show-fullscreen.blade.php +++ b/resources/views/portal/ninja2020/invoices/show-fullscreen.blade.php @@ -1,2 +1,2 @@ - + + diff --git a/resources/views/portal/ninja2020/purchase_orders/show-fullscreen.blade.php b/resources/views/portal/ninja2020/purchase_orders/show-fullscreen.blade.php index e69de29bb2d1..2aa2bf4b229b 100644 --- a/resources/views/portal/ninja2020/purchase_orders/show-fullscreen.blade.php +++ b/resources/views/portal/ninja2020/purchase_orders/show-fullscreen.blade.php @@ -0,0 +1,2 @@ + + From 30ddf4459800580cf3ffa189dbb7f472bde7a4ca Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 10:26:51 +1000 Subject: [PATCH 33/47] Working on refactor for displaying PDFs --- app/Models/BaseModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index f0b787f3372a..fc3dbface7c3 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -274,7 +274,7 @@ class BaseModel extends Model } if (! $invitation) { - throw new \Exception('Hard fail, could not create an invitation - is there a valid contact?'); + throw new \Exception('Hard fail, could not create an invitation.'); } if($this instanceof \App\Models\PurchaseOrder) From fa3fc05f7cf3ed6f788458334239b480daf127c0 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 10:37:13 +1000 Subject: [PATCH 34/47] minor fixes --- app/Services/PurchaseOrder/GetPurchaseOrderPdf.php | 2 +- resources/views/portal/ninja2020/statement/index.blade.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php b/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php index 2f7a56c9ee56..bccb238bf9a7 100644 --- a/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php +++ b/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php @@ -19,7 +19,7 @@ use Illuminate\Support\Facades\Storage; class GetPurchaseOrderPdf extends AbstractService { - public function __construct(public PurchaseOrder $purchase_order, public VendorContact $contact = null) + public function __construct(public PurchaseOrder $purchase_order, public ?VendorContact $contact = null) { $this->purchase_order = $purchase_order; diff --git a/resources/views/portal/ninja2020/statement/index.blade.php b/resources/views/portal/ninja2020/statement/index.blade.php index 14ea29843d5c..f0780705b29a 100644 --- a/resources/views/portal/ninja2020/statement/index.blade.php +++ b/resources/views/portal/ninja2020/statement/index.blade.php @@ -45,6 +45,7 @@ @include('portal.ninja2020.components.pdf-viewer', ['url' => route('client.statement.raw')]) + @endsection @push('footer') From 48c20b35b8b2769aded4ed94fafab6721e78c7d1 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 10:38:59 +1000 Subject: [PATCH 35/47] Fixes for pdf viewer --- app/Models/Invoice.php | 2 +- app/Services/PurchaseOrder/GetPurchaseOrderPdf.php | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index e4d09b6a24b4..a10fff5f7931 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -683,7 +683,7 @@ class Invoice extends BaseModel } public function pdf_file_path($invitation = null, string $type = 'path', bool $portal = false) - {return "data:application/pdf;base64,".base64_encode((new CreateRawPdf($invitation, $invitation->company->db))->handle()); + { if (! $invitation) { if ($this->invitations()->exists()) { diff --git a/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php b/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php index bccb238bf9a7..40044b90b6e5 100644 --- a/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php +++ b/app/Services/PurchaseOrder/GetPurchaseOrderPdf.php @@ -21,9 +21,6 @@ class GetPurchaseOrderPdf extends AbstractService { public function __construct(public PurchaseOrder $purchase_order, public ?VendorContact $contact = null) { - $this->purchase_order = $purchase_order; - - $this->contact = $contact; } public function run() From d53c36d3ef2c47e7f8a8e8070fbf5a3b008f462c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 14:30:27 +1000 Subject: [PATCH 36/47] Updates for access token with microsoft --- app/Http/Controllers/ConnectedAccountController.php | 7 ++++--- app/Models/Invoice.php | 1 - .../portal/ninja2020/credits/show-fullscreen.blade.php | 5 +++-- .../portal/ninja2020/quotes/show-fullscreen.blade.php | 5 +++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/Http/Controllers/ConnectedAccountController.php b/app/Http/Controllers/ConnectedAccountController.php index c93d05477935..614a4ccb9717 100644 --- a/app/Http/Controllers/ConnectedAccountController.php +++ b/app/Http/Controllers/ConnectedAccountController.php @@ -90,14 +90,15 @@ class ConnectedAccountController extends BaseController private function handleMicrosoftOauth($request) { - nlog($request->all()); + $access_token = false; + $access_token = $request->has('access_token') ? $request->input('access_token') : $request->input('accessToken'); - if (!$request->has('access_token')) { + if (!$access_token) { return response()->json(['message' => 'No access_token parameter found!'], 400); } $graph = new \Microsoft\Graph\Graph(); - $graph->setAccessToken($request->input('access_token')); + $graph->setAccessToken($access_token); $user = $graph->createRequest("GET", "/me") ->setReturnType(Model\User::class) diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index a10fff5f7931..f390f21fc507 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -727,7 +727,6 @@ class Invoice extends BaseModel return Storage::disk(config('filesystems.default'))->{$type}($file_path); } - try { $file_exists = Storage::disk('public')->exists($file_path); } catch (\Exception $e) { diff --git a/resources/views/portal/ninja2020/credits/show-fullscreen.blade.php b/resources/views/portal/ninja2020/credits/show-fullscreen.blade.php index 438899646beb..3655bf8f68e4 100644 --- a/resources/views/portal/ninja2020/credits/show-fullscreen.blade.php +++ b/resources/views/portal/ninja2020/credits/show-fullscreen.blade.php @@ -1,2 +1,3 @@ - + + + diff --git a/resources/views/portal/ninja2020/quotes/show-fullscreen.blade.php b/resources/views/portal/ninja2020/quotes/show-fullscreen.blade.php index 0cfa59fec10b..22043d045fe8 100644 --- a/resources/views/portal/ninja2020/quotes/show-fullscreen.blade.php +++ b/resources/views/portal/ninja2020/quotes/show-fullscreen.blade.php @@ -1,2 +1,3 @@ - + + + From 53a930f6c4f95970036ce09e4d59d324ea3f6029 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 14:34:24 +1000 Subject: [PATCH 37/47] Fixes for returning mail providers --- app/Jobs/Mail/NinjaMailerJob.php | 10 ++++++---- app/Services/Email/Email.php | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/Jobs/Mail/NinjaMailerJob.php b/app/Jobs/Mail/NinjaMailerJob.php index 3b8611bb3f1e..39179844a0f8 100644 --- a/app/Jobs/Mail/NinjaMailerJob.php +++ b/app/Jobs/Mail/NinjaMailerJob.php @@ -243,19 +243,19 @@ class NinjaMailerJob implements ShouldQueue case 'gmail': $this->mailer = 'gmail'; $this->setGmailMailer(); - return; + return $this; case 'office365': $this->mailer = 'office365'; $this->setOfficeMailer(); - return; + return $this; case 'client_postmark': $this->mailer = 'postmark'; $this->setPostmarkMailer(); - return; + return $this; case 'client_mailgun': $this->mailer = 'mailgun'; $this->setMailgunMailer(); - return; + return $this; default: break; @@ -264,6 +264,8 @@ class NinjaMailerJob implements ShouldQueue if (Ninja::isSelfHost()) { $this->setSelfHostMultiMailer(); } + + return $this; } /** diff --git a/app/Services/Email/Email.php b/app/Services/Email/Email.php index ac606a0b2e9e..941d1c150b3f 100644 --- a/app/Services/Email/Email.php +++ b/app/Services/Email/Email.php @@ -445,7 +445,8 @@ class Email implements ShouldQueue return $this; default: - break; + $this->mailer = config('mail.default'); + return $this; } if (Ninja::isSelfHost()) { From cf4b87e70165d3164664d20f687e44cce1db4190 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 14:50:20 +1000 Subject: [PATCH 38/47] Fixes for mailers --- app/Jobs/Mail/NinjaMailerJob.php | 1 + app/Services/Email/Email.php | 1 + phpstan.neon | 2 -- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Jobs/Mail/NinjaMailerJob.php b/app/Jobs/Mail/NinjaMailerJob.php index 39179844a0f8..0e81d544f9be 100644 --- a/app/Jobs/Mail/NinjaMailerJob.php +++ b/app/Jobs/Mail/NinjaMailerJob.php @@ -245,6 +245,7 @@ class NinjaMailerJob implements ShouldQueue $this->setGmailMailer(); return $this; case 'office365': + case 'microsoft': $this->mailer = 'office365'; $this->setOfficeMailer(); return $this; diff --git a/app/Services/Email/Email.php b/app/Services/Email/Email.php index 941d1c150b3f..4a9663ea43f4 100644 --- a/app/Services/Email/Email.php +++ b/app/Services/Email/Email.php @@ -432,6 +432,7 @@ class Email implements ShouldQueue $this->setGmailMailer(); return $this; case 'office365': + case 'microsoft': $this->mailer = 'office365'; $this->setOfficeMailer(); return $this; diff --git a/phpstan.neon b/phpstan.neon index 4fcf09b7dab7..148ec353ba82 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -6,8 +6,6 @@ parameters: ignoreErrors: - '#Call to an undefined method .*badMethod\(\)#' - '#Call to an undefined method Illuminate\Database\Eloquent\Builder::exclude#' - parallel: - maximumNumberOfProcesses: 1 level: 4 paths: - 'app/' From 8017b589c20a26e32091d17467d39b59ef6b33ab Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 15:28:04 +1000 Subject: [PATCH 39/47] Refactors for excessive PDF generation --- app/Http/Controllers/InvoiceController.php | 5 +++-- app/Jobs/Bank/MatchBankTransactions.php | 2 +- app/Jobs/Util/ReminderJob.php | 4 ++-- app/PaymentDrivers/BaseDriver.php | 4 ++-- app/Services/Invoice/HandleCancellation.php | 12 ------------ app/Services/Invoice/TriggeredActions.php | 2 +- 6 files changed, 9 insertions(+), 20 deletions(-) diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 6f515dbcf920..1c691f36f577 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -408,7 +408,7 @@ class InvoiceController extends BaseController $invoice->service() ->triggeredActions($request) - ->touchPdf() + ->deletePdf() ->adjustInventory($old_invoice); event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); @@ -740,7 +740,8 @@ class InvoiceController extends BaseController } break; case 'cancel': - $invoice = $invoice->service()->handleCancellation()->touchPdf()->save(); + $invoice = $invoice->service()->handleCancellation()->deletePdf()->save(); + // $invoice = $invoice->service()->handleCancellation()->touchPdf()->save(); if (! $bulk) { $this->itemResponse($invoice); diff --git a/app/Jobs/Bank/MatchBankTransactions.php b/app/Jobs/Bank/MatchBankTransactions.php index 31c1e1538059..f2a44c60c809 100644 --- a/app/Jobs/Bank/MatchBankTransactions.php +++ b/app/Jobs/Bank/MatchBankTransactions.php @@ -362,7 +362,7 @@ class MatchBankTransactions implements ShouldQueue $this->invoice ->service() ->applyNumber() - ->touchPdf() + ->deletePdf() ->save(); $payment->ledger() diff --git a/app/Jobs/Util/ReminderJob.php b/app/Jobs/Util/ReminderJob.php index e11234f6785c..879b759204fd 100644 --- a/app/Jobs/Util/ReminderJob.php +++ b/app/Jobs/Util/ReminderJob.php @@ -208,7 +208,8 @@ class ReminderJob implements ShouldQueue ->markSent() ->save(); - $invoice->service()->touchPdf(true); + //30-6-2023 - fix for duplicate touching + // $invoice->service()->touchPdf(true); $enabled_reminder = 'enable_'.$reminder_template; if ($reminder_template == 'endless_reminder') { @@ -268,7 +269,6 @@ class ReminderJob implements ShouldQueue } return [$late_fee_amount, $late_fee_percent]; - // return $this->setLateFee($invoice, $late_fee_amount, $late_fee_percent); } /** diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index 4bad13f054a3..4f2c6807b706 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -525,7 +525,7 @@ class BaseDriver extends AbstractPaymentDriver $invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get(); $invoices->each(function ($invoice) { - $invoice->service()->touchPdf(); + $invoice->service()->deletePdf(); }); $invoices->first()->invitations->each(function ($invitation) use ($nmo) { @@ -570,7 +570,7 @@ class BaseDriver extends AbstractPaymentDriver $invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->withTrashed()->get(); $invoices->each(function ($invoice) { - $invoice->service()->touchPdf(); + $invoice->service()->deletePdf(); }); $invoices->first()->invitations->each(function ($invitation) use ($nmo) { diff --git a/app/Services/Invoice/HandleCancellation.php b/app/Services/Invoice/HandleCancellation.php index fe83909e3e36..2fcd20013fee 100644 --- a/app/Services/Invoice/HandleCancellation.php +++ b/app/Services/Invoice/HandleCancellation.php @@ -44,9 +44,7 @@ class HandleCancellation extends AbstractService $this->invoice->balance = 0; $this->invoice = $this->invoice->service()->setStatus(Invoice::STATUS_CANCELLED)->save(); - //adjust client balance $this->invoice->client->service()->updateBalance($adjustment)->save(); - // $this->invoice->fresh(); $this->invoice->service()->workFlow()->save(); @@ -54,16 +52,6 @@ class HandleCancellation extends AbstractService event('eloquent.updated: App\Models\Invoice', $this->invoice); - $transaction = [ - 'invoice' => $this->invoice->transaction_event(), - 'payment' => [], - 'client' => $this->invoice->client->transaction_event(), - 'credit' => [], - 'metadata' => [], - ]; - - // TransactionLog::dispatch(TransactionEvent::INVOICE_CANCELLED, $transaction, $this->invoice->company->db); - return $this->invoice; } diff --git a/app/Services/Invoice/TriggeredActions.php b/app/Services/Invoice/TriggeredActions.php index 7c6e7c4f6ad9..3dae6339b743 100644 --- a/app/Services/Invoice/TriggeredActions.php +++ b/app/Services/Invoice/TriggeredActions.php @@ -54,7 +54,7 @@ class TriggeredActions extends AbstractService } if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') { - $this->invoice->service()->markSent()->touchPdf()->save(); + $this->invoice->service()->markSent()->save(); $this->sendEmail(); $this->updated = false; } From 2f49bc83823516f93eaba6cbf3f4517d858417d8 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 15:43:28 +1000 Subject: [PATCH 40/47] v5.6.5 --- VERSION.txt | 2 +- app/Services/Credit/ApplyPayment.php | 4 +-- app/Services/Credit/CreditService.php | 29 +++++++++++++++---- app/Services/Credit/MarkSent.php | 2 +- app/Services/Invoice/ApplyPayment.php | 2 +- app/Services/Invoice/InvoiceService.php | 4 +-- app/Services/Invoice/MarkPaid.php | 2 +- app/Services/Payment/UpdateInvoicePayment.php | 2 +- .../PurchaseOrder/TriggeredActions.php | 4 --- app/Services/Quote/MarkSent.php | 2 +- app/Services/Quote/QuoteService.php | 20 +++++++++++-- app/Services/Recurring/RecurringService.php | 19 +++++++++++- .../Subscription/SubscriptionService.php | 2 +- config/ninja.php | 4 +-- 14 files changed, 73 insertions(+), 25 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 2a06a418a773..fad8076f307d 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.6.4 \ No newline at end of file +5.6.5 \ No newline at end of file diff --git a/app/Services/Credit/ApplyPayment.php b/app/Services/Credit/ApplyPayment.php index 0f8af8b4aef7..70639ce02001 100644 --- a/app/Services/Credit/ApplyPayment.php +++ b/app/Services/Credit/ApplyPayment.php @@ -137,7 +137,7 @@ class ApplyPayment ->updateBalance($this->amount_applied * -1) ->updatePaidToDate($this->amount_applied) ->updateStatus() - ->touchPdf() + ->deletePdf() ->save(); $this->credit @@ -147,7 +147,7 @@ class ApplyPayment event(new InvoiceWasUpdated($this->invoice, $this->invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); if ((int) $this->invoice->balance == 0) { - $this->invoice->service()->touchPdf(); + $this->invoice->service()->deletePdf(); $this->invoice = $this->invoice->fresh(); event(new InvoiceWasPaid($this->invoice, $this->payment, $this->payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); } diff --git a/app/Services/Credit/CreditService.php b/app/Services/Credit/CreditService.php index ccc61a03d555..811ea7e4cf45 100644 --- a/app/Services/Credit/CreditService.php +++ b/app/Services/Credit/CreditService.php @@ -11,15 +11,17 @@ namespace App\Services\Credit; -use App\Factory\PaymentFactory; -use App\Jobs\Entity\CreateEntityPdf; -use App\Jobs\Util\UnlinkFile; +use App\Utils\Ninja; use App\Models\Credit; use App\Models\Payment; use App\Models\PaymentType; +use App\Jobs\Util\UnlinkFile; +use App\Factory\PaymentFactory; +use App\Utils\Traits\MakesHash; +use App\Jobs\Entity\CreateEntityPdf; use App\Repositories\CreditRepository; use App\Repositories\PaymentRepository; -use App\Utils\Traits\MakesHash; +use Illuminate\Support\Facades\Storage; class CreditService { @@ -235,7 +237,24 @@ class CreditService public function deletePdf() { $this->credit->invitations->each(function ($invitation) { - (new UnlinkFile(config('filesystems.default'), $this->credit->client->credit_filepath($invitation).$this->credit->numberFormatter().'.pdf'))->handle(); + // (new UnlinkFile(config('filesystems.default'), $this->credit->client->credit_filepath($invitation).$this->credit->numberFormatter().'.pdf'))->handle(); + + //30-06-2023 + try { + // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { + Storage::disk(config('filesystems.default'))->delete($this->credit->client->credit_filepath($invitation).$this->credit->numberFormatter().'.pdf'); + // } + + // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { + if (Ninja::isHosted()) { + Storage::disk('public')->delete($this->credit->client->credit_filepath($invitation).$this->credit->numberFormatter().'.pdf'); + } + } catch (\Exception $e) { + nlog($e->getMessage()); + } + + + }); return $this; diff --git a/app/Services/Credit/MarkSent.php b/app/Services/Credit/MarkSent.php index 3402a019aab9..890f6887c741 100644 --- a/app/Services/Credit/MarkSent.php +++ b/app/Services/Credit/MarkSent.php @@ -42,7 +42,7 @@ class MarkSent ->setStatus(Credit::STATUS_SENT) ->applyNumber() ->adjustBalance($this->credit->amount) - ->touchPdf() + ->deletePdf() ->save(); $this->client diff --git a/app/Services/Invoice/ApplyPayment.php b/app/Services/Invoice/ApplyPayment.php index 542e871876b4..a0a2fb5f83fd 100644 --- a/app/Services/Invoice/ApplyPayment.php +++ b/app/Services/Invoice/ApplyPayment.php @@ -92,7 +92,7 @@ class ApplyPayment extends AbstractService } }); - $this->invoice->service()->applyNumber()->workFlow()->touchPdf()->save(); + $this->invoice->service()->applyNumber()->workFlow()->deletePdf()->save(); return $this->invoice; } diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index e0a98b604cef..d5a0715ee7d2 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -338,7 +338,7 @@ class InvoiceService return $item; })->toArray(); - $this->touchPdf(); + $this->deletePdf(); return $this; } @@ -405,7 +405,7 @@ class InvoiceService })->toArray(); $this->invoice = $this->invoice->calc()->getInvoice(); - $this->touchPdf(); + $this->deletePdf(); /* 24-03-2022 */ $new_balance = $this->invoice->balance; diff --git a/app/Services/Invoice/MarkPaid.php b/app/Services/Invoice/MarkPaid.php index a056da4b6038..6b2c515a97cb 100644 --- a/app/Services/Invoice/MarkPaid.php +++ b/app/Services/Invoice/MarkPaid.php @@ -102,7 +102,7 @@ class MarkPaid extends AbstractService $this->invoice ->service() ->applyNumber() - ->touchPdf() + ->deletePdf() ->save(); $payment->ledger() diff --git a/app/Services/Payment/UpdateInvoicePayment.php b/app/Services/Payment/UpdateInvoicePayment.php index 4f088eacfc9f..882cba3e95bd 100644 --- a/app/Services/Payment/UpdateInvoicePayment.php +++ b/app/Services/Payment/UpdateInvoicePayment.php @@ -79,7 +79,7 @@ class UpdateInvoicePayment $invoice = $invoice->service() ->clearPartial() ->updateStatus() - ->touchPdf() + ->deletePdf() ->workFlow() ->save(); diff --git a/app/Services/PurchaseOrder/TriggeredActions.php b/app/Services/PurchaseOrder/TriggeredActions.php index 02e9e0bdc871..38510fc70962 100644 --- a/app/Services/PurchaseOrder/TriggeredActions.php +++ b/app/Services/PurchaseOrder/TriggeredActions.php @@ -43,10 +43,6 @@ class TriggeredActions extends AbstractService $this->purchase_order = $this->purchase_order->service()->markSent()->touchPdf()->save(); } - // if ($this->request->has('cancel') && $this->request->input('cancel') == 'true') { - // $this->purchase_order = $this->purchase_order->service()->handleCancellation()->save(); - // } - if ($this->request->has('save_default_footer') && $this->request->input('save_default_footer') == 'true') { $company = $this->purchase_order->company; $settings = $company->settings; diff --git a/app/Services/Quote/MarkSent.php b/app/Services/Quote/MarkSent.php index fa9c75a565b9..9969cbfc3f41 100644 --- a/app/Services/Quote/MarkSent.php +++ b/app/Services/Quote/MarkSent.php @@ -47,7 +47,7 @@ class MarkSent ->service() ->setStatus(Quote::STATUS_SENT) ->applyNumber() - ->touchPdf() + ->deletePdf() ->save(); event(new QuoteWasMarkedSent($this->quote, $this->quote->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null))); diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index fe6189106c47..45b38cc0b52b 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -19,6 +19,7 @@ use App\Exceptions\QuoteConversion; use App\Jobs\Entity\CreateEntityPdf; use App\Repositories\QuoteRepository; use App\Events\Quote\QuoteWasApproved; +use Illuminate\Support\Facades\Storage; class QuoteService { @@ -115,7 +116,7 @@ class QuoteService $this->invoice ->service() ->markSent() - ->touchPdf() + ->deletePdf() ->save(); } @@ -224,7 +225,22 @@ class QuoteService public function deletePdf() { $this->quote->invitations->each(function ($invitation) { - (new UnlinkFile(config('filesystems.default'), $this->quote->client->quote_filepath($invitation).$this->quote->numberFormatter().'.pdf'))->handle(); + // (new UnlinkFile(config('filesystems.default'), $this->quote->client->quote_filepath($invitation).$this->quote->numberFormatter().'.pdf'))->handle(); + + //30-06-2023 + try { + // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { + Storage::disk(config('filesystems.default'))->delete($this->quote->client->quote_filepath($invitation).$this->quote->numberFormatter().'.pdf'); + // } + + // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { + if (Ninja::isHosted()) { + Storage::disk('public')->delete($this->quote->client->quote_filepath($invitation).$this->quote->numberFormatter().'.pdf'); + } + } catch (\Exception $e) { + nlog($e->getMessage()); + } + }); return $this; diff --git a/app/Services/Recurring/RecurringService.php b/app/Services/Recurring/RecurringService.php index c962b5f45f45..721b94dcd183 100644 --- a/app/Services/Recurring/RecurringService.php +++ b/app/Services/Recurring/RecurringService.php @@ -11,11 +11,13 @@ namespace App\Services\Recurring; +use App\Utils\Ninja; use App\Jobs\Util\UnlinkFile; use App\Models\RecurringQuote; use Illuminate\Support\Carbon; use App\Models\RecurringExpense; use App\Models\RecurringInvoice; +use Illuminate\Support\Facades\Storage; use App\Jobs\RecurringInvoice\SendRecurring; class RecurringService @@ -88,7 +90,22 @@ class RecurringService public function deletePdf() { $this->recurring_entity->invitations->each(function ($invitation) { - (new UnlinkFile(config('filesystems.default'), $this->recurring_entity->client->recurring_invoice_filepath($invitation) . $this->recurring_entity->numberFormatter().'.pdf'))->handle(); + // (new UnlinkFile(config('filesystems.default'), $this->recurring_entity->client->recurring_invoice_filepath($invitation) . $this->recurring_entity->numberFormatter().'.pdf'))->handle(); + + //30-06-2023 + try { + Storage::disk(config('filesystems.default'))->delete($this->recurring_entity->client->recurring_invoice_filepath($invitation) . $this->recurring_entity->numberFormatter().'.pdf'); + // if (Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { + // } + + // if (Ninja::isHosted() && Storage::disk('public')->exists($this->invoice->client->invoice_filepath($invitation).$this->invoice->numberFormatter().'.pdf')) { + Storage::disk('public')->delete($this->recurring_entity->client->recurring_invoice_filepath($invitation) . $this->recurring_entity->numberFormatter().'.pdf'); + if (Ninja::isHosted()) { + } + } catch (\Exception $e) { + nlog($e->getMessage()); + } + }); diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 32df7b7468af..782f08446b6a 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -188,7 +188,7 @@ class SubscriptionService //update the invoice and attach to the recurring invoice!!!!! $invoice->recurring_id = $recurring_invoice->id; $invoice->is_proforma = false; - $invoice->service()->touchPdf(); + $invoice->service()->deletePdf(); $invoice->save(); $contact = $invoice->client->contacts()->whereNotNull('email')->first(); diff --git a/config/ninja.php b/config/ninja.php index 482d0131229a..86642783a8a0 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -15,8 +15,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.6.4', - 'app_tag' => '5.6.4', + 'app_version' => '5.6.5', + 'app_tag' => '5.6.5', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''), From 991728370d506efb6660f6e04468c758b9e30058 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 16:29:10 +1000 Subject: [PATCH 41/47] Fixes for redirects --- app/Http/Controllers/Auth/LoginController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index a2ad553c95e9..0eb14e57febb 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -699,7 +699,7 @@ class LoginController extends BaseController $request_from_react = Cache::pull("react_redir:".auth()->user()?->account?->key); - if($request_from_react) + // if($request_from_react) $redirect_url = config('ninja.react_url')."/#/settings/user_details/connect"; return redirect($redirect_url); From a449d3b4457959f26e47b85148f5fc0e415227fa Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 16:30:37 +1000 Subject: [PATCH 42/47] Fixes for redirects --- app/Http/Controllers/Auth/LoginController.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 0eb14e57febb..a32ea52c4efb 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -682,8 +682,6 @@ class LoginController extends BaseController 'email' => $socialite_user->getEmail(), 'oauth_user_id' => $socialite_user->getId(), 'oauth_provider_id' => $provider, - // 'oauth_user_token' => $oauth_user_token, - // 'oauth_user_refresh_token' => $socialite_user->refreshToken, ]; $user->update($update_user); @@ -735,6 +733,10 @@ class LoginController extends BaseController nlog('user not found for oauth'); } - return redirect('/#/'); + $redirect_url = config('ninja.react_url')."/#/settings/user_details/connect"; + + return redirect($redirect_url); + + // return redirect('/#/'); } } From 9551c7bd6e58efcd804092a2f6970186be18badd Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 30 Jun 2023 18:26:28 +1000 Subject: [PATCH 43/47] Additional filters --- app/Filters/UserFilters.php | 9 +++++++++ app/Http/Requests/Report/GenericReportRequest.php | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/Filters/UserFilters.php b/app/Filters/UserFilters.php index b0079e339189..20d2a7ce777f 100644 --- a/app/Filters/UserFilters.php +++ b/app/Filters/UserFilters.php @@ -89,6 +89,15 @@ class UserFilters extends QueryFilters ->where('account_id', auth()->user()->account_id); } + public function sending_users(string $value = ''): Builder + { + if (strlen($value) == 0 || $value != 'true') { + return $this->builder; + } + + return $this->builder->whereNotNull('oauth_user_refresh_token'); + } + /** * Exclude a list of user_ids, can pass multiple * user IDs by separating them with a comma. diff --git a/app/Http/Requests/Report/GenericReportRequest.php b/app/Http/Requests/Report/GenericReportRequest.php index 3e95479d23b5..d18bb516c233 100644 --- a/app/Http/Requests/Report/GenericReportRequest.php +++ b/app/Http/Requests/Report/GenericReportRequest.php @@ -33,7 +33,7 @@ class GenericReportRequest extends Request 'start_date' => 'bail|required_if:date_range,custom|nullable|date', 'report_keys' => 'present|array', 'send_email' => 'required|bool', - 'status' => 'sometimes|string|nullable|in:all,draft,sent,viewed,paid,unpaid,overdue', + // 'status' => 'sometimes|string|nullable|in:all,draft,sent,viewed,paid,unpaid,overdue', ]; } From 69867b844f606544c731c9a5187d2d59975cb629 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 1 Jul 2023 08:40:15 +1000 Subject: [PATCH 44/47] Show invoice number if set in live previews --- app/Http/Requests/Preview/PreviewInvoiceRequest.php | 2 +- app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Requests/Preview/PreviewInvoiceRequest.php b/app/Http/Requests/Preview/PreviewInvoiceRequest.php index b2da03628210..bfa4db546470 100644 --- a/app/Http/Requests/Preview/PreviewInvoiceRequest.php +++ b/app/Http/Requests/Preview/PreviewInvoiceRequest.php @@ -48,7 +48,7 @@ class PreviewInvoiceRequest extends Request $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; $input['amount'] = 0; $input['balance'] = 0; - $input['number'] = ctrans('texts.live_preview').' #'.rand(0, 1000); + $input['number'] = isset($input['number']) ? $input['number'] : ctrans('texts.live_preview').' #'.rand(0, 1000); $this->replace($input); } diff --git a/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php b/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php index d91de03c19ec..46e45f12591d 100644 --- a/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php +++ b/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php @@ -48,7 +48,7 @@ class PreviewPurchaseOrderRequest extends Request $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; $input['amount'] = 0; $input['balance'] = 0; - $input['number'] = ctrans('texts.live_preview') . " #". rand(0, 1000); + $input['number'] = isset($input['number']) ? $input['number'] : ctrans('texts.live_preview').' #'.rand(0, 1000); $this->replace($input); } From fcac5cf4d62e4ee9163e15d22b235d0418ea583f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 1 Jul 2023 08:40:27 +1000 Subject: [PATCH 45/47] Show invoice number if set in live previews --- app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php b/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php index 46e45f12591d..927937bf25a7 100644 --- a/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php +++ b/app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php @@ -48,7 +48,7 @@ class PreviewPurchaseOrderRequest extends Request $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : []; $input['amount'] = 0; $input['balance'] = 0; - $input['number'] = isset($input['number']) ? $input['number'] : ctrans('texts.live_preview').' #'.rand(0, 1000); + $input['number'] = isset($input['number']) ? $input['number'] : ctrans('texts.live_preview').' #'.rand(0, 1000); //30-06-2023 $this->replace($input); } From f7e3ebad970bcfbba9064af87fad4001f1670093 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 1 Jul 2023 09:41:01 +1000 Subject: [PATCH 46/47] Minor fixes for the calm design and shipping address configuration --- resources/views/pdf-designs/calm.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/pdf-designs/calm.html b/resources/views/pdf-designs/calm.html index 099bace18ba8..72eb8f6022aa 100644 --- a/resources/views/pdf-designs/calm.html +++ b/resources/views/pdf-designs/calm.html @@ -132,7 +132,7 @@ } #shipping-details { - visibility: $show_shipping_address_visibility; + opacity: $show_shipping_address_visibility; flex-direction: column; line-height: var(--line-height); } From d6f7f1adee766a16814c3babefb66410ea1c8302 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 2 Jul 2023 08:15:43 +1000 Subject: [PATCH 47/47] Set immediate payment notification on success --- app/PaymentDrivers/Stripe/iDeal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/PaymentDrivers/Stripe/iDeal.php b/app/PaymentDrivers/Stripe/iDeal.php index 5353181676e4..3e0c49cc7cab 100644 --- a/app/PaymentDrivers/Stripe/iDeal.php +++ b/app/PaymentDrivers/Stripe/iDeal.php @@ -106,7 +106,7 @@ class iDeal 'gateway_type_id' => GatewayType::IDEAL, ]; - $this->stripe->createPayment($data, Payment::STATUS_PENDING); + $this->stripe->createPayment($data, Payment::STATUS_COMPLETED); SystemLogger::dispatch( ['response' => $this->stripe->payment_hash->data, 'data' => $data],