From 778c30f7ed0c9230c67499f4a3268108cb969709 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 28 Nov 2022 12:16:58 +1100 Subject: [PATCH 01/29] refactor for data instead of file paths --- app/Filters/DocumentFilters.php | 10 ++++++++++ app/Mail/Engine/InvoiceEmailEngine.php | 23 +++++++++++++--------- app/Mail/TemplateEmail.php | 27 +++++++++++++++----------- app/Utils/HostedPDF/NinjaPdf.php | 2 +- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/app/Filters/DocumentFilters.php b/app/Filters/DocumentFilters.php index fade4950705a..bf7b589aeef0 100644 --- a/app/Filters/DocumentFilters.php +++ b/app/Filters/DocumentFilters.php @@ -11,6 +11,7 @@ namespace App\Filters; +use App\Models\Company; use App\Models\User; use Illuminate\Database\Eloquent\Builder; @@ -54,6 +55,15 @@ class DocumentFilters extends QueryFilters return $this->builder->orderBy($sort_col[0], $sort_col[1]); } + + public function company_documents($value = 'false') + { + if($value == 'true') + return $this->builder->where('documentable_type', Company::class); + + return $this->builder; + } + /** * Returns the base query. * diff --git a/app/Mail/Engine/InvoiceEmailEngine.php b/app/Mail/Engine/InvoiceEmailEngine.php index 000d2f72748f..e41f0fdc8c9f 100644 --- a/app/Mail/Engine/InvoiceEmailEngine.php +++ b/app/Mail/Engine/InvoiceEmailEngine.php @@ -13,6 +13,7 @@ namespace App\Mail\Engine; use App\DataMapper\EmailTemplateDefaults; use App\Jobs\Entity\CreateEntityPdf; +use App\Jobs\Entity\CreateRawPdf; use App\Models\Account; use App\Models\Expense; use App\Models\Task; @@ -126,11 +127,15 @@ class InvoiceEmailEngine extends BaseEmailEngine ->setTextBody($text_body); if ($this->client->getSetting('pdf_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { - if (Ninja::isHosted()) { - $this->setAttachments([$this->invoice->pdf_file_path($this->invitation, 'url', true)]); - } else { - $this->setAttachments([$this->invoice->pdf_file_path($this->invitation)]); - } + // if (Ninja::isHosted()) { + // $this->setAttachments([$this->invoice->pdf_file_path($this->invitation, 'url', true)]); + // } else { + // $this->setAttachments([$this->invoice->pdf_file_path($this->invitation)]); + // } + // $file = (new CreateRawPdf($invitation, $invitation->company->db))->handle(); + $pdf = ((new CreateRawPdf($this->invitation, $this->invitation->company->db))->handle()); + + $this->setAttachments([['file' => base64_encode($pdf), 'name' => $this->invoice->numberFormatter().'.pdf']]); } //attach third party documents @@ -138,11 +143,11 @@ class InvoiceEmailEngine extends BaseEmailEngine // Storage::url foreach ($this->invoice->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => $document->getFile()]]); } foreach ($this->invoice->company->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => $document->getFile()]]); } $line_items = $this->invoice->line_items; @@ -160,7 +165,7 @@ class InvoiceEmailEngine extends BaseEmailEngine ->cursor() ->each(function ($expense) { foreach ($expense->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => $document->getFile()]]); } }); } @@ -176,7 +181,7 @@ class InvoiceEmailEngine extends BaseEmailEngine ->cursor() ->each(function ($task) { foreach ($task->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => $document->getFile()]]); } }); } diff --git a/app/Mail/TemplateEmail.php b/app/Mail/TemplateEmail.php index cbf07442c075..8a892db39840 100644 --- a/app/Mail/TemplateEmail.php +++ b/app/Mail/TemplateEmail.php @@ -146,19 +146,24 @@ class TemplateEmail extends Mailable } + // $file = (new CreateRawPdf($invitation, $invitation->company->db))->handle(); + + //22-10-2022 - Performance - To improve the performance/reliability of sending emails, attaching as Data is much better, stubs in place foreach ($this->build_email->getAttachments() as $file) { - if (is_string($file)) { - // nlog($file); - // $file_data = file_get_contents($file); - // $this->attachData($file_data, basename($file)); - $this->attach($file); - } elseif (is_array($file)) { - // nlog($file['path']); - // $file_data = file_get_contents($file['path']); - // $this->attachData($file_data, $file['name']); - $this->attach($file['path'], ['as' => $file['name'], 'mime' => null]); - } + // if (is_string($file)) { + // // nlog($file); + // // $file_data = file_get_contents($file); + // // $this->attachData($file_data, basename($file)); + // $this->attach($file); + // } elseif (is_array($file)) { + // // nlog($file['path']); + // // $file_data = file_get_contents($file['path']); + // // $this->attachData($file_data, $file['name']); + // $this->attach($file['path'], ['as' => $file['name'], 'mime' => null]); + // } + + $this->attachData(base64_decode($file['file']), $file['name']); } if ($this->invitation && $this->invitation->invoice && $settings->ubl_email_attachment && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { diff --git a/app/Utils/HostedPDF/NinjaPdf.php b/app/Utils/HostedPDF/NinjaPdf.php index 7a6da2097b53..e0598b54c928 100644 --- a/app/Utils/HostedPDF/NinjaPdf.php +++ b/app/Utils/HostedPDF/NinjaPdf.php @@ -28,6 +28,6 @@ class NinjaPdf RequestOptions::JSON => ['html' => $html], ]); - return $response->getBody(); + return $response->getBody()->getContents(); } } From 93c96e0d7898e75b1f94fa3410665705075f1455 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 28 Nov 2022 12:24:07 +1100 Subject: [PATCH 02/29] Inject slight delay into emails --- app/Http/Controllers/EmailController.php | 4 ++-- app/Mail/Engine/InvoiceEmailEngine.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index 17b3f8ff0a78..fb081a9a4509 100644 --- a/app/Http/Controllers/EmailController.php +++ b/app/Http/Controllers/EmailController.php @@ -141,7 +141,7 @@ class EmailController extends BaseController if (! $invitation->contact->trashed() && $invitation->contact->email) { $entity_obj->service()->markSent()->save(); - EmailEntity::dispatch($invitation->fresh(), $invitation->company, $template, $data); + EmailEntity::dispatch($invitation->fresh(), $invitation->company, $template, $data)->delay(now()->addSeconds(2)); } }); @@ -194,7 +194,7 @@ class EmailController extends BaseController $data['template'] = $template; - PurchaseOrderEmail::dispatch($entity_obj, $entity_obj->company, $data); + PurchaseOrderEmail::dispatch($entity_obj, $entity_obj->company, $data)->delay(now()->addSeconds(2)); return $this->itemResponse($entity_obj); diff --git a/app/Mail/Engine/InvoiceEmailEngine.php b/app/Mail/Engine/InvoiceEmailEngine.php index e41f0fdc8c9f..fa88fa67a815 100644 --- a/app/Mail/Engine/InvoiceEmailEngine.php +++ b/app/Mail/Engine/InvoiceEmailEngine.php @@ -143,11 +143,11 @@ class InvoiceEmailEngine extends BaseEmailEngine // Storage::url foreach ($this->invoice->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => $document->getFile()]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } foreach ($this->invoice->company->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => $document->getFile()]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } $line_items = $this->invoice->line_items; @@ -165,7 +165,7 @@ class InvoiceEmailEngine extends BaseEmailEngine ->cursor() ->each(function ($expense) { foreach ($expense->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => $document->getFile()]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } }); } @@ -181,7 +181,7 @@ class InvoiceEmailEngine extends BaseEmailEngine ->cursor() ->each(function ($task) { foreach ($task->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => $document->getFile()]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } }); } From d0bb55f0c26a894c38a46c50d7fa3ffd001c5806 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 28 Nov 2022 14:16:46 +1100 Subject: [PATCH 03/29] Refactor remaining entities to attach using data rather than paths --- .../Company/ValidCompanyQuantity.php | 2 +- app/Mail/Engine/CreditEmailEngine.php | 21 ++++++---- app/Mail/Engine/PaymentEmailEngine.php | 15 ++++--- app/Mail/Engine/PurchaseOrderEmailEngine.php | 22 +++++++---- app/Mail/Engine/QuoteEmailEngine.php | 19 +++++---- app/Mail/TemplateEmail.php | 34 ++++++++-------- app/Mail/VendorTemplateEmail.php | 39 ++++++++++--------- lang/en/texts.php | 2 +- 8 files changed, 91 insertions(+), 63 deletions(-) diff --git a/app/Http/ValidationRules/Company/ValidCompanyQuantity.php b/app/Http/ValidationRules/Company/ValidCompanyQuantity.php index a90e861c9ae2..fa04edd4a721 100644 --- a/app/Http/ValidationRules/Company/ValidCompanyQuantity.php +++ b/app/Http/ValidationRules/Company/ValidCompanyQuantity.php @@ -39,6 +39,6 @@ class ValidCompanyQuantity implements Rule */ public function message() { - return ctrans('texts.company_limit_reached'); + return ctrans('texts.company_limit_reached', ['limit' => Ninja::isSelfHost() ? 10 : auth()->user()->company()->account->hosted_company_count]); } } diff --git a/app/Mail/Engine/CreditEmailEngine.php b/app/Mail/Engine/CreditEmailEngine.php index 12a12e600d88..25ac405d38ea 100644 --- a/app/Mail/Engine/CreditEmailEngine.php +++ b/app/Mail/Engine/CreditEmailEngine.php @@ -11,6 +11,7 @@ namespace App\Mail\Engine; +use App\Jobs\Entity\CreateRawPdf; use App\Models\Account; use App\Utils\HtmlEngine; use App\Utils\Ninja; @@ -117,11 +118,17 @@ class CreditEmailEngine extends BaseEmailEngine ->setTextBody($text_body); if ($this->client->getSetting('pdf_email_attachment') !== false && $this->credit->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { - if (Ninja::isHosted()) { - $this->setAttachments([$this->credit->pdf_file_path($this->invitation, 'url', true)]); - } else { - $this->setAttachments([$this->credit->pdf_file_path($this->invitation)]); - } + // if (Ninja::isHosted()) { + // $this->setAttachments([$this->credit->pdf_file_path($this->invitation, 'url', true)]); + // } else { + // $this->setAttachments([$this->credit->pdf_file_path($this->invitation)]); + // } + + $pdf = ((new CreateRawPdf($this->invitation, $this->invitation->company->db))->handle()); + + $this->setAttachments([['file' => base64_encode($pdf), 'name' => $this->credit->numberFormatter().'.pdf']]); + + } //attach third party documents @@ -129,11 +136,11 @@ class CreditEmailEngine extends BaseEmailEngine // Storage::url foreach ($this->credit->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } foreach ($this->credit->company->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } } diff --git a/app/Mail/Engine/PaymentEmailEngine.php b/app/Mail/Engine/PaymentEmailEngine.php index bf15b7aa2ca4..e9ad8767d284 100644 --- a/app/Mail/Engine/PaymentEmailEngine.php +++ b/app/Mail/Engine/PaymentEmailEngine.php @@ -12,6 +12,7 @@ namespace App\Mail\Engine; use App\DataMapper\EmailTemplateDefaults; +use App\Jobs\Entity\CreateRawPdf; use App\Models\Account; use App\Utils\Helpers; use App\Utils\Ninja; @@ -89,11 +90,15 @@ class PaymentEmailEngine extends BaseEmailEngine if ($this->client->getSetting('pdf_email_attachment') !== false && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { $this->payment->invoices->each(function ($invoice) { - if (Ninja::isHosted()) { - $this->setAttachments([$invoice->pdf_file_path($invoice->invitations->first(), 'url', true)]); - } else { - $this->setAttachments([$invoice->pdf_file_path($invoice->invitations->first())]); - } + // if (Ninja::isHosted()) { + // $this->setAttachments([$invoice->pdf_file_path($invoice->invitations->first(), 'url', true)]); + // } else { + // $this->setAttachments([$invoice->pdf_file_path($invoice->invitations->first())]); + // } + $pdf = ((new CreateRawPdf($invoice->invitations->first(), $invoice->company->db))->handle()); + + $this->setAttachments([['file' => base64_encode($pdf), 'name' => $invoice->numberFormatter().'.pdf']]); + }); } diff --git a/app/Mail/Engine/PurchaseOrderEmailEngine.php b/app/Mail/Engine/PurchaseOrderEmailEngine.php index fa6477c38c34..ce4a411b4840 100644 --- a/app/Mail/Engine/PurchaseOrderEmailEngine.php +++ b/app/Mail/Engine/PurchaseOrderEmailEngine.php @@ -13,6 +13,7 @@ namespace App\Mail\Engine; use App\DataMapper\EmailTemplateDefaults; use App\Jobs\Entity\CreateEntityPdf; +use App\Jobs\Vendor\CreatePurchaseOrderPdf; use App\Models\Account; use App\Models\Expense; use App\Models\PurchaseOrder; @@ -125,11 +126,16 @@ class PurchaseOrderEmailEngine extends BaseEmailEngine ->setTextBody($text_body); if ($this->vendor->getSetting('pdf_email_attachment') !== false && $this->purchase_order->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { - if (Ninja::isHosted()) { - $this->setAttachments([$this->purchase_order->pdf_file_path($this->invitation, 'url', true)]); - } else { - $this->setAttachments([$this->purchase_order->pdf_file_path($this->invitation)]); - } + // if (Ninja::isHosted()) { + // $this->setAttachments([$this->purchase_order->pdf_file_path($this->invitation, 'url', true)]); + // } else { + // $this->setAttachments([$this->purchase_order->pdf_file_path($this->invitation)]); + // } + + $pdf = (new CreatePurchaseOrderPdf($this->invitation))->rawPdf(); + + $this->setAttachments([['file' => base64_encode($pdf), 'name' => $this->purchase_order->numberFormatter().'.pdf']]); + } //attach third party documents @@ -137,11 +143,13 @@ class PurchaseOrderEmailEngine extends BaseEmailEngine // Storage::url foreach ($this->purchase_order->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + // $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } foreach ($this->purchase_order->company->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + // $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } } diff --git a/app/Mail/Engine/QuoteEmailEngine.php b/app/Mail/Engine/QuoteEmailEngine.php index 8b692c2f3e5d..5b1387ed6980 100644 --- a/app/Mail/Engine/QuoteEmailEngine.php +++ b/app/Mail/Engine/QuoteEmailEngine.php @@ -11,6 +11,7 @@ namespace App\Mail\Engine; +use App\Jobs\Entity\CreateRawPdf; use App\Models\Account; use App\Utils\HtmlEngine; use App\Utils\Ninja; @@ -116,11 +117,15 @@ class QuoteEmailEngine extends BaseEmailEngine ->setTextBody($text_body); if ($this->client->getSetting('pdf_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { - if (Ninja::isHosted()) { - $this->setAttachments([$this->quote->pdf_file_path($this->invitation, 'url', true)]); - } else { - $this->setAttachments([$this->quote->pdf_file_path($this->invitation)]); - } + // if (Ninja::isHosted()) { + // $this->setAttachments([$this->quote->pdf_file_path($this->invitation, 'url', true)]); + // } else { + // $this->setAttachments([$this->quote->pdf_file_path($this->invitation)]); + // } + + $pdf = ((new CreateRawPdf($this->invitation, $this->invitation->company->db))->handle()); + + $this->setAttachments([['file' => base64_encode($pdf), 'name' => $this->quote->numberFormatter().'.pdf']]); } //attach third party documents @@ -128,11 +133,11 @@ class QuoteEmailEngine extends BaseEmailEngine // Storage::url foreach ($this->quote->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } foreach ($this->quote->company->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } } diff --git a/app/Mail/TemplateEmail.php b/app/Mail/TemplateEmail.php index 8a892db39840..eb8bdaaed718 100644 --- a/app/Mail/TemplateEmail.php +++ b/app/Mail/TemplateEmail.php @@ -120,31 +120,31 @@ class TemplateEmail extends Mailable /*In the hosted platform we need to slow things down a little for Storage to catch up.*/ - if(Ninja::isHosted() && $this->invitation){ + // if(Ninja::isHosted() && $this->invitation){ - $path = false; + // $path = false; - if($this->invitation->invoice) - $path = $this->client->invoice_filepath($this->invitation).$this->invitation->invoice->numberFormatter().'.pdf'; - elseif($this->invitation->quote) - $path = $this->client->quote_filepath($this->invitation).$this->invitation->quote->numberFormatter().'.pdf'; - elseif($this->invitation->credit) - $path = $this->client->credit_filepath($this->invitation).$this->invitation->credit->numberFormatter().'.pdf'; + // if($this->invitation->invoice) + // $path = $this->client->invoice_filepath($this->invitation).$this->invitation->invoice->numberFormatter().'.pdf'; + // elseif($this->invitation->quote) + // $path = $this->client->quote_filepath($this->invitation).$this->invitation->quote->numberFormatter().'.pdf'; + // elseif($this->invitation->credit) + // $path = $this->client->credit_filepath($this->invitation).$this->invitation->credit->numberFormatter().'.pdf'; - sleep(1); + // sleep(1); - if($path && !Storage::disk(config('filesystems.default'))->exists($path)){ + // if($path && !Storage::disk(config('filesystems.default'))->exists($path)){ - sleep(2); + // sleep(2); - if(!Storage::disk(config('filesystems.default'))->exists($path)) { - (new CreateEntityPdf($this->invitation))->handle(); - sleep(2); - } + // if(!Storage::disk(config('filesystems.default'))->exists($path)) { + // (new CreateEntityPdf($this->invitation))->handle(); + // sleep(2); + // } - } + // } - } + // } // $file = (new CreateRawPdf($invitation, $invitation->company->db))->handle(); diff --git a/app/Mail/VendorTemplateEmail.php b/app/Mail/VendorTemplateEmail.php index 670a59e93676..0c8dae6738f2 100644 --- a/app/Mail/VendorTemplateEmail.php +++ b/app/Mail/VendorTemplateEmail.php @@ -116,34 +116,37 @@ class VendorTemplateEmail extends Mailable //}); // ->tag($this->company->company_key); - if(Ninja::isHosted() && $this->invitation){ + // if(Ninja::isHosted() && $this->invitation){ - $path = false; + // $path = false; - if($this->invitation->purchase_order) - $path = $this->vendor->purchase_order_filepath($this->invitation).$this->invitation->purchase_order->numberFormatter().'.pdf'; + // if($this->invitation->purchase_order) + // $path = $this->vendor->purchase_order_filepath($this->invitation).$this->invitation->purchase_order->numberFormatter().'.pdf'; - sleep(1); + // sleep(1); - if($path && !Storage::disk(config('filesystems.default'))->exists($path)){ + // if($path && !Storage::disk(config('filesystems.default'))->exists($path)){ - sleep(2); + // sleep(2); - if(!Storage::disk(config('filesystems.default'))->exists($path)) { - (new CreatePurchaseOrderPdf($this->invitation))->handle(); - sleep(2); - } + // if(!Storage::disk(config('filesystems.default'))->exists($path)) { + // (new CreatePurchaseOrderPdf($this->invitation))->handle(); + // sleep(2); + // } - } + // } - } + // } foreach ($this->build_email->getAttachments() as $file) { - if (is_string($file)) { - $this->attach($file); - } elseif (is_array($file)) { - $this->attach($file['path'], ['as' => $file['name'], 'mime' => null]); - } + // if (is_string($file)) { + // $this->attach($file); + // } elseif (is_array($file)) { + // $this->attach($file['path'], ['as' => $file['name'], 'mime' => null]); + // } + + $this->attachData(base64_decode($file['file']), $file['name']); + } return $this; diff --git a/lang/en/texts.php b/lang/en/texts.php index 1bc294749e4a..10c511a9ab0a 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -4061,7 +4061,7 @@ $LANG = array( 'save_payment_method_details' => 'Save payment method details', 'new_card' => 'New card', 'new_bank_account' => 'New bank account', - 'company_limit_reached' => 'Limit of 10 companies per account.', + 'company_limit_reached' => 'Limit of :limit companies per account.', 'credits_applied_validation' => 'Total credits applied cannot be MORE than total of invoices', 'credit_number_taken' => 'Credit number already taken', 'credit_not_found' => 'Credit not found', From 448d3a22464c7bb0630bd8e94f33f096c18a6498 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 28 Nov 2022 15:45:25 +1100 Subject: [PATCH 04/29] Refactor for attachments --- app/Mail/Engine/InvoiceEmailEngine.php | 8 ++++---- app/Mail/Engine/PurchaseOrderEmailEngine.php | 8 ++++---- app/Mail/Engine/QuoteEmailEngine.php | 6 +++--- app/Mail/TemplateEmail.php | 7 +++++-- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/Mail/Engine/InvoiceEmailEngine.php b/app/Mail/Engine/InvoiceEmailEngine.php index fa88fa67a815..69810ba626ca 100644 --- a/app/Mail/Engine/InvoiceEmailEngine.php +++ b/app/Mail/Engine/InvoiceEmailEngine.php @@ -143,11 +143,11 @@ class InvoiceEmailEngine extends BaseEmailEngine // Storage::url foreach ($this->invoice->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, ]]); } foreach ($this->invoice->company->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, ]]); } $line_items = $this->invoice->line_items; @@ -165,7 +165,7 @@ class InvoiceEmailEngine extends BaseEmailEngine ->cursor() ->each(function ($expense) { foreach ($expense->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, ]]); } }); } @@ -181,7 +181,7 @@ class InvoiceEmailEngine extends BaseEmailEngine ->cursor() ->each(function ($task) { foreach ($task->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, ]]); } }); } diff --git a/app/Mail/Engine/PurchaseOrderEmailEngine.php b/app/Mail/Engine/PurchaseOrderEmailEngine.php index ce4a411b4840..f11e046b68e2 100644 --- a/app/Mail/Engine/PurchaseOrderEmailEngine.php +++ b/app/Mail/Engine/PurchaseOrderEmailEngine.php @@ -143,13 +143,13 @@ class PurchaseOrderEmailEngine extends BaseEmailEngine // Storage::url foreach ($this->purchase_order->documents as $document) { - // $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + // $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } foreach ($this->purchase_order->company->documents as $document) { - // $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => null]]); + // $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); } } diff --git a/app/Mail/Engine/QuoteEmailEngine.php b/app/Mail/Engine/QuoteEmailEngine.php index 5b1387ed6980..63271c0600ba 100644 --- a/app/Mail/Engine/QuoteEmailEngine.php +++ b/app/Mail/Engine/QuoteEmailEngine.php @@ -123,7 +123,7 @@ class QuoteEmailEngine extends BaseEmailEngine // $this->setAttachments([$this->quote->pdf_file_path($this->invitation)]); // } - $pdf = ((new CreateRawPdf($this->invitation, $this->invitation->company->db))->handle()); + $pdf = ((new CreateRawPdf($this->invitation, $this->invitation->company->db))->handle()); $this->setAttachments([['file' => base64_encode($pdf), 'name' => $this->quote->numberFormatter().'.pdf']]); } @@ -133,11 +133,11 @@ class QuoteEmailEngine extends BaseEmailEngine // Storage::url foreach ($this->quote->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, ]]); } foreach ($this->quote->company->documents as $document) { - $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, 'file' => base64_encode($document->getFile())]]); + $this->setAttachments([['path' => $document->filePath(), 'name' => $document->name, 'mime' => NULL, ]]); } } diff --git a/app/Mail/TemplateEmail.php b/app/Mail/TemplateEmail.php index eb8bdaaed718..b5b443657f78 100644 --- a/app/Mail/TemplateEmail.php +++ b/app/Mail/TemplateEmail.php @@ -162,8 +162,11 @@ class TemplateEmail extends Mailable // // $this->attachData($file_data, $file['name']); // $this->attach($file['path'], ['as' => $file['name'], 'mime' => null]); // } - - $this->attachData(base64_decode($file['file']), $file['name']); + if(array_key_exists('file', $file)) + $this->attachData(base64_decode($file['file']), $file['name']); + else + $this->attach($file['path'], ['as' => $file['name'], 'mime' => null]); + } if ($this->invitation && $this->invitation->invoice && $settings->ubl_email_attachment && $this->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) { From 91126b2dad49189bf6370da23c0c7e8f4dcf5899 Mon Sep 17 00:00:00 2001 From: Lars Kusch Date: Tue, 29 Nov 2022 09:15:23 +0100 Subject: [PATCH 05/29] Translate Stripe payment texts --- app/PaymentDrivers/Stripe/Charge.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/Stripe/Charge.php b/app/PaymentDrivers/Stripe/Charge.php index 691f6ca5bb13..a9751a49ca73 100644 --- a/app/PaymentDrivers/Stripe/Charge.php +++ b/app/PaymentDrivers/Stripe/Charge.php @@ -62,9 +62,9 @@ class Charge $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); if ($invoice) { - $description = "Invoice {$invoice->number} for {$amount} for client {$this->stripe->client->present()->name()}"; + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => $amount, 'client' => $this->stripe->client->present()->name()]); } else { - $description = "Payment with no invoice for amount {$amount} for client {$this->stripe->client->present()->name()}"; + $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => $amount, 'client' => $this->stripe->client->present()->name()]); } $this->stripe->init(); From e9820ee984e8f8d896c63d47fb8bae47c79c2793 Mon Sep 17 00:00:00 2001 From: Lars Kusch Date: Tue, 29 Nov 2022 09:18:41 +0100 Subject: [PATCH 06/29] Add translation strings --- lang/en/texts.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lang/en/texts.php b/lang/en/texts.php index 1bc294749e4a..ce33ae3b3693 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -254,6 +254,8 @@ $LANG = array( 'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.', 'notification_invoice_sent' => 'The following client :client was emailed Invoice :invoice for :amount.', 'notification_invoice_viewed' => 'The following client :client viewed Invoice :invoice for :amount.', + 'stripe_paymenttext' => 'Invoice :invoicenumber for :amount for client :client', + 'stripe_paymenttext_without_invoice' => 'Payment with no invoice for amount :amount for client :client', 'reset_password' => 'You can reset your account password by clicking the following button:', 'secure_payment' => 'Secure Payment', 'card_number' => 'Card Number', From eecc2bb8af4f095319e94b9ce1f1f51b1f45b2dc Mon Sep 17 00:00:00 2001 From: Lars Kusch Date: Tue, 29 Nov 2022 09:28:37 +0100 Subject: [PATCH 07/29] ACH translations --- app/PaymentDrivers/Stripe/ACH.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/PaymentDrivers/Stripe/ACH.php b/app/PaymentDrivers/Stripe/ACH.php index 2a5689ccf901..c40ad045d64f 100644 --- a/app/PaymentDrivers/Stripe/ACH.php +++ b/app/PaymentDrivers/Stripe/ACH.php @@ -172,9 +172,9 @@ class ACH ->first(); if ($invoice) { - $description = "Invoice {$invoice->number} for {$amount} for client {$this->stripe->client->present()->name()}"; + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => $amount, 'client' => $this->stripe->client->present()->name()]); } else { - $description = "Payment with no invoice for amount {$amount} for client {$this->stripe->client->present()->name()}"; + $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => $amount, 'client' => $this->stripe->client->present()->name()]); } @@ -210,9 +210,9 @@ class ACH ->first(); if ($invoice) { - $description = "Invoice {$invoice->number} for {$amount} for client {$this->stripe->client->present()->name()}"; + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => $amount, 'client' => $this->stripe->client->present()->name()]); } else { - $description = "Payment with no invoice for amount {$amount} for client {$this->stripe->client->present()->name()}"; + $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => $amount, 'client' => $this->stripe->client->present()->name()]); } if (substr($cgt->token, 0, 2) === 'pm') { @@ -454,9 +454,9 @@ class ACH ->first(); if ($invoice) { - $description = "Invoice {$invoice->number} for {$amount} for client {$this->stripe->client->present()->name()}"; + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => $amount, 'client' => $this->stripe->client->present()->name()]); } else { - $description = "Payment with no invoice for amount {$amount} for client {$this->stripe->client->present()->name()}"; + $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => $amount, 'client' => $this->stripe->client->present()->name()]); } if (substr($source->token, 0, 2) === 'pm') { From 40a78a433631be01da59b37c83aed7db681ce6cd Mon Sep 17 00:00:00 2001 From: Lars Kusch Date: Tue, 29 Nov 2022 09:33:13 +0100 Subject: [PATCH 08/29] Add translation --- app/PaymentDrivers/Stripe/CreditCard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/PaymentDrivers/Stripe/CreditCard.php b/app/PaymentDrivers/Stripe/CreditCard.php index 838af9c2328c..445a513049a8 100644 --- a/app/PaymentDrivers/Stripe/CreditCard.php +++ b/app/PaymentDrivers/Stripe/CreditCard.php @@ -62,7 +62,7 @@ class CreditCard // $description = $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')) . " for client {$this->stripe->client->present()->name()}"; $invoice_numbers = collect($data['invoices'])->pluck('invoice_number')->implode(','); - $description = "Invoices: {$invoice_numbers} for {$data['total']['amount_with_fee']} for client {$this->stripe->client->present()->name()}"; + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice_numbers, 'amount' => $data['total']['amount_with_fee'], 'client' => $this->stripe->client->present()->name()]); $payment_intent_data = [ 'amount' => $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency()), From 974d2f9c755fbe0e12f1aa9814f1b795b15b7f34 Mon Sep 17 00:00:00 2001 From: Lars Kusch Date: Tue, 29 Nov 2022 09:54:05 +0100 Subject: [PATCH 09/29] Add currency sign to text --- app/PaymentDrivers/Stripe/Charge.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/Stripe/Charge.php b/app/PaymentDrivers/Stripe/Charge.php index a9751a49ca73..94798d485c79 100644 --- a/app/PaymentDrivers/Stripe/Charge.php +++ b/app/PaymentDrivers/Stripe/Charge.php @@ -32,6 +32,7 @@ use Stripe\Exception\CardException; use Stripe\Exception\InvalidRequestException; use Stripe\Exception\RateLimitException; use Stripe\StripeClient; +use App\Utils\Number; class Charge { @@ -62,9 +63,9 @@ class Charge $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); if ($invoice) { - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => $amount, 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { - $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => $amount, 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } $this->stripe->init(); From dd5c8129692a1fd0dd95866f8227718b65d8a266 Mon Sep 17 00:00:00 2001 From: Lars Kusch Date: Tue, 29 Nov 2022 09:55:20 +0100 Subject: [PATCH 10/29] Add currency sign --- app/PaymentDrivers/Stripe/ACH.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/PaymentDrivers/Stripe/ACH.php b/app/PaymentDrivers/Stripe/ACH.php index c40ad045d64f..cd386b8287b3 100644 --- a/app/PaymentDrivers/Stripe/ACH.php +++ b/app/PaymentDrivers/Stripe/ACH.php @@ -36,6 +36,7 @@ use Stripe\Exception\CardException; use Stripe\Exception\InvalidRequestException; use Stripe\Exception\RateLimitException; use Stripe\PaymentIntent; +use App\Utils\Number; class ACH { @@ -172,9 +173,9 @@ class ACH ->first(); if ($invoice) { - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => $amount, 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { - $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => $amount, 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } @@ -210,9 +211,9 @@ class ACH ->first(); if ($invoice) { - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => $amount, 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { - $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => $amount, 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } if (substr($cgt->token, 0, 2) === 'pm') { @@ -454,9 +455,9 @@ class ACH ->first(); if ($invoice) { - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => $amount, 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { - $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => $amount, 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } if (substr($source->token, 0, 2) === 'pm') { From c3a1d21c61cd931800c6be4d711179f9f7928133 Mon Sep 17 00:00:00 2001 From: Lars Kusch Date: Tue, 29 Nov 2022 09:56:16 +0100 Subject: [PATCH 11/29] Add currency sign --- app/PaymentDrivers/Stripe/CreditCard.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/PaymentDrivers/Stripe/CreditCard.php b/app/PaymentDrivers/Stripe/CreditCard.php index 445a513049a8..5fb8bd2e2d6a 100644 --- a/app/PaymentDrivers/Stripe/CreditCard.php +++ b/app/PaymentDrivers/Stripe/CreditCard.php @@ -23,6 +23,7 @@ use App\PaymentDrivers\StripePaymentDriver; use App\PaymentDrivers\Stripe\Jobs\UpdateCustomer; use Stripe\PaymentIntent; use Stripe\PaymentMethod; +use App\Utils\Number; class CreditCard { @@ -62,7 +63,7 @@ class CreditCard // $description = $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')) . " for client {$this->stripe->client->present()->name()}"; $invoice_numbers = collect($data['invoices'])->pluck('invoice_number')->implode(','); - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice_numbers, 'amount' => $data['total']['amount_with_fee'], 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice_numbers, 'amount' => Number::formatMoney($data['total']['amount_with_fee'], $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); $payment_intent_data = [ 'amount' => $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency()), From 0815a0ff69d53cb5b73663a1419b7c72eba82a54 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 29 Nov 2022 23:14:01 +1100 Subject: [PATCH 12/29] Implement checkout object for phone --- app/PaymentDrivers/CheckoutCom/CreditCard.php | 2 -- app/PaymentDrivers/CheckoutComPaymentDriver.php | 10 +++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/PaymentDrivers/CheckoutCom/CreditCard.php b/app/PaymentDrivers/CheckoutCom/CreditCard.php index 27e6c4d67243..1ada04574b5e 100644 --- a/app/PaymentDrivers/CheckoutCom/CreditCard.php +++ b/app/PaymentDrivers/CheckoutCom/CreditCard.php @@ -94,8 +94,6 @@ class CreditCard implements MethodInterface $customerRequest = $this->checkout->getCustomer(); - nlog($customerRequest); - $request = $this->bootRequest($gateway_response->token); $request->capture = false; $request->reference = '$1 payment for authorization.'; diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index daa9aa7fcd68..c59534a05788 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -34,6 +34,7 @@ use Checkout\CheckoutArgumentException; use Checkout\CheckoutAuthorizationException; use Checkout\CheckoutDefaultSdk; use Checkout\CheckoutFourSdk; +use Checkout\Common\Phone; use Checkout\Customers\CustomerRequest; use Checkout\Customers\Four\CustomerRequest as FourCustomerRequest; use Checkout\Environment; @@ -300,9 +301,12 @@ class CheckoutComPaymentDriver extends BaseDriver $request = new CustomerRequest(); } - $request->email = $this->client->present()->email(); - $request->name = $this->client->present()->name(); - $request->phone = $this->client->present()->phone(); + $phone = new Phone(); + $phone->number = $this->client->present()->phone(); + + $request->email = $this->client->present()->email(); + $request->name = $this->client->present()->name(); + $request->phone = $phone; try { $response = $this->gateway->getCustomersClient()->create($request); From ca75d0078ba8f45ea0c52f07742bcfee4d479027 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 07:37:50 +1100 Subject: [PATCH 13/29] Minor fixes for Stripe Payment Intent query --- app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php index 1caf382e567f..d3a8ad40e7d6 100644 --- a/app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php +++ b/app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php @@ -66,11 +66,9 @@ class PaymentIntentWebhook implements ShouldQueue { $payment = Payment::query() ->where('company_id', $company->id) - ->where(function ($query) use ($transaction) { - $query->where('transaction_reference', $transaction['payment_intent']) - ->orWhere('transaction_reference', $transaction['id']); - }) + ->where('transaction_reference', $transaction['payment_intent']) ->first(); + } else { From 925a6bdfc92d28be136d60faa7c3ce1694be4ca6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 08:25:24 +1100 Subject: [PATCH 14/29] Fixes for when no bank integration id is sent --- .../Requests/BankIntegration/StoreBankIntegrationRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Requests/BankIntegration/StoreBankIntegrationRequest.php b/app/Http/Requests/BankIntegration/StoreBankIntegrationRequest.php index 933f5848624d..80b53208a712 100644 --- a/app/Http/Requests/BankIntegration/StoreBankIntegrationRequest.php +++ b/app/Http/Requests/BankIntegration/StoreBankIntegrationRequest.php @@ -44,7 +44,7 @@ class StoreBankIntegrationRequest extends Request { $input = $this->all(); - if(!array_key_exists('provider_name', $input) || strlen($input['provider_name']) == 0 && array_key_exists('bank_account_name', $input)) + if((!array_key_exists('provider_name', $input) || strlen($input['provider_name']) == 0) && array_key_exists('bank_account_name', $input)) $input['provider_name'] = $input['bank_account_name']; $this->replace($input); From bf3713cf4fff41b8db2ede87e8c754ada7e2531e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 08:38:25 +1100 Subject: [PATCH 15/29] Fixes for store bank transaction --- .../Requests/BankTransaction/StoreBankTransactionRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php b/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php index 529eaa79a61a..98d199aa623b 100644 --- a/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php +++ b/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php @@ -44,7 +44,9 @@ class StoreBankTransactionRequest extends Request { $input = $this->all(); - if(array_key_exists('bank_integration_id', $input) && strlen($input['bank_integration_id']) > 1 && !is_numeric($input['bank_integration_id'])) + if(array_key_exists('bank_integration_id', $input) && $input['bank_integration_id'] == "") + unset($input['bank_integration_id']); + elseif(array_key_exists('bank_integration_id', $input) && strlen($input['bank_integration_id']) > 1 && !is_numeric($input['bank_integration_id'])) $input['bank_integration_id'] = $this->decodePrimaryKey($input['bank_integration_id']); $this->replace($input); From 0423e2f9b1ae635cd53fa8542b018f070a520e27 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 08:38:59 +1100 Subject: [PATCH 16/29] Fixes for store bank transaction --- .../Requests/BankTransaction/UpdateBankTransactionRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php b/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php index 4f251c916766..ed3ba8388544 100644 --- a/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php +++ b/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php @@ -69,7 +69,9 @@ class UpdateBankTransactionRequest extends Request if(array_key_exists('ninja_category_id', $input) && strlen($input['ninja_category_id']) > 1) $input['ninja_category_id'] = $this->decodePrimaryKey($input['ninja_category_id']); - if(array_key_exists('bank_integration_id', $input) && strlen($input['bank_integration_id']) > 1) + if(array_key_exists('bank_integration_id', $input) && $input['bank_integration_id'] == "") + unset($input['bank_integration_id']); + elseif(array_key_exists('bank_integration_id', $input) && strlen($input['bank_integration_id']) > 1) $input['bank_integration_id'] = $this->decodePrimaryKey($input['bank_integration_id']); $this->replace($input); From 9ff6bdc10448d5ec8af6877a0b68a2c9ba440a93 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 09:06:12 +1100 Subject: [PATCH 17/29] Add frequency to recurring invoice export --- app/Export/CSV/RecurringInvoiceExport.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Export/CSV/RecurringInvoiceExport.php b/app/Export/CSV/RecurringInvoiceExport.php index 30accbd22511..1bacb9d6a301 100644 --- a/app/Export/CSV/RecurringInvoiceExport.php +++ b/app/Export/CSV/RecurringInvoiceExport.php @@ -54,6 +54,7 @@ class RecurringInvoiceExport extends BaseExport 'po_number' => 'po_number', 'private_notes' => 'private_notes', 'public_notes' => 'public_notes', + 'next_send_date' => 'next_send_date', 'status' => 'status_id', 'tax_name1' => 'tax_name1', 'tax_name2' => 'tax_name2', @@ -66,6 +67,7 @@ class RecurringInvoiceExport extends BaseExport 'currency' => 'currency_id', 'vendor' => 'vendor_id', 'project' => 'project_id', + 'frequency' => 'frequency_id' ]; private array $decorate_keys = [ @@ -162,6 +164,8 @@ class RecurringInvoiceExport extends BaseExport $entity['vendor'] = $invoice->vendor ? $invoice->vendor->name : ''; } + $entity['frequency'] = $invoice->frequencyForKey($invoice->frequency_id); + return $entity; } } From b6035ca6760cda4905dcb5ddb158f44814011335 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 09:18:49 +1100 Subject: [PATCH 18/29] Fixes for storing bank transactions --- .../Requests/BankTransaction/StoreBankTransactionRequest.php | 3 +-- .../Requests/BankTransaction/UpdateBankTransactionRequest.php | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php b/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php index 98d199aa623b..c2e6fe68bde9 100644 --- a/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php +++ b/app/Http/Requests/BankTransaction/StoreBankTransactionRequest.php @@ -34,8 +34,7 @@ class StoreBankTransactionRequest extends Request $rules = []; - if(isset($this->bank_integration_id)) - $rules['bank_integration_id'] = 'bail|required|exists:bank_integrations,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; + $rules['bank_integration_id'] = 'bail|required|exists:bank_integrations,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; return $rules; } diff --git a/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php b/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php index ed3ba8388544..54f789714316 100644 --- a/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php +++ b/app/Http/Requests/BankTransaction/UpdateBankTransactionRequest.php @@ -45,8 +45,7 @@ class UpdateBankTransactionRequest extends Request if(isset($this->expense_id)) $rules['expense_id'] = 'bail|required|exists:expenses,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; - if(isset($this->bank_integration_id)) - $rules['bank_integration_id'] = 'bail|required|exists:bank_integrations,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; + $rules['bank_integration_id'] = 'bail|required|exists:bank_integrations,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; return $rules; From b63b53e9d39d80d4717e5e77da3c6918504bf758 Mon Sep 17 00:00:00 2001 From: checkitsedo <56700394+checkitsedo@users.noreply.github.com> Date: Wed, 30 Nov 2022 00:52:27 +0100 Subject: [PATCH 19/29] Add CSV delimiter Autodetection Line 139 and Lines 162-173: Checks $csvfile for the most accurate delimiter ($bestDelimiter) Line 140: Sets the Delimiter for league/csv Reader --- app/Http/Controllers/ImportController.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 25cc858e7500..41102869a90e 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -136,6 +136,8 @@ class ImportController extends Controller } $csv = Reader::createFromString($csvfile); + $csvdelimiter = self::detectDelimiter($csvfile); + $csv->setDelimiter($csvdelimiter); $stmt = new Statement(); $data = iterator_to_array($stmt->process($csv)); @@ -156,4 +158,17 @@ class ImportController extends Controller return $data; } + + public function detectDelimiter($csvfile) + { + $delimiters = array(',', '.', ';'); + $bestDelimiter = false; + $count = 0; + foreach ($delimiters as $delimiter) + if (substr_count($csvfile, $delimiter) > $count) { + $count = substr_count($csvfile, $delimiter); + $bestDelimiter = $delimiter; + } + return $bestDelimiter; + } } From eb0bdd12baf79f5d04c63e970027df0258a45937 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 11:46:02 +1100 Subject: [PATCH 20/29] Fixes for CSV imports, replace work_phone with phone --- app/Http/Controllers/OpenAPI/VendorSchema.php | 2 +- .../Transformer/Csv/ClientTransformer.php | 2 +- .../Transformer/Wave/ClientTransformer.php | 2 +- app/Import/Transformers/ClientTransformer.php | 2 +- .../Transformers/Csv/ClientTransformer.php | 2 +- .../Freshbooks/ClientTransformer.php | 2 +- .../Invoicely/ClientTransformer.php | 2 +- .../Waveaccounting/ClientTransformer.php | 2 +- .../Transformers/Zoho/ClientTransformer.php | 2 +- app/Models/Presenters/CompanyPresenter.php | 2 +- app/Repositories/ClientRepository.php | 18 +- app/Utils/Traits/ClientGroupSettingsSaver.php | 15 +- tests/Feature/ClientApiTest.php | 307 ++++++++++++++++++ 13 files changed, 323 insertions(+), 37 deletions(-) diff --git a/app/Http/Controllers/OpenAPI/VendorSchema.php b/app/Http/Controllers/OpenAPI/VendorSchema.php index 8cf71c4ca9ea..a50df21d6f07 100644 --- a/app/Http/Controllers/OpenAPI/VendorSchema.php +++ b/app/Http/Controllers/OpenAPI/VendorSchema.php @@ -26,7 +26,7 @@ * @OA\Property(property="city", type="string", example="", description="________"), * @OA\Property(property="state", type="string", example="", description="________"), * @OA\Property(property="postal_code", type="string", example="", description="________"), - * @OA\Property(property="work_phone", type="string", example="555-3434-3434", description="The client phone number"), + * @OA\Property(property="phone", type="string", example="555-3434-3434", description="The client phone number"), * @OA\Property(property="country_id", type="string", example="", description="________"), * @OA\Property(property="currency_id", type="string", example="4", description="________"), * @OA\Property(property="custom_value1", type="string", example="", description="________"), diff --git a/app/Import/Transformer/Csv/ClientTransformer.php b/app/Import/Transformer/Csv/ClientTransformer.php index a2c4721bb8eb..543ad1cd205a 100644 --- a/app/Import/Transformer/Csv/ClientTransformer.php +++ b/app/Import/Transformer/Csv/ClientTransformer.php @@ -38,7 +38,7 @@ class ClientTransformer extends BaseTransformer return [ 'company_id' => $this->company->id, 'name' => $this->getString($data, 'client.name'), - 'work_phone' => $this->getString($data, 'client.phone'), + 'phone' => $this->getString($data, 'client.phone'), 'address1' => $this->getString($data, 'client.address1'), 'address2' => $this->getString($data, 'client.address2'), 'postal_code' => $this->getString($data, 'client.postal_code'), diff --git a/app/Import/Transformer/Wave/ClientTransformer.php b/app/Import/Transformer/Wave/ClientTransformer.php index c5681e411152..844560f48679 100644 --- a/app/Import/Transformer/Wave/ClientTransformer.php +++ b/app/Import/Transformer/Wave/ClientTransformer.php @@ -42,7 +42,7 @@ class ClientTransformer extends BaseTransformer 'company_id' => $this->company->id, 'name' => $this->getString($data, 'customer_name'), 'number' => $this->getValueOrNull($data, 'account_number'), - 'work_phone' => $this->getString($data, 'phone'), + 'phone' => $this->getString($data, 'phone'), 'website' => $this->getString($data, 'website'), 'country_id' => ! empty($data['country']) ? $this->getCountryId($data['country']) : null, 'state' => $this->getString($data, 'province/state'), diff --git a/app/Import/Transformers/ClientTransformer.php b/app/Import/Transformers/ClientTransformer.php index 1e7ed43ae226..a77af36b5693 100644 --- a/app/Import/Transformers/ClientTransformer.php +++ b/app/Import/Transformers/ClientTransformer.php @@ -35,7 +35,7 @@ class ClientTransformer extends BaseTransformer return [ 'company_id' => $this->maps['company']->id, 'name' => $this->getString($data, 'client.name'), - 'work_phone' => $this->getString($data, 'client.phone'), + 'phone' => $this->getString($data, 'client.phone'), 'address1' => $this->getString($data, 'client.address1'), 'address2' => $this->getString($data, 'client.address2'), 'city' => $this->getString($data, 'client.city'), diff --git a/app/Import/Transformers/Csv/ClientTransformer.php b/app/Import/Transformers/Csv/ClientTransformer.php index 55d0baa8a1fa..44f826e1bbb5 100644 --- a/app/Import/Transformers/Csv/ClientTransformer.php +++ b/app/Import/Transformers/Csv/ClientTransformer.php @@ -37,7 +37,7 @@ class ClientTransformer extends BaseTransformer return [ 'company_id' => $this->maps['company']->id, 'name' => $this->getString($data, 'client.name'), - 'work_phone' => $this->getString($data, 'client.phone'), + 'phone' => $this->getString($data, 'client.phone'), 'address1' => $this->getString($data, 'client.address1'), 'address2' => $this->getString($data, 'client.address2'), 'postal_code' => $this->getString($data, 'client.postal_code'), diff --git a/app/Import/Transformers/Freshbooks/ClientTransformer.php b/app/Import/Transformers/Freshbooks/ClientTransformer.php index bfa8743ed62d..5b82f400c223 100644 --- a/app/Import/Transformers/Freshbooks/ClientTransformer.php +++ b/app/Import/Transformers/Freshbooks/ClientTransformer.php @@ -34,7 +34,7 @@ class ClientTransformer extends BaseTransformer return [ 'company_id' => $this->maps['company']->id, 'name' => $this->getString($data, 'Organization'), - 'work_phone' => $this->getString($data, 'Phone'), + 'phone' => $this->getString($data, 'Phone'), 'address1' => $this->getString($data, 'Street'), 'city' => $this->getString($data, 'City'), 'state' => $this->getString($data, 'Province/State'), diff --git a/app/Import/Transformers/Invoicely/ClientTransformer.php b/app/Import/Transformers/Invoicely/ClientTransformer.php index ddf3645b3610..5e2d58ae4a09 100644 --- a/app/Import/Transformers/Invoicely/ClientTransformer.php +++ b/app/Import/Transformers/Invoicely/ClientTransformer.php @@ -34,7 +34,7 @@ class ClientTransformer extends BaseTransformer return [ 'company_id' => $this->maps['company']->id, 'name' => $this->getString($data, 'Client Name'), - 'work_phone' => $this->getString($data, 'Phone'), + 'phone' => $this->getString($data, 'Phone'), 'country_id' => isset($data['Country']) ? $this->getCountryIdBy2($data['Country']) : null, 'credit_balance' => 0, 'settings' => new \stdClass, diff --git a/app/Import/Transformers/Waveaccounting/ClientTransformer.php b/app/Import/Transformers/Waveaccounting/ClientTransformer.php index a19616f968f1..f9b95a42e487 100644 --- a/app/Import/Transformers/Waveaccounting/ClientTransformer.php +++ b/app/Import/Transformers/Waveaccounting/ClientTransformer.php @@ -42,7 +42,7 @@ class ClientTransformer extends BaseTransformer 'company_id' => $this->maps['company']->id, 'name' => $this->getString($data, 'customer_name'), 'number' => $this->getString($data, 'account_number'), - 'work_phone' => $this->getString($data, 'phone'), + 'phone' => $this->getString($data, 'phone'), 'website' => $this->getString($data, 'website'), 'country_id' => ! empty($data['country']) ? $this->getCountryId($data['country']) : null, 'state' => $this->getString($data, 'province/state'), diff --git a/app/Import/Transformers/Zoho/ClientTransformer.php b/app/Import/Transformers/Zoho/ClientTransformer.php index e8e618d189be..6895fabdaeb2 100644 --- a/app/Import/Transformers/Zoho/ClientTransformer.php +++ b/app/Import/Transformers/Zoho/ClientTransformer.php @@ -41,7 +41,7 @@ class ClientTransformer extends BaseTransformer return [ 'company_id' => $this->maps['company']->id, 'name' => $this->getString($data, 'Company Name'), - 'work_phone' => $this->getString($data, 'Phone'), + 'phone' => $this->getString($data, 'Phone'), 'private_notes' => $this->getString($data, 'Notes'), 'website' => $this->getString($data, 'Website'), 'id_number' => $this->getString($data, 'Customer ID'), diff --git a/app/Models/Presenters/CompanyPresenter.php b/app/Models/Presenters/CompanyPresenter.php index 57408a788590..9d44bee8c60d 100644 --- a/app/Models/Presenters/CompanyPresenter.php +++ b/app/Models/Presenters/CompanyPresenter.php @@ -119,7 +119,7 @@ class CompanyPresenter extends EntityPresenter $str .= e($country->name).'
'; } if ($settings->phone) { - $str .= ctrans('texts.work_phone').': '.e($settings->phone).'
'; + $str .= ctrans('texts.phone').': '.e($settings->phone).'
'; } if ($settings->email) { $str .= ctrans('texts.work_email').': '.e($settings->email).'
'; diff --git a/app/Repositories/ClientRepository.php b/app/Repositories/ClientRepository.php index 23c6ae8cee28..6114916e80ad 100644 --- a/app/Repositories/ClientRepository.php +++ b/app/Repositories/ClientRepository.php @@ -56,6 +56,8 @@ class ClientRepository extends BaseRepository */ public function save(array $data, Client $client) : ?Client { + $contact_data = $data; + unset($data['contacts']); /* When uploading documents, only the document array is sent, so we must return early*/ if (array_key_exists('documents', $data) && count($data['documents']) >= 1) { @@ -67,7 +69,7 @@ class ClientRepository extends BaseRepository $client->fill($data); if (array_key_exists('settings', $data)) { - $client->saveSettings($data['settings'], $client); + $client->settings = $client->saveSettings($data['settings'], $client); } if (! $client->country_id) { @@ -75,19 +77,9 @@ class ClientRepository extends BaseRepository $client->country_id = $company->settings->country_id; } - try{ - $client->save(); - } - catch(\Exception $e) { - - nlog("client save failed"); - nlog($data); - - } + $client->save(); if (! isset($client->number) || empty($client->number) || strlen($client->number) == 0) { - // $client->number = $this->getNextClientNumber($client); - // $client->save(); $x = 1; @@ -111,7 +103,7 @@ class ClientRepository extends BaseRepository $data['name'] = $client->present()->name(); } - $this->contact_repo->save($data, $client); + $this->contact_repo->save($contact_data, $client); return $client; } diff --git a/app/Utils/Traits/ClientGroupSettingsSaver.php b/app/Utils/Traits/ClientGroupSettingsSaver.php index 67c2b6a774b3..270f2e0588cb 100644 --- a/app/Utils/Traits/ClientGroupSettingsSaver.php +++ b/app/Utils/Traits/ClientGroupSettingsSaver.php @@ -30,7 +30,7 @@ trait ClientGroupSettingsSaver * Saves a setting object. * * Works for groups|clients|companies - * @param array $settings The request input settings array + * @param array|object $settings The request input settings array * @param object $entity The entity which the settings belongs to * @return void */ @@ -64,19 +64,6 @@ trait ClientGroupSettingsSaver $entity_settings->{$key} = $value; } - $entity->settings = $entity_settings; - - try{ - $entity->save(); - } - catch(\Exception $e){ - - nlog("client settings failure"); - nlog($entity_settings); - nlog($e->getMessage()); - - } - return $entity_settings; } diff --git a/tests/Feature/ClientApiTest.php b/tests/Feature/ClientApiTest.php index aae531575656..14633a1c655d 100644 --- a/tests/Feature/ClientApiTest.php +++ b/tests/Feature/ClientApiTest.php @@ -11,12 +11,20 @@ namespace Tests\Feature; +use App\DataMapper\ClientSettings; +use App\Factory\ClientFactory; +use App\Http\Requests\Client\StoreClientRequest; +use App\Models\Client; use App\Models\Country; +use App\Repositories\ClientContactRepository; +use App\Repositories\ClientRepository; use App\Utils\Number; +use App\Utils\Traits\ClientGroupSettingsSaver; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\Session; +use Illuminate\Support\Facades\Validator; use Illuminate\Validation\ValidationException; use Tests\MockAccountData; use Tests\TestCase; @@ -30,6 +38,7 @@ class ClientApiTest extends TestCase use MakesHash; use DatabaseTransactions; use MockAccountData; + use ClientGroupSettingsSaver; protected function setUp() :void { @@ -44,6 +53,304 @@ class ClientApiTest extends TestCase Model::reguard(); } + public function testCsvImportRepositoryPersistance() + { + Client::unguard(); + + $data = [ + 'company_id' => $this->company->id, + 'name' => 'Christian xx', + 'phone' => '', + 'address1' => '', + 'address2' => '', + 'postal_code' => '', + 'city' => '', + 'state' => '', + 'shipping_address1' => '', + 'shipping_address2' => '', + 'shipping_city' => '', + 'shipping_state' => '', + 'shipping_postal_code' => '', + 'public_notes' => '', + 'private_notes' => '', + 'website' => '', + 'vat_number' => '', + 'id_number' => '', + 'custom_value1' => '', + 'custom_value2' => '', + 'custom_value3' => '', + 'custom_value4' => '', + 'balance' => '0', + 'paid_to_date' => '0', + 'credit_balance' => 0, + 'settings' => [ + 'entity' => 'App\\Models\\Client', + 'currency_id' => '3', + ], + 'client_hash' => 'xx', + 'contacts' => + [ + [ + 'first_name' => '', + 'last_name' => '', + 'email' => '', + 'phone' => '', + 'custom_value1' => '', + 'custom_value2' => '', + 'custom_value3' => '', + 'custom_value4' => '', + ] + ], + 'country_id' => NULL, + 'shipping_country_id' => NULL, + 'user_id' => $this->user->id, + ]; + + $repository_name = ClientRepository::class; + $factory_name = ClientFactory::class; + + $repository = app()->make($repository_name); + $repository->import_mode = true; + + $c = $repository->save(array_diff_key($data, ['user_id' => false]), ClientFactory::create($this->company->id, $this->user->id)); + + Client::reguard(); + + nlog($c->toArray()); + + $c->refresh(); + + $this->assertEquals("3", $c->settings->currency_id); + + } + + public function testClientSettingsSave() + { + + $std = new \stdClass; + $std->entity = 'App\\Models\\Client'; + $std->currency_id = 3; + + $this->settings = $this->client->settings; + + $this->saveSettings($std, $this->client); + + $this->assertTrue(true); + + } + + + public function testClientSettingsSave2() + { + + $std = new \stdClass; + $std->entity = 'App\\Models\\Client'; + $std->industry_id = ''; + $std->size_id = ''; + $std->currency_id = 3; + + $this->settings = $this->client->settings; + + $this->saveSettings($std, $this->client); + + $this->assertTrue(true); + + } + + public function testClientStoreValidation() + { + + auth()->login($this->user, false); + auth()->user()->setCompany($this->company); + + $data = array ( + 'company_id' => $this->company->id, + 'name' => 'Christian xx', + 'phone' => '', + 'address1' => '', + 'address2' => '', + 'postal_code' => '', + 'city' => '', + 'state' => '', + 'shipping_address1' => '', + 'shipping_address2' => '', + 'shipping_city' => '', + 'shipping_state' => '', + 'shipping_postal_code' => '', + 'public_notes' => '', + 'private_notes' => '', + 'website' => '', + 'vat_number' => '', + 'id_number' => '', + 'custom_value1' => '', + 'custom_value2' => '', + 'custom_value3' => '', + 'custom_value4' => '', + 'balance' => '0', + 'paid_to_date' => '0', + 'credit_balance' => 0, + 'settings' => + (object) array( + 'entity' => 'App\\Models\\Client', + 'currency_id' => '3', + ), + 'client_hash' => 'xx', + 'contacts' => + array ( + 0 => + array ( + 'first_name' => '', + 'last_name' => '', + 'email' => '', + 'phone' => '', + 'custom_value1' => '', + 'custom_value2' => '', + 'custom_value3' => '', + 'custom_value4' => '', + ), + ), + 'country_id' => NULL, + 'shipping_country_id' => NULL, + 'user_id' => $this->user->id, + ); + + + $request_name = StoreClientRequest::class; + $repository_name = ClientRepository::class; + $factory_name = ClientFactory::class; + + $repository = app()->make($repository_name); + $repository->import_mode = true; + + $_syn_request_class = new $request_name; + $_syn_request_class->setContainer(app()); + $_syn_request_class->initialize($data); + $_syn_request_class->prepareForValidation(); + + $validator = Validator::make($_syn_request_class->all(), $_syn_request_class->rules()); + + $_syn_request_class->setValidator($validator); + + $this->assertFalse($validator->fails()); + + + } + + + + public function testClientImportDataStructure() + { + + + $data = array ( + 'company_id' => $this->company->id, + 'name' => 'Christian xx', + 'phone' => '', + 'address1' => '', + 'address2' => '', + 'postal_code' => '', + 'city' => '', + 'state' => '', + 'shipping_address1' => '', + 'shipping_address2' => '', + 'shipping_city' => '', + 'shipping_state' => '', + 'shipping_postal_code' => '', + 'public_notes' => '', + 'private_notes' => '', + 'website' => '', + 'vat_number' => '', + 'id_number' => '', + 'custom_value1' => '', + 'custom_value2' => '', + 'custom_value3' => '', + 'custom_value4' => '', + 'balance' => '0', + 'paid_to_date' => '0', + 'credit_balance' => 0, + 'settings' => + (object) array( + 'entity' => 'App\\Models\\Client', + 'currency_id' => '3', + ), + 'client_hash' => 'xx', + 'contacts' => + array ( + 0 => + array ( + 'first_name' => '', + 'last_name' => '', + 'email' => '', + 'phone' => '', + 'custom_value1' => '', + 'custom_value2' => '', + 'custom_value3' => '', + 'custom_value4' => '', + ), + ), + 'country_id' => NULL, + 'shipping_country_id' => NULL, + 'user_id' => $this->user->id, + ); + + $crepo = new ClientRepository(new ClientContactRepository()); + + $c = $crepo->save(array_diff_key($data, ['user_id' => false]), ClientFactory::create($this->company->id, $this->user->id)); + $c->saveQuietly(); + + $this->assertEquals('Christian xx', $c->name); + $this->assertEquals('3', $c->settings->currency_id); + } + + public function testClientCsvImport() + { + + $settings = ClientSettings::defaults(); + $settings->currency_id = "840"; + + $data = [ + 'name' => $this->faker->firstName(), + 'id_number' => 'Coolio', + 'settings' => (array)$settings, + 'contacts' => [ + [ + 'first_name' => '', + 'last_name' => '', + 'email' => '', + 'phone' => '', + 'custom_value1' => '', + 'custom_value2' => '', + 'custom_value3' => '', + 'custom_value4' => '', + ] + ] + ]; + + $response = false; + + try { + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->post('/api/v1/clients/', $data); + } catch (ValidationException $e) { + $message = json_decode($e->validator->getMessageBag(), 1); + nlog($message); + } + + $response->assertStatus(200); + + $crepo = new ClientRepository(new ClientContactRepository()); + + $c = $crepo->save($data, ClientFactory::create($this->company->id, $this->user->id)); + $c->saveQuietly(); + + + } + + + + public function testIllegalPropertiesInClientSettings() { $settings = [ From 4d1555b46eab4aa49b3d9659ae62e7824f4084bd Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 13:10:24 +1100 Subject: [PATCH 21/29] Fixes for applying payment from a transaction, and then unwinding the transaction --- app/Jobs/Bank/MatchBankTransactions.php | 2 +- app/Services/Invoice/MarkInvoiceDeleted.php | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/app/Jobs/Bank/MatchBankTransactions.php b/app/Jobs/Bank/MatchBankTransactions.php index 9f5260e204ab..286e3f6ef7ba 100644 --- a/app/Jobs/Bank/MatchBankTransactions.php +++ b/app/Jobs/Bank/MatchBankTransactions.php @@ -315,7 +315,7 @@ class MatchBankTransactions implements ShouldQueue $this->invoice ->client ->service() - ->updateBalanceAndPaidToDate($amount*-1, $amount) + ->updateBalanceAndPaidToDate($this->applied_amount*-1, $amount) ->save(); $this->invoice = $this->invoice diff --git a/app/Services/Invoice/MarkInvoiceDeleted.php b/app/Services/Invoice/MarkInvoiceDeleted.php index b16c468c7c1e..2d123c8c9175 100644 --- a/app/Services/Invoice/MarkInvoiceDeleted.php +++ b/app/Services/Invoice/MarkInvoiceDeleted.php @@ -53,16 +53,6 @@ class MarkInvoiceDeleted extends AbstractService ->adjustPaidToDateAndBalance() ->adjustLedger(); - $transaction = [ - 'invoice' => $this->invoice->transaction_event(), - 'payment' => $this->invoice->payments()->exists() ? $this->invoice->payments()->first()->transaction_event() : [], - 'client' => $this->invoice->client->transaction_event(), - 'credit' => [], - 'metadata' => ['total_payments' => $this->total_payments, 'balance_adjustment' => $this->balance_adjustment, 'adjustment_amount' => $this->adjustment_amount], - ]; - - // TransactionLog::dispatch(TransactionEvent::INVOICE_DELETED, $transaction, $this->invoice->company->db); - return $this->invoice; } From 9e6948825426cca4045cdc0213a6b0579b4e0af9 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 14:39:45 +1100 Subject: [PATCH 22/29] Fixes for multiple deletes on a single invoice --- app/Jobs/Bank/MatchBankTransactions.php | 2 +- app/Services/Invoice/HandleRestore.php | 10 ++++------ app/Services/Invoice/MarkInvoiceDeleted.php | 21 ++++++--------------- tests/Feature/ClientApiTest.php | 2 -- tests/Feature/DeleteInvoiceTest.php | 1 + 5 files changed, 12 insertions(+), 24 deletions(-) diff --git a/app/Jobs/Bank/MatchBankTransactions.php b/app/Jobs/Bank/MatchBankTransactions.php index 286e3f6ef7ba..0532d51e8b58 100644 --- a/app/Jobs/Bank/MatchBankTransactions.php +++ b/app/Jobs/Bank/MatchBankTransactions.php @@ -266,7 +266,7 @@ class MatchBankTransactions implements ShouldQueue /* Create Payment */ $payment = PaymentFactory::create($this->invoice->company_id, $this->invoice->user_id); - $payment->amount = $amount; + $payment->amount = $this->bt->amount; $payment->applied = $this->applied_amount; $payment->status_id = Payment::STATUS_COMPLETED; $payment->client_id = $this->invoice->client_id; diff --git a/app/Services/Invoice/HandleRestore.php b/app/Services/Invoice/HandleRestore.php index 412013aceb4c..f0e7a4e89425 100644 --- a/app/Services/Invoice/HandleRestore.php +++ b/app/Services/Invoice/HandleRestore.php @@ -56,8 +56,7 @@ class HandleRestore extends AbstractService $this->invoice->client ->service() - ->updateBalance($this->invoice->balance) - ->updatePaidToDate($this->invoice->paid_to_date) + ->updateBalanceAndPaidToDate($this->invoice->balance,$this->invoice->paid_to_date) ->save(); $this->windBackInvoiceNumber(); @@ -120,11 +119,11 @@ class HandleRestore extends AbstractService if ($this->adjustment_amount == $this->total_payments) { $this->invoice->payments()->update(['payments.deleted_at' => null, 'payments.is_deleted' => false]); - } else { + } //adjust payments down by the amount applied to the invoice payment. - $this->invoice->payments->each(function ($payment) { + $this->invoice->payments->fresh()->each(function ($payment) { $payment_adjustment = $payment->paymentables ->where('paymentable_type', '=', 'invoices') ->where('paymentable_id', $this->invoice->id) @@ -141,8 +140,7 @@ class HandleRestore extends AbstractService $payment->restore(); $payment->save(); }); - } - + return $this; } diff --git a/app/Services/Invoice/MarkInvoiceDeleted.php b/app/Services/Invoice/MarkInvoiceDeleted.php index 2d123c8c9175..e317c403ade6 100644 --- a/app/Services/Invoice/MarkInvoiceDeleted.php +++ b/app/Services/Invoice/MarkInvoiceDeleted.php @@ -77,26 +77,17 @@ class MarkInvoiceDeleted extends AbstractService return $this; } - // @deprecated - private function adjustBalance() - { - // $client = $this->invoice->client->fresh(); - // $client->balance += $this->balance_adjustment * -1; - // $client->save(); - - // $this->invoice->client->service()->updateBalance($this->balance_adjustment * -1)->save(); //reduces the client balance by the invoice amount. - - return $this; - } - /* Adjust the payment amounts */ private function adjustPayments() { //if total payments = adjustment amount - that means we need to delete the payments as well. - if ($this->adjustment_amount == $this->total_payments) { +nlog($this->adjustment_amount); +nlog($this->total_payments); + + if ($this->adjustment_amount == $this->total_payments) $this->invoice->payments()->update(['payments.deleted_at' => now(), 'payments.is_deleted' => true]); - } else { + //adjust payments down by the amount applied to the invoice payment. @@ -115,7 +106,7 @@ class MarkInvoiceDeleted extends AbstractService $payment->applied -= $payment_adjustment; $payment->save(); }); - } + return $this; } diff --git a/tests/Feature/ClientApiTest.php b/tests/Feature/ClientApiTest.php index 14633a1c655d..40b11fc70a4a 100644 --- a/tests/Feature/ClientApiTest.php +++ b/tests/Feature/ClientApiTest.php @@ -116,8 +116,6 @@ class ClientApiTest extends TestCase Client::reguard(); - nlog($c->toArray()); - $c->refresh(); $this->assertEquals("3", $c->settings->currency_id); diff --git a/tests/Feature/DeleteInvoiceTest.php b/tests/Feature/DeleteInvoiceTest.php index d49f6f27c9e9..8dcf2daf4764 100644 --- a/tests/Feature/DeleteInvoiceTest.php +++ b/tests/Feature/DeleteInvoiceTest.php @@ -162,6 +162,7 @@ class DeleteInvoiceTest extends TestCase $payment = $payment->fresh(); $this->assertTrue($payment->is_deleted); + $this->assertEquals(0, $payment->amount); $this->assertEquals(4, $payment->status_id); $client->fresh(); From b831658da413376d89101ef9902acebbe78a8f04 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 15:36:30 +1100 Subject: [PATCH 23/29] Do not allow restoration of a invoice with a deleted payment --- app/Services/Invoice/HandleRestore.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/Services/Invoice/HandleRestore.php b/app/Services/Invoice/HandleRestore.php index f0e7a4e89425..0d46f8717e40 100644 --- a/app/Services/Invoice/HandleRestore.php +++ b/app/Services/Invoice/HandleRestore.php @@ -44,11 +44,12 @@ class HandleRestore extends AbstractService return $this->invoice; } - //determine whether we need to un-delete payments OR just modify the payment amount /applied balances. - + //cannot restore an invoice with a deleted payment foreach ($this->invoice->payments as $payment) { - //restore the payment record - $this->invoice->restore(); + + if(($this->invoice->paid_to_date == 0) && $payment->is_deleted) + return $this->invoice; + } //adjust ledger balance From e68bdeb4539912f3e4bc43407891ed7d0aeed57e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 16:37:20 +1100 Subject: [PATCH 24/29] Minor cleanup --- app/Mail/VendorTemplateEmail.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/Mail/VendorTemplateEmail.php b/app/Mail/VendorTemplateEmail.php index 0c8dae6738f2..ccf9ef06955e 100644 --- a/app/Mail/VendorTemplateEmail.php +++ b/app/Mail/VendorTemplateEmail.php @@ -110,11 +110,7 @@ class VendorTemplateEmail extends Mailable 'whitelabel' => $this->vendor->user->account->isPaid() ? true : false, 'logo' => $this->company->present()->logo($settings), ]); - //->withSymfonyMessage(function ($message) { - // $message->getHeaders()->addTextHeader('Tag', $this->company->company_key); - // $message->invitation = $this->invitation; - //}); - // ->tag($this->company->company_key); + // if(Ninja::isHosted() && $this->invitation){ From c4b7cc615ea152f72c79934871101ace1450a677 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 16:38:01 +1100 Subject: [PATCH 25/29] Minor cleanup --- app/Http/Controllers/EmailController.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index fb081a9a4509..7c2e75966b91 100644 --- a/app/Http/Controllers/EmailController.php +++ b/app/Http/Controllers/EmailController.php @@ -131,8 +131,6 @@ class EmailController extends BaseController if(Ninja::isHosted() && !$entity_obj->company->account->account_sms_verified) return response(['message' => 'Please verify your account to send emails.'], 400); - nlog($entity); - if($entity == 'purchaseOrder' || $entity == 'purchase_order' || $template == 'purchase_order' || $entity == 'App\Models\PurchaseOrder'){ return $this->sendPurchaseOrder($entity_obj, $data, $template); } From 4f06bd116b34c1d32e20bdfbfcaeffd45082832e Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 17:13:03 +1100 Subject: [PATCH 26/29] Fixes for expense category validation --- app/Http/Requests/Expense/StoreExpenseRequest.php | 5 ----- app/Http/Requests/Expense/UpdateExpenseRequest.php | 4 ---- 2 files changed, 9 deletions(-) diff --git a/app/Http/Requests/Expense/StoreExpenseRequest.php b/app/Http/Requests/Expense/StoreExpenseRequest.php index 0c964fef9016..019099c54f24 100644 --- a/app/Http/Requests/Expense/StoreExpenseRequest.php +++ b/app/Http/Requests/Expense/StoreExpenseRequest.php @@ -54,10 +54,6 @@ class StoreExpenseRequest extends Request $input = $this->decodePrimaryKeys($input); - if (array_key_exists('category_id', $input) && is_string($input['category_id'])) { - $input['category_id'] = $this->decodePrimaryKey($input['category_id']); - } - if (! array_key_exists('currency_id', $input) || strlen($input['currency_id']) == 0) { $input['currency_id'] = (string) auth()->user()->company()->settings->currency_id; } @@ -66,7 +62,6 @@ class StoreExpenseRequest extends Request $input['color'] = ''; } - /* Ensure the project is related */ if (array_key_exists('project_id', $input) && isset($input['project_id'])) { $project = Project::withTrashed()->where('id', $input['project_id'])->company()->first(); diff --git a/app/Http/Requests/Expense/UpdateExpenseRequest.php b/app/Http/Requests/Expense/UpdateExpenseRequest.php index 26b144731048..d8107dd3b4c9 100644 --- a/app/Http/Requests/Expense/UpdateExpenseRequest.php +++ b/app/Http/Requests/Expense/UpdateExpenseRequest.php @@ -50,10 +50,6 @@ class UpdateExpenseRequest extends Request $input = $this->decodePrimaryKeys($input); - if (array_key_exists('category_id', $input) && is_string($input['category_id'])) { - $input['category_id'] = $this->decodePrimaryKey($input['category_id']); - } - if (array_key_exists('documents', $input)) { unset($input['documents']); } From 0dc9129e767814a9d8d8f59f7273261fb5503c58 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 17:15:22 +1100 Subject: [PATCH 27/29] Fixes for expense category validation --- app/Http/Requests/Expense/StoreExpenseRequest.php | 2 ++ app/Http/Requests/Expense/UpdateExpenseRequest.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/Http/Requests/Expense/StoreExpenseRequest.php b/app/Http/Requests/Expense/StoreExpenseRequest.php index 019099c54f24..a36369f01e90 100644 --- a/app/Http/Requests/Expense/StoreExpenseRequest.php +++ b/app/Http/Requests/Expense/StoreExpenseRequest.php @@ -45,6 +45,8 @@ class StoreExpenseRequest extends Request $rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id; } + $rules['category_id'] = 'bail|nullable|sometimes|exists:expense_categories,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; + return $this->globalRules($rules); } diff --git a/app/Http/Requests/Expense/UpdateExpenseRequest.php b/app/Http/Requests/Expense/UpdateExpenseRequest.php index d8107dd3b4c9..348cad69ddba 100644 --- a/app/Http/Requests/Expense/UpdateExpenseRequest.php +++ b/app/Http/Requests/Expense/UpdateExpenseRequest.php @@ -41,6 +41,8 @@ class UpdateExpenseRequest extends Request $rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id)->ignore($this->expense->id); } + $rules['category_id'] = 'bail|sometimes|nullable|exists:expense_categories,id,company_id,'.auth()->user()->company()->id.',is_deleted,0'; + return $this->globalRules($rules); } From 31e3cbe18a363779389527525e40dad3cc39c397 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 17:15:53 +1100 Subject: [PATCH 28/29] Version bump --- VERSION.txt | 2 +- config/ninja.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index b2198ea2611b..faea5e9484eb 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.5.43 \ No newline at end of file +5.5.44 \ No newline at end of file diff --git a/config/ninja.php b/config/ninja.php index 314b877deb28..15fec9f598ce 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -14,8 +14,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.5.43', - 'app_tag' => '5.5.43', + 'app_version' => '5.5.44', + 'app_tag' => '5.5.44', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''), From 44da02f00efd9a5f8d9f7bd4266ff08be968af7f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 30 Nov 2022 17:20:58 +1100 Subject: [PATCH 29/29] Fixes for Stripe payment translations --- app/PaymentDrivers/Stripe/ACH.php | 6 +++--- app/PaymentDrivers/Stripe/Charge.php | 2 +- app/PaymentDrivers/Stripe/CreditCard.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/PaymentDrivers/Stripe/ACH.php b/app/PaymentDrivers/Stripe/ACH.php index 26481b8a64c3..8e8a8f70ebf4 100644 --- a/app/PaymentDrivers/Stripe/ACH.php +++ b/app/PaymentDrivers/Stripe/ACH.php @@ -173,7 +173,7 @@ class ACH ->first(); if ($invoice) { - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } @@ -211,7 +211,7 @@ class ACH ->first(); if ($invoice) { - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } @@ -455,7 +455,7 @@ class ACH ->first(); if ($invoice) { - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } diff --git a/app/PaymentDrivers/Stripe/Charge.php b/app/PaymentDrivers/Stripe/Charge.php index f9660170834e..dabef4a6fbf6 100644 --- a/app/PaymentDrivers/Stripe/Charge.php +++ b/app/PaymentDrivers/Stripe/Charge.php @@ -63,7 +63,7 @@ class Charge $invoice = Invoice::whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first(); if ($invoice) { - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice->number, 'amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } else { $description = ctrans('text.stripe_paymenttext_without_invoice', ['amount' => Number::formatMoney($amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); } diff --git a/app/PaymentDrivers/Stripe/CreditCard.php b/app/PaymentDrivers/Stripe/CreditCard.php index 5fb8bd2e2d6a..64b9df528317 100644 --- a/app/PaymentDrivers/Stripe/CreditCard.php +++ b/app/PaymentDrivers/Stripe/CreditCard.php @@ -63,7 +63,7 @@ class CreditCard // $description = $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')) . " for client {$this->stripe->client->present()->name()}"; $invoice_numbers = collect($data['invoices'])->pluck('invoice_number')->implode(','); - $description = ctrans('text.stripe_paymenttext', ['invoicenumber' => $invoice_numbers, 'amount' => Number::formatMoney($data['total']['amount_with_fee'], $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + $description = ctrans('texts.stripe_paymenttext', ['invoicenumber' => $invoice_numbers, 'amount' => Number::formatMoney($data['total']['amount_with_fee'], $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); $payment_intent_data = [ 'amount' => $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency()),