From a07f04e1df7de3f2d9377fee875a196243d32981 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 28 Oct 2020 16:50:06 +1100 Subject: [PATCH 1/4] Refactor Template Engine --- app/Models/Company.php | 1 + app/Transformers/CompanyTransformer.php | 2 +- app/Utils/TemplateEngine.php | 5 ++++- .../migrations/2020_10_27_021751_tasks_invoice_documents.php | 5 +++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/Models/Company.php b/app/Models/Company.php index 98e10abf485b..b7bc9676f614 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -69,6 +69,7 @@ class Company extends BaseModel protected $presenter = \App\Models\Presenters\CompanyPresenter::class; protected $fillable = [ + 'show_tasks_table', 'mark_expenses_invoiceable', 'mark_expenses_paid', 'enabled_item_tax_rates', diff --git a/app/Transformers/CompanyTransformer.php b/app/Transformers/CompanyTransformer.php index 1af4d6dfa8c5..cb3df61e8317 100644 --- a/app/Transformers/CompanyTransformer.php +++ b/app/Transformers/CompanyTransformer.php @@ -154,7 +154,7 @@ class CompanyTransformer extends EntityTransformer 'invoice_task_timelog' => (bool) $company->invoice_task_timelog, 'auto_start_tasks' => (bool) $company->auto_start_tasks, 'invoice_task_documents' => (bool) $company->invoice_task_documents, - // 'use_credits_payment' => 'always', //todo remove + 'use_credits_payment' => 'always', //todo remove ]; } diff --git a/app/Utils/TemplateEngine.php b/app/Utils/TemplateEngine.php index 1bf85b519cb1..f83e917fb0db 100644 --- a/app/Utils/TemplateEngine.php +++ b/app/Utils/TemplateEngine.php @@ -16,6 +16,7 @@ use App\Models\Client; use App\Models\ClientContact; use App\Models\Invoice; use App\Models\InvoiceInvitation; +use App\Utils\HtmlEngine; use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesInvoiceHtml; use App\Utils\Traits\MakesTemplateData; @@ -151,7 +152,9 @@ class TemplateEngine private function entityValues($contact) { - $data = $this->entity_obj->buildLabelsAndValues($contact); + //$data = $this->entity_obj->buildLabelsAndValues($contact); + + $data = (new HtmlEngine($this->entity_obj->invitations->first()))->generateLabelsAndValues(); // $arrKeysLength = array_map('strlen', array_keys($data)); // array_multisort($arrKeysLength, SORT_DESC, $data); diff --git a/database/migrations/2020_10_27_021751_tasks_invoice_documents.php b/database/migrations/2020_10_27_021751_tasks_invoice_documents.php index 653b74342e7f..3bb2c8ddd366 100644 --- a/database/migrations/2020_10_27_021751_tasks_invoice_documents.php +++ b/database/migrations/2020_10_27_021751_tasks_invoice_documents.php @@ -16,6 +16,11 @@ class TasksInvoiceDocuments extends Migration Schema::table('tasks', function(Blueprint $table){ $table->boolean('invoice_documents')->default(0); }); + + Schema::table('companies', function(Blueprint $table){ + $table->boolean('show_tasks_table')->default(); + }); + } /** From d7930e4c1427dc70cc2f8b1f277515b5bf9c6422 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 28 Oct 2020 17:27:10 +1100 Subject: [PATCH 2/4] Remove redundant classes --- app/Helpers/Email/InvoiceEmail.php | 3 +- app/Helpers/Email/QuoteEmail.php | 3 +- app/Jobs/Credit/EmailCredit.php | 101 ----- app/Jobs/Invoice/EmailInvoice.php | 114 ----- app/Jobs/Quote/EmailQuote.php | 87 ---- app/Mail/Engine/CreditEmailEngine.php | 3 +- app/Mail/Engine/InvoiceEmailEngine.php | 3 +- app/Mail/Engine/QuoteEmailEngine.php | 2 +- app/Models/Invoice.php | 2 - app/Utils/HtmlEngine.php | 13 + app/Utils/Traits/InvoiceEmailBuilder.php | 134 ------ app/Utils/Traits/MakesInvoiceHtml.php | 52 +-- app/Utils/Traits/MakesInvoiceValues.php | 516 +++++++++++------------ app/Utils/Traits/PaymentEmailBuilder.php | 2 +- app/Utils/Traits/QuoteEmailBuilder.php | 2 +- tests/Feature/InvoiceEmailTest.php | 25 +- 16 files changed, 317 insertions(+), 745 deletions(-) delete mode 100644 app/Jobs/Credit/EmailCredit.php delete mode 100644 app/Jobs/Invoice/EmailInvoice.php delete mode 100644 app/Jobs/Quote/EmailQuote.php delete mode 100644 app/Utils/Traits/InvoiceEmailBuilder.php diff --git a/app/Helpers/Email/InvoiceEmail.php b/app/Helpers/Email/InvoiceEmail.php index 58d92f747d8f..9fad11927ea8 100644 --- a/app/Helpers/Email/InvoiceEmail.php +++ b/app/Helpers/Email/InvoiceEmail.php @@ -11,6 +11,7 @@ namespace App\Helpers\Email; use App\Helpers\Email\EntityEmailInterface; use App\Models\Invoice; use App\Models\InvoiceInvitation; +use App\Utils\HtmlEngine; use App\Utils\Number; class InvoiceEmail extends EmailBuilder @@ -69,7 +70,7 @@ class InvoiceEmail extends EmailBuilder $this->setTemplate($client->getSetting('email_style')) ->setContact($contact) - ->setVariables($invoice->makeValues($contact)) + ->setVariables((new HtmlEngine($invitation))->makeValues()) ->setSubject($subject_template) ->setBody($body_template) ->setFooter("".ctrans('texts.view_invoice').'') diff --git a/app/Helpers/Email/QuoteEmail.php b/app/Helpers/Email/QuoteEmail.php index a1f91da900f2..c98f1d0532f3 100644 --- a/app/Helpers/Email/QuoteEmail.php +++ b/app/Helpers/Email/QuoteEmail.php @@ -10,6 +10,7 @@ namespace App\Helpers\Email; use App\Models\Quote; use App\Models\QuoteInvitation; +use App\Utils\HtmlEngine; class QuoteEmail extends EmailBuilder { @@ -56,7 +57,7 @@ class QuoteEmail extends EmailBuilder $this->setTemplate($quote->client->getSetting('email_style')) ->setContact($contact) ->setFooter("Quote Link") - ->setVariables($quote->makeValues($contact)) + ->setVariables((new HtmlEngine($invitation))->makeValues()) ->setSubject($subject_template) ->setBody($body_template); diff --git a/app/Jobs/Credit/EmailCredit.php b/app/Jobs/Credit/EmailCredit.php deleted file mode 100644 index 7356c4002070..000000000000 --- a/app/Jobs/Credit/EmailCredit.php +++ /dev/null @@ -1,101 +0,0 @@ -credit = $credit; - - $this->company = $company; - } - - /** - * Execute the job. - * - * - * @return void - */ - public function handle() - { - //todo - change runtime config of mail driver if necessary - MultiDB::setDb($this->company->db); - - $this->settings = $this->credit->client->getMergedSettings(); - - $template_style = $this->credit->client->getSetting('email_style'); - - $this->setMailDriver(); - - $this->credit->invitations->each(function ($invitation) use ($template_style) { - - if ($invitation->contact->send_email && $invitation->contact->email) - { - - $message_array = $this->credit->getEmailData('', $invitation->contact); - $message_array['title'] = &$message_array['subject']; - $message_array['footer'] = 'Sent to '.$invitation->contact->present()->name(); - - MailRouter::dispatch(new TemplateEmail($message_array, $template_style, $invitation->contact->user, $invitation->contact->client), $invitation->company, $invitation->contact); - - //fire any events - event(new CreditWasEmailed($this->credit, $this->company, Ninja::eventVars())); - } - - }); - } - - private function logMailError($errors) - { - SystemLogger::dispatch( - $errors, - SystemLog::CATEGORY_MAIL, - SystemLog::EVENT_MAIL_SEND, - SystemLog::TYPE_FAILURE, - $this->credit->client - ); - } -} diff --git a/app/Jobs/Invoice/EmailInvoice.php b/app/Jobs/Invoice/EmailInvoice.php deleted file mode 100644 index 8a3a92183f9b..000000000000 --- a/app/Jobs/Invoice/EmailInvoice.php +++ /dev/null @@ -1,114 +0,0 @@ -company = $company; - - $this->invoice_invitation = $invoice_invitation; - - $this->email_builder = $email_builder; - - $this->settings = $invoice_invitation->contact->client->getMergedSettings(); - } - - /** - * Execute the job. - * - * - * @return void - */ - public function handle() - { - - MultiDB::setDB($this->company->db); - - $this->setMailDriver(); - - try { - Mail::to($this->invoice_invitation->contact->email, $this->invoice_invitation->contact->present()->name()) - ->send( - new TemplateEmail( - $this->email_builder, - $this->invoice_invitation->contact->user, - $this->invoice_invitation->contact->client - ) - ); - } catch (\Swift_TransportException $e) { - event(new InvoiceWasEmailedAndFailed($this->invoice_invitation->invoice, $this->company, $e->getMessage(), Ninja::eventVars())); - } - - if (count(Mail::failures()) > 0) { - $this->logMailError(Mail::failures(), $this->invoice->client); - } else { - event(new InvoiceWasEmailed($this->invoice_invitation, $this->company, Ninja::eventVars())); - } - - /* Mark invoice sent */ - $this->invoice_invitation->invoice->service()->markSent()->save(); - } - - public function failed($exception = null) - { - info('the job failed'); - - $job_failure = new EmailInvoiceFailure(); - $job_failure->string_metric5 = get_class($this); - $job_failure->string_metric6 = $exception->getMessage(); - - LightLogs::create($job_failure) - ->batch(); - - } -} diff --git a/app/Jobs/Quote/EmailQuote.php b/app/Jobs/Quote/EmailQuote.php deleted file mode 100644 index 596944d5b12c..000000000000 --- a/app/Jobs/Quote/EmailQuote.php +++ /dev/null @@ -1,87 +0,0 @@ -quote_invitation = $quote_invitation; - $this->email_builder = $email_builder; - $this->company = $company; - } - - /** - * Execute the job. - * - * - * @return void - */ - public function handle() - { - MultiDB::setDb($this->company->db); - - $this->settings = $this->quote_invitation->contact->client->getMergedSettings(); - - $this->setMailDriver(); - - Mail::to($this->quote_invitation->contact->email, $this->quote_invitation->contact->present()->name()) - ->send( - new TemplateEmail( - $this->email_builder, - $this->quote_invitation->contact->user, - $this->quote_invitation->contact->client - ) - ); - - if (count(Mail::failures()) > 0) { - return $this->logMailError(Mail::failures()); - } - - $this->quote_invitation->quote->service()->markSent()->save(); - } - - private function logMailError($errors) - { - SystemLogger::dispatch( - $errors, - SystemLog::CATEGORY_MAIL, - SystemLog::EVENT_MAIL_SEND, - SystemLog::TYPE_FAILURE, - $this->quote->client - ); - } -} diff --git a/app/Mail/Engine/CreditEmailEngine.php b/app/Mail/Engine/CreditEmailEngine.php index 2ee6aed08493..019248b658ed 100644 --- a/app/Mail/Engine/CreditEmailEngine.php +++ b/app/Mail/Engine/CreditEmailEngine.php @@ -11,6 +11,7 @@ namespace App\Mail\Engine; +use App\Utils\HtmlEngine; use App\Utils\Number; class CreditEmailEngine extends BaseEmailEngine @@ -71,7 +72,7 @@ class CreditEmailEngine extends BaseEmailEngine $this->setTemplate($this->client->getSetting('email_style')) ->setContact($this->contact) - ->setVariables($this->credit->makeValues($this->contact))//move make values into the htmlengine + ->setVariables((new HtmlEngine($this->invitation))->makeValues())//move make values into the htmlengine ->setSubject($subject_template) ->setBody($body_template) ->setFooter("".ctrans('texts.view_credit').'') diff --git a/app/Mail/Engine/InvoiceEmailEngine.php b/app/Mail/Engine/InvoiceEmailEngine.php index 26feb3dd7ebb..90809330daa3 100644 --- a/app/Mail/Engine/InvoiceEmailEngine.php +++ b/app/Mail/Engine/InvoiceEmailEngine.php @@ -11,6 +11,7 @@ namespace App\Mail\Engine; +use App\Utils\HtmlEngine; use App\Utils\Number; class InvoiceEmailEngine extends BaseEmailEngine @@ -71,7 +72,7 @@ class InvoiceEmailEngine extends BaseEmailEngine $this->setTemplate($this->client->getSetting('email_style')) ->setContact($this->contact) - ->setVariables($this->invoice->makeValues($this->contact))//move make values into the htmlengine + ->setVariables((new HtmlEngine($this->invitation))->makeValues())//move make values into the htmlengine ->setSubject($subject_template) ->setBody($body_template) ->setFooter("".ctrans('texts.view_invoice').'') diff --git a/app/Mail/Engine/QuoteEmailEngine.php b/app/Mail/Engine/QuoteEmailEngine.php index 698127a98802..6121787c22b5 100644 --- a/app/Mail/Engine/QuoteEmailEngine.php +++ b/app/Mail/Engine/QuoteEmailEngine.php @@ -71,7 +71,7 @@ class QuoteEmailEngine extends BaseEmailEngine $this->setTemplate($this->client->getSetting('email_style')) ->setContact($this->contact) - ->setVariables($this->quote->makeValues($this->contact))//move make values into the htmlengine + ->setVariables((new HtmlEngine($this->invitation))->makeValues())//move make values into the htmlengine ->setSubject($subject_template) ->setBody($body_template) ->setFooter("".ctrans('texts.view_quote').'') diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index fb69794ccb0d..0d4f8df9f74f 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -29,7 +29,6 @@ use App\Services\Ledger\LedgerService; use App\Utils\Ninja; use App\Utils\Number; use App\Utils\Traits\Archivable; -use App\Utils\Traits\InvoiceEmailBuilder; use App\Utils\Traits\Invoice\ActionsInvoice; use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesInvoiceValues; @@ -50,7 +49,6 @@ class Invoice extends BaseModel use MakesDates; use PresentableTrait; use MakesInvoiceValues; - use InvoiceEmailBuilder; use MakesReminders; use ActionsInvoice; diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 5b67d43da7f5..f5d0953b5284 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -374,6 +374,19 @@ class HtmlEngine return $data; } + public function makeValues() :array + { + $data = []; + + $values = $this->buildEntityDataArray(); + + foreach ($values as $key => $value) { + $data[$key] = $value['value']; + } + + return $data; + } + public function generateLabelsAndValues() { $data = []; diff --git a/app/Utils/Traits/InvoiceEmailBuilder.php b/app/Utils/Traits/InvoiceEmailBuilder.php deleted file mode 100644 index c263e0808a08..000000000000 --- a/app/Utils/Traits/InvoiceEmailBuilder.php +++ /dev/null @@ -1,134 +0,0 @@ -client; - - if (! $reminder_template) { - $reminder_template = $this->calculateTemplate('invoice'); - } - - //Need to determine which email template we are producing - return $this->generateTemplateData($reminder_template, $contact); - } - - private function generateTemplateData(string $reminder_template, $contact) :array - { - $data = []; - - $client = $this->client; - - $body_template = $client->getSetting('email_template_'.$reminder_template); - - /* Use default translations if a custom message has not been set*/ - if (iconv_strlen($body_template) == 0) { - $body_template = trans('texts.invoice_message', ['amount'=>$this->present()->amount(), 'account'=>$this->company->present()->name()], null, $this->client->locale()); - } - - $subject_template = $client->getSetting('email_subject_'.$reminder_template); - - if (iconv_strlen($subject_template) == 0) { - if ($reminder_template == 'invoice') { - $subject_template = trans('texts.invoice_subject', ['number'=>$this->present()->invoice_number(), 'account'=>$this->company->present()->name()], null, $this->client->locale()); - } else { - $subject_template = trans('texts.reminder_subject', ['number'=>$this->present()->invoice_number(), 'account'=>$this->company->present()->name()], null, $this->client->locale()); - } - } - - $data['body'] = $this->parseTemplate($body_template, true, $contact); - - $data['subject'] = $this->parseTemplate($subject_template, false, $contact); - - if ($client->getSetting('pdf_email_attachment') !== false) { - $data['files'][] = $this->pdf_file_path(); - } - - return $data; - } - - private function parseTemplate(string $template_data, bool $is_markdown = true, $contact = null) :string - { - $invoice_variables = $this->makeValues($contact); - - $data = strtr($template_data, $invoice_variables); - - //process markdown - if ($is_markdown) { - $converter = new CommonMarkConverter([ - 'html_input' => 'allow', - 'allow_unsafe_links' => true, - ]); - - $data = $converter->convertToHtml($data); - } - - return $data; - } - - // private function calculateTemplate() :string - // { - // //if invoice is currently a draft, or being marked as sent, this will be the initial email - // $client = $this->client; - - // //if the invoice - // if ($this->status_id == Invoice::STATUS_DRAFT || Carbon::parse($this->due_date) > now()) { - // return 'invoice'; - // } elseif ($client->getSetting('enable_reminder1') !== false && $this->inReminderWindow($client->getSetting('schedule_reminder1'), $client->getSetting('num_days_reminder1'))) { - // return 'template1'; - // } elseif ($client->getSetting('enable_reminder2') !== false && $this->inReminderWindow($client->getSetting('schedule_reminder2'), $client->getSetting('num_days_reminder2'))) { - // return 'template2'; - // } elseif ($client->getSetting('enable_reminder3') !== false && $this->inReminderWindow($client->getSetting('schedule_reminder3'), $client->getSetting('num_days_reminder3'))) { - // return 'template3'; - // } else { - // return 'invoice'; - // } - - // //also implement endless reminders here - // } - - // private function inReminderWindow($schedule_reminder, $num_days_reminder) - // { - // switch ($schedule_reminder) { - // case 'after_invoice_date': - // return Carbon::parse($this->date)->addDays($num_days_reminder)->startOfDay()->eq(Carbon::now()->startOfDay()); - // break; - // case 'before_due_date': - // return Carbon::parse($this->due_date)->subDays($num_days_reminder)->startOfDay()->eq(Carbon::now()->startOfDay()); - // break; - // case 'after_due_date': - // return Carbon::parse($this->due_date)->addDays($num_days_reminder)->startOfDay()->eq(Carbon::now()->startOfDay()); - // break; - // default: - // # code... - // break; - // } - // } -} diff --git a/app/Utils/Traits/MakesInvoiceHtml.php b/app/Utils/Traits/MakesInvoiceHtml.php index 72dbca2f8dc1..3c747ebb21f1 100644 --- a/app/Utils/Traits/MakesInvoiceHtml.php +++ b/app/Utils/Traits/MakesInvoiceHtml.php @@ -33,45 +33,45 @@ trait MakesInvoiceHtml * * @return string The invoice string in HTML format */ - public function generateEntityHtml(Designer $designer, $entity, $contact = null) :string - { - $entity->load('client'); + // public function generateEntityHtml(Designer $designer, $entity, $contact = null) :string + // { + // $entity->load('client'); - $client = $entity->client; + // $client = $entity->client; - App::setLocale($client->preferredLocale()); + // App::setLocale($client->preferredLocale()); - $values_and_labels = $entity->buildLabelsAndValues($contact); + // $values_and_labels = $entity->buildLabelsAndValues($contact); - $designer->build(); + // $designer->build(); - $data = []; - $data['entity'] = $entity; - $data['lang'] = $client->preferredLocale(); - $data['includes'] = $designer->getIncludes(); - $data['header'] = $designer->getHeader(); - $data['body'] = $designer->getBody(); - $data['footer'] = $designer->getFooter(); + // $data = []; + // $data['entity'] = $entity; + // $data['lang'] = $client->preferredLocale(); + // $data['includes'] = $designer->getIncludes(); + // $data['header'] = $designer->getHeader(); + // $data['body'] = $designer->getBody(); + // $data['footer'] = $designer->getFooter(); - $html = view('pdf.stub', $data)->render(); + // $html = view('pdf.stub', $data)->render(); - $html = $this->parseLabelsAndValues($values_and_labels['labels'], $values_and_labels['values'], $html); + // $html = $this->parseLabelsAndValues($values_and_labels['labels'], $values_and_labels['values'], $html); - return $html; - } + // return $html; + // } - public function generateEmailEntityHtml($entity, $content, $contact = null) :string - { - $entity->load('client'); + // public function generateEmailEntityHtml($entity, $content, $contact = null) :string + // { + // $entity->load('client'); - $client = $entity->client; + // $client = $entity->client; - App::setLocale($client->preferredLocale()); + // App::setLocale($client->preferredLocale()); - $data = $entity->buildLabelsAndValues($contact); + // $data = $entity->buildLabelsAndValues($contact); - return $this->parseLabelsAndValues($data['labels'], $data['values'], $content); - } + // return $this->parseLabelsAndValues($data['labels'], $data['values'], $content); + // } private function parseLabelsAndValues($labels, $values, $section) :string { diff --git a/app/Utils/Traits/MakesInvoiceValues.php b/app/Utils/Traits/MakesInvoiceValues.php index 6c518a981781..c4f02543c46a 100644 --- a/app/Utils/Traits/MakesInvoiceValues.php +++ b/app/Utils/Traits/MakesInvoiceValues.php @@ -157,300 +157,300 @@ trait MakesInvoiceValues return $data; } - public function buildLabelsAndValues($contact) - { - $data = []; + // public function buildLabelsAndValues($contact) + // { + // $data = []; - $values = $this->makeLabelsAndValues($contact); + // $values = $this->makeLabelsAndValues($contact); - foreach ($values as $key => $value) { - $data['values'][$key] = $value['value']; - $data['labels'][$key.'_label'] = $value['label']; - } + // foreach ($values as $key => $value) { + // $data['values'][$key] = $value['value']; + // $data['labels'][$key.'_label'] = $value['label']; + // } - return $data; - } + // return $data; + // } - private function makeLabelsAndValues($contact = null) :array - { - if (! $this->client->currency() || ! $this->client) { - throw new \Exception(debug_backtrace()[1]['function'], 1); - exit; - } + // private function makeLabelsAndValues($contact = null) :array + // { + // if (! $this->client->currency() || ! $this->client) { + // throw new \Exception(debug_backtrace()[1]['function'], 1); + // exit; + // } - $settings = $this->client->getMergedSettings(); + // $settings = $this->client->getMergedSettings(); - if (! $contact) { - $contact = $this->client->primary_contact()->first(); - } + // if (! $contact) { + // $contact = $this->client->primary_contact()->first(); + // } - $calc = $this->calc(); - $invitation = $this->invitations->where('client_contact_id', $contact->id)->first(); + // $calc = $this->calc(); + // $invitation = $this->invitations->where('client_contact_id', $contact->id)->first(); - $data = []; - $data['$tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; - $data['$app_url'] = ['value' => $this->generateAppUrl(), 'label' => '']; - $data['$from'] = ['value' => '', 'label' => ctrans('texts.from')]; - $data['$to'] = ['value' => '', 'label' => ctrans('texts.to')]; - $data['$total_tax_labels'] = ['value' => $this->totalTaxLabels(), 'label' => ctrans('texts.taxes')]; - $data['$total_tax_values'] = ['value' => $this->totalTaxValues(), 'label' => ctrans('texts.taxes')]; - $data['$line_tax_labels'] = ['value' => $this->lineTaxLabels(), 'label' => ctrans('texts.taxes')]; - $data['$line_tax_values'] = ['value' => $this->lineTaxValues(), 'label' => ctrans('texts.taxes')]; - $data['$date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.date')]; - //$data['$invoice_date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.invoice_date')]; - $data['$invoice.date'] = &$data['$date']; - $data['$invoice.due_date'] = ['value' => $this->due_date ?: ' ', 'label' => ctrans('texts.due_date')]; - $data['$due_date'] = &$data['$invoice.due_date']; - $data['$invoice.number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.invoice_number')]; - $data['$invoice.po_number'] = ['value' => $this->po_number ?: ' ', 'label' => ctrans('texts.po_number')]; - $data['$line_taxes'] = ['value' => $this->makeLineTaxes() ?: ' ', 'label' => ctrans('texts.taxes')]; - $data['$invoice.line_taxes'] = &$data['$line_taxes']; - $data['$total_taxes'] = ['value' => $this->makeTotalTaxes() ?: ' ', 'label' => ctrans('texts.taxes')]; - $data['$invoice.total_taxes'] = &$data['$total_taxes']; + // $data = []; + // $data['$tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; + // $data['$app_url'] = ['value' => $this->generateAppUrl(), 'label' => '']; + // $data['$from'] = ['value' => '', 'label' => ctrans('texts.from')]; + // $data['$to'] = ['value' => '', 'label' => ctrans('texts.to')]; + // $data['$total_tax_labels'] = ['value' => $this->totalTaxLabels(), 'label' => ctrans('texts.taxes')]; + // $data['$total_tax_values'] = ['value' => $this->totalTaxValues(), 'label' => ctrans('texts.taxes')]; + // $data['$line_tax_labels'] = ['value' => $this->lineTaxLabels(), 'label' => ctrans('texts.taxes')]; + // $data['$line_tax_values'] = ['value' => $this->lineTaxValues(), 'label' => ctrans('texts.taxes')]; + // $data['$date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.date')]; + // //$data['$invoice_date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.invoice_date')]; + // $data['$invoice.date'] = &$data['$date']; + // $data['$invoice.due_date'] = ['value' => $this->due_date ?: ' ', 'label' => ctrans('texts.due_date')]; + // $data['$due_date'] = &$data['$invoice.due_date']; + // $data['$invoice.number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.invoice_number')]; + // $data['$invoice.po_number'] = ['value' => $this->po_number ?: ' ', 'label' => ctrans('texts.po_number')]; + // $data['$line_taxes'] = ['value' => $this->makeLineTaxes() ?: ' ', 'label' => ctrans('texts.taxes')]; + // $data['$invoice.line_taxes'] = &$data['$line_taxes']; + // $data['$total_taxes'] = ['value' => $this->makeTotalTaxes() ?: ' ', 'label' => ctrans('texts.taxes')]; + // $data['$invoice.total_taxes'] = &$data['$total_taxes']; - if ($this instanceof Invoice) { - $data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.invoice')]; - $data['$number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.invoice_number')]; - $data['$entity.terms'] = ['value' => $this->terms ?: ' ', 'label' => ctrans('texts.invoice_terms')]; - $data['$terms'] = &$data['$entity.terms']; + // if ($this instanceof Invoice) { + // $data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.invoice')]; + // $data['$number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.invoice_number')]; + // $data['$entity.terms'] = ['value' => $this->terms ?: ' ', 'label' => ctrans('texts.invoice_terms')]; + // $data['$terms'] = &$data['$entity.terms']; - if($invitation) - $data['$view_link'] = ['value' => ''.ctrans('texts.view_invoice').'', 'label' => ctrans('texts.view_invoice')]; - // $data['$view_link'] = ['value' => $invitation->getLink(), 'label' => ctrans('texts.view_invoice')]; - } + // if($invitation) + // $data['$view_link'] = ['value' => ''.ctrans('texts.view_invoice').'', 'label' => ctrans('texts.view_invoice')]; + // // $data['$view_link'] = ['value' => $invitation->getLink(), 'label' => ctrans('texts.view_invoice')]; + // } - if ($this instanceof Quote) { - $data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.quote')]; - $data['$number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.quote_number')]; - $data['$entity.terms'] = ['value' => $this->terms ?: ' ', 'label' => ctrans('texts.quote_terms')]; - $data['$terms'] = &$data['$entity.terms']; + // if ($this instanceof Quote) { + // $data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.quote')]; + // $data['$number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.quote_number')]; + // $data['$entity.terms'] = ['value' => $this->terms ?: ' ', 'label' => ctrans('texts.quote_terms')]; + // $data['$terms'] = &$data['$entity.terms']; - if($invitation) - $data['$view_link'] = ['value' => ''.ctrans('texts.view_quote').'', 'label' => ctrans('texts.view_quote')]; - // $data['$view_link'] = ['value' => $invitation->getLink(), 'label' => ctrans('texts.view_quote')]; - } + // if($invitation) + // $data['$view_link'] = ['value' => ''.ctrans('texts.view_quote').'', 'label' => ctrans('texts.view_quote')]; + // // $data['$view_link'] = ['value' => $invitation->getLink(), 'label' => ctrans('texts.view_quote')]; + // } - if ($this instanceof Credit) { - $data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.credit')]; - $data['$number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.credit_number')]; - $data['$entity.terms'] = ['value' => $this->terms ?: ' ', 'label' => ctrans('texts.credit_terms')]; - $data['$terms'] = &$data['$entity.terms']; + // if ($this instanceof Credit) { + // $data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.credit')]; + // $data['$number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.credit_number')]; + // $data['$entity.terms'] = ['value' => $this->terms ?: ' ', 'label' => ctrans('texts.credit_terms')]; + // $data['$terms'] = &$data['$entity.terms']; - if($invitation) - $data['$view_link'] = ['value' => ''.ctrans('texts.view_credit').'', 'label' => ctrans('texts.view_credit')]; - // $data['$view_link'] = ['value' => $invitation->getLink(), 'label' => ctrans('texts.view_credit')]; - } + // if($invitation) + // $data['$view_link'] = ['value' => ''.ctrans('texts.view_credit').'', 'label' => ctrans('texts.view_credit')]; + // // $data['$view_link'] = ['value' => $invitation->getLink(), 'label' => ctrans('texts.view_credit')]; + // } - $data['$entity_number'] = &$data['$number']; + // $data['$entity_number'] = &$data['$number']; - $data['$invoice.discount'] = ['value' => Number::formatMoney($calc->getTotalDiscount(), $this->client) ?: ' ', 'label' => ctrans('texts.discount')]; - $data['$discount'] = &$data['$invoice.discount']; - $data['$subtotal'] = ['value' => Number::formatMoney($calc->getSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')]; - $data['$invoice.subtotal'] = &$data['$subtotal']; - $data['$invoice.balance_due'] = ['value' => Number::formatMoney($this->balance, $this->client) ?: ' ', 'label' => ctrans('texts.balance_due')]; - $data['$quote.balance_due'] = &$data['$invoice.balance_due']; - $data['$balance_due'] = &$data['$invoice.balance_due']; - $data['$invoice.partial_due'] = ['value' => Number::formatMoney($this->partial, $this->client) ?: ' ', 'label' => ctrans('texts.partial_due')]; - $data['$total'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.total')]; - $data['$amount'] = &$data['$total']; - $data['$quote.total'] = &$data['$total']; - $data['$invoice.total'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.invoice_total')]; - $data['$invoice.amount'] = &$data['$total']; - $data['$quote.amount'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.quote_total')]; - $data['$credit.total'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_total')]; - $data['$credit.number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.credit_number')]; - $data['$credit.total'] = &$data['$credit.total']; - $data['$credit.po_number'] = &$data['$invoice.po_number']; - $data['$credit.date'] = ['value' => $this->date, 'label' => ctrans('texts.credit_date')]; - $data['$balance'] = ['value' => Number::formatMoney($calc->getBalance(), $this->client) ?: ' ', 'label' => ctrans('texts.balance')]; - $data['$credit.balance'] = &$data['$balance']; + // $data['$invoice.discount'] = ['value' => Number::formatMoney($calc->getTotalDiscount(), $this->client) ?: ' ', 'label' => ctrans('texts.discount')]; + // $data['$discount'] = &$data['$invoice.discount']; + // $data['$subtotal'] = ['value' => Number::formatMoney($calc->getSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')]; + // $data['$invoice.subtotal'] = &$data['$subtotal']; + // $data['$invoice.balance_due'] = ['value' => Number::formatMoney($this->balance, $this->client) ?: ' ', 'label' => ctrans('texts.balance_due')]; + // $data['$quote.balance_due'] = &$data['$invoice.balance_due']; + // $data['$balance_due'] = &$data['$invoice.balance_due']; + // $data['$invoice.partial_due'] = ['value' => Number::formatMoney($this->partial, $this->client) ?: ' ', 'label' => ctrans('texts.partial_due')]; + // $data['$total'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.total')]; + // $data['$amount'] = &$data['$total']; + // $data['$quote.total'] = &$data['$total']; + // $data['$invoice.total'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.invoice_total')]; + // $data['$invoice.amount'] = &$data['$total']; + // $data['$quote.amount'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.quote_total')]; + // $data['$credit.total'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_total')]; + // $data['$credit.number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.credit_number')]; + // $data['$credit.total'] = &$data['$credit.total']; + // $data['$credit.po_number'] = &$data['$invoice.po_number']; + // $data['$credit.date'] = ['value' => $this->date, 'label' => ctrans('texts.credit_date')]; + // $data['$balance'] = ['value' => Number::formatMoney($calc->getBalance(), $this->client) ?: ' ', 'label' => ctrans('texts.balance')]; + // $data['$credit.balance'] = &$data['$balance']; - $data['$invoice.balance'] = &$data['$balance']; - $data['$taxes'] = ['value' => Number::formatMoney($calc->getItemTotalTaxes(), $this->client) ?: ' ', 'label' => ctrans('texts.taxes')]; - $data['$invoice.taxes'] = &$data['$taxes']; + // $data['$invoice.balance'] = &$data['$balance']; + // $data['$taxes'] = ['value' => Number::formatMoney($calc->getItemTotalTaxes(), $this->client) ?: ' ', 'label' => ctrans('texts.taxes')]; + // $data['$invoice.taxes'] = &$data['$taxes']; - $data['$invoice.custom1'] = ['value' => $this->custom_value1 ?: ' ', 'label' => $this->makeCustomField('invoice1')]; - $data['$invoice.custom2'] = ['value' => $this->custom_value2 ?: ' ', 'label' => $this->makeCustomField('invoice2')]; - $data['$invoice.custom3'] = ['value' => $this->custom_value3 ?: ' ', 'label' => $this->makeCustomField('invoice3')]; - $data['$invoice.custom4'] = ['value' => $this->custom_value4 ?: ' ', 'label' => $this->makeCustomField('invoice4')]; - $data['$invoice.public_notes'] = ['value' => $this->public_notes ?: ' ', 'label' => ctrans('texts.public_notes')]; - $data['$entity.public_notes'] = &$data['$invoice.public_notes']; + // $data['$invoice.custom1'] = ['value' => $this->custom_value1 ?: ' ', 'label' => $this->makeCustomField('invoice1')]; + // $data['$invoice.custom2'] = ['value' => $this->custom_value2 ?: ' ', 'label' => $this->makeCustomField('invoice2')]; + // $data['$invoice.custom3'] = ['value' => $this->custom_value3 ?: ' ', 'label' => $this->makeCustomField('invoice3')]; + // $data['$invoice.custom4'] = ['value' => $this->custom_value4 ?: ' ', 'label' => $this->makeCustomField('invoice4')]; + // $data['$invoice.public_notes'] = ['value' => $this->public_notes ?: ' ', 'label' => ctrans('texts.public_notes')]; + // $data['$entity.public_notes'] = &$data['$invoice.public_notes']; - // $data['$your_invoice'] = ; - // $data['$quote'] = ; - // $data['$your_quote'] = ; - // - $data['$quote.date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.quote_date')]; - $data['$quote.number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.quote_number')]; - $data['$quote.po_number'] = &$data['$invoice.po_number']; - $data['$quote.quote_number'] = &$data['$quote.number']; - $data['$quote_no'] = &$data['$quote.number']; - $data['$quote.quote_no'] = &$data['$quote.number']; - $data['$quote.valid_until'] = ['value' => $this->due_date, 'label' => ctrans('texts.valid_until')]; - $data['$credit_amount'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_amount')]; - $data['$credit_balance'] = ['value' => Number::formatMoney($this->balance, $this->client) ?: ' ', 'label' => ctrans('texts.credit_balance')]; + // // $data['$your_invoice'] = ; + // // $data['$quote'] = ; + // // $data['$your_quote'] = ; + // // + // $data['$quote.date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.quote_date')]; + // $data['$quote.number'] = ['value' => $this->number ?: ' ', 'label' => ctrans('texts.quote_number')]; + // $data['$quote.po_number'] = &$data['$invoice.po_number']; + // $data['$quote.quote_number'] = &$data['$quote.number']; + // $data['$quote_no'] = &$data['$quote.number']; + // $data['$quote.quote_no'] = &$data['$quote.number']; + // $data['$quote.valid_until'] = ['value' => $this->due_date, 'label' => ctrans('texts.valid_until')]; + // $data['$credit_amount'] = ['value' => Number::formatMoney($calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_amount')]; + // $data['$credit_balance'] = ['value' => Number::formatMoney($this->balance, $this->client) ?: ' ', 'label' => ctrans('texts.credit_balance')]; - $data['$credit_number'] = &$data['$number']; - $data['$credit_no'] = &$data['$number']; - $data['$credit.credit_no'] = &$data['$number']; + // $data['$credit_number'] = &$data['$number']; + // $data['$credit_no'] = &$data['$number']; + // $data['$credit.credit_no'] = &$data['$number']; - // $data['$invoice_issued_to'] = ; - // $data['$quote_issued_to'] = ; - // $data['$rate'] = ; - // $data['$hours'] = ; - // $data['$from'] = ; - // $data['$to'] = ; - // $data['$invoice_to'] = ; - // $data['$quote_to'] = ; - // $data['$details'] = ; - $data['$invoice_no'] = &$data['$number']; - $data['$invoice.invoice_no'] = &$data['$number']; - $data['$client1'] = ['value' => $this->client->custom_value1 ?: ' ', 'label' => $this->makeCustomField('client1')]; - $data['$client2'] = ['value' => $this->client->custom_value2 ?: ' ', 'label' => $this->makeCustomField('client2')]; - $data['$client3'] = ['value' => $this->client->custom_value3 ?: ' ', 'label' => $this->makeCustomField('client3')]; - $data['$client4'] = ['value' => $this->client->custom_value4 ?: ' ', 'label' => $this->makeCustomField('client4')]; - $data['$address1'] = ['value' => $this->client->address1 ?: ' ', 'label' => ctrans('texts.address1')]; - $data['$address2'] = ['value' => $this->client->address2 ?: ' ', 'label' => ctrans('texts.address2')]; - $data['$id_number'] = ['value' => $this->client->id_number ?: ' ', 'label' => ctrans('texts.id_number')]; - $data['$vat_number'] = ['value' => $this->client->vat_number ?: ' ', 'label' => ctrans('texts.vat_number')]; - $data['$website'] = ['value' => $this->client->present()->website() ?: ' ', 'label' => ctrans('texts.website')]; - $data['$phone'] = ['value' => $this->client->present()->phone() ?: ' ', 'label' => ctrans('texts.phone')]; - $data['$country'] = ['value' => isset($this->client->country->name) ? $this->client->country->name : 'No Country Set', 'label' => ctrans('texts.country')]; - $data['$email'] = ['value' => isset($contact) ? $contact->email : 'no contact email on record', 'label' => ctrans('texts.email')]; - $data['$client_name'] = ['value' => $this->present()->clientName() ?: ' ', 'label' => ctrans('texts.client_name')]; - $data['$client.name'] = &$data['$client_name']; - $data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; - $data['$outstanding'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; + // // $data['$invoice_issued_to'] = ; + // // $data['$quote_issued_to'] = ; + // // $data['$rate'] = ; + // // $data['$hours'] = ; + // // $data['$from'] = ; + // // $data['$to'] = ; + // // $data['$invoice_to'] = ; + // // $data['$quote_to'] = ; + // // $data['$details'] = ; + // $data['$invoice_no'] = &$data['$number']; + // $data['$invoice.invoice_no'] = &$data['$number']; + // $data['$client1'] = ['value' => $this->client->custom_value1 ?: ' ', 'label' => $this->makeCustomField('client1')]; + // $data['$client2'] = ['value' => $this->client->custom_value2 ?: ' ', 'label' => $this->makeCustomField('client2')]; + // $data['$client3'] = ['value' => $this->client->custom_value3 ?: ' ', 'label' => $this->makeCustomField('client3')]; + // $data['$client4'] = ['value' => $this->client->custom_value4 ?: ' ', 'label' => $this->makeCustomField('client4')]; + // $data['$address1'] = ['value' => $this->client->address1 ?: ' ', 'label' => ctrans('texts.address1')]; + // $data['$address2'] = ['value' => $this->client->address2 ?: ' ', 'label' => ctrans('texts.address2')]; + // $data['$id_number'] = ['value' => $this->client->id_number ?: ' ', 'label' => ctrans('texts.id_number')]; + // $data['$vat_number'] = ['value' => $this->client->vat_number ?: ' ', 'label' => ctrans('texts.vat_number')]; + // $data['$website'] = ['value' => $this->client->present()->website() ?: ' ', 'label' => ctrans('texts.website')]; + // $data['$phone'] = ['value' => $this->client->present()->phone() ?: ' ', 'label' => ctrans('texts.phone')]; + // $data['$country'] = ['value' => isset($this->client->country->name) ? $this->client->country->name : 'No Country Set', 'label' => ctrans('texts.country')]; + // $data['$email'] = ['value' => isset($contact) ? $contact->email : 'no contact email on record', 'label' => ctrans('texts.email')]; + // $data['$client_name'] = ['value' => $this->present()->clientName() ?: ' ', 'label' => ctrans('texts.client_name')]; + // $data['$client.name'] = &$data['$client_name']; + // $data['$client.balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; + // $data['$outstanding'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; - $data['$client_balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; + // $data['$client_balance'] = ['value' => Number::formatMoney($this->client->balance, $this->client), 'label' => ctrans('texts.account_balance')]; - $data['$paid_to_date'] = ['value' => Number::formatMoney($this->client->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')]; + // $data['$paid_to_date'] = ['value' => Number::formatMoney($this->client->paid_to_date, $this->client), 'label' => ctrans('texts.paid_to_date')]; - $data['$client.address1'] = &$data['$address1']; - $data['$client.address2'] = &$data['$address2']; - $data['$client_address'] = ['value' => $this->present()->address() ?: ' ', 'label' => ctrans('texts.address')]; - $data['$client.address'] = &$data['$client_address']; - $data['$client.id_number'] = &$data['$id_number']; - $data['$client.vat_number'] = &$data['$vat_number']; - $data['$client.website'] = &$data['$website']; - $data['$client.phone'] = &$data['$phone']; - $data['$city_state_postal'] = ['value' => $this->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, false) ?: ' ', 'label' => ctrans('texts.city_state_postal')]; - $data['$client.city_state_postal'] = &$data['$city_state_postal']; - $data['$postal_city_state'] = ['value' => $this->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, true) ?: ' ', 'label' => ctrans('texts.postal_city_state')]; - $data['$client.postal_city_state'] = &$data['$postal_city_state']; - $data['$client.country'] = &$data['$country']; - $data['$client.email'] = &$data['$email']; + // $data['$client.address1'] = &$data['$address1']; + // $data['$client.address2'] = &$data['$address2']; + // $data['$client_address'] = ['value' => $this->present()->address() ?: ' ', 'label' => ctrans('texts.address')]; + // $data['$client.address'] = &$data['$client_address']; + // $data['$client.id_number'] = &$data['$id_number']; + // $data['$client.vat_number'] = &$data['$vat_number']; + // $data['$client.website'] = &$data['$website']; + // $data['$client.phone'] = &$data['$phone']; + // $data['$city_state_postal'] = ['value' => $this->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, false) ?: ' ', 'label' => ctrans('texts.city_state_postal')]; + // $data['$client.city_state_postal'] = &$data['$city_state_postal']; + // $data['$postal_city_state'] = ['value' => $this->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, true) ?: ' ', 'label' => ctrans('texts.postal_city_state')]; + // $data['$client.postal_city_state'] = &$data['$postal_city_state']; + // $data['$client.country'] = &$data['$country']; + // $data['$client.email'] = &$data['$email']; - $data['$contact.full_name'] = ['value' => $contact->present()->name(), 'label' => ctrans('texts.name')]; - $data['$contact.email'] = ['value' => $contact->email, 'label' => ctrans('texts.email')]; - $data['$contact.phone'] = ['value' => $contact->phone, 'label' => ctrans('texts.phone')]; + // $data['$contact.full_name'] = ['value' => $contact->present()->name(), 'label' => ctrans('texts.name')]; + // $data['$contact.email'] = ['value' => $contact->email, 'label' => ctrans('texts.email')]; + // $data['$contact.phone'] = ['value' => $contact->phone, 'label' => ctrans('texts.phone')]; - $data['$contact.name'] = ['value' => isset($contact) ? $contact->present()->name() : 'no contact name on record', 'label' => ctrans('texts.contact_name')]; - $data['$contact.first_name'] = ['value' => isset($contact) ? $contact->first_name : '', 'label' => ctrans('texts.first_name')]; - $data['$contact.last_name'] = ['value' => isset($contact) ? $contact->last_name : '', 'label' => ctrans('texts.last_name')]; - $data['$contact.custom1'] = ['value' => isset($contact) ? $contact->custom_value1 : ' ', 'label' => $this->makeCustomField('contact1')]; - $data['$contact.custom2'] = ['value' => isset($contact) ? $contact->custom_value2 : ' ', 'label' => $this->makeCustomField('contact1')]; - $data['$contact.custom3'] = ['value' => isset($contact) ? $contact->custom_value3 : ' ', 'label' => $this->makeCustomField('contact1')]; - $data['$contact.custom4'] = ['value' => isset($contact) ? $contact->custom_value4 : ' ', 'label' => $this->makeCustomField('contact1')]; + // $data['$contact.name'] = ['value' => isset($contact) ? $contact->present()->name() : 'no contact name on record', 'label' => ctrans('texts.contact_name')]; + // $data['$contact.first_name'] = ['value' => isset($contact) ? $contact->first_name : '', 'label' => ctrans('texts.first_name')]; + // $data['$contact.last_name'] = ['value' => isset($contact) ? $contact->last_name : '', 'label' => ctrans('texts.last_name')]; + // $data['$contact.custom1'] = ['value' => isset($contact) ? $contact->custom_value1 : ' ', 'label' => $this->makeCustomField('contact1')]; + // $data['$contact.custom2'] = ['value' => isset($contact) ? $contact->custom_value2 : ' ', 'label' => $this->makeCustomField('contact1')]; + // $data['$contact.custom3'] = ['value' => isset($contact) ? $contact->custom_value3 : ' ', 'label' => $this->makeCustomField('contact1')]; + // $data['$contact.custom4'] = ['value' => isset($contact) ? $contact->custom_value4 : ' ', 'label' => $this->makeCustomField('contact1')]; - $data['$company.city_state_postal'] = ['value' => $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, false) ?: ' ', 'label' => ctrans('texts.city_state_postal')]; - $data['$company.postal_city_state'] = ['value' => $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, true) ?: ' ', 'label' => ctrans('texts.postal_city_state')]; - $data['$company.name'] = ['value' => $this->company->present()->name() ?: ' ', 'label' => ctrans('texts.company_name')]; - $data['$company.address1'] = ['value' => $settings->address1 ?: ' ', 'label' => ctrans('texts.address1')]; - $data['$company.address2'] = ['value' => $settings->address2 ?: ' ', 'label' => ctrans('texts.address2')]; - $data['$company.city'] = ['value' => $settings->city ?: ' ', 'label' => ctrans('texts.city')]; - $data['$company.state'] = ['value' => $settings->state ?: ' ', 'label' => ctrans('texts.state')]; - $data['$company.postal_code'] = ['value' => $settings->postal_code ?: ' ', 'label' => ctrans('texts.postal_code')]; - $data['$company.country'] = ['value' => Country::find($settings->country_id)->first()->name ?: ' ', 'label' => ctrans('texts.country')]; - $data['$company.phone'] = ['value' => $settings->phone ?: ' ', 'label' => ctrans('texts.phone')]; - $data['$company.email'] = ['value' => $settings->email ?: ' ', 'label' => ctrans('texts.email')]; - $data['$company.vat_number'] = ['value' => $settings->vat_number ?: ' ', 'label' => ctrans('texts.vat_number')]; - $data['$company.id_number'] = ['value' => $settings->id_number ?: ' ', 'label' => ctrans('texts.id_number')]; - $data['$company.website'] = ['value' => $settings->website ?: ' ', 'label' => ctrans('texts.website')]; - $data['$company.address'] = ['value' => $this->company->present()->address($settings) ?: ' ', 'label' => ctrans('texts.address')]; + // $data['$company.city_state_postal'] = ['value' => $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, false) ?: ' ', 'label' => ctrans('texts.city_state_postal')]; + // $data['$company.postal_city_state'] = ['value' => $this->company->present()->cityStateZip($settings->city, $settings->state, $settings->postal_code, true) ?: ' ', 'label' => ctrans('texts.postal_city_state')]; + // $data['$company.name'] = ['value' => $this->company->present()->name() ?: ' ', 'label' => ctrans('texts.company_name')]; + // $data['$company.address1'] = ['value' => $settings->address1 ?: ' ', 'label' => ctrans('texts.address1')]; + // $data['$company.address2'] = ['value' => $settings->address2 ?: ' ', 'label' => ctrans('texts.address2')]; + // $data['$company.city'] = ['value' => $settings->city ?: ' ', 'label' => ctrans('texts.city')]; + // $data['$company.state'] = ['value' => $settings->state ?: ' ', 'label' => ctrans('texts.state')]; + // $data['$company.postal_code'] = ['value' => $settings->postal_code ?: ' ', 'label' => ctrans('texts.postal_code')]; + // $data['$company.country'] = ['value' => Country::find($settings->country_id)->first()->name ?: ' ', 'label' => ctrans('texts.country')]; + // $data['$company.phone'] = ['value' => $settings->phone ?: ' ', 'label' => ctrans('texts.phone')]; + // $data['$company.email'] = ['value' => $settings->email ?: ' ', 'label' => ctrans('texts.email')]; + // $data['$company.vat_number'] = ['value' => $settings->vat_number ?: ' ', 'label' => ctrans('texts.vat_number')]; + // $data['$company.id_number'] = ['value' => $settings->id_number ?: ' ', 'label' => ctrans('texts.id_number')]; + // $data['$company.website'] = ['value' => $settings->website ?: ' ', 'label' => ctrans('texts.website')]; + // $data['$company.address'] = ['value' => $this->company->present()->address($settings) ?: ' ', 'label' => ctrans('texts.address')]; - $logo = $this->company->present()->logo($settings); + // $logo = $this->company->present()->logo($settings); - $data['$company.logo'] = ['value' => "logo" ?: ' ', 'label' => ctrans('texts.logo')]; - $data['$company_logo'] = &$data['$company.logo']; - $data['$company1'] = ['value' => $settings->custom_value1 ?: ' ', 'label' => $this->makeCustomField('company1')]; - $data['$company2'] = ['value' => $settings->custom_value2 ?: ' ', 'label' => $this->makeCustomField('company2')]; - $data['$company3'] = ['value' => $settings->custom_value3 ?: ' ', 'label' => $this->makeCustomField('company3')]; - $data['$company4'] = ['value' => $settings->custom_value4 ?: ' ', 'label' => $this->makeCustomField('company4')]; + // $data['$company.logo'] = ['value' => "logo" ?: ' ', 'label' => ctrans('texts.logo')]; + // $data['$company_logo'] = &$data['$company.logo']; + // $data['$company1'] = ['value' => $settings->custom_value1 ?: ' ', 'label' => $this->makeCustomField('company1')]; + // $data['$company2'] = ['value' => $settings->custom_value2 ?: ' ', 'label' => $this->makeCustomField('company2')]; + // $data['$company3'] = ['value' => $settings->custom_value3 ?: ' ', 'label' => $this->makeCustomField('company3')]; + // $data['$company4'] = ['value' => $settings->custom_value4 ?: ' ', 'label' => $this->makeCustomField('company4')]; - $data['$custom_surcharge1'] = ['value' => $this->custom_surcharge1, 'label' => $this->makeCustomField('custom_surcharge1')]; - $data['$custom_surcharge2'] = ['value' => $this->custom_surcharge2, 'label' => $this->makeCustomField('custom_surcharge2')]; - $data['$custom_surcharge3'] = ['value' => $this->custom_surcharge3, 'label' => $this->makeCustomField('custom_surcharge3')]; - $data['$custom_surcharge4'] = ['value' => $this->custom_surcharge4, 'label' => $this->makeCustomField('custom_surcharge4')]; + // $data['$custom_surcharge1'] = ['value' => $this->custom_surcharge1, 'label' => $this->makeCustomField('custom_surcharge1')]; + // $data['$custom_surcharge2'] = ['value' => $this->custom_surcharge2, 'label' => $this->makeCustomField('custom_surcharge2')]; + // $data['$custom_surcharge3'] = ['value' => $this->custom_surcharge3, 'label' => $this->makeCustomField('custom_surcharge3')]; + // $data['$custom_surcharge4'] = ['value' => $this->custom_surcharge4, 'label' => $this->makeCustomField('custom_surcharge4')]; - $data['$product.date'] = ['value' => '', 'label' => ctrans('texts.date')]; - $data['$product.discount'] = ['value' => '', 'label' => ctrans('texts.discount')]; - $data['$product.product_key'] = ['value' => '', 'label' => ctrans('texts.product_key')]; - $data['$product.notes'] = ['value' => '', 'label' => ctrans('texts.notes')]; - $data['$product.cost'] = ['value' => '', 'label' => ctrans('texts.cost')]; - $data['$product.quantity'] = ['value' => '', 'label' => ctrans('texts.quantity')]; - $data['$product.tax_name1'] = ['value' => '', 'label' => ctrans('texts.tax')]; - $data['$product.tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; - $data['$product.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')]; - $data['$product.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')]; - $data['$product.line_total'] = ['value' => '', 'label' => ctrans('texts.line_total')]; + // $data['$product.date'] = ['value' => '', 'label' => ctrans('texts.date')]; + // $data['$product.discount'] = ['value' => '', 'label' => ctrans('texts.discount')]; + // $data['$product.product_key'] = ['value' => '', 'label' => ctrans('texts.product_key')]; + // $data['$product.notes'] = ['value' => '', 'label' => ctrans('texts.notes')]; + // $data['$product.cost'] = ['value' => '', 'label' => ctrans('texts.cost')]; + // $data['$product.quantity'] = ['value' => '', 'label' => ctrans('texts.quantity')]; + // $data['$product.tax_name1'] = ['value' => '', 'label' => ctrans('texts.tax')]; + // $data['$product.tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; + // $data['$product.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')]; + // $data['$product.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')]; + // $data['$product.line_total'] = ['value' => '', 'label' => ctrans('texts.line_total')]; - $data['$task.date'] = ['value' => '', 'label' => ctrans('texts.date')]; - $data['$task.discount'] = ['value' => '', 'label' => ctrans('texts.discount')]; - $data['$task.product_key'] = ['value' => '', 'label' => ctrans('texts.product_key')]; - $data['$task.notes'] = ['value' => '', 'label' => ctrans('texts.notes')]; - $data['$task.cost'] = ['value' => '', 'label' => ctrans('texts.cost')]; - $data['$task.quantity'] = ['value' => '', 'label' => ctrans('texts.quantity')]; - $data['$task.tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; - $data['$task.tax_name1'] = ['value' => '', 'label' => ctrans('texts.tax')]; - $data['$task.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')]; - $data['$task.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')]; - $data['$task.line_total'] = ['value' => '', 'label' => ctrans('texts.line_total')]; - //$data['$contact.signature'] + // $data['$task.date'] = ['value' => '', 'label' => ctrans('texts.date')]; + // $data['$task.discount'] = ['value' => '', 'label' => ctrans('texts.discount')]; + // $data['$task.product_key'] = ['value' => '', 'label' => ctrans('texts.product_key')]; + // $data['$task.notes'] = ['value' => '', 'label' => ctrans('texts.notes')]; + // $data['$task.cost'] = ['value' => '', 'label' => ctrans('texts.cost')]; + // $data['$task.quantity'] = ['value' => '', 'label' => ctrans('texts.quantity')]; + // $data['$task.tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; + // $data['$task.tax_name1'] = ['value' => '', 'label' => ctrans('texts.tax')]; + // $data['$task.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')]; + // $data['$task.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')]; + // $data['$task.line_total'] = ['value' => '', 'label' => ctrans('texts.line_total')]; + // //$data['$contact.signature'] - // $data['custom_label1'] = ['value' => '', 'label' => ctrans('texts.')]; - // $data['custom_label2'] = ['value' => '', 'label' => ctrans('texts.')]; - // $data['custom_label3'] = ['value' => '', 'label' => ctrans('texts.')]; - // $data['custom_label4'] = ['value' => '', 'label' => ctrans('texts.')]; - //$data['$blank'] = ; - //$data['$surcharge'] = ; - /* - $data['$tax_invoice'] = - $data['$tax_quote'] = - $data['$statement'] = ; - $data['$statement_date'] = ; - $data['$your_statement'] = ; - $data['$statement_issued_to'] = ; - $data['$statement_to'] = ; - $data['$credit_note'] = ; - $data['$credit_date'] = ; - $data['$credit_issued_to'] = ; - $data['$credit_to'] = ; - $data['$your_credit'] = ; - $data['$phone'] = ; + // // $data['custom_label1'] = ['value' => '', 'label' => ctrans('texts.')]; + // // $data['custom_label2'] = ['value' => '', 'label' => ctrans('texts.')]; + // // $data['custom_label3'] = ['value' => '', 'label' => ctrans('texts.')]; + // // $data['custom_label4'] = ['value' => '', 'label' => ctrans('texts.')]; + // //$data['$blank'] = ; + // //$data['$surcharge'] = ; + // /* + // $data['$tax_invoice'] = + // $data['$tax_quote'] = + // $data['$statement'] = ; + // $data['$statement_date'] = ; + // $data['$your_statement'] = ; + // $data['$statement_issued_to'] = ; + // $data['$statement_to'] = ; + // $data['$credit_note'] = ; + // $data['$credit_date'] = ; + // $data['$credit_issued_to'] = ; + // $data['$credit_to'] = ; + // $data['$your_credit'] = ; + // $data['$phone'] = ; - $data['$outstanding'] = ; - $data['$invoice_due_date'] = ; - $data['$quote_due_date'] = ; - $data['$service'] = ; - $data['$product_key'] = ; - $data['$unit_cost'] = ; - $data['$custom_value1'] = ; - $data['$custom_value2'] = ; - $data['$delivery_note'] = ; - $data['$date'] = ; - $data['$method'] = ; - $data['$payment_date'] = ; - $data['$reference'] = ; - $data['$amount'] = ; - $data['$amount_paid'] =; - */ + // $data['$outstanding'] = ; + // $data['$invoice_due_date'] = ; + // $data['$quote_due_date'] = ; + // $data['$service'] = ; + // $data['$product_key'] = ; + // $data['$unit_cost'] = ; + // $data['$custom_value1'] = ; + // $data['$custom_value2'] = ; + // $data['$delivery_note'] = ; + // $data['$date'] = ; + // $data['$method'] = ; + // $data['$payment_date'] = ; + // $data['$reference'] = ; + // $data['$amount'] = ; + // $data['$amount_paid'] =; + // */ - $arrKeysLength = array_map('strlen', array_keys($data)); - array_multisort($arrKeysLength, SORT_DESC, $data); + // $arrKeysLength = array_map('strlen', array_keys($data)); + // array_multisort($arrKeysLength, SORT_DESC, $data); - return $data; - } + // return $data; + // } /** * V2 of building a table header for PDFs. diff --git a/app/Utils/Traits/PaymentEmailBuilder.php b/app/Utils/Traits/PaymentEmailBuilder.php index 825dbcf956b0..d739aea896ec 100644 --- a/app/Utils/Traits/PaymentEmailBuilder.php +++ b/app/Utils/Traits/PaymentEmailBuilder.php @@ -67,7 +67,7 @@ trait PaymentEmailBuilder private function parseTemplate(string $template_data, bool $is_markdown, $contact) :string { - $invoice_variables = $this->makeValues($contact); + //$invoice_variables = $this->makeValues($contact); //process variables //$data = str_replace(array_keys($invoice_variables), array_values($invoice_variables), $template_data); diff --git a/app/Utils/Traits/QuoteEmailBuilder.php b/app/Utils/Traits/QuoteEmailBuilder.php index 3076ba6c650b..b31f7a3c771c 100644 --- a/app/Utils/Traits/QuoteEmailBuilder.php +++ b/app/Utils/Traits/QuoteEmailBuilder.php @@ -75,7 +75,7 @@ trait QuoteEmailBuilder private function parseTemplate(string $template_data, bool $is_markdown, $contact) :string { - $quote_variables = $this->makeValues($contact); + // $quote_variables = $this->makeValues($contact); //process variables // $data = str_replace(array_keys($quote_variables), array_values($quote_variables), $template_data); diff --git a/tests/Feature/InvoiceEmailTest.php b/tests/Feature/InvoiceEmailTest.php index 1e4887a75d30..84bf117858a6 100644 --- a/tests/Feature/InvoiceEmailTest.php +++ b/tests/Feature/InvoiceEmailTest.php @@ -11,7 +11,7 @@ namespace Feature; use App\Helpers\Email\InvoiceEmail; -use App\Jobs\Invoice\EmailInvoice; +use App\Jobs\Entity\EmailEntity; use App\Mail\TemplateEmail; use App\Models\ClientContact; use App\Models\Invoice; @@ -69,11 +69,10 @@ class InvoiceEmailTest extends TestCase $this->invoice->invitations->each(function ($invitation) { if ($invitation->contact->send_email && $invitation->contact->email) { - $email_builder = (new InvoiceEmail())->build($invitation, null); - EmailInvoice::dispatchNow($email_builder, $invitation, $invitation->company); + EmailEntity::dispatchNow($invitation, $invitation->company); - $this->expectsJobs(EmailInvoice::class); + $this->expectsJobs(EmailEntity::class); } }); @@ -99,11 +98,9 @@ class InvoiceEmailTest extends TestCase $this->invoice->invitations->each(function ($invitation) { if ($invitation->contact->send_email && $invitation->contact->email) { - $email_builder = (new InvoiceEmail())->build($invitation, null); + EmailEntity::dispatchNow($invitation, $invitation->company); - EmailInvoice::dispatchNow($email_builder, $invitation, $invitation->company); - - $this->expectsJobs(EmailInvoice::class); + $this->expectsJobs(EmailEntity::class); } }); @@ -129,11 +126,9 @@ class InvoiceEmailTest extends TestCase $this->invoice->invitations->each(function ($invitation) { if ($invitation->contact->send_email && $invitation->contact->email) { - $email_builder = (new InvoiceEmail())->build($invitation, null); + EmailEntity::dispatchNow($invitation, $invitation->company); - EmailInvoice::dispatchNow($email_builder, $invitation, $invitation->company); - - $this->expectsJobs(EmailInvoice::class); + $this->expectsJobs(EmailEntity::class); } }); @@ -154,11 +149,9 @@ class InvoiceEmailTest extends TestCase $this->invoice->invitations->each(function ($invitation) { if ($invitation->contact->send_email && $invitation->contact->email) { - $email_builder = (new InvoiceEmail())->build($invitation, null); + EmailEntity::dispatchNow($invitation, $invitation->company); - EmailInvoice::dispatchNow($email_builder, $invitation, $invitation->company); - - $this->expectsJobs(EmailInvoice::class); + $this->expectsJobs(EmailEntity::class); } }); From adeda5526eece7d092b565f0b2661ff4c1a92c14 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 28 Oct 2020 17:58:15 +1100 Subject: [PATCH 3/4] Add Psalm, code cleanup! --- app/Http/Controllers/InvoiceController.php | 4 +- app/Jobs/RecurringInvoice/SendRecurring.php | 4 +- app/Jobs/Util/SendFailedEmails.php | 6 +- app/Repositories/ClientContactRepository.php | 2 + app/Repositories/VendorContactRepository.php | 2 + app/Services/Invoice/SendEmail.php | 2 - app/Services/Invoice/TriggeredActions.php | 5 +- composer.json | 1 + composer.lock | 573 ++++++++++++++++++- psalm.xml | 38 ++ 10 files changed, 623 insertions(+), 14 deletions(-) create mode 100644 psalm.xml diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 5cfc5dbdc51a..b1312f7b04f1 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -28,7 +28,7 @@ use App\Http\Requests\Invoice\EditInvoiceRequest; use App\Http\Requests\Invoice\ShowInvoiceRequest; use App\Http\Requests\Invoice\StoreInvoiceRequest; use App\Http\Requests\Invoice\UpdateInvoiceRequest; -use App\Jobs\Invoice\EmailInvoice; +use App\Jobs\Entity\EmailEntity; use App\Jobs\Invoice\StoreInvoice; use App\Jobs\Invoice\ZipInvoices; use App\Jobs\Util\UnlinkFile; @@ -716,7 +716,7 @@ class InvoiceController extends BaseController $invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) use ($invoice) { $email_builder = (new InvoiceEmail())->build($invitation, $this->reminder_template); - EmailInvoice::dispatch($email_builder, $invitation, $invoice->company); + EmailEntity::dispatch($invitation, $invoice->company); }); if (! $bulk) { diff --git a/app/Jobs/RecurringInvoice/SendRecurring.php b/app/Jobs/RecurringInvoice/SendRecurring.php index 9a0f0b74cbcd..e06624942224 100644 --- a/app/Jobs/RecurringInvoice/SendRecurring.php +++ b/app/Jobs/RecurringInvoice/SendRecurring.php @@ -15,7 +15,7 @@ use App\DataMapper\Analytics\SendRecurringFailure; use App\Events\Invoice\InvoiceWasEmailed; use App\Factory\RecurringInvoiceToInvoiceFactory; use App\Helpers\Email\InvoiceEmail; -use App\Jobs\Invoice\EmailInvoice; +use App\Jobs\Entity\EmailEntity; use App\Models\Invoice; use App\Models\RecurringInvoice; use App\Utils\Ninja; @@ -76,7 +76,7 @@ class SendRecurring implements ShouldQueue $email_builder = (new InvoiceEmail())->build($invitation); if($invitation->contact && strlen($invitation->contact->email) >=1){ - EmailInvoice::dispatch($email_builder, $invitation, $invoice->company); + EmailEntity::dispatch($invitation, $invoice->company); info("Firing email for invoice {$invoice->number}"); } diff --git a/app/Jobs/Util/SendFailedEmails.php b/app/Jobs/Util/SendFailedEmails.php index 329ed566c00b..91f0850657e6 100644 --- a/app/Jobs/Util/SendFailedEmails.php +++ b/app/Jobs/Util/SendFailedEmails.php @@ -12,6 +12,7 @@ namespace App\Jobs\Util; use App\Helpers\Email\InvoiceEmail; +use App\Jobs\Entity\EmailEntity; use App\Jobs\Invoice\EmailInvoice; use App\Libraries\MultiDB; use App\Models\SystemLog; @@ -56,9 +57,6 @@ class SendFailedEmails implements ShouldQueue private function processEmails() { - //\Log::error('processing emails'); - //info("process emails"); - //@todo check that the quota is available for the job $email_jobs = SystemLog::where('event_id', SystemLog::EVENT_MAIL_RETRY_QUEUE)->get(); @@ -71,7 +69,7 @@ class SendFailedEmails implements ShouldQueue $email_builder = (new InvoiceEmail())->build($invitation, $job_meta_array['reminder_template']); if ($invitation->contact->send_email && $invitation->contact->email) { - EmailInvoice::dispatch($email_builder, $invitation, $invitation->company); + EmailEntity::dispatch($invitation, $invitation->company); } } }); diff --git a/app/Repositories/ClientContactRepository.php b/app/Repositories/ClientContactRepository.php index 79f0ce397dcd..fe14030a5b19 100644 --- a/app/Repositories/ClientContactRepository.php +++ b/app/Repositories/ClientContactRepository.php @@ -22,6 +22,8 @@ use Illuminate\Support\Str; */ class ClientContactRepository extends BaseRepository { + public $is_primary; + public function save(array $data, Client $client) : void { if (isset($data['contacts'])) { diff --git a/app/Repositories/VendorContactRepository.php b/app/Repositories/VendorContactRepository.php index f9aab86646eb..8682c4ec460f 100644 --- a/app/Repositories/VendorContactRepository.php +++ b/app/Repositories/VendorContactRepository.php @@ -21,6 +21,8 @@ use Illuminate\Support\Str; */ class VendorContactRepository extends BaseRepository { + public $is_primary; + public function save($contacts, Vendor $vendor) : void { diff --git a/app/Services/Invoice/SendEmail.php b/app/Services/Invoice/SendEmail.php index 332ae1e812a0..911aea4411e9 100644 --- a/app/Services/Invoice/SendEmail.php +++ b/app/Services/Invoice/SendEmail.php @@ -13,7 +13,6 @@ namespace App\Services\Invoice; use App\Helpers\Email\InvoiceEmail; use App\Jobs\Entity\EmailEntity; -use App\Jobs\Invoice\EmailInvoice; use App\Models\ClientContact; use App\Models\Invoice; use App\Services\AbstractService; @@ -51,7 +50,6 @@ class SendEmail extends AbstractService $email_builder = (new InvoiceEmail())->build($invitation, $this->reminder_template); if ($invitation->contact->send_email && $invitation->contact->email) { -// EmailInvoice::dispatch($email_builder, $invitation, $invitation->company); EmailEntity::dispatchNow($invitation, $invitation->company); } diff --git a/app/Services/Invoice/TriggeredActions.php b/app/Services/Invoice/TriggeredActions.php index e1b439459684..ad4ba23074eb 100644 --- a/app/Services/Invoice/TriggeredActions.php +++ b/app/Services/Invoice/TriggeredActions.php @@ -15,7 +15,7 @@ use App\Events\Invoice\InvoiceWasEmailed; use App\Events\Payment\PaymentWasCreated; use App\Factory\PaymentFactory; use App\Helpers\Email\InvoiceEmail; -use App\Jobs\Invoice\EmailInvoice; +use App\Jobs\Invoice\EmailEntity; use App\Models\Client; use App\Models\Invoice; use App\Models\Payment; @@ -69,9 +69,8 @@ class TriggeredActions extends AbstractService $reminder_template = 'payment'; $this->invoice->invitations->load('contact.client.country', 'invoice.client.country', 'invoice.company')->each(function ($invitation) use ($reminder_template) { - $email_builder = (new InvoiceEmail())->build($invitation, $reminder_template); - EmailInvoice::dispatch($email_builder, $invitation, $this->invoice->company); + EmailEntity::dispatch($invitation, $this->invoice->company); }); if ($this->invoice->invitations->count() > 0) { diff --git a/composer.json b/composer.json index 3eb140e72ee2..1508529e0b2d 100644 --- a/composer.json +++ b/composer.json @@ -74,6 +74,7 @@ "mockery/mockery": "^1.3.1", "nunomaduro/collision": "^5.0", "phpunit/phpunit": "^9.0", + "vimeo/psalm": "^4.0", "wildbit/postmark-php": "^4.0" }, "autoload": { diff --git a/composer.lock b/composer.lock index 2fffb3750509..b13bd824bad7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "152c174ecc48f87a2c7fd00335c6fc86", + "content-hash": "5055049d1f5fa8418925b54a94265526", "packages": [ { "name": "asgrim/ofxparser", @@ -9801,6 +9801,166 @@ } ], "packages-dev": [ + { + "name": "amphp/amp", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "f220a51458bf4dd0dedebb171ac3457813c72bbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/f220a51458bf4dd0dedebb171ac3457813c72bbc", + "reference": "f220a51458bf4dd0dedebb171ac3457813c72bbc", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6.0.9 | ^7", + "psalm/phar": "^3.11@dev", + "react/promise": "^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\": "lib" + }, + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "http://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/master" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2020-07-14T21:47:18+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/f0c20cf598a958ba2aa8c6e5a71c697d652c7088", + "reference": "f0c20cf598a958ba2aa8c6e5a71c697d652c7088", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.4", + "friendsofphp/php-cs-fixer": "^2.3", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6 || ^7 || ^8", + "psalm/phar": "^3.11.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\ByteStream\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/byte-stream/issues", + "source": "https://github.com/amphp/byte-stream/tree/master" + }, + "time": "2020-06-29T18:35:05+00:00" + }, { "name": "anahkiasen/former", "version": "4.5.0", @@ -10503,6 +10663,107 @@ }, "time": "2020-10-16T08:27:54+00:00" }, + { + "name": "felixfbecker/advanced-json-rpc", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", + "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40", + "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40", + "shasum": "" + }, + "require": { + "netresearch/jsonmapper": "^1.0 || ^2.0", + "php": ">=7.0", + "phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdvancedJsonRpc\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "A more advanced JSONRPC implementation", + "support": { + "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", + "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/master" + }, + "time": "2020-03-11T15:21:41+00:00" + }, + { + "name": "felixfbecker/language-server-protocol", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-language-server-protocol.git", + "reference": "85e83cacd2ed573238678c6875f8f0d7ec699541" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/85e83cacd2ed573238678c6875f8f0d7ec699541", + "reference": "85e83cacd2ed573238678c6875f8f0d7ec699541", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpstan/phpstan": "*", + "squizlabs/php_codesniffer": "^3.1", + "vimeo/psalm": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "LanguageServerProtocol\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "PHP classes for the Language Server Protocol", + "keywords": [ + "language", + "microsoft", + "php", + "server" + ], + "support": { + "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.0" + }, + "time": "2020-10-23T13:55:30+00:00" + }, { "name": "filp/whoops", "version": "2.9.0", @@ -10814,6 +11075,57 @@ ], "time": "2020-06-29T13:22:24+00:00" }, + { + "name": "netresearch/jsonmapper", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e", + "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0", + "squizlabs/php_codesniffer": "~3.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonMapper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "OSL-3.0" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de", + "homepage": "http://github.com/cweiske/jsonmapper/", + "role": "Developer" + } + ], + "description": "Map nested JSON structures onto PHP classes", + "support": { + "email": "cweiske@cweiske.de", + "issues": "https://github.com/cweiske/jsonmapper/issues", + "source": "https://github.com/cweiske/jsonmapper/tree/master" + }, + "time": "2020-04-16T18:48:43+00:00" + }, { "name": "nunomaduro/collision", "version": "v5.0.2", @@ -10902,6 +11214,59 @@ ], "time": "2020-08-27T18:58:22+00:00" }, + { + "name": "openlss/lib-array2xml", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nullivex/lib-array2xml.git", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "LSS": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Bryan Tong", + "email": "bryan@nullivex.com", + "homepage": "https://www.nullivex.com" + }, + { + "name": "Tony Butler", + "email": "spudz76@gmail.com", + "homepage": "https://www.nullivex.com" + } + ], + "description": "Array2XML conversion library credit to lalit.org", + "homepage": "https://www.nullivex.com", + "keywords": [ + "array", + "array conversion", + "xml", + "xml conversion" + ], + "support": { + "issues": "https://github.com/nullivex/lib-array2xml/issues", + "source": "https://github.com/nullivex/lib-array2xml/tree/master" + }, + "time": "2019-03-29T20:06:56+00:00" + }, { "name": "phar-io/manifest", "version": "2.0.1", @@ -12967,6 +13332,111 @@ ], "time": "2020-07-12T23:59:07+00:00" }, + { + "name": "vimeo/psalm", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/vimeo/psalm.git", + "reference": "b1e2e30026936ef8d5bf6a354d1c3959b6231f44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/b1e2e30026936ef8d5bf6a354d1c3959b6231f44", + "reference": "b1e2e30026936ef8d5bf6a354d1c3959b6231f44", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.1", + "amphp/byte-stream": "^1.5", + "composer/package-versions-deprecated": "^1.8.0", + "composer/semver": "^1.4 || ^2.0 || ^3.0", + "composer/xdebug-handler": "^1.1", + "dnoegel/php-xdg-base-dir": "^0.1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "felixfbecker/advanced-json-rpc": "^3.0.3", + "felixfbecker/language-server-protocol": "^1.4", + "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0", + "nikic/php-parser": "^4.10.1", + "openlss/lib-array2xml": "^1.0", + "php": "^7.3|^8", + "sebastian/diff": "^3.0 || ^4.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "webmozart/glob": "^4.1", + "webmozart/path-util": "^2.3" + }, + "provide": { + "psalm/psalm": "self.version" + }, + "require-dev": { + "amphp/amp": "^2.4.2", + "bamarni/composer-bin-plugin": "^1.2", + "brianium/paratest": "^4.0.0", + "ext-curl": "*", + "phpdocumentor/reflection-docblock": "^5", + "phpmyadmin/sql-parser": "5.1.0", + "phpspec/prophecy": ">=1.9.0", + "phpunit/phpunit": "^9.0", + "psalm/plugin-phpunit": "^0.13", + "slevomat/coding-standard": "^5.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.3", + "weirdan/prophecy-shim": "^1.0 || ^2.0" + }, + "suggest": { + "ext-igbinary": "^2.0.5" + }, + "bin": [ + "psalm", + "psalm-language-server", + "psalm-plugin", + "psalm-refactor", + "psalter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev", + "dev-3.x": "3.x-dev", + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psalm\\": "src/Psalm/" + }, + "files": [ + "src/functions.php", + "src/spl_object_id.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Brown" + } + ], + "description": "A static analysis tool for finding errors in PHP applications", + "keywords": [ + "code", + "inspection", + "php" + ], + "support": { + "issues": "https://github.com/vimeo/psalm/issues", + "source": "https://github.com/vimeo/psalm/tree/4.0.1" + }, + "time": "2020-10-20T13:40:17+00:00" + }, { "name": "webmozart/assert", "version": "1.9.1", @@ -13020,6 +13490,107 @@ }, "time": "2020-07-08T17:02:28+00:00" }, + { + "name": "webmozart/glob", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/glob.git", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/glob/zipball/3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0", + "webmozart/path-util": "^2.2" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1", + "symfony/filesystem": "^2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "support": { + "issues": "https://github.com/webmozart/glob/issues", + "source": "https://github.com/webmozart/glob/tree/master" + }, + "time": "2015-12-29T11:14:33+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "support": { + "issues": "https://github.com/webmozart/path-util/issues", + "source": "https://github.com/webmozart/path-util/tree/2.3.0" + }, + "time": "2015-12-17T08:42:14+00:00" + }, { "name": "wildbit/postmark-php", "version": "4.0.0", diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 000000000000..151fa3530cc5 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7886482fb502546583bf3cce67c9ecc65cc33c81 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 28 Oct 2020 19:32:14 +1100 Subject: [PATCH 4/4] Localize dates in entities --- app/Utils/HtmlEngine.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index f5d0953b5284..aabbe2e2754b 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -104,11 +104,11 @@ class HtmlEngine $data['$total_tax_values'] = ['value' => $this->totalTaxValues(), 'label' => ctrans('texts.taxes')]; $data['$line_tax_labels'] = ['value' => $this->lineTaxLabels(), 'label' => ctrans('texts.taxes')]; $data['$line_tax_values'] = ['value' => $this->lineTaxValues(), 'label' => ctrans('texts.taxes')]; - $data['$date'] = ['value' => $this->entity->date ?: ' ', 'label' => ctrans('texts.date')]; + $data['$date'] = ['value' => $this->formatDate($this->entity->date, $this->client->date_format()) ?: ' ', 'label' => ctrans('texts.date')]; //$data['$invoice_date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.invoice_date')]; $data['$invoice.date'] = &$data['$date']; - $data['$due_date'] = ['value' => $this->entity->due_date ?: ' ', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')]; - $data['$payment_due'] = ['value' => $this->entity->due_date ?: ' ', 'label' => ctrans('texts.payment_due')]; + $data['$due_date'] = ['value' => $this->formatDate($this->entity->due_date, $this->client->date_format()) ?: ' ', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')]; + $data['$payment_due'] = ['value' => $this->formatDate($this->entity->due_date, $this->client->date_format()) ?: ' ', 'label' => ctrans('texts.payment_due')]; $data['$invoice.due_date'] = &$data['$due_date']; $data['$invoice.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')]; $data['$invoice.po_number'] = ['value' => $this->entity->po_number ?: ' ', 'label' => ctrans('texts.po_number')]; @@ -168,7 +168,7 @@ class HtmlEngine $data['$credit.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.credit_number')]; $data['$credit.total'] = &$data['$credit.total']; $data['$credit.po_number'] = &$data['$invoice.po_number']; - $data['$credit.date'] = ['value' => $this->entity->date, 'label' => ctrans('texts.credit_date')]; + $data['$credit.date'] = ['value' => $this->formatDate($this->entity->date, $this->client->date_format()), 'label' => ctrans('texts.credit_date')]; $data['$balance'] = ['value' => Number::formatMoney($this->entity_calc->getBalance(), $this->client) ?: ' ', 'label' => ctrans('texts.balance')]; $data['$credit.balance'] = &$data['$balance']; @@ -186,13 +186,13 @@ class HtmlEngine $data['$entity_issued_to'] = ['value' => '', 'label' => ctrans("texts.{$this->entity_string}_issued_to")]; $data['$your_entity'] = ['value' => '', 'label' => ctrans("texts.your_{$this->entity_string}")]; - $data['$quote.date'] = ['value' => $this->entity->date ?: ' ', 'label' => ctrans('texts.quote_date')]; + $data['$quote.date'] = ['value' => $this->formatDate($this->entity->date, $this->client->date_format()) ?: ' ', 'label' => ctrans('texts.quote_date')]; $data['$quote.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.quote_number')]; $data['$quote.po_number'] = &$data['$invoice.po_number']; $data['$quote.quote_number'] = &$data['$quote.number']; $data['$quote_no'] = &$data['$quote.number']; $data['$quote.quote_no'] = &$data['$quote.number']; - $data['$quote.valid_until'] = ['value' => $this->entity->due_date, 'label' => ctrans('texts.valid_until')]; + $data['$quote.valid_until'] = ['value' => $this->formatDate($this->entity->due_date, $this->client->date_format()), 'label' => ctrans('texts.valid_until')]; $data['$credit_amount'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_amount')]; $data['$credit_balance'] = ['value' => Number::formatMoney($this->entity->balance, $this->client) ?: ' ', 'label' => ctrans('texts.credit_balance')];