diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index bfecb4de8b0d..bf6e5c97ec06 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -841,10 +841,10 @@ class InvoiceController extends BaseController */ public function deliveryNote(ShowInvoiceRequest $request, Invoice $invoice) { + $file_path = $invoice->service()->getInvoiceDeliveryNote($invoice, $invoice->invitations->first()->contact); + + $file = base_path("storage/app/public/{$file_path}"); - $file_path = $invoice->service()->getInvoiceDeliveryNote($invoice->invitations->first()->contact); - - return response()->download($file_path, basename($file_path)); - + return response()->download($file, basename($file)); } } diff --git a/app/Services/Invoice/GenerateDeliveryNote.php b/app/Services/Invoice/GenerateDeliveryNote.php new file mode 100644 index 000000000000..74170974a596 --- /dev/null +++ b/app/Services/Invoice/GenerateDeliveryNote.php @@ -0,0 +1,95 @@ +invoice = $invoice; + + $this->contact = $contact; + + $this->disk = $disk ?? config('filesystems.default'); + } + + public function run() + { + $design_id = $this->invoice->design_id + ? $this->invoice->design_id + : $this->decodePrimaryKey($this->invoice->client->getSetting('invoice_design_id')); + + $file_path = sprintf('%s%s_delivery_note.pdf', $this->invoice->client->invoice_filepath(), $this->invoice->number); + + $design = Design::find($design_id); + $html = new HtmlEngine($this->invoice->invitations->first()); + + if ($design->is_custom) { + $options = ['custom_partials' => json_decode(json_encode($design->design), true)]; + $template = new PdfMakerDesign(PdfMakerDesign::CUSTOM, $options); + } else { + $template = new PdfMakerDesign(strtolower($design->name)); + } + + $state = [ + 'template' => $template->elements([ + 'client' => $this->invoice->client, + 'entity' => $this->invoice, + 'pdf_variables' => (array) $this->invoice->company->settings->pdf_variables, + 'contact' => $this->contact, + ], 'delivery_note'), + 'variables' => $html->generateLabelsAndValues(), + ]; + + $maker = new PdfMakerService($state); + + $maker + ->design($template) + ->build(); + + Storage::makeDirectory($this->invoice->client->invoice_filepath(), 0775); + + $pdf = $this->makePdf(null, null, $maker->getCompiledHTML()); + + Storage::disk($this->disk)->put($file_path, $pdf); + + return $file_path; + } +} diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 5171752aea9e..820da9613352 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -143,9 +143,9 @@ class InvoiceService return (new GetInvoicePdf($this->invoice, $contact))->run(); } - public function getInvoiceDeliveryNote($contact = null) + public function getInvoiceDeliveryNote(\App\Models\Invoice $invoice, \App\Models\ClientContact $contact = null) { - //stubbed + return (new GenerateDeliveryNote($invoice, $contact))->run(); } public function sendEmail($contact = null) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 42dde49f3a12..2043d73eaaa0 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -102,6 +102,10 @@ class Design extends BaseDesign 'id' => 'entity-details', 'elements' => $this->entityDetails(), ], + 'delivery-note-table' => [ + 'id' => 'delivery-note-table', + 'elements' => $this->deliveryNoteTable(), + ], 'product-table' => [ 'id' => 'product-table', 'elements' => $this->productTable(), @@ -151,10 +155,26 @@ class Design extends BaseDesign public function clientDetails(): array { - $variables = $this->context['pdf_variables']['client_details']; - $elements = []; + if ($this->type == 'delivery_note') { + $elements = [ + ['element' => 'p', 'content' => $this->entity->client->name, 'show_empty' => false], + ['element' => 'p', 'content' => $this->entity->client->shipping_address1, 'show_empty' => false], + ['element' => 'p', 'content' => $this->entity->client->shipping_address2, 'show_empty' => false], + ['element' => 'p', 'content' => "{$this->entity->client->shipping_city} {$this->entity->client->shipping_state} {$this->entity->client->shipping_postal_code}", 'show_empty' => false], + ['element' => 'p', 'content' => optional($this->entity->client->shipping_country)->name, 'show_empty' => false], + ]; + + if (!is_null($this->context['contact'])) { + $elements[] = ['element' => 'p', 'content' => $this->context['contact']->email, 'show_empty' => false]; + } + + return $elements; + } + + $variables = $this->context['pdf_variables']['client_details']; + foreach ($variables as $variable) { $elements[] = ['element' => 'p', 'content' => $variable, 'show_empty' => false]; } @@ -192,6 +212,24 @@ class Design extends BaseDesign return $elements; } + public function deliveryNoteTable(): array + { + if ($this->type !== 'delivery_note') { + return []; + } + + $elements = [ + ['element' => 'thead', 'elements' => [ + ['element' => 'th', 'content' => '$item_label'], + ['element' => 'th', 'content' => '$description_label'], + ['element' => 'th', 'content' => '$product.quantity_label'], + ]], + ['element' => 'tbody', 'elements' => $this->buildTableBody('delivery_note')], + ]; + + return $elements; + } + /** * Parent method for building products table. * @@ -207,6 +245,10 @@ class Design extends BaseDesign return []; } + if ($this->type == 'delivery_note') { + return []; + } + return [ ['element' => 'thead', 'elements' => $this->buildTableHeader('product')], ['element' => 'tbody', 'elements' => $this->buildTableBody('$product')], @@ -221,13 +263,17 @@ class Design extends BaseDesign public function taskTable(): array { $task_items = collect($this->entity->line_items)->filter(function ($item) { - return $item->type_id = 2; + return $item->type_id == 2; }); if (count($task_items) == 0) { return []; } + if ($this->type == 'delivery_note') { + return []; + } + return [ ['element' => 'thead', 'elements' => $this->buildTableHeader('task')], ['element' => 'tbody', 'elements' => $this->buildTableBody('$task')], @@ -269,6 +315,20 @@ class Design extends BaseDesign return []; } + if ($type == 'delivery_note') { + foreach ($items as $row) { + $element = ['element' => 'tr', 'elements' => []]; + + $element['elements'][] = ['element' => 'td', 'content' => $row['delivery_note.product_key']]; + $element['elements'][] = ['element' => 'td', 'content' => $row['delivery_note.notes']]; + $element['elements'][] = ['element' => 'td', 'content' => $row['delivery_note.quantity']]; + + $elements[] = $element; + } + + return $elements; + } + foreach ($items as $row) { $element = ['element' => 'tr', 'elements' => []]; @@ -331,6 +391,10 @@ class Design extends BaseDesign public function tableTotals(): array { + if ($this->type == 'delivery_note') { + return []; + } + $variables = $this->context['pdf_variables']['total_columns']; $elements = [ diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 9eae2077ff07..e669dca1d4ae 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -333,6 +333,9 @@ class HtmlEngine $data['$primary_color'] = ['value' => $this->settings->primary_color, 'label' => '']; $data['$secondary_color'] = ['value' => $this->settings->secondary_color, 'label' => '']; + $data['$item'] = ['value' => '', 'label' => ctrans('texts.item')]; + $data['$description'] = ['value' => '', 'label' => ctrans('texts.description')]; + // $data['custom_label1'] = ['value' => '', 'label' => ctrans('texts.')]; // $data['custom_label2'] = ['value' => '', 'label' => ctrans('texts.')]; // $data['custom_label3'] = ['value' => '', 'label' => ctrans('texts.')]; diff --git a/resources/views/pdf-designs/bold.html b/resources/views/pdf-designs/bold.html index 7eff09713eaf..5807917df101 100644 --- a/resources/views/pdf-designs/bold.html +++ b/resources/views/pdf-designs/bold.html @@ -83,7 +83,8 @@ } #product-table, - #task-table { + #task-table, + #delivery-note-table { min-width: 100%; table-layout: fixed; overflow-wrap: break-word; @@ -98,37 +99,44 @@ } #product-table > thead, + #delivery-note-table > thead, #task-table > thead { text-align: left; } #product-table > thead > tr > th, + #delivery-note-table > thead > tr > th, #task-table > thead > tr > th { padding: 2rem; font-size: 1.5rem; } #product-table > thead > tr > th:last-child, + #delivery-note-table > thead > tr > th:last-child, #task-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 { padding: 1.5rem; } #product-table > tbody > tr > td:last-child, + #delivery-note-table > tbody > tr > td:last-child, #task-table > tbody > tr > td:last-child { text-align: right; } #product-table > tbody > tr > td:first-child, + #delivery-note-table > tbody > tr > td:first-child, #task-table > tbody > tr > td:first-child { font-weight: bold; } #product-table > tbody > tr:nth-child(odd), + #delivery-note-table > tbody > tr:nth-child(odd), #task-table > tbody > tr:nth-child(odd) { background-color: #ebebeb; } @@ -194,6 +202,8 @@
+ +
diff --git a/resources/views/pdf-designs/business.html b/resources/views/pdf-designs/business.html index a18ff9bb44b3..a455f777be29 100644 --- a/resources/views/pdf-designs/business.html +++ b/resources/views/pdf-designs/business.html @@ -93,6 +93,7 @@ } #product-table, + #delivery-note-table, #task-table { margin-top: 3.5rem; /* margin-bottom: 200px; */ @@ -108,12 +109,14 @@ } #product-table > thead, + #delivery-note-table > thead, #task-table > thead { text-align: left; background: var(--secondary-color); } #product-table > thead > tr > th, + #delivery-note-table > thead > tr > th, #task-table > thead > tr > th { padding: 1rem; color: white; @@ -121,32 +124,38 @@ } #product-table > thead > tr > th:first-child, + #delivery-note-table > thead > tr > th:first-child, #task-table > thead > tr > th:first-child { border-top-left-radius: 1rem; } #product-table > thead > tr > th:last-child, + #delivery-note-table > thead > tr > th:last-child, #task-table > thead > tr > th:last-child { border-top-right-radius: 1rem; text-align: right; } #product-table > tbody > tr > td, + #delivery-note-table > tbody > tr > td, #task-table > tbody > tr > td { padding: 1rem; } #product-table > tbody > tr > td:last-child, + #delivery-note-table > tbody > tr > td:last-child, #task-table > tbody > tr > td:last-child { text-align: right; } #product-table > tbody > tr:nth-child(odd) > td, + #delivery-note-table > tbody > tr:nth-child(odd) > td, #task-table > tbody > tr:nth-child(odd) > td { background: #e8e8e8; } #product-table > tbody > tr:nth-child(even) > td, + #delivery-note-table > tbody > tr:nth-child(even) > td, #task-table > tbody > tr:nth-child(even) > td { background: #f7f7f7; } @@ -235,6 +244,8 @@
+ +
diff --git a/resources/views/pdf-designs/clean.html b/resources/views/pdf-designs/clean.html index 223cdbddeb5d..94742d4e25b2 100644 --- a/resources/views/pdf-designs/clean.html +++ b/resources/views/pdf-designs/clean.html @@ -78,6 +78,7 @@ } #product-table, + #delivery-note-table, #task-table { margin-top: 3rem; /* margin-bottom: 200px; */ @@ -93,11 +94,13 @@ } #product-table > thead, + #delivery-note-table > thead, #task-table > thead { text-align: left; } #product-table > thead > tr > th, + #delivery-note-table > thead > tr > th, #task-table > thead > tr > th { font-size: 1.1rem; padding-bottom: 1.5rem; @@ -105,17 +108,20 @@ } #product-table > tbody > tr > td, + #delivery-note-table > tbody > tr > td, #task-table > tbody > tr > td { border-bottom: 1px solid #9f9f9f; padding: 1rem; } #product-table > tbody > tr > td:first-child, + #delivery-note-table > tbody > tr > td:first-child, #task-table > tbody > tr > td:first-child { color: var(--primary-color); } #product-table > tbody > tr:nth-child(odd), + #delivery-note-table > tbody > tr:nth-child(odd), #task-table > tbody > tr:nth-child(odd) { background-color: #f5f5f5; } @@ -179,6 +185,8 @@
+ +
diff --git a/resources/views/pdf-designs/creative.html b/resources/views/pdf-designs/creative.html index faa2e3045b45..12cb0bda26b2 100644 --- a/resources/views/pdf-designs/creative.html +++ b/resources/views/pdf-designs/creative.html @@ -87,6 +87,7 @@ } #product-table, + #delivery-note-table, #task-table { margin-top: 3rem; /* margin-bottom: 200px; */ @@ -103,32 +104,38 @@ } #product-table > thead, + #delivery-note-table > thead, #task-table > thead { text-align: left; } #product-table > thead > tr > th, + #delivery-note-table > thead > tr > th, #task-table > thead > tr > th { font-size: 1.1rem; padding: 1rem; } #product-table > thead > tr > th:last-child, + #delivery-note-table > thead > tr > th:last-child, #task-table > thead > tr > th:last-child { text-align: right; } #product-table > tbody > tr > td:last-child, + #delivery-note-table > tbody > tr > td:last-child, #task-table > tbody > tr > td:last-child { text-align: right; } #product-table > tbody > tr > td, + #delivery-note-table > tbody > tr > td, #task-table > tbody > tr > td { padding: 1rem; } #product-table > tbody > tr:nth-child(odd), + #delivery-note-table > tbody > tr:nth-child(odd), #task-table > tbody > tr:nth-child(odd) { background-color: #e8e8e8; } @@ -197,6 +204,8 @@
+ +
diff --git a/resources/views/pdf-designs/elegant.html b/resources/views/pdf-designs/elegant.html index f31e4aa3dc74..61da203f96bf 100644 --- a/resources/views/pdf-designs/elegant.html +++ b/resources/views/pdf-designs/elegant.html @@ -80,6 +80,7 @@ } #product-table, + #delivery-note-table, #task-table { margin-top: 3rem; /* margin-bottom: 200px; */ @@ -95,11 +96,13 @@ } #product-table > thead, + #delivery-note-table > thead, #task-table > thead { text-align: left; } #product-table > thead > tr > th, + #delivery-note-table > thead > tr > th, #task-table > thead > tr > th { font-size: 1.1rem; padding-bottom: 1.5rem; @@ -109,17 +112,20 @@ } #product-table > thead > tr > th:last-child, + #delivery-note-table > thead > tr > th:last-child, #task-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 { border-bottom: 1px solid; padding: 1rem; } #product-table > tbody > tr > td:last-child, + #delivery-note-table > tbody > tr > td:last-child, #task-table > tbody > tr > td:last-child { text-align: right; } @@ -204,6 +210,8 @@
+ +

