From 2e3179d83e6818597ff1bfabdd0c04ab70aec421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 29 Jul 2020 13:37:05 +0200 Subject: [PATCH 01/22] Extract variables from the HtmlEngine --- app/Services/PdfMaker/PdfMakerUtilities.php | 3 +- app/Utils/HtmlEngine.php | 8 ++--- .../PdfMaker/ExampleIntegrationTest.php | 36 +++++++++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 tests/Feature/PdfMaker/ExampleIntegrationTest.php diff --git a/app/Services/PdfMaker/PdfMakerUtilities.php b/app/Services/PdfMaker/PdfMakerUtilities.php index 174caec83fe9..56e57be52d0f 100644 --- a/app/Services/PdfMaker/PdfMakerUtilities.php +++ b/app/Services/PdfMaker/PdfMakerUtilities.php @@ -116,7 +116,8 @@ trait PdfMakerUtilities public function updateVariables(array $variables) { - $html = strtr($this->getCompiledHTML(), $variables); + $html = strtr($this->getCompiledHTML(), $variables['labels']); + $html = strtr($this->getCompiledHTML(), $variables['values']); $this->document->loadHTML($html); diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index fc922bc5f3cd..677f98137472 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -29,18 +29,14 @@ class HtmlEngine public $company; - public $designer; - public $settings; public $entity_calc; public $entity_string; - public function __construct(Designer $designer, $invitation, $entity_string) + public function __construct($invitation, $entity_string) { - $this->designer = $designer; - $this->invitation = $invitation; $this->entity = $invitation->{$entity_string}; @@ -347,7 +343,7 @@ class HtmlEngine return $data; } - private function generateLabelsAndValues() + public function generateLabelsAndValues() { $data = []; diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php new file mode 100644 index 000000000000..78096a7bf95a --- /dev/null +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -0,0 +1,36 @@ +invitations()->first(); + + $engine = new HtmlEngine($invitation, 'invoice'); + + $state = [ + 'template' => [ + + ], + 'variables' => $engine->generateLabelsAndValues(), + ]; + + $maker = new PdfMaker($state); + + $maker + ->design(Plain::class) + ->build(); + + info($state); + info($maker->getCompiledHTML()); + } +} From cb4efc8c615c284940993bc08afb6b47d7ced37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 29 Jul 2020 14:53:58 +0200 Subject: [PATCH 02/22] wip --- app/Services/PdfMaker/Designs/Plain.php | 68 ++++++++++++++++++- app/Utils/HtmlEngine.php | 3 +- resources/views/pdf-designs/plain.html | 6 +- .../PdfMaker/ExampleIntegrationTest.php | 7 +- 4 files changed, 73 insertions(+), 11 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index 36b6ea628262..7c69b13de34c 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -14,10 +14,74 @@ namespace App\Services\PdfMaker\Designs; class Plain { - public function html() + public function html(): ?string { return file_get_contents( base_path('resources/views/pdf-designs//plain.html') ); } -} + + public static function elements(): array + { + return [ + 'company-address' => [ + 'id' => 'company-address', + 'elements' => [ + ['element' => 'p', 'content' => '$company.address1'], + ['element' => 'p', 'content' => '$company.address2'], + ['element' => 'p', 'content' => '$company.city_state_postal'], + ['element' => 'p', 'content' => '$company.postal_city_state'], + ['element' => 'p', 'content' => '$company.country'], + ['element' => 'p', 'content' => '$company1'], + ['element' => 'p', 'content' => '$company2'], + ['element' => 'p', 'content' => '$company3'], + ['element' => 'p', 'content' => '$company4'], + ], + ], + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => '$entity-number-label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => '$entity-number', 'properties' => ['class' => 'text-left pr-4 font-medium']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => '$entity-date-label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => '$entity-date', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => '$due-date-label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => '$due-date', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'bg-gray-200'], 'elements' => [ + ['element' => 'th', 'content' => '$balance-due-label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => '$balance-due', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ]], + ], + ], + 'client-details' => [ + 'id' => 'client-details', + 'properties' => ['hidden' => 'true'], + 'elements' => [ + ['element' => 'p', 'content' => '$client.name', 'properties' => ['class' => 'font-medium']], + ['element' => 'p', 'content' => '$client.id_number'], + ['element' => 'p', 'content' => '$client.vat_number'], + ['element' => 'p', 'content' => '$client.address1'], + ['element' => 'p', 'content' => '$client.address2'], + ['element' => 'p', 'content' => '$client.city_state_postal'], + ['element' => 'p', 'content' => '$client.postal_city_state'], + ['element' => 'p', 'content' => '$client.country'], + ['element' => 'p', 'content' => '$client.email'], + ['element' => 'p', 'content' => '$client.custom1'], + ['element' => 'p', 'content' => '$client.custom2'], + ['element' => 'p', 'content' => '$client.custom3'], + ['element' => 'p', 'content' => '$client.custom4'], + ['element' => 'p', 'content' => '$contact.custom1'], + ['element' => 'p', 'content' => '$contact.custom2'], + ['element' => 'p', 'content' => '$contact.custom3'], + ['element' => 'p', 'content' => '$contact.custom4'], + ], + ], + ]; + } +} \ No newline at end of file diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php index 677f98137472..2c741d0c1117 100644 --- a/app/Utils/HtmlEngine.php +++ b/app/Utils/HtmlEngine.php @@ -103,6 +103,7 @@ class HtmlEngine } $data = []; + $data['$global-margin'] = ['value' => 'm-12', 'label' => '']; $data['$tax'] = ['value' => '', 'label' => ctrans('texts.tax')]; $data['$app_url'] = ['value' => $this->generateAppUrl(), 'label' => '']; $data['$from'] = ['value' => '', 'label' => ctrans('texts.from')]; @@ -267,7 +268,7 @@ class HtmlEngine $logo = $this->company->present()->logo($this->settings); - $data['$company.logo'] = ['value' => "logo" ?: ' ', 'label' => ctrans('texts.logo')]; + $data['$company.logo'] = ['value' => $logo ?: ' ', 'label' => ctrans('texts.logo')]; $data['$company_logo'] = &$data['$company.logo']; $data['$company1'] = ['value' => $this->settings->custom_value1 ?: ' ', 'label' => $this->makeCustomField('company1')]; $data['$company2'] = ['value' => $this->settings->custom_value2 ?: ' ', 'label' => $this->makeCustomField('company2')]; diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index 45950ea3b96d..a6f4901e8d7f 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -14,12 +14,12 @@
-
$company-name
+
$company.name
$company->name logo
diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 78096a7bf95a..0aa1e072ebb9 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -18,9 +18,7 @@ class ExampleIntegrationTest extends TestCase $engine = new HtmlEngine($invitation, 'invoice'); $state = [ - 'template' => [ - - ], + 'template' => Plain::elements(), 'variables' => $engine->generateLabelsAndValues(), ]; @@ -30,7 +28,6 @@ class ExampleIntegrationTest extends TestCase ->design(Plain::class) ->build(); - info($state); - info($maker->getCompiledHTML()); + // info($maker->getCompiledHTML()); } } From 70ee47619305046a5505776ac9d1a04c3b1ce255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 30 Jul 2020 16:43:57 +0200 Subject: [PATCH 03/22] wip --- app/Designs/Designer.php | 2 +- app/Services/PdfMaker/Designs/Plain.php | 78 +++++++------------ app/Services/PdfMaker/PdfMaker.php | 2 +- app/Services/PdfMaker/PdfMakerUtilities.php | 3 +- database/seeds/RandomDataSeeder.php | 12 +-- .../PdfMaker/ExampleIntegrationTest.php | 7 +- 6 files changed, 41 insertions(+), 63 deletions(-) diff --git a/app/Designs/Designer.php b/app/Designs/Designer.php index ea62c407ac64..5dd5bdfaafda 100644 --- a/app/Designs/Designer.php +++ b/app/Designs/Designer.php @@ -51,7 +51,7 @@ class Designer 'company4', ]; - public function __construct($entity, $design, $input_variables, $entity_string) +public function __construct($entity, $design, $input_variables, $entity_string) { $this->entity = $entity; diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index 7c69b13de34c..54564ff25510 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -14,74 +14,48 @@ namespace App\Services\PdfMaker\Designs; class Plain { + public $elements; + + public function html(): ?string { return file_get_contents( - base_path('resources/views/pdf-designs//plain.html') + base_path('resources/views/pdf-designs/plain.html') ); } - public static function elements(): array + public function elements($elements): array { return [ 'company-address' => [ 'id' => 'company-address', 'elements' => [ ['element' => 'p', 'content' => '$company.address1'], - ['element' => 'p', 'content' => '$company.address2'], - ['element' => 'p', 'content' => '$company.city_state_postal'], - ['element' => 'p', 'content' => '$company.postal_city_state'], - ['element' => 'p', 'content' => '$company.country'], - ['element' => 'p', 'content' => '$company1'], - ['element' => 'p', 'content' => '$company2'], - ['element' => 'p', 'content' => '$company3'], - ['element' => 'p', 'content' => '$company4'], ], ], - 'entity-details' => [ - 'id' => 'entity-details', + 'product-table' => [ + 'id' => 'product-table', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'th', 'content' => '$entity-number-label', 'properties' => ['class' => 'text-left pr-4 font-normal']], - ['element' => 'th', 'content' => '$entity-number', 'properties' => ['class' => 'text-left pr-4 font-medium']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'th', 'content' => '$entity-date-label', 'properties' => ['class' => 'text-left pr-4 font-normal']], - ['element' => 'th', 'content' => '$entity-date', 'properties' => ['class' => 'text-left pr-4 font-normal']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'th', 'content' => '$due-date-label', 'properties' => ['class' => 'text-left pr-4 font-normal']], - ['element' => 'th', 'content' => '$due-date', 'properties' => ['class' => 'text-left pr-4 font-normal']], - ]], - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'bg-gray-200'], 'elements' => [ - ['element' => 'th', 'content' => '$balance-due-label', 'properties' => ['class' => 'text-left pr-4 font-normal']], - ['element' => 'th', 'content' => '$balance-due', 'properties' => ['class' => 'text-left pr-4 font-normal']], - ]], - ], - ], - 'client-details' => [ - 'id' => 'client-details', - 'properties' => ['hidden' => 'true'], - 'elements' => [ - ['element' => 'p', 'content' => '$client.name', 'properties' => ['class' => 'font-medium']], - ['element' => 'p', 'content' => '$client.id_number'], - ['element' => 'p', 'content' => '$client.vat_number'], - ['element' => 'p', 'content' => '$client.address1'], - ['element' => 'p', 'content' => '$client.address2'], - ['element' => 'p', 'content' => '$client.city_state_postal'], - ['element' => 'p', 'content' => '$client.postal_city_state'], - ['element' => 'p', 'content' => '$client.country'], - ['element' => 'p', 'content' => '$client.email'], - ['element' => 'p', 'content' => '$client.custom1'], - ['element' => 'p', 'content' => '$client.custom2'], - ['element' => 'p', 'content' => '$client.custom3'], - ['element' => 'p', 'content' => '$client.custom4'], - ['element' => 'p', 'content' => '$contact.custom1'], - ['element' => 'p', 'content' => '$contact.custom2'], - ['element' => 'p', 'content' => '$contact.custom3'], - ['element' => 'p', 'content' => '$contact.custom4'], + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left bg-gray-200'], 'elements' => $this->tableHeader($elements)], + ['element' => 'tbody', 'content' => '', 'elements' => $this->tableBody()], ], ], ]; } -} \ No newline at end of file + + public function tableHeader($columns) + { + $elements = []; + + foreach ($columns as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'px-4 py-2']]; + } + + return $elements; + } + + public function tableBody() + { + return []; + } +} diff --git a/app/Services/PdfMaker/PdfMaker.php b/app/Services/PdfMaker/PdfMaker.php index 0aef04315cbc..7640b4d95c1b 100644 --- a/app/Services/PdfMaker/PdfMaker.php +++ b/app/Services/PdfMaker/PdfMaker.php @@ -55,7 +55,7 @@ class PdfMaker if (isset($this->data['variables'])) { $this->updateVariables($this->data['variables']); } - + return $this; } diff --git a/app/Services/PdfMaker/PdfMakerUtilities.php b/app/Services/PdfMaker/PdfMakerUtilities.php index 56e57be52d0f..a696f5012fb5 100644 --- a/app/Services/PdfMaker/PdfMakerUtilities.php +++ b/app/Services/PdfMaker/PdfMakerUtilities.php @@ -117,7 +117,8 @@ trait PdfMakerUtilities public function updateVariables(array $variables) { $html = strtr($this->getCompiledHTML(), $variables['labels']); - $html = strtr($this->getCompiledHTML(), $variables['values']); + + $html = strtr($html, $variables['values']); $this->document->loadHTML($html); diff --git a/database/seeds/RandomDataSeeder.php b/database/seeds/RandomDataSeeder.php index 10f6b1faad2a..013fe1df92ea 100644 --- a/database/seeds/RandomDataSeeder.php +++ b/database/seeds/RandomDataSeeder.php @@ -157,7 +157,7 @@ class RandomDataSeeder extends Seeder ]); - factory(\App\Models\Client::class, 10)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company) { + factory(\App\Models\Client::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company) { factory(\App\Models\ClientContact::class, 1)->create([ 'user_id' => $user->id, 'client_id' => $c->id, @@ -173,10 +173,10 @@ class RandomDataSeeder extends Seeder }); /** Product Factory */ - factory(\App\Models\Product::class, 20)->create(['user_id' => $user->id, 'company_id' => $company->id]); + factory(\App\Models\Product::class, 2)->create(['user_id' => $user->id, 'company_id' => $company->id]); /** Invoice Factory */ - factory(\App\Models\Invoice::class, 20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); + factory(\App\Models\Invoice::class, 2)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); $invoices = Invoice::all(); $invoice_repo = new InvoiceRepository(); @@ -225,7 +225,7 @@ class RandomDataSeeder extends Seeder }); /*Credits*/ - factory(\App\Models\Credit::class, 20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); + factory(\App\Models\Credit::class, 2)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); $credits = Credit::cursor(); $credit_repo = new CreditRepository(); @@ -250,12 +250,12 @@ class RandomDataSeeder extends Seeder }); /** Recurring Invoice Factory */ - factory(\App\Models\RecurringInvoice::class, 10)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); + factory(\App\Models\RecurringInvoice::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); // factory(\App\Models\Payment::class,20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id, 'settings' => ClientSettings::buildClientSettings($company->settings, $client->settings)]); /*Credits*/ - factory(\App\Models\Quote::class, 20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); + factory(\App\Models\Quote::class, 1)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]); $quotes = Quote::cursor(); $quote_repo = new QuoteRepository(); diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 0aa1e072ebb9..8aa201e09fcc 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -2,6 +2,7 @@ namespace Tests\Feature\PdfMaker; +use App\Models\Design; use App\Models\Invoice; use App\Services\PdfMaker\Designs\Plain; use App\Services\PdfMaker\PdfMaker; @@ -16,9 +17,11 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine($invitation, 'invoice'); + $design = new Plain(); + $state = [ - 'template' => Plain::elements(), + 'template' => $design->elements(json_decode(json_encode($invoice->company->settings->pdf_variables), 1)['product_columns']), 'variables' => $engine->generateLabelsAndValues(), ]; @@ -28,6 +31,6 @@ class ExampleIntegrationTest extends TestCase ->design(Plain::class) ->build(); - // info($maker->getCompiledHTML()); + info($maker->getCompiledHTML()); } } From 184f60785fc620692958a11a7a39f647573ca1f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Thu, 30 Jul 2020 17:47:40 +0200 Subject: [PATCH 04/22] wip with table bodies & footer --- app/Services/PdfMaker/Designs/Plain.php | 82 ++++++++++++++++--- app/Utils/Traits/MakesInvoiceValues.php | 2 +- .../PdfMaker/ExampleIntegrationTest.php | 14 +++- 3 files changed, 84 insertions(+), 14 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index 54564ff25510..32b9608dddfa 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -12,10 +12,19 @@ namespace App\Services\PdfMaker\Designs; +use App\Utils\Traits\MakesInvoiceValues; + class Plain { + use MakesInvoiceValues; + public $elements; + public $client; + + public $invoice; + + public $context; public function html(): ?string { @@ -24,8 +33,20 @@ class Plain ); } - public function elements($elements): array + public function setup(): void { + $this->client = $this->context['client']; + + $this->invoice = $this->context['invoice']; + + /** @todo: Wrap the elements with correct checks & exceptions. */ + } + + public function elements(array $context): array + { + $this->context = $context; + $this->setup(); + return [ 'company-address' => [ 'id' => 'company-address', @@ -33,29 +54,68 @@ class Plain ['element' => 'p', 'content' => '$company.address1'], ], ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left bg-gray-200'], 'elements' => $this->tableHeader($elements)], - ['element' => 'tbody', 'content' => '', 'elements' => $this->tableBody()], - ], + $this->productTable(), + ]; + } + + public function productTable() + { + return [ + 'id' => 'product-table', + 'elements' => [ + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left bg-gray-200'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2 bg-gray-300'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ]], ], ]; } - public function tableHeader($columns) + public function buildTableHeader(): array { $elements = []; - foreach ($columns as $column) { + foreach ($this->context['product-table-columns'] as $column) { $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'px-4 py-2']]; } return $elements; } - public function tableBody() + public function buildTableBody(): array { - return []; + $elements = []; + + $items = $this->transformLineItems($this->invoice->line_items); + + if (count($items) == 0) { + return []; + } + + foreach ($items as $row) { + $element = ['element' => 'tr', 'content' => '', 'elements' => []]; + + foreach ($row as $child) { + $element['elements'][] = ['element' => 'td', 'content' => $child, 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']]; + } + + $elements[] = $element; + } + + return $elements; } } diff --git a/app/Utils/Traits/MakesInvoiceValues.php b/app/Utils/Traits/MakesInvoiceValues.php index 626241f57894..7982bdf14ee0 100644 --- a/app/Utils/Traits/MakesInvoiceValues.php +++ b/app/Utils/Traits/MakesInvoiceValues.php @@ -569,7 +569,7 @@ trait MakesInvoiceValues * @param array $items The array of invoice items * @return array The formatted array of invoice items */ - private function transformLineItems($items, $table_type = '$product') :array + public function transformLineItems($items, $table_type = '$product') :array { $data = []; diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 8aa201e09fcc..a79d05317106 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -7,10 +7,13 @@ use App\Models\Invoice; use App\Services\PdfMaker\Designs\Plain; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; +use App\Utils\Traits\MakesInvoiceValues; use Tests\TestCase; class ExampleIntegrationTest extends TestCase { + use MakesInvoiceValues; + public function testExample() { $invoice = Invoice::first(); @@ -18,10 +21,17 @@ class ExampleIntegrationTest extends TestCase $engine = new HtmlEngine($invitation, 'invoice'); $design = new Plain(); - + + $product_table_columns = json_decode( + json_encode($invoice->company->settings->pdf_variables), 1 + )['product_columns']; $state = [ - 'template' => $design->elements(json_decode(json_encode($invoice->company->settings->pdf_variables), 1)['product_columns']), + 'template' => $design->elements([ + 'client' => $invoice->client, + 'invoice' => $invoice, + 'product-table-columns' => $product_table_columns, + ]), 'variables' => $engine->generateLabelsAndValues(), ]; From efd698c9c58542fea2dfda0118fc014a704da4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Mon, 3 Aug 2020 13:29:57 +0200 Subject: [PATCH 05/22] wip with table body --- app/Services/PdfMaker/Designs/Plain.php | 35 +++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index 32b9608dddfa..3b523df8f468 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -89,6 +89,33 @@ class Plain { $elements = []; + if (isset($this->context['product-table-columns']['$product.tax'])) { + $line_items = collect($this->invoice->line_items); + + $tax1 = $line_items->where('tax_name1', '<>', '')->where('type_id', 1)->count(); + $tax2 = $line_items->where('tax_name2', '<>', '')->where('type_id', 1)->count(); + $tax3 = $line_items->where('tax_name3', '<>', '')->where('type_id', 1)->count(); + $taxes = []; + + if ($tax1 > 0) { + array_push($taxes, '$product.tax_rate1'); + } + + if ($tax2 > 0) { + array_push($taxes, '$product.tax_rate2'); + } + + if ($tax3 > 0) { + array_push($taxes, '$product.tax_rate3'); + } + + $key = array_search('$product.tax', $this->context['product-table-columns'], true); + + if ($key) { + array_splice($this->context['product-table-columns'], $key, 1, $taxes); + } + } + foreach ($this->context['product-table-columns'] as $column) { $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'px-4 py-2']]; } @@ -109,10 +136,14 @@ class Plain foreach ($items as $row) { $element = ['element' => 'tr', 'content' => '', 'elements' => []]; - foreach ($row as $child) { - $element['elements'][] = ['element' => 'td', 'content' => $child, 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']]; + foreach ($this->context['product-table-columns'] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']]; } + // foreach ($row as $child) { + // $element['elements'][] = ['element' => 'td', 'content' => $child, 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']]; + // } + $elements[] = $element; } From ee6da44a9426d64d0e9037b6c0b82b46595062d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 4 Aug 2020 13:33:38 +0200 Subject: [PATCH 06/22] Extract helpers for tax calculations into another file --- app/Services/PdfMaker/Designs/Plain.php | 36 ++---------- .../Designs/Utilities/BuildTableHeader.php | 55 +++++++++++++++++++ 2 files changed, 59 insertions(+), 32 deletions(-) create mode 100644 app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index 3b523df8f468..de38aa181703 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -12,11 +12,12 @@ namespace App\Services\PdfMaker\Designs; +use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; use App\Utils\Traits\MakesInvoiceValues; class Plain { - use MakesInvoiceValues; + use MakesInvoiceValues, BuildTableHeader; public $elements; @@ -87,35 +88,10 @@ class Plain public function buildTableHeader(): array { + $this->processTaxColumns(); + $elements = []; - if (isset($this->context['product-table-columns']['$product.tax'])) { - $line_items = collect($this->invoice->line_items); - - $tax1 = $line_items->where('tax_name1', '<>', '')->where('type_id', 1)->count(); - $tax2 = $line_items->where('tax_name2', '<>', '')->where('type_id', 1)->count(); - $tax3 = $line_items->where('tax_name3', '<>', '')->where('type_id', 1)->count(); - $taxes = []; - - if ($tax1 > 0) { - array_push($taxes, '$product.tax_rate1'); - } - - if ($tax2 > 0) { - array_push($taxes, '$product.tax_rate2'); - } - - if ($tax3 > 0) { - array_push($taxes, '$product.tax_rate3'); - } - - $key = array_search('$product.tax', $this->context['product-table-columns'], true); - - if ($key) { - array_splice($this->context['product-table-columns'], $key, 1, $taxes); - } - } - foreach ($this->context['product-table-columns'] as $column) { $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'px-4 py-2']]; } @@ -140,10 +116,6 @@ class Plain $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']]; } - // foreach ($row as $child) { - // $element['elements'][] = ['element' => 'td', 'content' => $child, 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']]; - // } - $elements[] = $element; } diff --git a/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php b/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php new file mode 100644 index 000000000000..c6e7dbf15932 --- /dev/null +++ b/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php @@ -0,0 +1,55 @@ +context['product-table-columns']['$product.tax'])) { + $line_items = collect($this->invoice->line_items); + + $tax1 = $line_items->where('tax_name1', '<>', '')->where('type_id', 1)->count(); + $tax2 = $line_items->where('tax_name2', '<>', '')->where('type_id', 1)->count(); + $tax3 = $line_items->where('tax_name3', '<>', '')->where('type_id', 1)->count(); + $taxes = []; + + if ($tax1 > 0) { + array_push($taxes, '$product.tax_rate1'); + } + + if ($tax2 > 0) { + array_push($taxes, '$product.tax_rate2'); + } + + if ($tax3 > 0) { + array_push($taxes, '$product.tax_rate3'); + } + + $key = array_search('$product.tax', $this->context['product-table-columns'], true); + + if ($key) { + array_splice($this->context['product-table-columns'], $key, 1, $taxes); + } + } + } +} From 96fdf787dee73bcbfd51fab9838c987066c062d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 4 Aug 2020 13:37:51 +0200 Subject: [PATCH 07/22] add comments --- app/Services/PdfMaker/Designs/Plain.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index de38aa181703..4e71d91112fc 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -19,12 +19,16 @@ class Plain { use MakesInvoiceValues, BuildTableHeader; + /** Global list of table elements, @var array */ public $elements; + /** @var App\Models\Client */ public $client; + /** @var App\Models\Invoice */ public $invoice; + /** Global state of the design, @var string */ public $context; public function html(): ?string @@ -36,11 +40,13 @@ class Plain public function setup(): void { - $this->client = $this->context['client']; + if (isset($this->context['client'])) { + $this->client = $this->context['client']; + } - $this->invoice = $this->context['invoice']; - - /** @todo: Wrap the elements with correct checks & exceptions. */ + if (isset($this->context['invoice'])) { + $this->invoice = $this->context['invoice']; + } } public function elements(array $context): array @@ -72,7 +78,6 @@ class Plain ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], ]], - ['element' => 'tr', 'content' => '', 'elements' => [ ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], From 7c4d2cf96f5f1bead76e96e7668d354983959157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 4 Aug 2020 16:41:18 +0200 Subject: [PATCH 08/22] change from isset to in_array --- app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php b/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php index c6e7dbf15932..5459242cb570 100644 --- a/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php +++ b/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php @@ -25,7 +25,7 @@ trait BuildTableHeader */ public function processTaxColumns(): void { - if (isset($this->context['product-table-columns']['$product.tax'])) { + if (in_array('$product.tax', $this->context['product-table-columns'])) { $line_items = collect($this->invoice->line_items); $tax1 = $line_items->where('tax_name1', '<>', '')->where('type_id', 1)->count(); From e5defd870b4fd46377dbd7793fe99f9bd0ef6c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 4 Aug 2020 16:56:17 +0200 Subject: [PATCH 09/22] implement design interface --- app/Services/PdfMaker/Designs/Plain.php | 5 ++-- .../Designs/Utilities/DesignInterface.php | 28 +++++++++++++++++++ resources/views/pdf-designs/plain.html | 1 + 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 app/Services/PdfMaker/Designs/Utilities/DesignInterface.php diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index 4e71d91112fc..4d947f8d0aa2 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -13,9 +13,10 @@ namespace App\Services\PdfMaker\Designs; use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; +use App\Services\PdfMaker\Designs\Utilities\DesignInterface; use App\Utils\Traits\MakesInvoiceValues; -class Plain +class Plain implements DesignInterface { use MakesInvoiceValues, BuildTableHeader; @@ -65,7 +66,7 @@ class Plain ]; } - public function productTable() + public function productTable(): array { return [ 'id' => 'product-table', diff --git a/app/Services/PdfMaker/Designs/Utilities/DesignInterface.php b/app/Services/PdfMaker/Designs/Utilities/DesignInterface.php new file mode 100644 index 000000000000..07f1cf376341 --- /dev/null +++ b/app/Services/PdfMaker/Designs/Utilities/DesignInterface.php @@ -0,0 +1,28 @@ + + From ad2ff79336652d3c104c3ffbdd14194dcda27b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 4 Aug 2020 17:32:28 +0200 Subject: [PATCH 10/22] Complete Plain.php --- app/Services/PdfMaker/Designs/Plain.php | 94 ++++++++++++++----- resources/views/pdf-designs/plain.html | 4 +- .../PdfMaker/ExampleIntegrationTest.php | 9 +- 3 files changed, 80 insertions(+), 27 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index 4d947f8d0aa2..b300ee058e85 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -58,37 +58,85 @@ class Plain implements DesignInterface return [ 'company-address' => [ 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '$company.address1'], - ], + 'elements' => $this->companyAddress(), + ], + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => $this->entityDetails(), + ], + 'client-details' => [ + 'id' => 'client-details', + 'elements' => $this->clientDetails(), + ], + 'product-table' => [ + 'id' => 'product-table', + 'elements' => $this->productTable(), ], - $this->productTable(), ]; } + public function companyAddress(): array + { + $variables = $this->invoice->company->settings->pdf_variables->company_address; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function entityDetails(): array + { + $variables = $this->invoice->company->settings->pdf_variables->invoice_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => $variable . '_label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => $variable, 'properties' => ['class' => 'text-left pr-4 font-medium']], + ]]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->invoice->company->settings->pdf_variables->client_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + public function productTable(): array { return [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left bg-gray-200'], 'elements' => $this->buildTableHeader()], - ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '2']], - ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2 bg-gray-300'], 'elements' => [ - ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left bg-gray-200'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '4']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], ]], - ], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2 bg-gray-300'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ]], ]; } diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index b2951b016cdf..2e9f38b0c30e 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -28,13 +28,13 @@
-
+
-
+
diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index a79d05317106..7e3b6d468879 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -23,7 +23,8 @@ class ExampleIntegrationTest extends TestCase $design = new Plain(); $product_table_columns = json_decode( - json_encode($invoice->company->settings->pdf_variables), 1 + json_encode($invoice->company->settings->pdf_variables), + 1 )['product_columns']; $state = [ @@ -41,6 +42,10 @@ class ExampleIntegrationTest extends TestCase ->design(Plain::class) ->build(); - info($maker->getCompiledHTML()); + exec('echo "" > storage/logs/laravel.log'); + + info($maker->getCompiledHTML(true)); + + $this->assertTrue(true); } } From 0855c10fb3e130a4fad4df16e2064fe2c31d589b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 4 Aug 2020 17:33:57 +0200 Subject: [PATCH 11/22] Remove cdn from plain.html --- resources/views/pdf-designs/plain.html | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index 2e9f38b0c30e..55af58327409 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -8,7 +8,6 @@ /> - From 35af6e137a6daee9dff4f8bf9bee3339588aa21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 11:44:05 +0200 Subject: [PATCH 12/22] Update padding on plain.html --- resources/views/pdf-designs/plain.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index 55af58327409..66753866b91e 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -27,7 +27,7 @@
-
+
From 17858dae45f33494188af10a4cb785b9a9d34d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 11:47:32 +0200 Subject: [PATCH 13/22] Implement base design class & remove design interface --- app/Services/PdfMaker/Designs/Plain.php | 15 ++----------- .../{DesignInterface.php => BaseDesign.php} | 21 +++++++++---------- 2 files changed, 12 insertions(+), 24 deletions(-) rename app/Services/PdfMaker/Designs/Utilities/{DesignInterface.php => BaseDesign.php} (52%) diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index b300ee058e85..33d6f7cd605c 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -12,11 +12,11 @@ namespace App\Services\PdfMaker\Designs; +use App\Services\PdfMaker\Designs\Utilities\BaseDesign; use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; -use App\Services\PdfMaker\Designs\Utilities\DesignInterface; use App\Utils\Traits\MakesInvoiceValues; -class Plain implements DesignInterface +class Plain extends BaseDesign { use MakesInvoiceValues, BuildTableHeader; @@ -39,17 +39,6 @@ class Plain implements DesignInterface ); } - public function setup(): void - { - if (isset($this->context['client'])) { - $this->client = $this->context['client']; - } - - if (isset($this->context['invoice'])) { - $this->invoice = $this->context['invoice']; - } - } - public function elements(array $context): array { $this->context = $context; diff --git a/app/Services/PdfMaker/Designs/Utilities/DesignInterface.php b/app/Services/PdfMaker/Designs/Utilities/BaseDesign.php similarity index 52% rename from app/Services/PdfMaker/Designs/Utilities/DesignInterface.php rename to app/Services/PdfMaker/Designs/Utilities/BaseDesign.php index 07f1cf376341..36e36b474640 100644 --- a/app/Services/PdfMaker/Designs/Utilities/DesignInterface.php +++ b/app/Services/PdfMaker/Designs/Utilities/BaseDesign.php @@ -12,17 +12,16 @@ namespace App\Services\PdfMaker\Designs\Utilities; -interface DesignInterface +class BaseDesign { - public function html(): ?string; + public function setup(): void + { + if (isset($this->context['client'])) { + $this->client = $this->context['client']; + } - public function setup(): void; - - public function elements(array $context): array; - - public function productTable(): array; - - public function buildTableHeader(): array; - - public function buildTableBody(): array; + if (isset($this->context['invoice'])) { + $this->invoice = $this->context['invoice']; + } + } } From 438054744ef1e1f26af72c6f3d076698f6c17040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 11:52:01 +0200 Subject: [PATCH 14/22] refactor invoice to entity --- app/Services/PdfMaker/Designs/Plain.php | 21 ++++++++++++------- .../PdfMaker/Designs/Utilities/BaseDesign.php | 4 ++-- .../Designs/Utilities/BuildTableHeader.php | 2 +- .../PdfMaker/ExampleIntegrationTest.php | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Plain.php b/app/Services/PdfMaker/Designs/Plain.php index 33d6f7cd605c..fc251b272fd2 100644 --- a/app/Services/PdfMaker/Designs/Plain.php +++ b/app/Services/PdfMaker/Designs/Plain.php @@ -26,12 +26,15 @@ class Plain extends BaseDesign /** @var App\Models\Client */ public $client; - /** @var App\Models\Invoice */ - public $invoice; + /** @var App\Models\Invoice || @var App\Models\Quote */ + public $entity; - /** Global state of the design, @var string */ + /** Global state of the design, @var array */ public $context; + /** Type of entity => invoice||quote */ + public $type; + public function html(): ?string { return file_get_contents( @@ -39,9 +42,11 @@ class Plain extends BaseDesign ); } - public function elements(array $context): array + public function elements(array $context, string $type = 'invoice'): array { $this->context = $context; + $this->type = $type; + $this->setup(); return [ @@ -66,7 +71,7 @@ class Plain extends BaseDesign public function companyAddress(): array { - $variables = $this->invoice->company->settings->pdf_variables->company_address; + $variables = $this->entity->company->settings->pdf_variables->company_address; $elements = []; @@ -79,7 +84,7 @@ class Plain extends BaseDesign public function entityDetails(): array { - $variables = $this->invoice->company->settings->pdf_variables->invoice_details; + $variables = $this->entity->company->settings->pdf_variables->invoice_details; $elements = []; @@ -95,7 +100,7 @@ class Plain extends BaseDesign public function clientDetails(): array { - $variables = $this->invoice->company->settings->pdf_variables->client_details; + $variables = $this->entity->company->settings->pdf_variables->client_details; $elements = []; @@ -146,7 +151,7 @@ class Plain extends BaseDesign { $elements = []; - $items = $this->transformLineItems($this->invoice->line_items); + $items = $this->transformLineItems($this->entity->line_items); if (count($items) == 0) { return []; diff --git a/app/Services/PdfMaker/Designs/Utilities/BaseDesign.php b/app/Services/PdfMaker/Designs/Utilities/BaseDesign.php index 36e36b474640..9a01ee42da63 100644 --- a/app/Services/PdfMaker/Designs/Utilities/BaseDesign.php +++ b/app/Services/PdfMaker/Designs/Utilities/BaseDesign.php @@ -20,8 +20,8 @@ class BaseDesign $this->client = $this->context['client']; } - if (isset($this->context['invoice'])) { - $this->invoice = $this->context['invoice']; + if (isset($this->context['entity'])) { + $this->entity = $this->context['entity']; } } } diff --git a/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php b/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php index 5459242cb570..41529dc16b75 100644 --- a/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php +++ b/app/Services/PdfMaker/Designs/Utilities/BuildTableHeader.php @@ -26,7 +26,7 @@ trait BuildTableHeader public function processTaxColumns(): void { if (in_array('$product.tax', $this->context['product-table-columns'])) { - $line_items = collect($this->invoice->line_items); + $line_items = collect($this->entity->line_items); $tax1 = $line_items->where('tax_name1', '<>', '')->where('type_id', 1)->count(); $tax2 = $line_items->where('tax_name2', '<>', '')->where('type_id', 1)->count(); diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 7e3b6d468879..92d6efdb04bc 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -30,13 +30,13 @@ class ExampleIntegrationTest extends TestCase $state = [ 'template' => $design->elements([ 'client' => $invoice->client, - 'invoice' => $invoice, + 'entity' => $invoice, 'product-table-columns' => $product_table_columns, ]), 'variables' => $engine->generateLabelsAndValues(), ]; - $maker = new PdfMaker($state); + $maker = new PdfMaker($state, 'invoice'); $maker ->design(Plain::class) From d63678435f4d3d2569cd6561c6fffe348c5a280c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 12:13:48 +0200 Subject: [PATCH 15/22] Bold design --- app/Services/PdfMaker/Designs/Bold.php | 168 +++++++++++++++++- resources/views/pdf-designs/bold.html | 5 +- resources/views/pdf-designs/plain.html | 2 +- .../PdfMaker/ExampleIntegrationTest.php | 6 +- 4 files changed, 174 insertions(+), 7 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Bold.php b/app/Services/PdfMaker/Designs/Bold.php index 64b2dec6076a..e35bc8281e2d 100644 --- a/app/Services/PdfMaker/Designs/Bold.php +++ b/app/Services/PdfMaker/Designs/Bold.php @@ -12,12 +12,178 @@ namespace App\Services\PdfMaker\Designs; -class Bold +use App\Services\PdfMaker\Designs\Utilities\BaseDesign; +use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; +use App\Utils\Traits\MakesInvoiceValues; + +class Bold extends BaseDesign { + use MakesInvoiceValues, BuildTableHeader; + + /** Global list of table elements, @var array */ + public $elements; + + /** @var App\Models\Client */ + public $client; + + /** @var App\Models\Invoice || @var App\Models\Quote */ + public $entity; + + /** Global state of the design, @var array */ + public $context; + + /** Type of entity => invoice||quote */ + public $type; + public function html() { return file_get_contents( base_path('resources/views/pdf-designs//bold.html') ); } + + public function elements(array $context, string $type = 'invoice'): array + { + $this->context = $context; + $this->type = $type; + + $this->setup(); + + return [ + 'company-details' => [ + 'id' => 'company-details', + 'elements' => $this->companyDetails(), + ], + 'company-address' => [ + 'id' => 'company-address', + 'elements' => $this->companyAddress(), + ], + 'client-details' => [ + 'id' => 'client-details', + 'elements' => $this->clientDetails(), + ], + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => $this->entityDetails(), + ], + 'product-table' => [ + 'id' => 'product-table', + 'elements' => $this->productTable(), + ], + ]; + } + + public function companyDetails() + { + $variables = $this->entity->company->settings->pdf_variables->company_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function companyAddress(): array + { + $variables = $this->entity->company->settings->pdf_variables->company_address; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->client_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function entityDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->invoice_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => $variable . '_label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => $variable, 'properties' => ['class' => 'text-left pr-4 font-normal']], + ]]; + } + + return $elements; + } + + public function productTable(): array + { + return [ + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left rounded-t-lg'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right text-xl text-teal-600 font-semibold', 'colspan' => '6']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ]], + ]; + } + + public function buildTableHeader(): array + { + $this->processTaxColumns(); + + $elements = []; + + foreach ($this->context['product-table-columns'] as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'text-xl px-4 py-2']]; + } + + return $elements; + } + + public function buildTableBody(): array + { + $elements = []; + + $items = $this->transformLineItems($this->entity->line_items); + + if (count($items) == 0) { + return []; + } + + foreach ($items as $row) { + $element = ['element' => 'tr', 'content' => '', 'elements' => []]; + + foreach ($this->context['product-table-columns'] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'px-4 py-4']]; + } + + $elements[] = $element; + } + + return $elements; + } } diff --git a/resources/views/pdf-designs/bold.html b/resources/views/pdf-designs/bold.html index 4a2e7a494981..f8ae4539a63e 100644 --- a/resources/views/pdf-designs/bold.html +++ b/resources/views/pdf-designs/bold.html @@ -23,8 +23,8 @@
$company->name logo
@@ -36,6 +36,7 @@
+
diff --git a/resources/views/pdf-designs/plain.html b/resources/views/pdf-designs/plain.html index 66753866b91e..55af58327409 100644 --- a/resources/views/pdf-designs/plain.html +++ b/resources/views/pdf-designs/plain.html @@ -27,7 +27,7 @@
-
+
diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 92d6efdb04bc..1a35bae8bb3c 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -4,7 +4,7 @@ namespace Tests\Feature\PdfMaker; use App\Models\Design; use App\Models\Invoice; -use App\Services\PdfMaker\Designs\Plain; +use App\Services\PdfMaker\Designs\Bold; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; use App\Utils\Traits\MakesInvoiceValues; @@ -20,7 +20,7 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine($invitation, 'invoice'); - $design = new Plain(); + $design = new Bold(); $product_table_columns = json_decode( json_encode($invoice->company->settings->pdf_variables), @@ -39,7 +39,7 @@ class ExampleIntegrationTest extends TestCase $maker = new PdfMaker($state, 'invoice'); $maker - ->design(Plain::class) + ->design(Bold::class) ->build(); exec('echo "" > storage/logs/laravel.log'); From 2333a78775f217a326ee7e46ca7a90d81163e4e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 12:35:38 +0200 Subject: [PATCH 16/22] Business design --- app/Services/PdfMaker/Designs/Business.php | 168 +++++++++++++++++- resources/views/pdf-designs/business.html | 115 +++++++----- .../PdfMaker/ExampleIntegrationTest.php | 6 +- 3 files changed, 241 insertions(+), 48 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Business.php b/app/Services/PdfMaker/Designs/Business.php index b6c368f5ac2d..65470bbdff7d 100644 --- a/app/Services/PdfMaker/Designs/Business.php +++ b/app/Services/PdfMaker/Designs/Business.php @@ -12,12 +12,178 @@ namespace App\Services\PdfMaker\Designs; -class Business +use App\Services\PdfMaker\Designs\Utilities\BaseDesign; +use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; +use App\Utils\Traits\MakesInvoiceValues; + +class Business extends BaseDesign { + use MakesInvoiceValues, BuildTableHeader; + + /** Global list of table elements, @var array */ + public $elements; + + /** @var App\Models\Client */ + public $client; + + /** @var App\Models\Invoice || @var App\Models\Quote */ + public $entity; + + /** Global state of the design, @var array */ + public $context; + + /** Type of entity => invoice||quote */ + public $type; + public function html() { return file_get_contents( base_path('resources/views/pdf-designs//business.html') ); } + + public function elements(array $context, string $type = 'invoice'): array + { + $this->context = $context; + $this->type = $type; + + $this->setup(); + + return [ + 'company-details' => [ + 'id' => 'company-details', + 'elements' => $this->companyDetails(), + ], + 'company-address' => [ + 'id' => 'company-address', + 'elements' => $this->companyAddress(), + ], + 'client-details' => [ + 'id' => 'client-details', + 'elements' => $this->clientDetails(), + ], + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => $this->entityDetails(), + ], + 'product-table' => [ + 'id' => 'product-table', + 'elements' => $this->productTable(), + ], + ]; + } + + public function companyDetails() + { + $variables = $this->entity->company->settings->pdf_variables->company_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function companyAddress(): array + { + $variables = $this->entity->company->settings->pdf_variables->company_address; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->client_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function entityDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->invoice_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => $variable . '_label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => $variable, 'properties' => ['class' => 'text-left pr-4 font-normal']], + ]]; + } + + return $elements; + } + + public function productTable(): array + { + return [ + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left rounded-t-lg'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right text-xl text-blue-900 font-semibold', 'colspan' => '6']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right text-blue-900 font-semibold']], + ]], + ]], + ]; + } + + public function buildTableHeader(): array + { + $this->processTaxColumns(); + + $elements = []; + + foreach ($this->context['product-table-columns'] as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'font-semibold text-white px-4 bg-blue-900 py-5']]; + } + + return $elements; + } + + public function buildTableBody(): array + { + $elements = []; + + $items = $this->transformLineItems($this->entity->line_items); + + if (count($items) == 0) { + return []; + } + + foreach ($items as $row) { + $element = ['element' => 'tr', 'content' => '', 'elements' => []]; + + foreach ($this->context['product-table-columns'] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'border-4 border-white px-4 py-4 bg-gray-200']]; + } + + $elements[] = $element; + } + + return $elements; + } } diff --git a/resources/views/pdf-designs/business.html b/resources/views/pdf-designs/business.html index 9508212e1f38..925f8e657cff 100644 --- a/resources/views/pdf-designs/business.html +++ b/resources/views/pdf-designs/business.html @@ -1,54 +1,82 @@ + + + + - - - - + + + - - + + tbody > tr > td:first-child { + color: #d03801; + } + - - -
- $company-name -
-
-
-
-
- - -
-
-

$invoice-issued-to

-
-
-
-
-
+ + +
+ $company.name +
+
+
-
- -
+ +
+
+

$invoice-issued-to

+
+
+
+
+
+
+
+
- -
+ +
+ + + + + diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 1a35bae8bb3c..6a9831228bea 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -4,7 +4,7 @@ namespace Tests\Feature\PdfMaker; use App\Models\Design; use App\Models\Invoice; -use App\Services\PdfMaker\Designs\Bold; +use App\Services\PdfMaker\Designs\Business; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; use App\Utils\Traits\MakesInvoiceValues; @@ -20,7 +20,7 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine($invitation, 'invoice'); - $design = new Bold(); + $design = new Business(); $product_table_columns = json_decode( json_encode($invoice->company->settings->pdf_variables), @@ -39,7 +39,7 @@ class ExampleIntegrationTest extends TestCase $maker = new PdfMaker($state, 'invoice'); $maker - ->design(Bold::class) + ->design(Business::class) ->build(); exec('echo "" > storage/logs/laravel.log'); From 1876b228edd5a79292cc4544d61a1e3ab9ae2886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 14:24:10 +0200 Subject: [PATCH 17/22] Clean --- app/Services/PdfMaker/Designs/Clean.php | 170 +++++++++++++++++- resources/views/pdf-designs/business.html | 4 - resources/views/pdf-designs/clean.html | 69 ++++--- .../PdfMaker/ExampleIntegrationTest.php | 7 +- 4 files changed, 211 insertions(+), 39 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Clean.php b/app/Services/PdfMaker/Designs/Clean.php index eb621e0ca7fd..64c1b61e1e5b 100644 --- a/app/Services/PdfMaker/Designs/Clean.php +++ b/app/Services/PdfMaker/Designs/Clean.php @@ -12,12 +12,178 @@ namespace App\Services\PdfMaker\Designs; -class Clean +use App\Services\PdfMaker\Designs\Utilities\BaseDesign; +use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; +use App\Utils\Traits\MakesInvoiceValues; + +class Clean extends BaseDesign { + use MakesInvoiceValues, BuildTableHeader; + + /** Global list of table elements, @var array */ + public $elements; + + /** @var App\Models\Client */ + public $client; + + /** @var App\Models\Invoice || @var App\Models\Quote */ + public $entity; + + /** Global state of the design, @var array */ + public $context; + + /** Type of entity => invoice||quote */ + public $type; + public function html() { return file_get_contents( - base_path('resources/views/pdf-designs//clean.html') + base_path('resources/views/pdf-designs/clean.html') ); } + + public function elements(array $context, string $type = 'invoice'): array + { + $this->context = $context; + $this->type = $type; + + $this->setup(); + + return [ + 'company-details' => [ + 'id' => 'company-details', + 'elements' => $this->companyDetails(), + ], + 'company-address' => [ + 'id' => 'company-address', + 'elements' => $this->companyAddress(), + ], + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => $this->entityDetails(), + ], + 'client-details' => [ + 'id' => 'client-details', + 'elements' => $this->clientDetails(), + ], + 'product-table' => [ + 'id' => 'product-table', + 'elements' => $this->productTable(), + ] + ]; + } + + public function companyDetails() + { + $variables = $this->entity->company->settings->pdf_variables->company_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function companyAddress(): array + { + $variables = $this->entity->company->settings->pdf_variables->company_address; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function entityDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->invoice_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => $variable . '_label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => $variable, 'properties' => ['class' => 'text-left pr-4 font-normal']], + ]]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->client_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function productTable(): array + { + return [ + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left rounded-t-lg'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right font-semibold', 'colspan' => '6']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ]], + ]; + } + + public function buildTableHeader(): array + { + $this->processTaxColumns(); + + $elements = []; + + foreach ($this->context['product-table-columns'] as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'font-semibold px-4 py-5']]; + } + + return $elements; + } + + public function buildTableBody(): array + { + $elements = []; + + $items = $this->transformLineItems($this->entity->line_items); + + if (count($items) == 0) { + return []; + } + + foreach ($items as $row) { + $element = ['element' => 'tr', 'content' => '', 'elements' => []]; + + foreach ($this->context['product-table-columns'] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'border-t border-b px-4 py-4']]; + } + + $elements[] = $element; + } + + return $elements; + } } diff --git a/resources/views/pdf-designs/business.html b/resources/views/pdf-designs/business.html index 925f8e657cff..956e98e2bad9 100644 --- a/resources/views/pdf-designs/business.html +++ b/resources/views/pdf-designs/business.html @@ -9,10 +9,6 @@ - - - - - -
- $company-name logo -
-
-
+ + +
+ $company_name logo +
+
+
+
-
- -

$entity

-
-
-
-
+ +

$entity

+
+
+
+
+
+
- -
- \ No newline at end of file + +
+ + diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 6a9831228bea..d954a6dda0d9 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -2,9 +2,8 @@ namespace Tests\Feature\PdfMaker; -use App\Models\Design; use App\Models\Invoice; -use App\Services\PdfMaker\Designs\Business; +use App\Services\PdfMaker\Designs\Clean; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; use App\Utils\Traits\MakesInvoiceValues; @@ -20,7 +19,7 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine($invitation, 'invoice'); - $design = new Business(); + $design = new Clean(); $product_table_columns = json_decode( json_encode($invoice->company->settings->pdf_variables), @@ -39,7 +38,7 @@ class ExampleIntegrationTest extends TestCase $maker = new PdfMaker($state, 'invoice'); $maker - ->design(Business::class) + ->design(Clean::class) ->build(); exec('echo "" > storage/logs/laravel.log'); From b1b42f59199f7e87c86b33608b550316bea00b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 14:34:22 +0200 Subject: [PATCH 18/22] Creative --- app/Services/PdfMaker/Designs/Creative.php | 168 +++++++++++++++++- resources/views/pdf-designs/creative.html | 4 +- .../PdfMaker/ExampleIntegrationTest.php | 6 +- 3 files changed, 172 insertions(+), 6 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Creative.php b/app/Services/PdfMaker/Designs/Creative.php index 20275744b424..c62ff86d79d0 100644 --- a/app/Services/PdfMaker/Designs/Creative.php +++ b/app/Services/PdfMaker/Designs/Creative.php @@ -12,12 +12,178 @@ namespace App\Services\PdfMaker\Designs; -class Creative +use App\Services\PdfMaker\Designs\Utilities\BaseDesign; +use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; +use App\Utils\Traits\MakesInvoiceValues; + +class Creative extends BaseDesign { + use MakesInvoiceValues, BuildTableHeader; + + /** Global list of table elements, @var array */ + public $elements; + + /** @var App\Models\Client */ + public $client; + + /** @var App\Models\Invoice || @var App\Models\Quote */ + public $entity; + + /** Global state of the design, @var array */ + public $context; + + /** Type of entity => invoice||quote */ + public $type; + public function html() { return file_get_contents( base_path('resources/views/pdf-designs//creative.html') ); } + + public function elements(array $context, string $type = 'invoice'): array + { + $this->context = $context; + $this->type = $type; + + $this->setup(); + + return [ + 'company-details' => [ + 'id' => 'company-details', + 'elements' => $this->companyDetails(), + ], + 'company-address' => [ + 'id' => 'company-address', + 'elements' => $this->companyAddress(), + ], + 'client-details' => [ + 'id' => 'client-details', + 'elements' => $this->clientDetails(), + ], + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => $this->entityDetails(), + ], + 'product-table' => [ + 'id' => 'product-table', + 'elements' => $this->productTable(), + ], + ]; + } + + public function companyDetails() + { + $variables = $this->entity->company->settings->pdf_variables->company_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function companyAddress(): array + { + $variables = $this->entity->company->settings->pdf_variables->company_address; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->client_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function entityDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->invoice_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => $variable . '_label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => $variable, 'properties' => ['class' => 'text-left pr-4 font-normal']], + ]]; + } + + return $elements; + } + + public function productTable(): array + { + return [ + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2 border-t-4 border-pink-700'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right font-semibold text-pink-700']], + ]], + ]], + ]; + } + + public function buildTableHeader(): array + { + $this->processTaxColumns(); + + $elements = []; + + foreach ($this->context['product-table-columns'] as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'font-medium uppercase text-pink-700 text-xl px-4 py-5']]; + } + + return $elements; + } + + public function buildTableBody(): array + { + $elements = []; + + $items = $this->transformLineItems($this->entity->line_items); + + if (count($items) == 0) { + return []; + } + + foreach ($items as $row) { + $element = ['element' => 'tr', 'content' => '', 'elements' => []]; + + foreach ($this->context['product-table-columns'] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'px-4 py-4']]; + } + + $elements[] = $element; + } + + return $elements; + } } diff --git a/resources/views/pdf-designs/creative.html b/resources/views/pdf-designs/creative.html index 3f15dda7ec20..f9b247a992d1 100644 --- a/resources/views/pdf-designs/creative.html +++ b/resources/views/pdf-designs/creative.html @@ -38,8 +38,8 @@
$company-name logo
diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index d954a6dda0d9..0af0ead399a4 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -3,7 +3,7 @@ namespace Tests\Feature\PdfMaker; use App\Models\Invoice; -use App\Services\PdfMaker\Designs\Clean; +use App\Services\PdfMaker\Designs\Creative; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; use App\Utils\Traits\MakesInvoiceValues; @@ -19,7 +19,7 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine($invitation, 'invoice'); - $design = new Clean(); + $design = new Creative(); $product_table_columns = json_decode( json_encode($invoice->company->settings->pdf_variables), @@ -38,7 +38,7 @@ class ExampleIntegrationTest extends TestCase $maker = new PdfMaker($state, 'invoice'); $maker - ->design(Clean::class) + ->design(Creative::class) ->build(); exec('echo "" > storage/logs/laravel.log'); From 66ff55cddf81ce15b76bf4c89d29d3c539ca5c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 14:43:51 +0200 Subject: [PATCH 19/22] Elegant --- app/Services/PdfMaker/Designs/Elegant.php | 171 +++++++++++++++++- resources/views/pdf-designs/elegant.html | 8 +- .../PdfMaker/ExampleIntegrationTest.php | 6 +- .../Feature/PdfMaker/PdfMakerDesignsTest.php | 2 +- 4 files changed, 175 insertions(+), 12 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Elegant.php b/app/Services/PdfMaker/Designs/Elegant.php index 947ffc9ba0b8..dcc8dbfe0be2 100644 --- a/app/Services/PdfMaker/Designs/Elegant.php +++ b/app/Services/PdfMaker/Designs/Elegant.php @@ -12,12 +12,179 @@ namespace App\Services\PdfMaker\Designs; -class Elegant +use App\Services\PdfMaker\Designs\Utilities\BaseDesign; +use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; +use App\Utils\Traits\MakesInvoiceValues; + +class Elegant extends BaseDesign { + use MakesInvoiceValues, BuildTableHeader; + + /** Global list of table elements, @var array */ + public $elements; + + /** @var App\Models\Client */ + public $client; + + /** @var App\Models\Invoice || @var App\Models\Quote */ + public $entity; + + /** Global state of the design, @var array */ + public $context; + + /** Type of entity => invoice||quote */ + public $type; + public function html() { return file_get_contents( - base_path('resources/views/pdf-designs//elegant.html') + base_path('resources/views/pdf-designs/elegant.html') ); } + + public function elements(array $context, string $type = 'invoice'): array + { + $this->context = $context; + $this->type = $type; + + $this->setup(); + + return [ + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => $this->entityDetails(), + ], + 'company-details' => [ + 'id' => 'company-details', + 'elements' => $this->companyDetails(), + ], + 'company-address' => [ + 'id' => 'company-address', + 'elements' => $this->companyAddress(), + ], + 'client-details' => [ + 'id' => 'client-details', + 'elements' => $this->clientDetails(), + ], + 'product-table' => [ + 'id' => 'product-table', + 'elements' => $this->productTable(), + ], + ]; + } + + public function entityDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->invoice_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => $variable . '_label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => $variable, 'properties' => ['class' => 'text-left pr-4 font-normal']], + ]]; + } + + return $elements; + } + + + public function companyDetails() + { + $variables = $this->entity->company->settings->pdf_variables->company_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function companyAddress(): array + { + $variables = $this->entity->company->settings->pdf_variables->company_address; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->client_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function productTable(): array + { + return [ + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left border-dashed border-b border-black'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'px-4 text-right text-xl text-green-600 font-semibold', 'colspan' => '6']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right text-green-600']], + ]], + ]], + ]; + } + + public function buildTableHeader(): array + { + $this->processTaxColumns(); + + $elements = []; + + foreach ($this->context['product-table-columns'] as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'font-normal text-green-700 px-4 py-2']]; + } + + return $elements; + } + + public function buildTableBody(): array + { + $elements = []; + + $items = $this->transformLineItems($this->entity->line_items); + + if (count($items) == 0) { + return []; + } + + foreach ($items as $row) { + $element = ['element' => 'tr', 'properties' => ['class' => 'border-dashed border-b border-black'] ,'content' => '', 'elements' => []]; + + foreach ($this->context['product-table-columns'] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'px-4 py-3']]; + } + + $elements[] = $element; + } + + return $elements; + } } diff --git a/resources/views/pdf-designs/elegant.html b/resources/views/pdf-designs/elegant.html index c1177ca7b606..120e9891d5a4 100644 --- a/resources/views/pdf-designs/elegant.html +++ b/resources/views/pdf-designs/elegant.html @@ -9,10 +9,6 @@ - @@ -20,8 +16,8 @@
$company-name logo
diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 0af0ead399a4..4b0a5391a15b 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -3,7 +3,7 @@ namespace Tests\Feature\PdfMaker; use App\Models\Invoice; -use App\Services\PdfMaker\Designs\Creative; +use App\Services\PdfMaker\Designs\Elegant; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; use App\Utils\Traits\MakesInvoiceValues; @@ -19,7 +19,7 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine($invitation, 'invoice'); - $design = new Creative(); + $design = new Elegant(); $product_table_columns = json_decode( json_encode($invoice->company->settings->pdf_variables), @@ -38,7 +38,7 @@ class ExampleIntegrationTest extends TestCase $maker = new PdfMaker($state, 'invoice'); $maker - ->design(Creative::class) + ->design(Elegant::class) ->build(); exec('echo "" > storage/logs/laravel.log'); diff --git a/tests/Feature/PdfMaker/PdfMakerDesignsTest.php b/tests/Feature/PdfMaker/PdfMakerDesignsTest.php index da5c5da2ed9f..681eaa7c7b35 100644 --- a/tests/Feature/PdfMaker/PdfMakerDesignsTest.php +++ b/tests/Feature/PdfMaker/PdfMakerDesignsTest.php @@ -799,7 +799,7 @@ class PdfMakerDesignsTest extends TestCase ['element' => 'td', 'content' => '$2.00', 'properties' => ['class' => 'px-4 py-2 text-right']], ]], ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2'], 'elements' => [ - ['element' => 'td', 'content' => 'Balance due', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => 'Balance due', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], ['element' => 'td', 'content' => '$2.00', 'properties' => ['class' => 'px-4 py-2 text-right']], ]], ]], From 7a9c8ca9a0760403901d21a2f85cc8a690e9fb0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 15:02:32 +0200 Subject: [PATCH 20/22] Hipster design --- app/Services/PdfMaker/Designs/Hipster.php | 170 +++++++++++++++++- resources/views/pdf-designs/hipster.html | 14 +- .../PdfMaker/ExampleIntegrationTest.php | 6 +- .../Feature/PdfMaker/PdfMakerDesignsTest.php | 2 +- 4 files changed, 182 insertions(+), 10 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Hipster.php b/app/Services/PdfMaker/Designs/Hipster.php index d4ff9b42ecd0..d459a8b15c16 100644 --- a/app/Services/PdfMaker/Designs/Hipster.php +++ b/app/Services/PdfMaker/Designs/Hipster.php @@ -12,12 +12,178 @@ namespace App\Services\PdfMaker\Designs; -class Hipster +use App\Services\PdfMaker\Designs\Utilities\BaseDesign; +use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; +use App\Utils\Traits\MakesInvoiceValues; + +class Hipster extends BaseDesign { + use MakesInvoiceValues, BuildTableHeader; + + /** Global list of table elements, @var array */ + public $elements; + + /** @var App\Models\Client */ + public $client; + + /** @var App\Models\Invoice || @var App\Models\Quote */ + public $entity; + + /** Global state of the design, @var array */ + public $context; + + /** Type of entity => invoice||quote */ + public $type; + public function html() { return file_get_contents( - base_path('resources/views/pdf-designs//hipster.html') + base_path('resources/views/pdf-designs/hipster.html') ); } + + public function elements(array $context, string $type = 'invoice'): array + { + $this->context = $context; + $this->type = $type; + + $this->setup(); + + return [ + 'company-details' => [ + 'id' => 'company-details', + 'elements' => $this->companyDetails(), + ], + 'company-address' => [ + 'id' => 'company-address', + 'elements' => $this->companyAddress(), + ], + 'client-details' => [ + 'id' => 'client-details', + 'elements' => $this->clientDetails(), + ], + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => $this->entityDetails(), + ], + 'product-table' => [ + 'id' => 'product-table', + 'elements' => $this->productTable(), + ], + ]; + } + + public function companyDetails() + { + $variables = $this->entity->company->settings->pdf_variables->company_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function companyAddress(): array + { + $variables = $this->entity->company->settings->pdf_variables->company_address; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->client_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function entityDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->invoice_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'div', 'properties' => ['class' => 'space-x-4'], 'content' => '', 'elements' => [ + ['element' => 'span', 'content' => $variable . '_label', 'properties' => ['class' => 'font-semibold uppercase text-yellow-600']], + ['element' => 'span', 'content' => $variable, 'properties' => ['class' => 'uppercase']], + ]]; + } + + return $elements; + } + + public function productTable(): array + { + return [ + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'px-4 py-4 text-rightt', 'colspan' => '4']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 text-right']], + ]], + ]], + ]; + } + + public function buildTableHeader(): array + { + $this->processTaxColumns(); + + $elements = []; + + foreach ($this->context['product-table-columns'] as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 uppercase']]; + } + + return $elements; + } + + public function buildTableBody(): array + { + $elements = []; + + $items = $this->transformLineItems($this->entity->line_items); + + if (count($items) == 0) { + return []; + } + + foreach ($items as $row) { + $element = ['element' => 'tr', 'content' => '', 'elements' => []]; + + foreach ($this->context['product-table-columns'] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']]; + } + + $elements[] = $element; + } + + return $elements; + } } diff --git a/resources/views/pdf-designs/hipster.html b/resources/views/pdf-designs/hipster.html index a22732965dcf..416f56354b48 100644 --- a/resources/views/pdf-designs/hipster.html +++ b/resources/views/pdf-designs/hipster.html @@ -9,6 +9,10 @@ + @@ -30,16 +34,18 @@
$company-name logo
-

$entity

-
+

+ $entity +

+
diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 4b0a5391a15b..c43f353b26ab 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -3,7 +3,7 @@ namespace Tests\Feature\PdfMaker; use App\Models\Invoice; -use App\Services\PdfMaker\Designs\Elegant; +use App\Services\PdfMaker\Designs\Hipster; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; use App\Utils\Traits\MakesInvoiceValues; @@ -19,7 +19,7 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine($invitation, 'invoice'); - $design = new Elegant(); + $design = new Hipster(); $product_table_columns = json_decode( json_encode($invoice->company->settings->pdf_variables), @@ -38,7 +38,7 @@ class ExampleIntegrationTest extends TestCase $maker = new PdfMaker($state, 'invoice'); $maker - ->design(Elegant::class) + ->design(Hipster::class) ->build(); exec('echo "" > storage/logs/laravel.log'); diff --git a/tests/Feature/PdfMaker/PdfMakerDesignsTest.php b/tests/Feature/PdfMaker/PdfMakerDesignsTest.php index 681eaa7c7b35..393496d4d9fe 100644 --- a/tests/Feature/PdfMaker/PdfMakerDesignsTest.php +++ b/tests/Feature/PdfMaker/PdfMakerDesignsTest.php @@ -707,7 +707,7 @@ class PdfMakerDesignsTest extends TestCase $this->assertTrue(true); } - public function testElegant() +public function testElegant() { $state = [ 'template' => [ From 4f69a874cfdffac2851a5ef3452aa912269fd9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 15:17:45 +0200 Subject: [PATCH 21/22] Modern design --- app/Services/PdfMaker/Designs/Modern.php | 170 +++++++++++++++++- resources/views/pdf-designs/hipster.html | 9 +- resources/views/pdf-designs/modern.html | 85 +++++---- .../PdfMaker/ExampleIntegrationTest.php | 6 +- 4 files changed, 222 insertions(+), 48 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Modern.php b/app/Services/PdfMaker/Designs/Modern.php index 8c4dfec47dc2..c08c284c7f2b 100644 --- a/app/Services/PdfMaker/Designs/Modern.php +++ b/app/Services/PdfMaker/Designs/Modern.php @@ -12,12 +12,178 @@ namespace App\Services\PdfMaker\Designs; -class Modern +use App\Services\PdfMaker\Designs\Utilities\BaseDesign; +use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; +use App\Utils\Traits\MakesInvoiceValues; + +class Modern extends BaseDesign { + use MakesInvoiceValues, BuildTableHeader; + + /** Global list of table elements, @var array */ + public $elements; + + /** @var App\Models\Client */ + public $client; + + /** @var App\Models\Invoice || @var App\Models\Quote */ + public $entity; + + /** Global state of the design, @var array */ + public $context; + + /** Type of entity => invoice||quote */ + public $type; + public function html() { return file_get_contents( - base_path('resources/views/pdf-designs//modern.html') + base_path('resources/views/pdf-designs/modern.html') ); } + + public function elements(array $context, string $type = 'invoice'): array + { + $this->context = $context; + $this->type = $type; + + $this->setup(); + + return [ + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => $this->entityDetails(), + ], + 'client-details' => [ + 'id' => 'client-details', + 'elements' => $this->clientDetails(), + ], + 'product-table' => [ + 'id' => 'product-table', + 'elements' => $this->productTable(), + ], + 'company-details' => [ + 'id' => 'company-details', + 'elements' => $this->companyDetails(), + ], + 'company-address' => [ + 'id' => 'company-address', + 'elements' => $this->companyAddress(), + ], + ]; + } + + public function entityDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->invoice_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => $variable . '_label', 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-normal']], + ['element' => 'th', 'content' => $variable, 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-normal']], + ]]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->client_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function productTable(): array + { + return [ + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left text-white bg-gray-900'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2 bg-gray-900 text-white text-xl'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right font-semibold', 'colspan' => '6']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ]], + ]; + } + + public function buildTableHeader(): array + { + $this->processTaxColumns(); + + $elements = []; + + foreach ($this->context['product-table-columns'] as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'px-4 py-2']]; + } + + return $elements; + } + + public function buildTableBody(): array + { + $elements = []; + + $items = $this->transformLineItems($this->entity->line_items); + + if (count($items) == 0) { + return []; + } + + foreach ($items as $row) { + $element = ['element' => 'tr', 'properties' => ['class' => 'border-t border-b border-gray-900'], 'content' => '', 'elements' => []]; + + foreach ($this->context['product-table-columns'] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'px-4 py-4']]; + } + + $elements[] = $element; + } + + return $elements; + } + + public function companyDetails() + { + $variables = $this->entity->company->settings->pdf_variables->company_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function companyAddress(): array + { + $variables = $this->entity->company->settings->pdf_variables->company_address; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } } diff --git a/resources/views/pdf-designs/hipster.html b/resources/views/pdf-designs/hipster.html index 416f56354b48..f9e7b2b89f0f 100644 --- a/resources/views/pdf-designs/hipster.html +++ b/resources/views/pdf-designs/hipster.html @@ -9,10 +9,6 @@ - @@ -45,7 +41,10 @@

$entity

-
+
diff --git a/resources/views/pdf-designs/modern.html b/resources/views/pdf-designs/modern.html index 63f540fcd9c5..4807d549b3ef 100644 --- a/resources/views/pdf-designs/modern.html +++ b/resources/views/pdf-designs/modern.html @@ -1,51 +1,60 @@ + + + + - - - - + + - - - - - -
-
-
-
-

$company-name

-
-
-
+ + +
+
+
+
+

+ $company.name +

+
+
+
+
-
-
- -
- $company-name logo -
+
+ +
+ $company.name logo +
+
+ + +
- -
-
- - -
-
-
-
-
-
+ +
+
+
+
+
+
+
-
- - - \ No newline at end of file + + diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index c43f353b26ab..59ce1d2bf356 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -3,7 +3,7 @@ namespace Tests\Feature\PdfMaker; use App\Models\Invoice; -use App\Services\PdfMaker\Designs\Hipster; +use App\Services\PdfMaker\Designs\Modern; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; use App\Utils\Traits\MakesInvoiceValues; @@ -19,7 +19,7 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine($invitation, 'invoice'); - $design = new Hipster(); + $design = new Modern(); $product_table_columns = json_decode( json_encode($invoice->company->settings->pdf_variables), @@ -38,7 +38,7 @@ class ExampleIntegrationTest extends TestCase $maker = new PdfMaker($state, 'invoice'); $maker - ->design(Hipster::class) + ->design(Modern::class) ->build(); exec('echo "" > storage/logs/laravel.log'); From 6676cab698cb55b3ebbfe9d446e5dd7f9e60aa89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Wed, 5 Aug 2020 15:40:57 +0200 Subject: [PATCH 22/22] Playful --- app/Services/PdfMaker/Designs/Playful.php | 170 +++++++++++++++++- resources/views/pdf-designs/playful.html | 11 +- .../PdfMaker/ExampleIntegrationTest.php | 6 +- .../Feature/PdfMaker/PdfMakerDesignsTest.php | 2 +- 4 files changed, 176 insertions(+), 13 deletions(-) diff --git a/app/Services/PdfMaker/Designs/Playful.php b/app/Services/PdfMaker/Designs/Playful.php index 693d32516b5f..1e1db7661ff1 100644 --- a/app/Services/PdfMaker/Designs/Playful.php +++ b/app/Services/PdfMaker/Designs/Playful.php @@ -12,12 +12,178 @@ namespace App\Services\PdfMaker\Designs; -class Playful +use App\Services\PdfMaker\Designs\Utilities\BaseDesign; +use App\Services\PdfMaker\Designs\Utilities\BuildTableHeader; +use App\Utils\Traits\MakesInvoiceValues; + +class Playful extends BaseDesign { + use MakesInvoiceValues, BuildTableHeader; + + /** Global list of table elements, @var array */ + public $elements; + + /** @var App\Models\Client */ + public $client; + + /** @var App\Models\Invoice || @var App\Models\Quote */ + public $entity; + + /** Global state of the design, @var array */ + public $context; + + /** Type of entity => invoice||quote */ + public $type; + public function html() { return file_get_contents( - base_path('resources/views/pdf-designs//playful.html') + base_path('resources/views/pdf-designs/playful.html') ); } + + public function elements(array $context, string $type = 'invoice'): array + { + $this->context = $context; + $this->type = $type; + + $this->setup(); + + return [ + 'entity-details' => [ + 'id' => 'entity-details', + 'elements' => $this->entityDetails(), + ], + 'company-details' => [ + 'id' => 'company-details', + 'elements' => $this->companyDetails(), + ], + 'company-address' => [ + 'id' => 'company-address', + 'elements' => $this->companyAddress(), + ], + 'client-details' => [ + 'id' => 'client-details', + 'elements' => $this->clientDetails(), + ], + 'product-table' => [ + 'id' => 'product-table', + 'elements' => $this->productTable(), + ], + ]; + } + + public function entityDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->invoice_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'th', 'content' => $variable . '_label', 'properties' => ['class' => 'text-left pr-4 font-normal']], + ['element' => 'th', 'content' => $variable, 'properties' => ['class' => 'text-left pr-4 font-medium']], + ]]; + } + + return $elements; + } + + public function companyDetails() + { + $variables = $this->entity->company->settings->pdf_variables->company_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function companyAddress(): array + { + $variables = $this->entity->company->settings->pdf_variables->company_address; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->entity->company->settings->pdf_variables->client_details; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function productTable(): array + { + return [ + ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left bg-teal-600'], 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'content' => '', 'elements' => [ + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], + ['element' => 'td', 'content' => '$subtotal_label', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], + ['element' => 'td', 'content' => '$subtotal', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'elements' => [ + ['element' => 'td', 'content' => '$discount_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '6']], + ['element' => 'td', 'content' => '$discount', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2'], 'elements' => [ + ['element' => 'td', 'content' => '$balance_due_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right font-semibold text-teal-600', 'colspan' => '6']], + ['element' => 'td', 'content' => '$balance_due', 'properties' => ['class' => 'px-4 py-2 text-right']], + ]], + ]], + ]; + } + + public function buildTableHeader(): array + { + $this->processTaxColumns(); + + $elements = []; + + foreach ($this->context['product-table-columns'] as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'font-semibold text-white px-4 py-3']]; + } + + return $elements; + } + + public function buildTableBody(): array + { + $elements = []; + + $items = $this->transformLineItems($this->entity->line_items); + + if (count($items) == 0) { + return []; + } + + foreach ($items as $row) { + $element = ['element' => 'tr', 'properties' => ['class' => 'border-b-2 border-teal-600'], 'content' => '', 'elements' => []]; + + foreach ($this->context['product-table-columns'] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'px-4 py-4']]; + } + + $elements[] = $element; + } + + return $elements; + } } diff --git a/resources/views/pdf-designs/playful.html b/resources/views/pdf-designs/playful.html index 9dcf6241a1ec..1c0dd74ef079 100644 --- a/resources/views/pdf-designs/playful.html +++ b/resources/views/pdf-designs/playful.html @@ -9,10 +9,6 @@ - @@ -30,12 +27,12 @@
$company-name logo
-
+
diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index 59ce1d2bf356..e6949528c3d8 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -3,7 +3,7 @@ namespace Tests\Feature\PdfMaker; use App\Models\Invoice; -use App\Services\PdfMaker\Designs\Modern; +use App\Services\PdfMaker\Designs\Playful; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; use App\Utils\Traits\MakesInvoiceValues; @@ -19,7 +19,7 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine($invitation, 'invoice'); - $design = new Modern(); + $design = new Playful(); $product_table_columns = json_decode( json_encode($invoice->company->settings->pdf_variables), @@ -38,7 +38,7 @@ class ExampleIntegrationTest extends TestCase $maker = new PdfMaker($state, 'invoice'); $maker - ->design(Modern::class) + ->design(Playful::class) ->build(); exec('echo "" > storage/logs/laravel.log'); diff --git a/tests/Feature/PdfMaker/PdfMakerDesignsTest.php b/tests/Feature/PdfMaker/PdfMakerDesignsTest.php index 393496d4d9fe..4858957741d4 100644 --- a/tests/Feature/PdfMaker/PdfMakerDesignsTest.php +++ b/tests/Feature/PdfMaker/PdfMakerDesignsTest.php @@ -999,7 +999,7 @@ public function testElegant() ['element' => 'th', 'content' => 'Line total', 'properties' => ['class' => 'font-semibold text-white px-4 py-3']], ]], ['element' => 'tbody', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'border-b-2 border-teal-600 '], 'elements' => [ + ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'border-b-2 border-teal-600'], 'elements' => [ ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'px-4 py-4']], ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'px-4 py-4']], ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'px-4 py-4']],