From c6826d495a1f556745a242dcea0592a8b2a3de5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 20 Aug 2021 15:37:42 +0200 Subject: [PATCH 01/40] Add `statement_invoice_columns` to CompanySettings --- app/DataMapper/CompanySettings.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index b5afc076f092..a6a203ca7696 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -676,6 +676,13 @@ class CompanySettings extends BaseSettings '$paid_to_date', '$outstanding', ], + 'statement_invoice_columns' => [ + '$invoice.number', + '$invoice.date', + '$due_date', + '$total', + '$outstanding', + ], ]; return json_decode(json_encode($variables)); From 4cbdc8b521d9af66c0b30ca6b228f2a2911609b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 20 Aug 2021 15:38:15 +0200 Subject: [PATCH 02/40] Construct & update `entity` if `invoices` is available in `context` --- app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php index d43465d0ed60..b9134d52620b 100644 --- a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php +++ b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php @@ -36,6 +36,11 @@ trait DesignHelpers $this->entity = $this->context['entity']; } + if (isset($this->context['invoices'])) { + $this->invoices = $this->context['invoices']; + $this->entity = $this->invoices->first(); + } + $this->document(); return $this; From 712b8d882ac13c2e028f631dcea2b2494fb1602b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 20 Aug 2021 15:39:27 +0200 Subject: [PATCH 03/40] Update constants on `DELIVERY_NOTE` and `STATEMENT` and scaffold `statementInvoiceTable` --- app/Services/PdfMaker/Design.php | 85 ++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 9 deletions(-) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 76595fc02a2f..7a56b2696bc0 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -17,13 +17,14 @@ use App\Models\Quote; use App\Services\PdfMaker\Designs\Utilities\BaseDesign; use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; use App\Utils\Number; +use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesInvoiceValues; use DOMDocument; use Illuminate\Support\Str; class Design extends BaseDesign { - use MakesInvoiceValues, DesignHelpers; + use MakesInvoiceValues, DesignHelpers, MakesDates; /** @var App\Models\Invoice || @var App\Models\Quote */ public $entity; @@ -43,6 +44,9 @@ class Design extends BaseDesign /** Construct options */ public $options; + /** @var Invoice[] */ + public $invoices; + const BOLD = 'bold'; const BUSINESS = 'business'; const CLEAN = 'clean'; @@ -54,6 +58,9 @@ class Design extends BaseDesign const PLAYFUL = 'playful'; const CUSTOM = 'custom'; + const DELIVERY_NOTE = 'delivery_note'; + const STATEMENT = 'statement'; + public function __construct(string $design = null, array $options = []) { Str::endsWith('.html', $design) ? $this->design = $design : $this->design = "{$design}.html"; @@ -115,6 +122,10 @@ class Design extends BaseDesign 'id' => 'task-table', 'elements' => $this->taskTable(), ], + 'statement-invoice-table' => [ + 'id' => 'statement-invoice-table', + 'elements' => $this->statementInvoiceTable(), + ], 'table-totals' => [ 'id' => 'table-totals', 'elements' => $this->tableTotals(), @@ -158,7 +169,7 @@ class Design extends BaseDesign { $elements = []; - if ($this->type == 'delivery_note') { + if ($this->type == self::DELIVERY_NOTE) { $elements = [ ['element' => 'p', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']], ['element' => 'p', 'content' => $this->entity->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']], @@ -190,6 +201,19 @@ class Design extends BaseDesign public function entityDetails(): array { + if ($this->type === 'statement') { + return [ + ['element' => 'tr', 'properties' => [], 'elements' => [ + ['element' => 'th', 'properties' => [], 'content' => '$statement_date_label'], + ['element' => 'th', 'properties' => [], 'content' => '$statement_date'], + ]], + ['element' => 'tr', 'properties' => [], 'elements' => [ + ['element' => 'th', 'properties' => [], 'content' => '$balance_due_label'], + ['element' => 'th', 'properties' => [], 'content' => '$balance_due'], + ]], + ]; + } + $variables = $this->context['pdf_variables']['invoice_details']; if ($this->entity instanceof Quote) { @@ -203,7 +227,7 @@ class Design extends BaseDesign $elements = []; // We don't want to show account balance or invoice total on PDF.. or any amount with currency. - if ($this->type == 'delivery_note') { + if ($this->type == self::DELIVERY_NOTE) { $variables = array_filter($variables, function ($m) { return !in_array($m, ['$invoice.balance_due', '$invoice.total']); }); @@ -231,7 +255,7 @@ class Design extends BaseDesign public function deliveryNoteTable(): array { - if ($this->type !== 'delivery_note') { + if ($this->type !== self::DELIVERY_NOTE) { return []; } @@ -241,7 +265,7 @@ class Design extends BaseDesign ['element' => 'th', 'content' => '$description_label', 'properties' => ['data-ref' => 'delivery_note-description_label']], ['element' => 'th', 'content' => '$product.quantity_label', 'properties' => ['data-ref' => 'delivery_note-product.quantity_label']], ]], - ['element' => 'tbody', 'elements' => $this->buildTableBody('delivery_note')], + ['element' => 'tbody', 'elements' => $this->buildTableBody(self::DELIVERY_NOTE)], ]; } @@ -260,7 +284,7 @@ class Design extends BaseDesign return []; } - if ($this->type == 'delivery_note') { + if ($this->type === self::DELIVERY_NOTE || $this->type === self::STATEMENT) { return []; } @@ -285,7 +309,7 @@ class Design extends BaseDesign return []; } - if ($this->type == 'delivery_note') { + if ($this->type === self::DELIVERY_NOTE || $this->type === self::STATEMENT) { return []; } @@ -295,6 +319,33 @@ class Design extends BaseDesign ]; } + /** + * Parent method for building invoices table within statement. + * + * @return array + */ + public function statementInvoiceTable(): array + { + $tbody = []; + + foreach ($this->invoices as $invoice) { + $element = ['element' => 'tr', 'elements' => []]; + + $element['elements'][] = ['element' => 'td', 'content' => $invoice->number]; + $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->due_date, $invoice->client->date_format(), $invoice->client->locale()) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->calc()->getTotal(), $invoice->client) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->partial, $invoice->client) ?: ' ']; + + $tbody[] = $element; + } + + return [ + ['element' => 'thead', 'elements' => $this->buildTableHeader('statement_invoice')], + ['element' => 'tbody', 'elements' => $tbody], + ]; + } + /** * Generate the structure of table headers. () * @@ -354,7 +405,7 @@ class Design extends BaseDesign return []; } - if ($type == 'delivery_note') { + if ($type == self::DELIVERY_NOTE) { foreach ($items as $row) { $element = ['element' => 'tr', 'elements' => []]; @@ -432,6 +483,22 @@ class Design extends BaseDesign public function tableTotals(): array { + if ($this->type === 'statement') { + return [ + ['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [ + ['element' => 'div', 'properties' => ['style' => 'margin-top: 1.5rem; display: flex; align-items: flex-start;'], 'elements' => [ + ['element' => 'img', 'properties' => ['src' => '$invoiceninja.whitelabel', 'style' => 'height: 2.5rem;', 'hidden' => $this->entity->user->account->isPaid() ? 'true' : 'false', 'id' => 'invoiceninja-whitelabel-logo']], + ]], + ]], + ['element' => 'div', 'properties' => ['class' => 'totals-table-right-side', 'dir' => '$dir'], 'elements' => [ + ['element' => 'div', 'elements' => [ + ['element' => 'span', 'content' => '$balance_due_label', 'properties' => ['data-ref' => 'total-table-balance-due-label']], + ['element' => 'span', 'content' => '$balance_due', 'properties' => ['data-ref' => 'total-table-balance-due']], + ]], + ]], + ]; + } + $_variables = array_key_exists('variables', $this->context) ? $this->context['variables'] : ['values' => ['$entity.public_notes' => $this->entity->public_notes, '$entity.terms' => $this->entity->terms, '$entity_footer' => $this->entity->footer], 'labels' => []]; @@ -453,7 +520,7 @@ class Design extends BaseDesign ['element' => 'div', 'properties' => ['class' => 'totals-table-right-side', 'dir' => '$dir'], 'elements' => []], ]; - if ($this->type == 'delivery_note') { + if ($this->type == self::DELIVERY_NOTE) { return $elements; } From 2553297edd0c3d58f59f2a07580e0073f6df65d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 20 Aug 2021 15:39:54 +0200 Subject: [PATCH 04/40] Add `$statement_date` variable (wip) --- app/Utils/HtmlEngine.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index c3f0f81c6d25..d05ce3a6744a 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -439,6 +439,8 @@ class HtmlEngine $data['$dir'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'rtl' : 'ltr', 'label' => '']; $data['$dir_text_align'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'right' : 'left', 'label' => '']; + $data['$statement_date'] = ['value' => '{CHANGE_THIS}', 'label' => ctrans('texts.statement_date')]; + $arrKeysLength = array_map('strlen', array_keys($data)); array_multisort($arrKeysLength, SORT_DESC, $data); From 3912e8c4fe107d4a3220f1b963d17957871f838d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Fri, 20 Aug 2021 15:40:09 +0200 Subject: [PATCH 05/40] Add `#statement-invoice-table` to Plain --- resources/views/pdf-designs/plain.html | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index aad262998cb4..59ddeeab421c 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -70,7 +70,8 @@ #product-table, #delivery-note-table, - #task-table { + #task-table, + #statement-invoice-table { min-width: 100%; table-layout: fixed; overflow-wrap: break-word; @@ -86,33 +87,38 @@ #product-table > thead, #delivery-note-table > thead, - #task-table > thead { + #task-table > thead, + #statement-invoice-table > thead { text-align: left; } #product-table > thead > tr > th, #delivery-note-table > thead > tr > th, - #task-table > thead > tr > th { + #task-table > thead > tr > th, + #statement-invoice-table > thead > tr > th { padding: 1rem; background-color: #e6e6e6; } #product-table > thead > tr > th:last-child, #delivery-note-table > thead > tr > th:last-child, - #task-table > thead > tr > th:last-child { + #task-table > thead > tr > th:last-child, + #statement-invoice-table > thead > tr > th:last-child { text-align: right; } #product-table > tbody > tr > td, #delivery-note-table > tbody > tr > td, - #task-table > tbody > tr > td { + #task-table > tbody > tr > td, + #statement-invoice-table > tbody > tr > td { border-bottom: 1px solid #e6e6e6; padding: 1rem; } #product-table > tbody > tr > td:last-child, #delivery-note-table > tbody > tr > td:last-child, - #task-table > tbody > tr > td:last-child { + #task-table > tbody > tr > td:last-child, + #statement-invoice-table > tbody > tr > td:last-child { text-align: right; } @@ -181,7 +187,8 @@ /** Markdown-specific styles. **/ #product-table h3, #task-table h3, - #delivery-note-table h3 { + #delivery-note-table, + #statement-invoice-table h3 { font-size: 1rem; margin-bottom: 0; } @@ -251,6 +258,8 @@
+
+
From 56b48ee3b76e641a48ee7aa5c3c1cb68009d9dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 23 Aug 2021 14:05:17 +0200 Subject: [PATCH 06/40] Skip rendering statements table if `invoices` is null --- app/Services/PdfMaker/Design.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 7a56b2696bc0..9b4ca31d1da9 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -328,6 +328,10 @@ class Design extends BaseDesign { $tbody = []; + if (is_null($this->invoices)) { + return []; + } + foreach ($this->invoices as $invoice) { $element = ['element' => 'tr', 'elements' => []]; From e12a8d94dc08d66e24095064895e2f648ff1a8dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 23 Aug 2021 14:21:11 +0200 Subject: [PATCH 07/40] Add variables for `statement_payment_columns` --- app/DataMapper/CompanySettings.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index a6a203ca7696..54b589718b62 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -683,6 +683,12 @@ class CompanySettings extends BaseSettings '$total', '$outstanding', ], + 'statement_payment_columns' => [ + '$invoice.number', + '$payment_date', + '$method', + '$outstanding', + ], ]; return json_decode(json_encode($variables)); From 9dc61da56e14f84bb721889030fcb6838eeaa2f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 23 Aug 2021 14:21:28 +0200 Subject: [PATCH 08/40] Add option to accept `payments` in the Design --- app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php index b9134d52620b..fd224d10260d 100644 --- a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php +++ b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php @@ -41,6 +41,10 @@ trait DesignHelpers $this->entity = $this->invoices->first(); } + if (isset($this->context['payments'])) { + $this->payments = $this->context['payments']; + } + $this->document(); return $this; From 2709572276797cd30f78ffa7c744099d62aa0d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 23 Aug 2021 14:22:07 +0200 Subject: [PATCH 09/40] Support for payments on statement --- app/Services/PdfMaker/Design.php | 48 ++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 9b4ca31d1da9..7fab4d4b089d 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -13,6 +13,9 @@ namespace App\Services\PdfMaker; use App\Models\Credit; +use App\Models\GatewayType; +use App\Models\Invoice; +use App\Models\Payment; use App\Models\Quote; use App\Services\PdfMaker\Designs\Utilities\BaseDesign; use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; @@ -47,6 +50,9 @@ class Design extends BaseDesign /** @var Invoice[] */ public $invoices; + /** @var Payment[] */ + public $payments; + const BOLD = 'bold'; const BUSINESS = 'business'; const CLEAN = 'clean'; @@ -126,6 +132,10 @@ class Design extends BaseDesign 'id' => 'statement-invoice-table', 'elements' => $this->statementInvoiceTable(), ], + 'statement-payment-table' => [ + 'id' => 'statement-payment-table', + 'elements' => $this->statementPaymentTable(), + ], 'table-totals' => [ 'id' => 'table-totals', 'elements' => $this->tableTotals(), @@ -326,12 +336,12 @@ class Design extends BaseDesign */ public function statementInvoiceTable(): array { - $tbody = []; - - if (is_null($this->invoices)) { + if (is_null($this->invoices) || $this->type !== self::STATEMENT) { return []; } + $tbody = []; + foreach ($this->invoices as $invoice) { $element = ['element' => 'tr', 'elements' => []]; @@ -350,6 +360,38 @@ class Design extends BaseDesign ]; } + /** + * Parent method for building payments table within statement. + * + * @return array + */ + public function statementPaymentTable() + { + if (is_null($this->payments) || $this->type !== self::STATEMENT) { + return []; + } + + $tbody = []; + + foreach ($this->payments as $payment) { + foreach ($payment->invoices as $invoice) { + $element = ['element' => 'tr', 'elements' => []]; + + $element['elements'][] = ['element' => 'td', 'content' => $invoice->number]; + $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($payment->date, $payment->client->date_format(), $payment->client->locale()) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => GatewayType::getAlias($payment->gateway_type_id) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->partial, $payment->client) ?: ' ']; + + $tbody[] = $element; + } + } + + return [ + ['element' => 'thead', 'elements' => $this->buildTableHeader('statement_payment')], + ['element' => 'tbody', 'elements' => $tbody], + ]; + } + /** * Generate the structure of table headers. () * From 053f951fef8a3cb483920615606c5662575bfd5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 23 Aug 2021 14:22:22 +0200 Subject: [PATCH 10/40] Add `payment_date` and `method` variables to `HtmlEngine` --- app/Utils/HtmlEngine.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index d05ce3a6744a..bfe341274b29 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -440,6 +440,8 @@ class HtmlEngine $data['$dir_text_align'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'right' : 'left', 'label' => '']; $data['$statement_date'] = ['value' => '{CHANGE_THIS}', 'label' => ctrans('texts.statement_date')]; + $data['$payment_date'] = ['value' => ' ', 'label' => ctrans('texts.payment_date')]; + $data['$method'] = ['value' => ' ', 'label' => ctrans('texts.method')]; $arrKeysLength = array_map('strlen', array_keys($data)); array_multisort($arrKeysLength, SORT_DESC, $data); From c7cd6e8281318b4ef746e5b11df414de65eee03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 23 Aug 2021 14:22:38 +0200 Subject: [PATCH 11/40] Add `#statement-payment-table` to Plain --- resources/views/pdf-designs/plain.html | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index 59ddeeab421c..ff6971bdac81 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -71,7 +71,8 @@ #product-table, #delivery-note-table, #task-table, - #statement-invoice-table { + #statement-invoice-table, + #statement-payment-table { min-width: 100%; table-layout: fixed; overflow-wrap: break-word; @@ -88,14 +89,16 @@ #product-table > thead, #delivery-note-table > thead, #task-table > thead, - #statement-invoice-table > thead { + #statement-invoice-table > thead, + #statement-payment-table > thead { text-align: left; } #product-table > thead > tr > th, #delivery-note-table > thead > tr > th, #task-table > thead > tr > th, - #statement-invoice-table > thead > tr > th { + #statement-invoice-table > thead > tr > th, + #statement-payment-table > thead > tr > th { padding: 1rem; background-color: #e6e6e6; } @@ -103,14 +106,16 @@ #product-table > thead > tr > th:last-child, #delivery-note-table > thead > tr > th:last-child, #task-table > thead > tr > th:last-child, - #statement-invoice-table > thead > tr > th:last-child { + #statement-invoice-table > thead > tr > th:last-child, + #statement-payment-table > thead > tr > th:last-child { text-align: right; } #product-table > tbody > tr > td, #delivery-note-table > tbody > tr > td, #task-table > tbody > tr > td, - #statement-invoice-table > tbody > tr > td { + #statement-invoice-table > tbody > tr > td, + #statement-payment-table > tbody > tr > td { border-bottom: 1px solid #e6e6e6; padding: 1rem; } @@ -118,7 +123,8 @@ #product-table > tbody > tr > td:last-child, #delivery-note-table > tbody > tr > td:last-child, #task-table > tbody > tr > td:last-child, - #statement-invoice-table > tbody > tr > td:last-child { + #statement-invoice-table > tbody > tr > td:last-child, + #statement-payment-table > tbody > tr > td:last-child { text-align: right; } @@ -188,7 +194,8 @@ #product-table h3, #task-table h3, #delivery-note-table, - #statement-invoice-table h3 { + #statement-invoice-table h3, + #statement-payment-table h3 { font-size: 1rem; margin-bottom: 0; } @@ -260,6 +267,8 @@
+
+
From 8a188dd73139a1e2d4b2effcd11ee59c4df64260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 23 Aug 2021 14:50:39 +0200 Subject: [PATCH 12/40] Scaffold `statement-aging-table` --- app/Services/PdfMaker/Design.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 7fab4d4b089d..2a957f1526e1 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -136,6 +136,10 @@ class Design extends BaseDesign 'id' => 'statement-payment-table', 'elements' => $this->statementPaymentTable(), ], + 'statement-aging-table' => [ + 'id' => 'statement-aging-table', + 'elements' => $this->statementAgingTable(), + ], 'table-totals' => [ 'id' => 'table-totals', 'elements' => $this->tableTotals(), @@ -392,6 +396,32 @@ class Design extends BaseDesign ]; } + public function statementAgingTable() + { + if (is_null($this->payments) || $this->type !== self::STATEMENT) { + return []; + } + + return [ + ['element' => 'thead', 'elements' => [ + ['element' => 'th', 'content' => '0-30', 'properties' => []], + ['element' => 'th', 'content' => '30-60', 'properties' => []], + ['element' => 'th', 'content' => '60-90', 'properties' => []], + ['element' => 'th', 'content' => '90-120', 'properties' => []], + ['element' => 'th', 'content' => '120+', 'properties' => []], + ]], + ['element' => 'tbody', 'elements' => [ + ['element' => 'tr', 'elements' => [ + ['element' => 'td', 'content' => '$0.00'], + ['element' => 'td', 'content' => '$0.00'], + ['element' => 'td', 'content' => '$0.00'], + ['element' => 'td', 'content' => '$0.00'], + ['element' => 'td', 'content' => '$0.00'], + ]], + ]], + ]; + } + /** * Generate the structure of table headers. () * From 34d539bb5299fd7aefdadfa4cde46e9f01d4487b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 23 Aug 2021 14:50:52 +0200 Subject: [PATCH 13/40] Add `#statement-aging-table` to Plain --- resources/views/pdf-designs/plain.html | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index ff6971bdac81..2a99e10d9130 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -72,7 +72,8 @@ #delivery-note-table, #task-table, #statement-invoice-table, - #statement-payment-table { + #statement-payment-table, + #statement-aging-table { min-width: 100%; table-layout: fixed; overflow-wrap: break-word; @@ -90,7 +91,8 @@ #delivery-note-table > thead, #task-table > thead, #statement-invoice-table > thead, - #statement-payment-table > thead { + #statement-payment-table > thead, + #statement-aging-table > thead { text-align: left; } @@ -98,7 +100,8 @@ #delivery-note-table > thead > tr > th, #task-table > thead > tr > th, #statement-invoice-table > thead > tr > th, - #statement-payment-table > thead > tr > th { + #statement-payment-table > thead > tr > th, + #statement-aging-table > thead > tr > th { padding: 1rem; background-color: #e6e6e6; } @@ -107,7 +110,8 @@ #delivery-note-table > thead > tr > th:last-child, #task-table > thead > tr > th:last-child, #statement-invoice-table > thead > tr > th:last-child, - #statement-payment-table > thead > tr > th:last-child { + #statement-payment-table > thead > tr > th:last-child, + #statement-aging-table > thead > tr > th:last-child { text-align: right; } @@ -115,7 +119,8 @@ #delivery-note-table > tbody > tr > td, #task-table > tbody > tr > td, #statement-invoice-table > tbody > tr > td, - #statement-payment-table > tbody > tr > td { + #statement-payment-table > tbody > tr > td, + #statement-aging-table > tbody > tr > td { border-bottom: 1px solid #e6e6e6; padding: 1rem; } @@ -124,7 +129,8 @@ #delivery-note-table > tbody > tr > td:last-child, #task-table > tbody > tr > td:last-child, #statement-invoice-table > tbody > tr > td:last-child, - #statement-payment-table > tbody > tr > td:last-child { + #statement-payment-table > tbody > tr > td:last-child, + #statement-aging-table > tbody > tr > td:last-child { text-align: right; } @@ -195,7 +201,8 @@ #task-table h3, #delivery-note-table, #statement-invoice-table h3, - #statement-payment-table h3 { + #statement-payment-table h3, + #statement-aging-table h3 { font-size: 1rem; margin-bottom: 0; } @@ -269,6 +276,8 @@
+
+
From 6d1916ea5cd7c4cdcc0578143d1188684575251f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 12:43:06 +0200 Subject: [PATCH 14/40] Remove `statement` method from `ClientController` --- app/Http/Controllers/ClientController.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index bcca4e6368a9..9d3d272e65bd 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -521,16 +521,6 @@ class ClientController extends BaseController return $this->listResponse(Client::withTrashed()->whereIn('id', $this->transformKeys($ids))); } - /** - * Returns a client statement. - * - * @return void [type] [description] - */ - public function statement() - { - //todo - } - /** * Update the specified resource in storage. * From 792eb003e3b4617875ef556b8628441b5836fd2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 12:43:44 +0200 Subject: [PATCH 15/40] Clean up `ClientStatementController` --- .../Controllers/ClientStatementController.php | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/app/Http/Controllers/ClientStatementController.php b/app/Http/Controllers/ClientStatementController.php index 002e45b9c1e8..edf574020af1 100644 --- a/app/Http/Controllers/ClientStatementController.php +++ b/app/Http/Controllers/ClientStatementController.php @@ -11,9 +11,6 @@ namespace App\Http\Controllers; -/** - * Class ClientStatementController. - */ class ClientStatementController extends BaseController { public function __construct() @@ -21,21 +18,8 @@ class ClientStatementController extends BaseController parent::__construct(); } - /** - * Displays a client statement view for a given - * client_id. - * @return void - */ - public function show() - { - } - - /** - * Updates the show view data dependent on - * configured variables. - * @return void - */ - public function update() + public function statement() { + } } From c6bc102c6d7cfba8be83c49cfd04e742e9be2612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 13:18:32 +0200 Subject: [PATCH 16/40] Update `client.statement` route --- .../Controllers/ClientStatementController.php | 4 ++- .../Statements/CreateStatementRequest.php | 31 +++++++++++++++++++ routes/api.php | 2 +- 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 app/Http/Requests/Statements/CreateStatementRequest.php diff --git a/app/Http/Controllers/ClientStatementController.php b/app/Http/Controllers/ClientStatementController.php index edf574020af1..553413914fac 100644 --- a/app/Http/Controllers/ClientStatementController.php +++ b/app/Http/Controllers/ClientStatementController.php @@ -11,6 +11,8 @@ namespace App\Http\Controllers; +use App\Http\Requests\Statements\CreateStatementRequest; + class ClientStatementController extends BaseController { public function __construct() @@ -18,7 +20,7 @@ class ClientStatementController extends BaseController parent::__construct(); } - public function statement() + public function statement(CreateStatementRequest $request) { } diff --git a/app/Http/Requests/Statements/CreateStatementRequest.php b/app/Http/Requests/Statements/CreateStatementRequest.php new file mode 100644 index 000000000000..ac0f1a205e1f --- /dev/null +++ b/app/Http/Requests/Statements/CreateStatementRequest.php @@ -0,0 +1,31 @@ +user()->isAdmin(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'start_date' => ['required'], + 'end_date' => ['required'], + ]; + } +} diff --git a/routes/api.php b/routes/api.php index ceeb78fadf6e..e004a6bb72be 100644 --- a/routes/api.php +++ b/routes/api.php @@ -43,7 +43,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a Route::post('connected_account', 'ConnectedAccountController@index'); Route::post('connected_account/gmail', 'ConnectedAccountController@handleGmailOauth'); - Route::resource('client_statement', 'ClientStatementController@statement'); // name = (client_statement. index / create / show / update / destroy / edit + Route::post('client_statement', 'ClientStatementController@statement')->name('client.statement'); Route::post('companies/purge/{company}', 'MigrationController@purgeCompany')->middleware('password_protected'); Route::post('companies/purge_save_settings/{company}', 'MigrationController@purgeCompanySaveSettings')->middleware('password_protected'); From 35bcb1d779969772d0b5b22ae55a6591b3952b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 15:31:07 +0200 Subject: [PATCH 17/40] API endpoint for creating statements --- .../Controllers/ClientStatementController.php | 103 +++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/ClientStatementController.php b/app/Http/Controllers/ClientStatementController.php index 553413914fac..61aaafc47dce 100644 --- a/app/Http/Controllers/ClientStatementController.php +++ b/app/Http/Controllers/ClientStatementController.php @@ -12,9 +12,23 @@ namespace App\Http\Controllers; use App\Http\Requests\Statements\CreateStatementRequest; +use App\Models\Design; +use App\Models\InvoiceInvitation; +use App\Services\PdfMaker\Design as PdfDesignModel; +use App\Services\PdfMaker\Design as PdfMakerDesign; +use App\Services\PdfMaker\PdfMaker as PdfMakerService; +use App\Utils\HostedPDF\NinjaPdf; +use App\Utils\HtmlEngine; +use App\Utils\Traits\MakesHash; +use App\Utils\Traits\Pdf\PdfMaker; class ClientStatementController extends BaseController { + use MakesHash, PdfMaker; + + /** @var \App\Models\Invoice|\App\Models\Payment */ + protected $entity; + public function __construct() { parent::__construct(); @@ -22,6 +36,93 @@ class ClientStatementController extends BaseController public function statement(CreateStatementRequest $request) { - + $pdf = $this->createStatement($request); + + if ($pdf) { + return response()->streamDownload(function () use ($pdf) { + echo $pdf; + }, 'statement.pdf', ['Content-Type' => 'application/pdf']); + } + + return response()->json(['message' => 'Something went wrong. Please check logs.']); + } + + protected function createStatement(CreateStatementRequest $request): ?string + { + $invitation = InvoiceInvitation::first(); + + if (count($request->getInvoices()) >= 1) { + $this->entity = $request->getInvoices()->first(); + } + + if (count($request->getPayments()) >= 1) { + $this->entity = $request->getPayments()->first(); + } + + $entity_design_id = 1; + + $entity_design_id = $this->entity->design_id + ? $this->entity->design_id + : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id)); + + $design = Design::find($entity_design_id); + + if (!$design) { + $design = Design::find(1); + } + + $html = new HtmlEngine($invitation); + + $options = [ + 'start_date' => $request->start_date, + 'end_date' => $request->end_date, + 'show_payments_table' => $request->show_payments_table, + 'show_aging_table' => $request->show_aging_table, + ]; + + 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), $options); + } + + $variables = $html->generateLabelsAndValues(); + + $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, + 'invoices' => $request->getInvoices(), + 'payments' => $request->getPayments(), + 'aging' => $request->getAging(), + ], \App\Services\PdfMaker\Design::STATEMENT), + 'variables' => $variables, + 'options' => [], + 'process_markdown' => $this->entity->client->company->markdown_enabled, + ]; + + $maker = new PdfMakerService($state); + + $maker + ->design($template) + ->build(); + + $pdf = null; + + try { + if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') { + $pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true)); + } else { + $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); + } + } catch (\Exception $e) { + nlog(print_r($e->getMessage(), 1)); + } + + return $pdf; } } From bcd29b93e1937788939ad3bb3e45b0a26892071b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 15:31:40 +0200 Subject: [PATCH 18/40] CreateStatementRequest.php --- .../Statements/CreateStatementRequest.php | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/app/Http/Requests/Statements/CreateStatementRequest.php b/app/Http/Requests/Statements/CreateStatementRequest.php index ac0f1a205e1f..a8577c538367 100644 --- a/app/Http/Requests/Statements/CreateStatementRequest.php +++ b/app/Http/Requests/Statements/CreateStatementRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests\Statements; +use App\Models\Invoice; +use App\Models\Payment; use Illuminate\Foundation\Http\FormRequest; class CreateStatementRequest extends FormRequest @@ -28,4 +30,42 @@ class CreateStatementRequest extends FormRequest 'end_date' => ['required'], ]; } + + /** + * The collection of invoices for the statement. + * + * @return Invoice[]|\Illuminate\Database\Eloquent\Collection + */ + public function getInvoices() + { + // $this->request->start_date & $this->request->end_date are available. + + return Invoice::all(); + } + + /** + * The collection of payments for the statement. + * + * @return Payment[]|\Illuminate\Database\Eloquent\Collection + */ + public function getPayments() + { + // $this->request->start_date & $this->request->end_date are available. + + return Payment::all(); + } + + /** + * The array of aging data. + */ + public function getAging(): array + { + return [ + '0-30' => 1000, + '30-60' => 2000, + '60-90' => 3000, + '90-120' => 4000, + '120+' => 5000, + ]; + } } From cc95f89a9c0143275499a34043774d72bcdc0b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 15:33:23 +0200 Subject: [PATCH 19/40] Design.php: - Add `aging` property - Add `statement-invoice-table-totals`, `statement-payment-table-totals` - Update `entityDetails` for statements --- app/Services/PdfMaker/Design.php | 82 +++++++++++++++----------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 2a957f1526e1..806959590ab7 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -53,6 +53,9 @@ class Design extends BaseDesign /** @var Payment[] */ public $payments; + /** @var array */ + public $aging = []; + const BOLD = 'bold'; const BUSINESS = 'business'; const CLEAN = 'clean'; @@ -82,9 +85,7 @@ class Design extends BaseDesign ); } - $path = isset($this->options['custom_path']) - ? $this->options['custom_path'] - : config('ninja.designs.base_path'); + $path = $this->options['custom_path'] ?? config('ninja.designs.base_path'); return file_get_contents( $path . $this->design @@ -132,10 +133,22 @@ class Design extends BaseDesign 'id' => 'statement-invoice-table', 'elements' => $this->statementInvoiceTable(), ], + 'statement-invoice-table-totals' => [ + 'id' => 'statement-invoice-table-totals', + 'elements' => [ + ['element' => 'p', 'content' => '$outstanding_label: $outstanding'], + ], + ], 'statement-payment-table' => [ 'id' => 'statement-payment-table', 'elements' => $this->statementPaymentTable(), ], + 'statement-payment-table-totals' => [ + 'id' => 'statement-payment-table-totals', + 'elements' => [ + ['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), 1000)], + ], + ], 'statement-aging-table' => [ 'id' => 'statement-aging-table', 'elements' => $this->statementAgingTable(), @@ -218,14 +231,14 @@ class Design extends BaseDesign if ($this->type === 'statement') { return [ ['element' => 'tr', 'properties' => [], 'elements' => [ - ['element' => 'th', 'properties' => [], 'content' => '$statement_date_label'], - ['element' => 'th', 'properties' => [], 'content' => '$statement_date'], + ['element' => 'th', 'properties' => [], 'content' => ctrans('texts.statement_date')], + ['element' => 'th', 'properties' => [], 'content' => $this->options['end_date'] ?? ''], ]], ['element' => 'tr', 'properties' => [], 'elements' => [ ['element' => 'th', 'properties' => [], 'content' => '$balance_due_label'], ['element' => 'th', 'properties' => [], 'content' => '$balance_due'], ]], - ]; + ]; } $variables = $this->context['pdf_variables']['invoice_details']; @@ -369,9 +382,9 @@ class Design extends BaseDesign * * @return array */ - public function statementPaymentTable() + public function statementPaymentTable(): array { - if (is_null($this->payments) || $this->type !== self::STATEMENT) { + if (is_null($this->payments) && $this->type !== self::STATEMENT) { return []; } @@ -385,7 +398,7 @@ class Design extends BaseDesign $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($payment->date, $payment->client->date_format(), $payment->client->locale()) ?: ' ']; $element['elements'][] = ['element' => 'td', 'content' => GatewayType::getAlias($payment->gateway_type_id) ?: ' ']; $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->partial, $payment->client) ?: ' ']; - + $tbody[] = $element; } } @@ -396,30 +409,29 @@ class Design extends BaseDesign ]; } - public function statementAgingTable() + public function statementAgingTable(): array { - if (is_null($this->payments) || $this->type !== self::STATEMENT) { + if ($this->type !== self::STATEMENT) { return []; } - return [ - ['element' => 'thead', 'elements' => [ - ['element' => 'th', 'content' => '0-30', 'properties' => []], - ['element' => 'th', 'content' => '30-60', 'properties' => []], - ['element' => 'th', 'content' => '60-90', 'properties' => []], - ['element' => 'th', 'content' => '90-120', 'properties' => []], - ['element' => 'th', 'content' => '120+', 'properties' => []], - ]], + if (\array_key_exists('show_aging_table', $this->options) && $this->options['show_aging_table'] === false) { + return []; + } + + $elements = [ + ['element' => 'thead', 'elements' => []], ['element' => 'tbody', 'elements' => [ - ['element' => 'tr', 'elements' => [ - ['element' => 'td', 'content' => '$0.00'], - ['element' => 'td', 'content' => '$0.00'], - ['element' => 'td', 'content' => '$0.00'], - ['element' => 'td', 'content' => '$0.00'], - ['element' => 'td', 'content' => '$0.00'], - ]], + ['element' => 'tr', 'elements' => []], ]], ]; + + foreach ($this->aging as $column => $value) { + $elements[0]['elements'][] = ['element' => 'th', 'content' => $column]; + $elements[1]['elements'][] = ['element' => 'td', 'content' => $value]; + } + + return $elements; } /** @@ -559,22 +571,6 @@ class Design extends BaseDesign public function tableTotals(): array { - if ($this->type === 'statement') { - return [ - ['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [ - ['element' => 'div', 'properties' => ['style' => 'margin-top: 1.5rem; display: flex; align-items: flex-start;'], 'elements' => [ - ['element' => 'img', 'properties' => ['src' => '$invoiceninja.whitelabel', 'style' => 'height: 2.5rem;', 'hidden' => $this->entity->user->account->isPaid() ? 'true' : 'false', 'id' => 'invoiceninja-whitelabel-logo']], - ]], - ]], - ['element' => 'div', 'properties' => ['class' => 'totals-table-right-side', 'dir' => '$dir'], 'elements' => [ - ['element' => 'div', 'elements' => [ - ['element' => 'span', 'content' => '$balance_due_label', 'properties' => ['data-ref' => 'total-table-balance-due-label']], - ['element' => 'span', 'content' => '$balance_due', 'properties' => ['data-ref' => 'total-table-balance-due']], - ]], - ]], - ]; - } - $_variables = array_key_exists('variables', $this->context) ? $this->context['variables'] : ['values' => ['$entity.public_notes' => $this->entity->public_notes, '$entity.terms' => $this->entity->terms, '$entity_footer' => $this->entity->footer], 'labels' => []]; @@ -596,7 +592,7 @@ class Design extends BaseDesign ['element' => 'div', 'properties' => ['class' => 'totals-table-right-side', 'dir' => '$dir'], 'elements' => []], ]; - if ($this->type == self::DELIVERY_NOTE) { + if ($this->type == self::DELIVERY_NOTE || $this->type == self::STATEMENT) { return $elements; } From a730900a09e252bab000cb32968a9aaf4cfeec59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 15:33:41 +0200 Subject: [PATCH 20/40] Enable passing `aging` in the `context` --- app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php index fd224d10260d..9fea0b23cd10 100644 --- a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php +++ b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php @@ -45,6 +45,10 @@ trait DesignHelpers $this->payments = $this->context['payments']; } + if (isset($this->context['aging'])) { + $this->aging = $this->context['aging']; + } + $this->document(); return $this; From 6de3637501d7d2300a8603c99dbd4ff4aab35b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 15:34:40 +0200 Subject: [PATCH 21/40] Plain: `#statement-invoice-table-details`, `#statement-payment-table-totals` --- resources/views/pdf-designs/plain.html | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index 2a99e10d9130..ab2487d66997 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -2,7 +2,7 @@ :root { --primary-color: $primary_color; --secondary-color: $secondary_color; - --line-height: 1.6; + --line-height: 1.6; } body { @@ -216,8 +216,15 @@ padding-right: 7px; } + #statement-invoice-table-totals, + #statement-payment-table-totals { + margin-top: 1rem; + text-align: right; + margin-right: .75rem; + } + /** Useful snippets, uncomment to enable. **/ - + /** Hide company logo **/ /* .company-logo { display: none } */ @@ -273,10 +280,13 @@
+
+
+
From 1f341fb29a98f2937b3c9d4ec2ffd1befc8a2ff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 15:36:08 +0200 Subject: [PATCH 22/40] Option to pass `show_payment_table` for `statementPaymentTable` --- app/Services/PdfMaker/Design.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 806959590ab7..e330ade5697f 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -388,6 +388,10 @@ class Design extends BaseDesign return []; } + if (\array_key_exists('show_payment_table', $this->options) && $this->options['show_payment_table'] === false) { + return []; + } + $tbody = []; foreach ($this->payments as $payment) { From a5f8d8c0428cc98b7590dc212c5987cfecf00061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 15:37:16 +0200 Subject: [PATCH 23/40] Rename `$payment_date` to `$payment.date` --- app/DataMapper/CompanySettings.php | 4 ++-- app/Utils/HtmlEngine.php | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index 54b589718b62..38193e0a8bdf 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -71,7 +71,7 @@ class CompanySettings extends BaseSettings public $inclusive_taxes = false; //@implemented public $quote_footer = ''; //@implmented - public $translations; + public $translations; public $counter_number_applied = 'when_saved'; // when_saved , when_sent //@implemented public $quote_number_applied = 'when_saved'; // when_saved , when_sent //@implemented @@ -685,7 +685,7 @@ class CompanySettings extends BaseSettings ], 'statement_payment_columns' => [ '$invoice.number', - '$payment_date', + '$payment.date', '$method', '$outstanding', ], diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index bfe341274b29..0f6b81bf3b22 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -190,7 +190,7 @@ class HtmlEngine } else{ $data['$balance_due'] = ['value' => Number::formatMoney($this->entity->balance, $this->client) ?: ' ', 'label' => ctrans('texts.balance_due')]; - $data['$balance_due_raw'] = ['value' => $this->entity->balance, 'label' => ctrans('texts.balance_due')]; + $data['$balance_due_raw'] = ['value' => $this->entity->balance, 'label' => ctrans('texts.balance_due')]; } } @@ -302,7 +302,7 @@ class HtmlEngine $data['$contact.full_name'] = ['value' => $this->contact->present()->name(), 'label' => ctrans('texts.name')]; $data['$contact'] = &$data['$contact.full_name']; - + $data['$contact.email'] = ['value' => $this->contact->email, 'label' => ctrans('texts.email')]; $data['$contact.phone'] = ['value' => $this->contact->phone, 'label' => ctrans('texts.phone')]; @@ -439,8 +439,7 @@ class HtmlEngine $data['$dir'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'rtl' : 'ltr', 'label' => '']; $data['$dir_text_align'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'right' : 'left', 'label' => '']; - $data['$statement_date'] = ['value' => '{CHANGE_THIS}', 'label' => ctrans('texts.statement_date')]; - $data['$payment_date'] = ['value' => ' ', 'label' => ctrans('texts.payment_date')]; + $data['$payment.date'] = ['value' => ' ', 'label' => ctrans('texts.payment_date')]; $data['$method'] = ['value' => ' ', 'label' => ctrans('texts.method')]; $arrKeysLength = array_map('strlen', array_keys($data)); From 7639746178c47f4bf82299cb5133eea96082a244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 16:06:16 +0200 Subject: [PATCH 24/40] Make `CompanySettings::getEntityVariableDefaults` public --- app/DataMapper/CompanySettings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index 38193e0a8bdf..7342e628a0eb 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -594,7 +594,7 @@ class CompanySettings extends BaseSettings * * @return stdClass The stdClass of PDF variables */ - private static function getEntityVariableDefaults() :stdClass + public static function getEntityVariableDefaults() :stdClass { $variables = [ 'client_details' => [ From 00dbec0ce16b199bd9386e8e6b9128506de4ec4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 16:06:34 +0200 Subject: [PATCH 25/40] Functionality to inject the setting if it doesn't exists --- .../PdfMaker/Designs/Utilities/DesignHelpers.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php index 9fea0b23cd10..b9aea8184d42 100644 --- a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php +++ b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php @@ -28,6 +28,8 @@ trait DesignHelpers public function setup(): self { + $this->syncPdfVariables(); + if (isset($this->context['client'])) { $this->client = $this->context['client']; } @@ -54,6 +56,20 @@ trait DesignHelpers return $this; } + protected function syncPdfVariables(): void + { + $default = (array) \App\DataMapper\CompanySettings::getEntityVariableDefaults(); + $variables = $this->context['pdf_variables']; + + foreach ($default as $property => $value) { + if (array_key_exists($property, $variables)) { + continue; + } + + $variables[$property] = $value; + } + } + /** * Initialize local dom document instance. Used for getting raw HTML out of template. * From 50a666b1ce5fe3c3b733a5faf1fefd2bc5fdceb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 16:09:15 +0200 Subject: [PATCH 26/40] Fixes for payment amount --- app/Services/PdfMaker/Design.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index e330ade5697f..db1551da2f85 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -401,7 +401,7 @@ class Design extends BaseDesign $element['elements'][] = ['element' => 'td', 'content' => $invoice->number]; $element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($payment->date, $payment->client->date_format(), $payment->client->locale()) ?: ' ']; $element['elements'][] = ['element' => 'td', 'content' => GatewayType::getAlias($payment->gateway_type_id) ?: ' ']; - $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->partial, $payment->client) ?: ' ']; + $element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->amount, $payment->client) ?: ' ']; $tbody[] = $element; } From 6c32d905aead68e69e530d5db5742865d91f9f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 24 Aug 2021 16:13:52 +0200 Subject: [PATCH 27/40] Extract totals table for statements into separate methods --- app/Services/PdfMaker/Design.php | 30 ++++++++++++++++++++------ resources/views/pdf-designs/plain.html | 7 +++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index db1551da2f85..88ee420bf970 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -135,9 +135,7 @@ class Design extends BaseDesign ], 'statement-invoice-table-totals' => [ 'id' => 'statement-invoice-table-totals', - 'elements' => [ - ['element' => 'p', 'content' => '$outstanding_label: $outstanding'], - ], + 'elements' => $this->statementInvoiceTableTotals(), ], 'statement-payment-table' => [ 'id' => 'statement-payment-table', @@ -145,9 +143,7 @@ class Design extends BaseDesign ], 'statement-payment-table-totals' => [ 'id' => 'statement-payment-table-totals', - 'elements' => [ - ['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), 1000)], - ], + 'elements' => $this->statementPaymentTableTotals(), ], 'statement-aging-table' => [ 'id' => 'statement-aging-table', @@ -377,6 +373,17 @@ class Design extends BaseDesign ]; } + public function statementInvoiceTableTotals(): array + { + if ($this->type !== self::STATEMENT) { + return []; + } + + return [ + ['element' => 'p', 'content' => '$outstanding_label: $outstanding'], + ]; + } + /** * Parent method for building payments table within statement. * @@ -413,6 +420,17 @@ class Design extends BaseDesign ]; } + public function statementPaymentTableTotals(): array + { + if ($this->type !== self::STATEMENT) { + return []; + } + + return [ + ['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), 1000)], + ]; + } + public function statementAgingTable(): array { if ($this->type !== self::STATEMENT) { diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index ab2487d66997..7026d615fbea 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -297,7 +297,12 @@