$thanks_label!

diff --git a/resources/views/pdf-designs/hipster.html b/resources/views/pdf-designs/hipster.html index 00b68b5772c6..79574945f766 100644 --- a/resources/views/pdf-designs/hipster.html +++ b/resources/views/pdf-designs/hipster.html @@ -98,6 +98,7 @@ } #product-table, + #delivery-note-table, #task-table { margin-top: 3rem; /* margin-bottom: 200px; */ @@ -112,6 +113,7 @@ color: grey; } + #product-table > thead, #product-table > thead, #task-table > thead { text-align: left; @@ -120,6 +122,7 @@ } #product-table > thead > tr > th, + #delivery-note-table > thead > tr > th, #task-table > thead > tr > th { font-size: 1.1rem; padding-bottom: 1.5rem; @@ -128,17 +131,20 @@ } #product-table > thead > tr > th:last-child, + #delivery-note-table > thead > tr > th:last-child, #task-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 { padding: 1rem; border-left: 1px solid; } #product-table > tbody > tr td:last-child, + #delivery-note-table > tbody > tr td:last-child, #task-table > tbody > tr td:last-child { text-align: right; } @@ -233,6 +239,8 @@
+ +
diff --git a/resources/views/pdf-designs/modern.html b/resources/views/pdf-designs/modern.html index 703d697ab4b8..6eedb324c0f6 100644 --- a/resources/views/pdf-designs/modern.html +++ b/resources/views/pdf-designs/modern.html @@ -71,6 +71,7 @@ } #product-table, + #delivery-note-table, #task-table { min-width: 100%; table-layout: fixed; @@ -78,11 +79,13 @@ } #product-table > thead, + #delivery-note-table > thead, #task-table > thead { text-align: left; } #product-table > thead > tr > th, + #delivery-note-table > thead > tr > th, #task-table > thead > tr > th { padding: 0.8rem; background-color: var(--secondary-color); @@ -90,22 +93,26 @@ } #product-table > thead > tr > th:last-child, + #delivery-note-table > thead > tr > th:last-child, #task-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 { border-bottom: 1px solid var(--secondary-color); padding: 1rem; } #product-table > tbody > tr > td:first-child, + #delivery-note-table > tbody > tr > td:first-child, #task-table > tbody > tr > td:first-child { font-weight: bold; } #product-table > tbody > tr > td:last-child, + #delivery-note-table > tbody > tr > td:last-child, #task-table > tbody > tr > td:last-child { text-align: right; } @@ -235,6 +242,7 @@
+
diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index 21692efec73e..637b398686da 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -58,7 +58,9 @@ flex-direction: column; } - #product-table, #task-table { + #product-table, + #delivery-note-table, + #task-table { min-width: 100%; table-layout: fixed; overflow-wrap: break-word; @@ -72,28 +74,34 @@ color: grey; } - #product-table, #task-table > thead { + #product-table > thead, + #delivery-note-table > thead, + #task-table > thead { text-align: left; } #product-table > thead > tr > th, + #delivery-note-table > thead > tr > th, #task-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 { text-align: right; } #product-table > tbody > tr > td, + #delivery-note-table > tbody > tr > td, #task-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 { text-align: right; } @@ -150,6 +158,8 @@
+ +
diff --git a/resources/views/pdf-designs/playful.html b/resources/views/pdf-designs/playful.html index 51297ad7d5c9..baa349c421d8 100644 --- a/resources/views/pdf-designs/playful.html +++ b/resources/views/pdf-designs/playful.html @@ -88,6 +88,7 @@ } #product-table, + #delivery-note-table, #task-table { margin-top: 3rem; /* margin-bottom: 200px; */ @@ -103,11 +104,13 @@ } #product-table > thead, + #delivery-note-table > thead, #task-table > thead { text-align: left; } #product-table > thead > tr > th, + #delivery-note-table > thead > tr > th, #task-table > thead > tr > th { font-size: 1.2rem; padding: 1rem; @@ -116,34 +119,40 @@ } #product-table > thead tr > th:last-child, + #delivery-note-table > thead tr > th:last-child, #task-table > thead tr > th:last-child { text-align: right; } #product-table > thead tr > th:first-child, + #delivery-note-table > thead tr > th:first-child, #task-table > thead tr > th:first-child { border-top-left-radius: 10px; border-bottom-left-radius: 10px; } #product-table > thead tr > th:last-child, + #delivery-note-table > thead tr > th:last-child, #task-table > thead tr > th:last-child { border-top-right-radius: 10px; border-bottom-right-radius: 10px; } #product-table > tbody > tr > td, + #delivery-note-table > tbody > tr > td, #task-table > tbody > tr > td { border-bottom: 1px solid var(--primary-color); padding: 1rem; } #product-table > tbody > tr > td:first-child, + #delivery-note-table > tbody > tr > td:first-child, #task-table > tbody > tr > td:first-child { color: var(--primary-color); } #product-table > tbody > tr > td:last-child, + #delivery-note-table > tbody > tr > td:last-child, #task-table > tbody > tr > td:last-child { text-align: right; } @@ -218,6 +227,8 @@
+ +