From 9294e2c347d28f5f93e196ce943d63d88af47eaf Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 13 Oct 2023 13:43:59 +1100 Subject: [PATCH 1/4] Minor Fixes for templates --- app/Services/Client/Statement.php | 4 ++-- app/Services/Pdf/PdfMock.php | 25 +++++++++++++---------- app/Services/Template/TemplateService.php | 6 ++++++ lang/en/texts.php | 2 ++ 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/app/Services/Client/Statement.php b/app/Services/Client/Statement.php index 4cca2b8bb770..7bd42e14cef9 100644 --- a/app/Services/Client/Statement.php +++ b/app/Services/Client/Statement.php @@ -144,8 +144,8 @@ class Statement 'variables' => collect([$variables]), 'invoices' => $this->getInvoices()->get(), 'payments' => $this->options['show_payments_table'] ? $this->getPayments()->get() : collect([]), - 'credits' => $this->options['show_credits_table'] ? $this->getCredits()->get() : [], - 'aging' => $this->options['show_aging_table'] ? $this->getAging() : [], + 'credits' => $this->options['show_credits_table'] ? $this->getCredits()->get() : collect([]), + 'aging' => $this->options['show_aging_table'] ? $this->getAging() : collect([]), ]); $html = $ts->getHtml(); diff --git a/app/Services/Pdf/PdfMock.php b/app/Services/Pdf/PdfMock.php index c120168f2427..c7b98de46a71 100644 --- a/app/Services/Pdf/PdfMock.php +++ b/app/Services/Pdf/PdfMock.php @@ -195,7 +195,6 @@ class PdfMock { return ['values' => [ - '$client.shipping_postal_code' => '46420', '$client.billing_postal_code' => '11243', '$company.city_state_postal' => 'Beveley Hills, CA, 90210', @@ -496,6 +495,8 @@ class PdfMock '$show_shipping_address' => $this->settings->show_shipping_address ? 'flex' : 'none', '$show_shipping_address_block' => $this->settings->show_shipping_address ? 'block' : 'none', '$show_shipping_address_visibility' => $this->settings->show_shipping_address ? 'visible' : 'hidden', + '$start_date' => '31/01/2023', + '$end_date' => '31/12/2023', ], 'labels' => $this->mockTranslatedLabels(), ]; @@ -811,21 +812,23 @@ class PdfMock '$tax_label' => ctrans('texts.tax'), '$dir_label' => '', '$to_label' => ctrans('texts.to'), + '$start_date_label' => ctrans('texts.start_date'), + '$end_date_label' => ctrans('texts.end_date'), ]; } - + private function getVendorStubVariables() { return ['values' => [ - '$vendor.billing_postal_code' => '06270-5526', - '$company.postal_city_state' => '29359 New Loy, Delaware', - '$company.city_state_postal' => 'New Loy, Delaware 29359', - '$product.gross_line_total' => '', - '$purchase_order.po_number' => 'PO12345', - '$vendor.postal_city_state' => '06270-5526 Jameyhaven, West Virginia', - '$vendor.city_state_postal' => 'Jameyhaven, West Virginia 06270-5526', - '$purchase_order.due_date' => '02-12-2021', - '$vendor.billing_address1' => '589', + '$vendor.billing_postal_code' => '06270-5526', + '$company.postal_city_state' => '29359 New Loy, Delaware', + '$company.city_state_postal' => 'New Loy, Delaware 29359', + '$product.gross_line_total' => '', + '$purchase_order.po_number' => 'PO12345', + '$vendor.postal_city_state' => '06270-5526 Jameyhaven, West Virginia', + '$vendor.city_state_postal' => 'Jameyhaven, West Virginia 06270-5526', + '$purchase_order.due_date' => '02-12-2021', + '$vendor.billing_address1' => '589', '$vendor.billing_address2' => '761 Odessa Centers Suite 673', '$invoiceninja.whitelabel' => 'https://invoicing.co/images/new_logo.png', '$purchase_order.custom1' => 'Custom 1', diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index d7b0264e928a..8c4bd93b8ba3 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -84,6 +84,12 @@ class TemplateService }); $this->twig->addFunction($function); + $filter = new \Twig\TwigFilter('sum', function (array $array, string $column) { + return array_sum(array_column($array, $column)); + }); + + $this->twig->addFilter($filter); + return $this; } diff --git a/lang/en/texts.php b/lang/en/texts.php index aa407bc9b054..68ebe6f49f11 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5163,6 +5163,8 @@ $LANG = array( 'click_or_drop_files_here' => 'Click or drop files here', 'payment_refund_receipt' => 'Payment Refund Receipt # :number', 'payment_receipt' => 'Payment Receipt # :number', + 'load_template_description' => 'The template will be applied to following:', + 'run_template' => 'Run template', ); return $LANG; From 89e58b7693f9632186ae9e8f86b800e447fff1db Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 24 Oct 2023 16:00:13 +1100 Subject: [PATCH 2/4] WOrking on merging twig inside of custom designs --- app/Jobs/Entity/CreateRawPdf.php | 138 ++++++++++++---------- app/Services/Pdf/PdfBuilder.php | 49 +++++++- app/Services/Pdf/PdfService.php | 4 +- app/Services/Template/TemplateService.php | 7 +- 4 files changed, 125 insertions(+), 73 deletions(-) diff --git a/app/Jobs/Entity/CreateRawPdf.php b/app/Jobs/Entity/CreateRawPdf.php index 1be6cd24e114..aae40197a7a4 100644 --- a/app/Jobs/Entity/CreateRawPdf.php +++ b/app/Jobs/Entity/CreateRawPdf.php @@ -23,6 +23,7 @@ use App\Models\QuoteInvitation; use App\Utils\Traits\MakesHash; use App\Models\CreditInvitation; use App\Models\RecurringInvoice; +use App\Services\Pdf\PdfService; use App\Utils\PhantomJS\Phantom; use App\Models\InvoiceInvitation; use App\Utils\HostedPDF\NinjaPdf; @@ -123,87 +124,96 @@ class CreateRawPdf implements ShouldQueue $file_path = $path.$this->entity->numberFormatter().'.pdf'; - $entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id)); - $design = Design::query()->withTrashed()->find($entity_design_id); +$ps = new PdfService($this->invitation, 'product', [ + 'client' => $this->entity->client, + "{$this->entity_string}s" => [$this->entity], +]); - /* Catch all in case migration doesn't pass back a valid design */ - if (! $design) { - $design = Design::query()->find(2); - } +$pdf = $ps->boot()->getPdf(); - $html = new HtmlEngine($this->invitation); - if ($design->is_custom) { - $options = [ - 'custom_partials' => json_decode(json_encode($design->design), true), - ]; - $template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options); - } else { - $template = new PdfMakerDesign(strtolower($design->name)); - } + // $entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id)); - $variables = $html->generateLabelsAndValues(); + // $design = Design::query()->withTrashed()->find($entity_design_id); - $state = [ - 'template' => $template->elements([ - 'client' => $this->entity->client, - 'entity' => $this->entity, - 'pdf_variables' => (array) $this->entity->company->settings->pdf_variables, - '$product' => $design->design->product, - 'variables' => $variables, - ]), - 'variables' => $variables, - 'options' => [ - 'all_pages_header' => $this->entity->client->getSetting('all_pages_header'), - 'all_pages_footer' => $this->entity->client->getSetting('all_pages_footer'), - 'client' => $this->entity->client, - 'entity' => $this->entity, - 'variables' => $variables, - ], - 'process_markdown' => $this->entity->client->company->markdown_enabled, - ]; + // /* Catch all in case migration doesn't pass back a valid design */ + // if (! $design) { + // $design = Design::query()->find(2); + // } - $maker = new PdfMakerService($state); + // $html = new HtmlEngine($this->invitation); - $maker - ->design($template) - ->build(); + // if ($design->is_custom) { + // $options = [ + // 'custom_partials' => json_decode(json_encode($design->design), true), + // ]; + // $template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options); + // } else { + // $template = new PdfMakerDesign(strtolower($design->name)); + // } - $pdf = null; + // $variables = $html->generateLabelsAndValues(); - try { - if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') { - $pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true)); + // $state = [ + // 'template' => $template->elements([ + // 'client' => $this->entity->client, + // 'entity' => $this->entity, + // 'pdf_variables' => (array) $this->entity->company->settings->pdf_variables, + // '$product' => $design->design->product, + // 'variables' => $variables, + // ]), + // 'variables' => $variables, + // 'options' => [ + // 'all_pages_header' => $this->entity->client->getSetting('all_pages_header'), + // 'all_pages_footer' => $this->entity->client->getSetting('all_pages_footer'), + // 'client' => $this->entity->client, + // 'entity' => $this->entity, + // 'variables' => $variables, + // ], + // 'process_markdown' => $this->entity->client->company->markdown_enabled, + // ]; - $finfo = new \finfo(FILEINFO_MIME); + // $maker = new PdfMakerService($state); - //fallback in case hosted PDF fails. - if ($finfo->buffer($pdf) != 'application/pdf; charset=binary') { - $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); + // $maker + // ->design($template) + // ->build(); - $numbered_pdf = $this->pageNumbering($pdf, $this->company); + // $pdf = null; - if ($numbered_pdf) { - $pdf = $numbered_pdf; - } - } - } else { - $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); + // try { + // if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') { + // $pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true)); - $numbered_pdf = $this->pageNumbering($pdf, $this->company); + // $finfo = new \finfo(FILEINFO_MIME); - if ($numbered_pdf) { - $pdf = $numbered_pdf; - } - } - } catch (\Exception $e) { - nlog(print_r($e->getMessage(), 1)); - } + // //fallback in case hosted PDF fails. + // if ($finfo->buffer($pdf) != 'application/pdf; charset=binary') { + // $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); - if (config('ninja.log_pdf_html')) { - info($maker->getCompiledHTML()); - } + // $numbered_pdf = $this->pageNumbering($pdf, $this->company); + + // if ($numbered_pdf) { + // $pdf = $numbered_pdf; + // } + // } + // } else { + // $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); + + // $numbered_pdf = $this->pageNumbering($pdf, $this->company); + + // if ($numbered_pdf) { + // $pdf = $numbered_pdf; + // } + // } + // } catch (\Exception $e) { + // nlog(print_r($e->getMessage(), 1)); + // } + + // if (config('ninja.log_pdf_html')) { + // info($maker->getCompiledHTML()); + // } if ($pdf) { $maker =null; diff --git a/app/Services/Pdf/PdfBuilder.php b/app/Services/Pdf/PdfBuilder.php index 2852345f2f7a..cae7ecaa94de 100644 --- a/app/Services/Pdf/PdfBuilder.php +++ b/app/Services/Pdf/PdfBuilder.php @@ -11,13 +11,14 @@ namespace App\Services\Pdf; -use App\Models\Credit; -use App\Models\Quote; -use App\Utils\Helpers; -use App\Utils\Traits\MakesDates; use DOMDocument; -use Illuminate\Support\Carbon; +use App\Models\Quote; +use App\Models\Credit; +use App\Utils\Helpers; use Illuminate\Support\Str; +use Illuminate\Support\Carbon; +use App\Utils\Traits\MakesDates; +use App\Services\Template\TemplateService; use League\CommonMark\CommonMarkConverter; class PdfBuilder @@ -67,6 +68,7 @@ class PdfBuilder ->buildSections() ->getEmptyElements() ->updateElementProperties() + ->parseTwigElements() ->updateVariables(); return $this; @@ -104,6 +106,40 @@ class PdfBuilder return $this; } + private function parseTwigElements() + { + + $replacements = []; + $contents = $this->document->getElementsByTagName('ninja'); + + $template_service = new TemplateService(); + $data = $template_service->processData($this->service->options)->getData(); + + $twig = $template_service->twig; + + foreach ($contents as $content) { + + $template = $content->ownerDocument->saveHTML($content); + + $template = $twig->createTemplate(html_entity_decode($template)); + $template = $template->render($data); + + $f = $this->document->createDocumentFragment(); + $f->appendXML($template); + $replacements[] = $f; + + } + + foreach($contents as $key => $content) { + $content->parentNode->replaceChild($replacements[$key], $content); + } + + $contents = null; + + return $this; + + } + public function setDocument($document): self { $this->document = $document; @@ -1091,7 +1127,8 @@ class PdfBuilder } elseif (Str::startsWith($variable, '$custom_surcharge')) { $_variable = ltrim($variable, '$'); // $custom_surcharge1 -> custom_surcharge1 - $visible = intval($this->service->config->entity->{$_variable}) != 0; + // $visible = intval($this->service->config->entity->{$_variable}) != 0; + $visible = intval(str_replace(['0','.'], '', $this->service->config->entity->{$_variable})) != 0; $elements[1]['elements'][] = ['element' => 'div', 'elements' => [ ['element' => 'span', 'content' => $variable . '_label', 'properties' => ['hidden' => !$visible, 'data-ref' => 'totals_table-' . substr($variable, 1) . '-label']], diff --git a/app/Services/Pdf/PdfService.php b/app/Services/Pdf/PdfService.php index d7fde2b8cc5a..3f3bc07343a4 100644 --- a/app/Services/Pdf/PdfService.php +++ b/app/Services/Pdf/PdfService.php @@ -61,7 +61,7 @@ class PdfService } public function boot(): self - { + {nlog("booties"); $this->init(); return $this; @@ -104,7 +104,7 @@ class PdfService $html = $this->builder->getCompiledHTML(); if (config('ninja.log_pdf_html')) { - info($html); + nlog($html); } return $html; diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index 8c4bd93b8ba3..4efdc9d8f04b 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -156,7 +156,12 @@ class TemplateService } - private function processData($data): self + public function getData(): array + { + return $this->data; + } + + public function processData($data): self { $this->data = $this->preProcessDataBlocks($data); From d5339d0864753cec3dc8b88cca9cabac9d5bff3c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 24 Oct 2023 16:26:16 +1100 Subject: [PATCH 3/4] Improvements for twig --- app/Jobs/Entity/CreateRawPdf.php | 148 ++++++++++++++++--------------- app/Services/Pdf/PdfService.php | 12 ++- 2 files changed, 86 insertions(+), 74 deletions(-) diff --git a/app/Jobs/Entity/CreateRawPdf.php b/app/Jobs/Entity/CreateRawPdf.php index aae40197a7a4..4f1619587e9a 100644 --- a/app/Jobs/Entity/CreateRawPdf.php +++ b/app/Jobs/Entity/CreateRawPdf.php @@ -90,6 +90,17 @@ class CreateRawPdf implements ShouldQueue public function handle() { + /** Testing this override to improve PDF generation performance */ + $ps = new PdfService($this->invitation, 'product', [ + 'client' => $this->entity->client, + "{$this->entity_string}s" => [$this->entity], + ]); + + $pdf = $ps->boot()->getPdf(); + nlog("pdf timer = ". $ps->execution_time); + + + /* Forget the singleton*/ App::forgetInstance('translator'); @@ -124,96 +135,87 @@ class CreateRawPdf implements ShouldQueue $file_path = $path.$this->entity->numberFormatter().'.pdf'; + $entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id)); -$ps = new PdfService($this->invitation, 'product', [ - 'client' => $this->entity->client, - "{$this->entity_string}s" => [$this->entity], -]); + $design = Design::query()->withTrashed()->find($entity_design_id); -$pdf = $ps->boot()->getPdf(); + /* Catch all in case migration doesn't pass back a valid design */ + if (! $design) { + $design = Design::query()->find(2); + } + $html = new HtmlEngine($this->invitation); - // $entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id)); + if ($design->is_custom) { + $options = [ + 'custom_partials' => json_decode(json_encode($design->design), true), + ]; + $template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options); + } else { + $template = new PdfMakerDesign(strtolower($design->name)); + } - // $design = Design::query()->withTrashed()->find($entity_design_id); + $variables = $html->generateLabelsAndValues(); - // /* Catch all in case migration doesn't pass back a valid design */ - // if (! $design) { - // $design = Design::query()->find(2); - // } + $state = [ + 'template' => $template->elements([ + 'client' => $this->entity->client, + 'entity' => $this->entity, + 'pdf_variables' => (array) $this->entity->company->settings->pdf_variables, + '$product' => $design->design->product, + 'variables' => $variables, + ]), + 'variables' => $variables, + 'options' => [ + 'all_pages_header' => $this->entity->client->getSetting('all_pages_header'), + 'all_pages_footer' => $this->entity->client->getSetting('all_pages_footer'), + 'client' => $this->entity->client, + 'entity' => $this->entity, + 'variables' => $variables, + ], + 'process_markdown' => $this->entity->client->company->markdown_enabled, + ]; - // $html = new HtmlEngine($this->invitation); + $maker = new PdfMakerService($state); - // if ($design->is_custom) { - // $options = [ - // 'custom_partials' => json_decode(json_encode($design->design), true), - // ]; - // $template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options); - // } else { - // $template = new PdfMakerDesign(strtolower($design->name)); - // } + $maker + ->design($template) + ->build(); - // $variables = $html->generateLabelsAndValues(); + $pdf = null; - // $state = [ - // 'template' => $template->elements([ - // 'client' => $this->entity->client, - // 'entity' => $this->entity, - // 'pdf_variables' => (array) $this->entity->company->settings->pdf_variables, - // '$product' => $design->design->product, - // 'variables' => $variables, - // ]), - // 'variables' => $variables, - // 'options' => [ - // 'all_pages_header' => $this->entity->client->getSetting('all_pages_header'), - // 'all_pages_footer' => $this->entity->client->getSetting('all_pages_footer'), - // 'client' => $this->entity->client, - // 'entity' => $this->entity, - // 'variables' => $variables, - // ], - // 'process_markdown' => $this->entity->client->company->markdown_enabled, - // ]; + try { + if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') { + $pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true)); - // $maker = new PdfMakerService($state); + $finfo = new \finfo(FILEINFO_MIME); - // $maker - // ->design($template) - // ->build(); + //fallback in case hosted PDF fails. + if ($finfo->buffer($pdf) != 'application/pdf; charset=binary') { + $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); - // $pdf = null; + $numbered_pdf = $this->pageNumbering($pdf, $this->company); - // try { - // if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') { - // $pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true)); + if ($numbered_pdf) { + $pdf = $numbered_pdf; + } + } + } else { + $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); - // $finfo = new \finfo(FILEINFO_MIME); + $numbered_pdf = $this->pageNumbering($pdf, $this->company); - // //fallback in case hosted PDF fails. - // if ($finfo->buffer($pdf) != 'application/pdf; charset=binary') { - // $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); + if ($numbered_pdf) { + $pdf = $numbered_pdf; + } + } + } catch (\Exception $e) { + nlog(print_r($e->getMessage(), 1)); + } - // $numbered_pdf = $this->pageNumbering($pdf, $this->company); - - // if ($numbered_pdf) { - // $pdf = $numbered_pdf; - // } - // } - // } else { - // $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); - - // $numbered_pdf = $this->pageNumbering($pdf, $this->company); - - // if ($numbered_pdf) { - // $pdf = $numbered_pdf; - // } - // } - // } catch (\Exception $e) { - // nlog(print_r($e->getMessage(), 1)); - // } - - // if (config('ninja.log_pdf_html')) { - // info($maker->getCompiledHTML()); - // } + if (config('ninja.log_pdf_html')) { + info($maker->getCompiledHTML()); + } if ($pdf) { $maker =null; diff --git a/app/Services/Pdf/PdfService.php b/app/Services/Pdf/PdfService.php index 3f3bc07343a4..f680e389019e 100644 --- a/app/Services/Pdf/PdfService.php +++ b/app/Services/Pdf/PdfService.php @@ -44,6 +44,10 @@ class PdfService public array $options; + private float $start_time; + + public float $execution_time; + const DELIVERY_NOTE = 'delivery_note'; const STATEMENT = 'statement'; const PURCHASE_ORDER = 'purchase_order'; @@ -61,7 +65,9 @@ class PdfService } public function boot(): self - {nlog("booties"); + { + $this->start_time = microtime(true); + $this->init(); return $this; @@ -90,6 +96,8 @@ class PdfService throw new \Exception($e->getMessage(), $e->getCode()); } + $this->execution_time = microtime(true) - $this->start_time; + return $pdf; } @@ -107,6 +115,8 @@ class PdfService nlog($html); } + $this->execution_time = microtime(true) - $this->start_time; + return $html; } From 17eaec31860861e1ddefb2e068c449832e4cfd8a Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 6 Nov 2023 08:50:36 +1100 Subject: [PATCH 4/4] Grafting field stacks into templates --- app/Services/Pdf/PdfBuilder.php | 6 - app/Services/Pdf/PdfService.php | 4 +- app/Services/Template/TemplateService.php | 487 ++++++++++++++-------- 3 files changed, 319 insertions(+), 178 deletions(-) diff --git a/app/Services/Pdf/PdfBuilder.php b/app/Services/Pdf/PdfBuilder.php index cae7ecaa94de..cc6631e5d542 100644 --- a/app/Services/Pdf/PdfBuilder.php +++ b/app/Services/Pdf/PdfBuilder.php @@ -1583,12 +1583,6 @@ class PdfBuilder // Dom Traversal /////////////////////////////////////// - - public function getSectionNode(string $selector) - { - return $this->document->getElementById($selector); - } - public function updateElementProperties() :self { foreach ($this->sections as $element) { diff --git a/app/Services/Pdf/PdfService.php b/app/Services/Pdf/PdfService.php index f680e389019e..1bf803edba87 100644 --- a/app/Services/Pdf/PdfService.php +++ b/app/Services/Pdf/PdfService.php @@ -62,11 +62,13 @@ class PdfService $this->document_type = $document_type; $this->options = $options; + + $this->start_time = microtime(true); + } public function boot(): self { - $this->start_time = microtime(true); $this->init(); diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index 4efdc9d8f04b..461e6766bbb1 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -11,32 +11,31 @@ namespace App\Services\Template; -use App\Utils\Number; use App\Models\Client; +use App\Models\Company; use App\Models\Credit; use App\Models\Design; -use App\Models\Company; use App\Models\Invoice; use App\Models\Payment; use App\Models\Project; -use App\Models\Activity; -use App\Utils\HtmlEngine; -use League\Fractal\Manager; use App\Models\PurchaseOrder; -use App\Utils\VendorHtmlEngine; -use App\Utils\PaymentHtmlEngine; -use App\Utils\Traits\MakesDates; -use App\Utils\HostedPDF\NinjaPdf; -use App\Utils\Traits\Pdf\PdfMaker; -use Twig\Extra\Intl\IntlExtension; -use App\Transformers\TaskTransformer; -use App\Transformers\QuoteTransformer; -use App\Services\Template\TemplateMock; -use App\Transformers\CreditTransformer; -use App\Transformers\InvoiceTransformer; +use App\Models\Quote; +use App\Models\RecurringInvoice; +use App\Models\Vendor; use App\Transformers\ProjectTransformer; use App\Transformers\PurchaseOrderTransformer; +use App\Transformers\QuoteTransformer; +use App\Transformers\TaskTransformer; +use App\Utils\HostedPDF\NinjaPdf; +use App\Utils\HtmlEngine; +use App\Utils\Number; +use App\Utils\PaymentHtmlEngine; +use App\Utils\Traits\MakesDates; +use App\Utils\Traits\Pdf\PdfMaker; +use App\Utils\VendorHtmlEngine; +use League\Fractal\Manager; use League\Fractal\Serializer\ArraySerializer; +use Twig\Extra\Intl\IntlExtension; class TemplateService { @@ -54,6 +53,14 @@ class TemplateService public ?Company $company; + private ?Client $client; + + private ?Vendor $vendor; + + private Invoice | Quote | Credit | PurchaseOrder | RecurringInvoice $entity; + + private Payment $payment; + public function __construct(public ?Design $template = null) { $this->template = $template; @@ -71,7 +78,7 @@ class TemplateService $this->document->validateOnParse = true; $loader = new \Twig\Loader\FilesystemLoader(storage_path()); - $this->twig = new \Twig\Environment($loader,[ + $this->twig = new \Twig\Environment($loader, [ 'debug' => true, ]); $string_extension = new \Twig\Extension\StringLoaderExtension(); @@ -106,7 +113,7 @@ class TemplateService ->processData($data) ->parseNinjaBlocks() ->processVariables($data) - ->parseVariables(); + ->parseVariables(); return $this; } @@ -142,7 +149,12 @@ class TemplateService { return $this->compiled_html; } - + + /** + * Returns the PDF string + * + * @return mixed + */ public function getPdf(): mixed { @@ -155,12 +167,23 @@ class TemplateService return $pdf; } - + + /** + * Get the parsed data + * + * @return array + */ public function getData(): array { return $this->data; } - + + /** + * Process data variables + * + * @param mixed $data + * @return self + */ public function processData($data): self { @@ -171,7 +194,7 @@ class TemplateService /** * Parses all Ninja tags in the document - * + * * @return self */ private function parseNinjaBlocks(): self @@ -186,24 +209,19 @@ class TemplateService try { $template = $this->twig->createTemplate(html_entity_decode($template)); - } - catch(\Twig\Error\SyntaxError $e) { + } catch(\Twig\Error\SyntaxError $e) { nlog($e->getMessage()); throw ($e); - } - catch(\Twig\Error\Error $e) { + } catch(\Twig\Error\Error $e) { nlog("error = " .$e->getMessage()); throw ($e); - } - catch(\Twig\Error\RuntimeError $e) { + } catch(\Twig\Error\RuntimeError $e) { nlog("runtime = " .$e->getMessage()); throw ($e); - } - catch(\Twig\Error\LoaderError $e) { + } catch(\Twig\Error\LoaderError $e) { nlog("loader = " . $e->getMessage()); throw ($e); - } - catch(\Twig\Error\SecurityError $e) { + } catch(\Twig\Error\SecurityError $e) { nlog("security = " . $e->getMessage()); throw ($e); } @@ -229,7 +247,7 @@ class TemplateService /** * Parses all variables in the document - * + * * @return self */ private function parseVariables(): self @@ -239,8 +257,7 @@ class TemplateService foreach($this->variables as $key => $variable) { - if(isset($variable['labels']) && isset($variable['values'])) - { + if(isset($variable['labels']) && isset($variable['values'])) { $html = strtr($html, $variable['labels']); $html = strtr($html, $variable['values']); } @@ -271,8 +288,9 @@ class TemplateService */ private function compose(): self { - if(!$this->template) + if(!$this->template) { return $this; + } $html = ''; $html .= $this->template->design->includes; @@ -287,7 +305,7 @@ class TemplateService } /** - * Inject the template components + * Inject the template components * manually * * @return self @@ -319,11 +337,12 @@ class TemplateService $processed = []; - if(in_array($key, ['tasks','projects','aging']) || !$value->first() ) + if(in_array($key, ['tasks','projects','aging']) || !$value->first()) { return $processed; + } match ($key) { - 'variables' => $processed = $value->first() ?? [], + 'variables' => $processed = $value->first() ?? [], 'invoices' => $processed = (new HtmlEngine($value->first()->invitations()->first()))->generateLabelsAndValues() ?? [], 'quotes' => $processed = (new HtmlEngine($value->first()->invitations()->first()))->generateLabelsAndValues() ?? [], 'credits' => $processed = (new HtmlEngine($value->first()->invitations()->first()))->generateLabelsAndValues() ?? [], @@ -343,7 +362,7 @@ class TemplateService private function preProcessDataBlocks($data): array { - return collect($data)->map(function ($value, $key){ + return collect($data)->map(function ($value, $key) { $processed = []; @@ -367,75 +386,76 @@ class TemplateService public function processInvoices($invoices): array { $invoices = collect($invoices) - ->map(function ($invoice){ + ->map(function ($invoice) { - $payments = []; - - if($invoice->payments ?? false) { - $payments = $invoice->payments->map(function ($payment) { - return $this->transformPayment($payment); - })->toArray(); - } + $payments = []; + $this->entity = $invoice; - return [ - 'amount' => Number::formatMoney($invoice->amount, $invoice->client), - 'balance' => Number::formatMoney($invoice->balance, $invoice->client), - 'balance_raw' => $invoice->balance, - 'number' => $invoice->number ?: '', - 'discount' => $invoice->discount, - 'po_number' => $invoice->po_number ?: '', - 'date' => $this->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()), - 'last_sent_date' => $this->translateDate($invoice->last_sent_date, $invoice->client->date_format(), $invoice->client->locale()), - 'next_send_date' => $this->translateDate($invoice->next_send_date, $invoice->client->date_format(), $invoice->client->locale()), - 'due_date' => $this->translateDate($invoice->due_date, $invoice->client->date_format(), $invoice->client->locale()), - 'terms' => $invoice->terms ?: '', - 'public_notes' => $invoice->public_notes ?: '', - 'private_notes' => $invoice->private_notes ?: '', - 'uses_inclusive_taxes' => (bool) $invoice->uses_inclusive_taxes, - 'tax_name1' => $invoice->tax_name1 ?? '', - 'tax_rate1' => (float) $invoice->tax_rate1, - 'tax_name2' => $invoice->tax_name2 ?? '', - 'tax_rate2' => (float) $invoice->tax_rate2, - 'tax_name3' => $invoice->tax_name3 ?? '', - 'tax_rate3' => (float) $invoice->tax_rate3, - 'total_taxes' => Number::formatMoney($invoice->total_taxes, $invoice->client), - 'total_taxes_raw' => $invoice->total_taxes, - 'is_amount_discount' => (bool) $invoice->is_amount_discount ?? false, - 'footer' => $invoice->footer ?? '', - 'partial' => $invoice->partial ?? 0, - 'partial_due_date' => $this->translateDate($invoice->partial_due_date, $invoice->client->date_format(), $invoice->client->locale()), - 'custom_value1' => (string) $invoice->custom_value1 ?: '', - 'custom_value2' => (string) $invoice->custom_value2 ?: '', - 'custom_value3' => (string) $invoice->custom_value3 ?: '', - 'custom_value4' => (string) $invoice->custom_value4 ?: '', - 'custom_surcharge1' => (float) $invoice->custom_surcharge1, - 'custom_surcharge2' => (float) $invoice->custom_surcharge2, - 'custom_surcharge3' => (float) $invoice->custom_surcharge3, - 'custom_surcharge4' => (float) $invoice->custom_surcharge4, - 'exchange_rate' => (float) $invoice->exchange_rate, - 'custom_surcharge_tax1' => (bool) $invoice->custom_surcharge_tax1, - 'custom_surcharge_tax2' => (bool) $invoice->custom_surcharge_tax2, - 'custom_surcharge_tax3' => (bool) $invoice->custom_surcharge_tax3, - 'custom_surcharge_tax4' => (bool) $invoice->custom_surcharge_tax4, - 'line_items' => $invoice->line_items ? $this->padLineItems($invoice->line_items, $invoice->client): (array) [], - 'reminder1_sent' => $this->translateDate($invoice->reminder1_sent, $invoice->client->date_format(), $invoice->client->locale()), - 'reminder2_sent' => $this->translateDate($invoice->reminder2_sent, $invoice->client->date_format(), $invoice->client->locale()), - 'reminder3_sent' => $this->translateDate($invoice->reminder3_sent, $invoice->client->date_format(), $invoice->client->locale()), - 'reminder_last_sent' => $this->translateDate($invoice->reminder_last_sent, $invoice->client->date_format(), $invoice->client->locale()), - 'paid_to_date' => Number::formatMoney($invoice->paid_to_date, $invoice->client), - 'auto_bill_enabled' => (bool) $invoice->auto_bill_enabled, - 'client' => [ - 'name' => $invoice->client->present()->name(), - 'balance' => $invoice->client->balance, - 'payment_balance' => $invoice->client->payment_balance, - 'credit_balance' => $invoice->client->credit_balance, - ], - 'payments' => $payments, - 'total_tax_map' => $invoice->calc()->getTotalTaxMap(), - 'line_tax_map' => $invoice->calc()->getTaxMap(), - ]; + if($invoice->payments ?? false) { + $payments = $invoice->payments->map(function ($payment) { + return $this->transformPayment($payment); + })->toArray(); + } - }); + return [ + 'amount' => Number::formatMoney($invoice->amount, $invoice->client), + 'balance' => Number::formatMoney($invoice->balance, $invoice->client), + 'balance_raw' => $invoice->balance, + 'number' => $invoice->number ?: '', + 'discount' => $invoice->discount, + 'po_number' => $invoice->po_number ?: '', + 'date' => $this->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()), + 'last_sent_date' => $this->translateDate($invoice->last_sent_date, $invoice->client->date_format(), $invoice->client->locale()), + 'next_send_date' => $this->translateDate($invoice->next_send_date, $invoice->client->date_format(), $invoice->client->locale()), + 'due_date' => $this->translateDate($invoice->due_date, $invoice->client->date_format(), $invoice->client->locale()), + 'terms' => $invoice->terms ?: '', + 'public_notes' => $invoice->public_notes ?: '', + 'private_notes' => $invoice->private_notes ?: '', + 'uses_inclusive_taxes' => (bool) $invoice->uses_inclusive_taxes, + 'tax_name1' => $invoice->tax_name1 ?? '', + 'tax_rate1' => (float) $invoice->tax_rate1, + 'tax_name2' => $invoice->tax_name2 ?? '', + 'tax_rate2' => (float) $invoice->tax_rate2, + 'tax_name3' => $invoice->tax_name3 ?? '', + 'tax_rate3' => (float) $invoice->tax_rate3, + 'total_taxes' => Number::formatMoney($invoice->total_taxes, $invoice->client), + 'total_taxes_raw' => $invoice->total_taxes, + 'is_amount_discount' => (bool) $invoice->is_amount_discount ?? false, + 'footer' => $invoice->footer ?? '', + 'partial' => $invoice->partial ?? 0, + 'partial_due_date' => $this->translateDate($invoice->partial_due_date, $invoice->client->date_format(), $invoice->client->locale()), + 'custom_value1' => (string) $invoice->custom_value1 ?: '', + 'custom_value2' => (string) $invoice->custom_value2 ?: '', + 'custom_value3' => (string) $invoice->custom_value3 ?: '', + 'custom_value4' => (string) $invoice->custom_value4 ?: '', + 'custom_surcharge1' => (float) $invoice->custom_surcharge1, + 'custom_surcharge2' => (float) $invoice->custom_surcharge2, + 'custom_surcharge3' => (float) $invoice->custom_surcharge3, + 'custom_surcharge4' => (float) $invoice->custom_surcharge4, + 'exchange_rate' => (float) $invoice->exchange_rate, + 'custom_surcharge_tax1' => (bool) $invoice->custom_surcharge_tax1, + 'custom_surcharge_tax2' => (bool) $invoice->custom_surcharge_tax2, + 'custom_surcharge_tax3' => (bool) $invoice->custom_surcharge_tax3, + 'custom_surcharge_tax4' => (bool) $invoice->custom_surcharge_tax4, + 'line_items' => $invoice->line_items ? $this->padLineItems($invoice->line_items, $invoice->client): (array) [], + 'reminder1_sent' => $this->translateDate($invoice->reminder1_sent, $invoice->client->date_format(), $invoice->client->locale()), + 'reminder2_sent' => $this->translateDate($invoice->reminder2_sent, $invoice->client->date_format(), $invoice->client->locale()), + 'reminder3_sent' => $this->translateDate($invoice->reminder3_sent, $invoice->client->date_format(), $invoice->client->locale()), + 'reminder_last_sent' => $this->translateDate($invoice->reminder_last_sent, $invoice->client->date_format(), $invoice->client->locale()), + 'paid_to_date' => Number::formatMoney($invoice->paid_to_date, $invoice->client), + 'auto_bill_enabled' => (bool) $invoice->auto_bill_enabled, + 'client' => [ + 'name' => $invoice->client->present()->name(), + 'balance' => $invoice->client->balance, + 'payment_balance' => $invoice->client->payment_balance, + 'credit_balance' => $invoice->client->credit_balance, + ], + 'payments' => $payments, + 'total_tax_map' => $invoice->calc()->getTotalTaxMap(), + 'line_tax_map' => $invoice->calc()->getTaxMap(), + ]; + + }); return $invoices->toArray(); @@ -443,7 +463,7 @@ class TemplateService public function padLineItems(array $items, Client $client): array { - return collect($items)->map(function ($item) use ($client){ + return collect($items)->map(function ($item) use ($client) { $item->cost_raw = $item->cost ?? 0; $item->discount_raw = $item->discount ?? 0; @@ -454,8 +474,9 @@ class TemplateService $item->cost = Number::formatMoney($item->cost_raw, $client); - if($item->is_amount_discount) + if($item->is_amount_discount) { $item->discount = Number::formatMoney($item->discount_raw, $client); + } $item->line_total = Number::formatMoney($item->line_total_raw, $client); $item->gross_line_total = Number::formatMoney($item->gross_line_total_raw, $client); @@ -471,7 +492,9 @@ class TemplateService { $data = []; - + + $this->payment = $payment; + $credits = $payment->credits->map(function ($credit) use ($payment) { return [ 'credit' => $credit->number, @@ -570,7 +593,7 @@ class TemplateService { return collect($payment->refund_meta ?? []) - ->map(function ($refund) use($payment){ + ->map(function ($refund) use ($payment) { $date = \Carbon\Carbon::parse($refund['date'])->addSeconds($payment->client->timezone_offset()); $date = $this->translateDate($date, $payment->client->date_format(), $payment->client->locale()); @@ -579,7 +602,7 @@ class TemplateService $map = []; foreach($refund['invoices'] as $refunded_invoice) { - $invoice = Invoice::withTrashed()->find($refunded_invoice['invoice_id']); + $invoice = Invoice::withTrashed()->find($refunded_invoice['invoice_id']); $amount = Number::formatMoney($refunded_invoice['amount'], $payment->client); $notes = ctrans('texts.status_partially_refunded_amount', ['amount' => $amount]); @@ -623,67 +646,69 @@ class TemplateService public function processCredits($credits): array { $credits = collect($credits) - ->map(function ($credit){ + ->map(function ($credit) { - return [ - 'amount' => Number::formatMoney($credit->amount, $credit->client), - 'balance' => Number::formatMoney($credit->balance, $credit->client), - 'balance_raw' => $credit->balance, - 'number' => $credit->number ?: '', - 'discount' => $credit->discount, - 'po_number' => $credit->po_number ?: '', - 'date' => $this->translateDate($credit->date, $credit->client->date_format(), $credit->client->locale()), - 'last_sent_date' => $this->translateDate($credit->last_sent_date, $credit->client->date_format(), $credit->client->locale()), - 'next_send_date' => $this->translateDate($credit->next_send_date, $credit->client->date_format(), $credit->client->locale()), - 'due_date' => $this->translateDate($credit->due_date, $credit->client->date_format(), $credit->client->locale()), - 'terms' => $credit->terms ?: '', - 'public_notes' => $credit->public_notes ?: '', - 'private_notes' => $credit->private_notes ?: '', - 'uses_inclusive_taxes' => (bool) $credit->uses_inclusive_taxes, - 'tax_name1' => $credit->tax_name1 ?? '', - 'tax_rate1' => (float) $credit->tax_rate1, - 'tax_name2' => $credit->tax_name2 ?? '', - 'tax_rate2' => (float) $credit->tax_rate2, - 'tax_name3' => $credit->tax_name3 ?? '', - 'tax_rate3' => (float) $credit->tax_rate3, - 'total_taxes' => Number::formatMoney($credit->total_taxes, $credit->client), - 'total_taxes_raw' => $credit->total_taxes, - 'is_amount_discount' => (bool) $credit->is_amount_discount ?? false, - 'footer' => $credit->footer ?? '', - 'partial' => $credit->partial ?? 0, - 'partial_due_date' => $this->translateDate($credit->partial_due_date, $credit->client->date_format(), $credit->client->locale()), - 'custom_value1' => (string) $credit->custom_value1 ?: '', - 'custom_value2' => (string) $credit->custom_value2 ?: '', - 'custom_value3' => (string) $credit->custom_value3 ?: '', - 'custom_value4' => (string) $credit->custom_value4 ?: '', - 'custom_surcharge1' => (float) $credit->custom_surcharge1, - 'custom_surcharge2' => (float) $credit->custom_surcharge2, - 'custom_surcharge3' => (float) $credit->custom_surcharge3, - 'custom_surcharge4' => (float) $credit->custom_surcharge4, - 'exchange_rate' => (float) $credit->exchange_rate, - 'custom_surcharge_tax1' => (bool) $credit->custom_surcharge_tax1, - 'custom_surcharge_tax2' => (bool) $credit->custom_surcharge_tax2, - 'custom_surcharge_tax3' => (bool) $credit->custom_surcharge_tax3, - 'custom_surcharge_tax4' => (bool) $credit->custom_surcharge_tax4, - 'line_items' => $credit->line_items ? $this->padLineItems($credit->line_items, $credit->client): (array) [], - 'reminder1_sent' => $this->translateDate($credit->reminder1_sent, $credit->client->date_format(), $credit->client->locale()), - 'reminder2_sent' => $this->translateDate($credit->reminder2_sent, $credit->client->date_format(), $credit->client->locale()), - 'reminder3_sent' => $this->translateDate($credit->reminder3_sent, $credit->client->date_format(), $credit->client->locale()), - 'reminder_last_sent' => $this->translateDate($credit->reminder_last_sent, $credit->client->date_format(), $credit->client->locale()), - 'paid_to_date' => Number::formatMoney($credit->paid_to_date, $credit->client), - 'auto_bill_enabled' => (bool) $credit->auto_bill_enabled, - 'client' => [ - 'name' => $credit->client->present()->name(), - 'balance' => $credit->client->balance, - 'payment_balance' => $credit->client->payment_balance, - 'credit_balance' => $credit->client->credit_balance, - ], - 'payments' => [], - 'total_tax_map' => $credit->calc()->getTotalTaxMap(), - 'line_tax_map' => $credit->calc()->getTaxMap(), - ]; + $this->entity = $credit; + + return [ + 'amount' => Number::formatMoney($credit->amount, $credit->client), + 'balance' => Number::formatMoney($credit->balance, $credit->client), + 'balance_raw' => $credit->balance, + 'number' => $credit->number ?: '', + 'discount' => $credit->discount, + 'po_number' => $credit->po_number ?: '', + 'date' => $this->translateDate($credit->date, $credit->client->date_format(), $credit->client->locale()), + 'last_sent_date' => $this->translateDate($credit->last_sent_date, $credit->client->date_format(), $credit->client->locale()), + 'next_send_date' => $this->translateDate($credit->next_send_date, $credit->client->date_format(), $credit->client->locale()), + 'due_date' => $this->translateDate($credit->due_date, $credit->client->date_format(), $credit->client->locale()), + 'terms' => $credit->terms ?: '', + 'public_notes' => $credit->public_notes ?: '', + 'private_notes' => $credit->private_notes ?: '', + 'uses_inclusive_taxes' => (bool) $credit->uses_inclusive_taxes, + 'tax_name1' => $credit->tax_name1 ?? '', + 'tax_rate1' => (float) $credit->tax_rate1, + 'tax_name2' => $credit->tax_name2 ?? '', + 'tax_rate2' => (float) $credit->tax_rate2, + 'tax_name3' => $credit->tax_name3 ?? '', + 'tax_rate3' => (float) $credit->tax_rate3, + 'total_taxes' => Number::formatMoney($credit->total_taxes, $credit->client), + 'total_taxes_raw' => $credit->total_taxes, + 'is_amount_discount' => (bool) $credit->is_amount_discount ?? false, + 'footer' => $credit->footer ?? '', + 'partial' => $credit->partial ?? 0, + 'partial_due_date' => $this->translateDate($credit->partial_due_date, $credit->client->date_format(), $credit->client->locale()), + 'custom_value1' => (string) $credit->custom_value1 ?: '', + 'custom_value2' => (string) $credit->custom_value2 ?: '', + 'custom_value3' => (string) $credit->custom_value3 ?: '', + 'custom_value4' => (string) $credit->custom_value4 ?: '', + 'custom_surcharge1' => (float) $credit->custom_surcharge1, + 'custom_surcharge2' => (float) $credit->custom_surcharge2, + 'custom_surcharge3' => (float) $credit->custom_surcharge3, + 'custom_surcharge4' => (float) $credit->custom_surcharge4, + 'exchange_rate' => (float) $credit->exchange_rate, + 'custom_surcharge_tax1' => (bool) $credit->custom_surcharge_tax1, + 'custom_surcharge_tax2' => (bool) $credit->custom_surcharge_tax2, + 'custom_surcharge_tax3' => (bool) $credit->custom_surcharge_tax3, + 'custom_surcharge_tax4' => (bool) $credit->custom_surcharge_tax4, + 'line_items' => $credit->line_items ? $this->padLineItems($credit->line_items, $credit->client): (array) [], + 'reminder1_sent' => $this->translateDate($credit->reminder1_sent, $credit->client->date_format(), $credit->client->locale()), + 'reminder2_sent' => $this->translateDate($credit->reminder2_sent, $credit->client->date_format(), $credit->client->locale()), + 'reminder3_sent' => $this->translateDate($credit->reminder3_sent, $credit->client->date_format(), $credit->client->locale()), + 'reminder_last_sent' => $this->translateDate($credit->reminder_last_sent, $credit->client->date_format(), $credit->client->locale()), + 'paid_to_date' => Number::formatMoney($credit->paid_to_date, $credit->client), + 'auto_bill_enabled' => (bool) $credit->auto_bill_enabled, + 'client' => [ + 'name' => $credit->client->present()->name(), + 'balance' => $credit->client->balance, + 'payment_balance' => $credit->client->payment_balance, + 'credit_balance' => $credit->client->credit_balance, + ], + 'payments' => [], + 'total_tax_map' => $credit->calc()->getTotalTaxMap(), + 'line_tax_map' => $credit->calc()->getTaxMap(), + ]; - }); + }); return $credits->toArray(); @@ -775,5 +800,125 @@ class TemplateService return $this; } + + /** + * Parses and finds any stacks to replace + * + * @return self + */ + private function parseGlobalStacks(): self + { + $stacks = [ + 'entity-details', + 'client-details', + 'vendor-details', + 'company-details', + 'company-address', + 'shipping-details', + ]; -} \ No newline at end of file + collect($stacks)->filter(function ($stack) { + $this->document->getElementById($stack); + + })->each(function ($stack){ + $this->parseStack($stack); + }); + + return $this; + + } + + /** + * Injects field stacks into Template + * + * @param string $stack + * @return self + */ + private function parseStack(string $stack): self + { + match($stack){ + 'entity-details' => $this->entityDetails(), + 'client-details' => $this->clientDetails(), + 'vendor-details' => $this->vendorDetails(), + 'company-details' => $this->companyDetails(), + 'company-address' => $this->companyAddress(), + 'shipping-details' => $this->shippingDetails(), + }; + + return $this; + } + + private function companyDetails(): self + { + + collect($this->company->settings->pdf_variables['company_details']) + ->filter(function ($variable) { + return isset($this->variables['values'][$variable]) && !empty($this->variables['values'][$variable]); + }) + ->map(function ($variable) { + return ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_details-' . substr($variable, 1)]]; + }); + + + return $this; + } + + private function companyAddress(): self + { + + $variables = $this->company->settings->pdf_variables['company_address']; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'company_address-' . substr($variable, 1)]]; + } + + return $elements; + + return $this; + } + + private function shippingDetails(): self + { + + return $this; + } + + private function clientDetails(): self + { + + return $this; + } + + private function entityDetails(): self + { + + return $this; + } + + private function vendorDetails(): self + { + + + $elements = []; + + if (!$this->vendor) { + return $elements; + } + + $variables = $this->context['pdf_variables']['vendor_details']; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false, 'properties' => ['data-ref' => 'vendor_details-' . substr($variable, 1)]]; + } + + return $elements; + + + return $this; + } + + + +}