diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php new file mode 100644 index 000000000000..59a2c0cac1dc --- /dev/null +++ b/app/Services/PdfMaker/Design.php @@ -0,0 +1,227 @@ + product||task */ + public $type; + + /** Design string */ + public $design; + + /** Construct options */ + public $options; + + const BOLD = 'bold.html'; + const BUSINESS = 'business.html'; + const CLEAN = 'clean.html'; + const CREATIVE = 'creative.html'; + const ELEGANT = 'elegant.html'; + const HIPSTER = 'hipster.html'; + const MODERN = 'modern.html'; + const PLAIN = 'plain.html'; + const PLAYFUL = 'playful.html'; + + public function __construct(string $design = null, array $options = []) + { + $this->design = $design; + + $this->options = $options; + } + + public function html(): ?string + { + $path = isset($this->options['custom_path']) + ? $this->options['custom_path'] + : config('ninja.designs.base_path'); + + return file_get_contents( + $path . $this->design + ); + } + + public function elements(array $context, string $type = 'product'): 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(), + ], + 'footer-elements' => [ + 'id' => 'footer', + 'elements' => [ + $this->sharedFooterElements(), + ], + ], + ]; + } + + public function companyDetails() + { + $variables = $this->context['pdf_variables']['company_details']; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function companyAddress(): array + { + $variables = $this->context['pdf_variables']['company_address']; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function clientDetails(): array + { + $variables = $this->context['pdf_variables']['client_details']; + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'p', 'content' => $variable]; + } + + return $elements; + } + + public function entityDetails(): array + { + $variables = $this->context['pdf_variables']['invoice_details']; + + if ($this->entity instanceof \App\Models\Quote) { + $variables = $this->context['pdf_variables']['quote_details']; + } + + $elements = []; + + foreach ($variables as $variable) { + $elements[] = ['element' => 'tr', 'properties' => ['hidden' => $this->entityVariableCheck($variable)], 'elements' => [ + ['element' => 'th', 'content' => $variable . '_label'], + ['element' => 'th', 'content' => $variable], + ]]; + } + + return $elements; + } + + public function productTable(): array + { + return [ + ['element' => 'thead', 'elements' => $this->buildTableHeader()], + ['element' => 'tbody', 'elements' => $this->buildTableBody()], + ['element' => 'tfoot', 'elements' => $this->tableFooter()], + ]; + } + + public function buildTableHeader(): array + { + $this->processTaxColumns(); + + $elements = []; + + foreach ($this->context['pdf_variables']["{$this->type}_columns"] as $column) { + $elements[] = ['element' => 'th', 'content' => $column . '_label']; + } + + 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', 'elements' => []]; + + foreach ($this->context['pdf_variables']["{$this->type}_columns"] as $key => $cell) { + $element['elements'][] = ['element' => 'td', 'content' => $row[$cell]]; + } + + $elements[] = $element; + } + + return $elements; + } + + public function tableFooter() + { + $variables = $this->context['pdf_variables']['total_columns']; + + $elements = [ + ['element' => 'tr', 'elements' => [ + ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['colspan' => '100%']], + ]], + ]; + + foreach ($variables as $variable) { + ['element' => 'tr', 'properties' => ['hidden' => 'false'], 'elements' => [ + ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['colspan' => $this->calculateColspan(1)]], + ['element' => 'td', 'content' => $variable], + ]]; + } + + return $elements; + } +} diff --git a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php index cf5f5127086f..724db96dfb2e 100644 --- a/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php +++ b/app/Services/PdfMaker/Designs/Utilities/DesignHelpers.php @@ -159,9 +159,9 @@ trait DesignHelpers public function sharedFooterElements() { - return ['element' => 'div', 'properties' => ['class' => 'flex items-center justify-between mt-10'], 'content' => '', 'elements' => [ - ['element' => 'img', 'content' => '', 'properties' => ['src' => '$contact.signature', 'class' => 'h-32']], - ['element' => 'img', 'content' => '', 'properties' => ['src' => '$app_url/images/created-by-invoiceninja-new.png', 'class' => 'h-24', 'hidden' => $this->entity->user->account->isPaid() ? 'true' : 'false']], + return ['element' => 'div', 'properties' => ['style' => 'display: flex; justify-content: space-between'], 'elements' => [ + ['element' => 'img', 'properties' => ['src' => '$contact.signature', 'style' => 'height: 5rem;']], + ['element' => 'img', 'properties' => ['src' => '$app_url/images/created-by-invoiceninja-new.png', 'style' => 'height: 5rem;', 'hidden' => $this->entity->user->account->isPaid() ? 'true' : 'false']], ]]; } @@ -177,16 +177,13 @@ trait DesignHelpers } if (is_null($this->entity->{$_variable})) { - // info("{$this->entity->id} $_variable is null!"); return true; } if (empty($this->entity->{$_variable})) { - // info("{$this->entity->id} $_variable is empty!"); return true; } - // info("{$this->entity->id} $_variable ALL GOOD!!"); return false; } } diff --git a/app/Services/PdfMaker/PdfMaker.php b/app/Services/PdfMaker/PdfMaker.php index 7e0e793fcbcd..57460b0f565b 100644 --- a/app/Services/PdfMaker/PdfMaker.php +++ b/app/Services/PdfMaker/PdfMaker.php @@ -43,9 +43,9 @@ class PdfMaker } } - public function design(string $design) + public function design(Design $design) { - $this->design = new $design(); + $this->design = $design; $this->initializeDomDocument(); @@ -71,12 +71,12 @@ class PdfMaker { if ($final) { $html = $this->document->saveXML(); - + $filtered = strtr($html, $this->filters); - + return $filtered; } - + return $this->document->saveXML(); } } diff --git a/app/Services/PdfMaker/PdfMakerUtilities.php b/app/Services/PdfMaker/PdfMakerUtilities.php index af2444478e7b..6339d2f27b5e 100644 --- a/app/Services/PdfMaker/PdfMakerUtilities.php +++ b/app/Services/PdfMaker/PdfMakerUtilities.php @@ -48,10 +48,17 @@ trait PdfMakerUtilities public function updateElementProperties(array $elements) { foreach ($elements as $element) { + + // if (!isset($element['tag']) || !isset($element['id']) || is_null($this->document->getElementById($element['id']))) { + // continue; + // } + if (isset($element['tag'])) { $node = $this->document->getElementsByTagName($element['tag'])->item(0); - } else { + } elseif(!is_null($this->document->getElementById($element['id']))) { $node = $this->document->getElementById($element['id']); + } else { + continue; } if (isset($element['properties'])) { @@ -109,7 +116,7 @@ trait PdfMakerUtilities public function createElementContent($element, $children) { foreach ($children as $child) { - $_child = $this->document->createElement($child['element'], $child['content']); + $_child = $this->document->createElement($child['element'], isset($child['content']) ? $child['content'] : ''); $element->appendChild($_child); if (isset($child['properties'])) { @@ -259,7 +266,7 @@ trait PdfMakerUtilities } if ( - $header = $this->document->getElementById('header') && + $header = $this->document->getElementById('header') && isset($this->data['options']['all_pages_header']) && $this->data['options']['all_pages_header'] ) { diff --git a/config/ninja.php b/config/ninja.php index a93e874ae942..085a22d5b291 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -130,7 +130,6 @@ return [ 'npm_path' => env('NPM_PATH', false) ], 'designs' => [ - 'base_path' => resource_path('views/pdf-designs'), - 'templates' => ['bold', 'business', 'clean', 'creative', 'elegant', 'hipster', 'modern', 'plain', 'playful'], + 'base_path' => resource_path('views/pdf-designs/new/'), ], ]; diff --git a/tests/Feature/PdfMaker/ExampleIntegrationTest.php b/tests/Feature/PdfMaker/ExampleIntegrationTest.php index f95829a92444..c8e87bd5e4e7 100644 --- a/tests/Feature/PdfMaker/ExampleIntegrationTest.php +++ b/tests/Feature/PdfMaker/ExampleIntegrationTest.php @@ -3,6 +3,7 @@ namespace Tests\Feature\PdfMaker; use App\Models\Invoice; +use App\Services\PdfMaker\Design; use App\Services\PdfMaker\Designs\Playful; use App\Services\PdfMaker\PdfMaker; use App\Utils\HtmlEngine; @@ -27,7 +28,10 @@ class ExampleIntegrationTest extends TestCase $invitation = $invoice->invitations()->first(); $engine = new HtmlEngine(null, $invitation, 'invoice'); - $design = new Playful(); + + $design = new Design( + Design::CLEAN + ); $state = [ 'template' => $design->elements([ @@ -41,12 +45,12 @@ class ExampleIntegrationTest extends TestCase $maker = new PdfMaker($state); $maker - ->design(Playful::class) + ->design($design) ->build(); // exec('echo "" > storage/logs/laravel.log'); - info($maker->getCompiledHTML(true)); + // info($maker->getCompiledHTML(true)); $this->assertTrue(true); } diff --git a/tests/Feature/PdfMaker/PdfMakerDesignsTest.php b/tests/Feature/PdfMaker/PdfMakerDesignsTest.php deleted file mode 100644 index 8b0cb03a1a88..000000000000 --- a/tests/Feature/PdfMaker/PdfMakerDesignsTest.php +++ /dev/null @@ -1,1042 +0,0 @@ -state = [ - 'variables' => [ - 'labels' => [], - 'values' => [ - '$css' => asset('css/tailwindcss@1.4.6.css'), - '$global-margin' => 'm-12', - '$global-padding' => 'p-12', - - '$company-logo' => 'https://invoiceninja-invoice-templates.netlify.app/assets/images/invoiceninja-logo.png', - '$company-name' => 'Invoice Ninja', - '$entity-number-label' => 'Invoice number', - '$entity-number' => '10000', - '$entity-date-label' => 'Invoice date', - '$entity-date' => '3th of June, 2025.', - '$due-date-label' => 'Due date', - '$due-date' => '5th of June, 2025.', - '$balance-due-label' => 'Balance due', - '$balance-due' => '$800.50', - - '$terms-label' => 'Terms', - '$terms' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', - - '$invoice-issued-to' => 'Invoice issued to:', - - '$entity' => 'Invoice', - ], - ], - ]; - - exec('echo "" > storage/logs/laravel.log'); - } - - public function testBusiness() - { - $state = [ - 'template' => [ - 'company-details' => [ - 'id' => 'company-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Ninja Sample'], - ['element' => 'p', 'content' => 'contact@invoiceninja.com'], - ['element' => 'p', 'content' => '1-800-555-Ninja'], - ], - ], - 'company-address' => [ - 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '123 Ninja Blvd.'], - ['element' => 'p', 'content' => 'NinjaLand, 97315'], - ['element' => 'p', 'content' => 'United States'], - ], - ], - 'client-details' => [ - 'id' => 'client-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Winterfield Medical Supply '], - ['element' => 'p', 'content' => '65 Medical Complex Rd., D98'], - ['element' => 'p', 'content' => 'Atlanta, GA 22546'], - ['element' => 'p', 'content' => 'United States'], - ['element' => 'p', 'content' => 'demo@invoiceninja.com'], - ], - ], - 'entity-details' => [ - 'id' => 'entity-details', - 'elements' => [ - ['element' => 'div', 'content' => '', 'elements' => [ - ['element' => 'p', 'content' => '$entity-number-label'], - ['element' => 'p', 'content' => '$entity-date-label'], - ['element' => 'p', 'content' => '$due-date-label'], - ['element' => 'p', 'content' => '$balance-due-label'], - ]], - ['element' => 'div', 'content' => '', 'elements' => [ - ['element' => 'p', 'content' => '$entity-number'], - ['element' => 'p', 'content' => '$entity-date'], - ['element' => 'p', 'content' => '$due-date'], - ['element' => 'p', 'content' => '$balance-due'], - ]], - ], - ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left rounded-t-lg'], 'elements' => [ - ['element' => 'th', 'content' => 'Item', 'properties' => ['class' => 'font-semibold text-white px-4 bg-blue-900 py-5']], - ['element' => 'th', 'content' => 'Description', 'properties' => ['class' => 'font-semibold text-white px-4 bg-blue-900 py-5']], - ['element' => 'th', 'content' => 'Unit cost', 'properties' => ['class' => 'font-semibold text-white px-4 bg-blue-900 py-5']], - ['element' => 'th', 'content' => 'Quantity', 'properties' => ['class' => 'font-semibold text-white px-4 bg-blue-900 py-5']], - ['element' => 'th', 'content' => 'Line total', 'properties' => ['class' => 'font-semibold text-white px-4 bg-blue-900 py-5']], - ]], - ['element' => 'tbody', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'border-4 border-white text-orange-700 px-4 py-4 bg-gray-200']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'border-4 border-white text-orange-700 px-4 py-4 bg-gray-200']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'border-4 border-white text-orange-700 px-4 py-4 bg-gray-200']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'border-4 border-white text-orange-700 px-4 py-4 bg-gray-200']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'border-4 border-white text-orange-700 px-4 py-4 bg-gray-200']], - ]], - ]], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4 bg-gray-200', 'colspan' => '2']], - ['element' => 'td', 'content' => 'Subtotal', 'properties' => ['class' => 'px-4 py-4 bg-gray-200 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$0', 'properties' => ['class' => 'px-4 py-4 bg-gray-200 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Paid to date', 'properties' => ['class' => 'border-l-4 border-white px-4 bg-gray-200 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$0.00', 'properties' => ['class' => 'px-4 py-4 bg-gray-200 text-right']], - ]], - ]], - ], - ], - ], - 'variables' => array_merge([ - '#invoice-issued-to' => 'Invoice issued to', - ], $this->state['variables']), - ]; - - $maker = new PdfMaker($state); - - $maker - ->design(Business::class) - ->build(); - - exec('echo "" > storage/logs/laravel.log'); - - info($maker->getCompiledHTML()); - - $this->assertTrue(true); - } - - public function testClean() - { - $state = [ - 'template' => [ - 'company-details' => [ - 'id' => 'company-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Ninja Sample', 'properties' => ['class' => 'text-blue-500']], - ['element' => 'p', 'content' => 'contact@invoiceninja.com'], - ['element' => 'p', 'content' => '1-800-555-Ninja'], - ], - ], - 'company-address' => [ - 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '123 Ninja Blvd.'], - ['element' => 'p', 'content' => 'NinjaLand, 97315'], - ['element' => 'p', 'content' => 'United States'], - ], - ], - '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' => '', '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', - 'elements' => [ - ['element' => 'p', 'content' => 'Winterfield Medical Supply', 'properties' => ['class' => 'font-medium']], - ['element' => 'p', 'content' => '65 Medical Complex Rd., D98'], - ['element' => 'p', 'content' => 'Atlanta, GA 22546'], - ['element' => 'p', 'content' => 'United States'], - ['element' => 'p', 'content' => 'demo@invoiceninja.com'], - ], - ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left rounded-t-lg'], 'elements' => [ - ['element' => 'th', 'content' => 'Item', 'properties' => ['class' => 'font-semibold px-4 py-5']], - ['element' => 'th', 'content' => 'Description', 'properties' => ['class' => 'font-semibold px-4 py-5']], - ['element' => 'th', 'content' => 'Unit cost', 'properties' => ['class' => 'font-semibold px-4 py-5']], - ['element' => 'th', 'content' => 'Quantity', 'properties' => ['class' => 'font-semibold px-4 py-5']], - ['element' => 'th', 'content' => 'Line total', 'properties' => ['class' => 'font-semibold px-4 py-5']], - ]], - ['element' => 'tbody', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'border-t border-b px-4 py-4']], - ]], - ]], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '2']], - ['element' => 'td', 'content' => 'Subtotal', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$0', 'properties' => ['class' => 'px-4 py-4 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Paid to date', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$0.00', 'properties' => ['class' => 'px-4 py-4 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Discount %20', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$2.00', 'properties' => ['class' => 'px-4 py-4 text-right']], - ]], - ]], - ], - ], - ], - 'variables' => array_merge([], $this->state['variables']), - ]; - - $maker = new PdfMaker($state); - - $maker - ->design(Clean::class) - ->build(); - - info($maker->getCompiledHTML(true)); - - $this->assertTrue(true); - } - - public function testModern() - { - $state = [ - 'template' => [ - 'entity-details' => [ - 'id' => 'entity-details', - 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'th', 'content' => '$entity-number-label', 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-normal']], - ['element' => 'th', 'content' => '$entity-number', 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-medium']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'th', 'content' => '$entity-date-label', 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-normal']], - ['element' => 'th', 'content' => '$entity-date', 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-normal']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'th', 'content' => '$due-date-label', 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-normal']], - ['element' => 'th', 'content' => '$due-date', 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-normal']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'th', 'content' => '$balance-due-label', 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-normal']], - ['element' => 'th', 'content' => '$balance-due', 'properties' => ['class' => 'text-left pr-16 lg:pr-24 font-normal']], - ]], - ], - ], - 'client-details' => [ - 'id' => 'client-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Winterfield Medical Supply', 'properties' => ['class' => 'font-medium']], - ['element' => 'p', 'content' => '65 Medical Complex Rd., D98'], - ['element' => 'p', 'content' => 'Atlanta, GA 22546'], - ['element' => 'p', 'content' => 'United States'], - ['element' => 'p', 'content' => 'demo@invoiceninja.com'], - ], - ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left text-white bg-gray-900'], 'elements' => [ - ['element' => 'th', 'content' => 'Item', 'properties' => ['class' => 'px-4 py-2']], - ['element' => 'th', 'content' => 'Description', 'properties' => ['class' => 'px-4 py-2']], - ['element' => 'th', 'content' => 'Unit cost', 'properties' => ['class' => 'px-4 py-2']], - ['element' => 'th', 'content' => 'Quantity', 'properties' => ['class' => 'px-4 py-2']], - ['element' => 'th', 'content' => 'Line total', 'properties' => ['class' => 'px-4 py-2']], - ]], - ['element' => 'tbody', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'font-bold border-t border-b border-gray-900 px-4 py-4']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'border-t border-b border-gray-900 px-4 py-4']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'border-t border-b border-gray-900 px-4 py-4']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'border-t border-b border-gray-900 px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'border-t border-b border-gray-900 px-4 py-4']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'font-bold border-t border-b border-gray-900 px-4 py-4']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'border-t border-b border-gray-900 px-4 py-4']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'border-t border-b border-gray-900 px-4 py-4']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'border-t border-b border-gray-900 px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'border-t border-b border-gray-900 px-4 py-4']], - ]], - ]], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '2']], - ['element' => 'td', 'content' => 'Subtotal', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$0', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Paid to date', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$0.00', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Discount %20', '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']], - ]], - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2 bg-gray-900 text-white'], 'elements' => [ - ['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']], - ]], - ]], - ], - ], - 'company-details' => [ - 'id' => 'company-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Ninja Sample'], - ['element' => 'p', 'content' => 'contact@invoiceninja.com'], - ['element' => 'p', 'content' => '1-800-555-Ninja'], - ], - ], - 'company-address' => [ - 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '123 Ninja Blvd.'], - ['element' => 'p', 'content' => 'NinjaLand, 97315'], - ['element' => 'p', 'content' => 'United States'], - ], - ], - ], - 'variables' => array_merge([], $this->state['variables']), - ]; - - $maker = new PdfMaker($state); - - $maker - ->design(Modern::class) - ->build(); - - info($maker->getCompiledHTML()); - - //exec('echo "" > storage/logs/laravel.log'); - - //info($maker->getCompiledHTML(true)); - - $this->assertTrue(true); - } - - public function testBold() - { - $state = [ - 'template' => [ - 'company-details' => [ - 'id' => 'company-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Ninja Sample'], - ['element' => 'p', 'content' => 'contact@invoiceninja.com'], - ['element' => 'p', 'content' => '1-800-555-Ninja'], - ], - ], - 'company-address' => [ - 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '123 Ninja Blvd.'], - ['element' => 'p', 'content' => 'NinjaLand, 97315'], - ['element' => 'p', 'content' => 'United States'], - ], - ], - 'client-details' => [ - 'id' => 'client-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Winterfield Medical Supply', 'properties' => ['class' => 'font-medium']], - ['element' => 'p', 'content' => '65 Medical Complex Rd., D98'], - ['element' => 'p', 'content' => 'Atlanta, GA 22546'], - ['element' => 'p', 'content' => 'United States'], - ['element' => 'p', 'content' => 'demo@invoiceninja.com'], - ], - ], - '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' => '', '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']], - ]], - ], - ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left rounded-t-lg'], 'elements' => [ - ['element' => 'th', 'content' => 'Item', 'properties' => ['class' => 'text-xl px-4 py-2']], - ['element' => 'th', 'content' => 'Description', 'properties' => ['class' => 'text-xl px-4 py-2']], - ['element' => 'th', 'content' => 'Unit cost', 'properties' => ['class' => 'text-xl px-4 py-2']], - ['element' => 'th', 'content' => 'Quantity', 'properties' => ['class' => 'text-xl px-4 py-2']], - ['element' => 'th', 'content' => 'Line total', 'properties' => ['class' => 'text-xl px-4 py-2']], - ]], - ['element' => 'tbody', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', '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']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'px-4 py-4']], - ]], - ['element' => 'tr', 'content' => '', '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']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'px-4 py-4']], - ]], - ]], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', 'properties' => ['class' => 'border-l-4 border-white px-4 py-2', 'colspan' => '2']], - ['element' => 'td', 'content' => 'Subtotal', 'properties' => ['class' => 'px-4 py-2 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$0', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Paid to date', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$0.00', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Discount %20', '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']], - ]], - ['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 text-xl text-teal-600 font-semibold', 'colspan' => '4']], - ['element' => 'td', 'content' => '$2.00', 'properties' => ['class' => 'px-4 py-2 text-right text-xl text-teal-600 font-semibold']], - ]], - ]], - ], - ], - ], - 'variables' => array_merge([], $this->state['variables']), - ]; - - $maker = new PdfMaker($state); - - $maker - ->design(Bold::class) - ->build(); - - info($maker->getCompiledHTML()); - - $this->assertTrue(true); - } - - public function testPlain() - { - $state = [ - 'template' => [ - 'company-address' => [ - 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '123 Ninja Blvd.'], - ['element' => 'p', 'content' => 'NinjaLand, 97315'], - ['element' => 'p', 'content' => 'United States'], - ], - ], - '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', - 'elements' => [ - ['element' => 'p', 'content' => 'Winterfield Medical Supply', 'properties' => ['class' => 'font-medium']], - ['element' => 'p', 'content' => '65 Medical Complex Rd., D98'], - ['element' => 'p', 'content' => 'Atlanta, GA 22546'], - ['element' => 'p', 'content' => 'United States'], - ['element' => 'p', 'content' => 'demo@invoiceninja.com'], - ], - ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left bg-gray-200'], 'elements' => [ - ['element' => 'th', 'content' => 'Item', 'properties' => ['class' => 'px-4 py-2']], - ['element' => 'th', 'content' => 'Description', 'properties' => ['class' => 'px-4 py-2']], - ['element' => 'th', 'content' => 'Unit cost', 'properties' => ['class' => 'px-4 py-2']], - ['element' => 'th', 'content' => 'Quantity', 'properties' => ['class' => 'px-4 py-2']], - ['element' => 'th', 'content' => 'Line total', 'properties' => ['class' => 'px-4 py-2']], - ]], - ['element' => 'tbody', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'border-t-2 border-b border-gray-200 px-4 py-4']], - ]], - ]], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '2']], - ['element' => 'td', 'content' => 'Subtotal', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$0', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Paid to date', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$0.00', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Discount %20', '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']], - ]], - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2 bg-gray-300'], 'elements' => [ - ['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']], - ]], - ]], - ], - ], - ], - 'variables' => array_merge([], $this->state['variables']), - ]; - - $maker = new PdfMaker($state); - - $maker - ->design(Plain::class) - ->build(); - - exec('echo "" > storage/logs/laravel.log'); - - info($maker->getCompiledHTML(true)); - - $this->assertTrue(true); - } - - public function testHipster() - { - $state = [ - 'template' => [ - 'company-details' => [ - 'id' => 'company-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Ninja Sample'], - ['element' => 'p', 'content' => 'contact@invoiceninja.com'], - ['element' => 'p', 'content' => '1-800-555-Ninja'], - ], - ], - 'company-address' => [ - 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '123 Ninja Blvd.'], - ['element' => 'p', 'content' => 'NinjaLand, 97315'], - ['element' => 'p', 'content' => 'United States'], - ], - ], - 'client-details' => [ - 'id' => 'client-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Winterfield Medical Supply', 'properties' => ['class' => 'font-medium']], - ['element' => 'p', 'content' => '65 Medical Complex Rd., D98'], - ['element' => 'p', 'content' => 'Atlanta, GA 22546'], - ['element' => 'p', 'content' => 'United States'], - ['element' => 'p', 'content' => 'demo@invoiceninja.com'], - ], - ], - 'entity-details' => [ - 'id' => 'entity-details', - 'elements' => [ - ['element' => 'div', 'content' => '', 'properties' => ['class' => 'space-x-4'], 'elements' => [ - ['element' => 'span', 'content' => '$entity-number-label', 'properties' => ['class' => 'font-semibold uppercase text-yellow-600']], - ['element' => 'span', 'content' => '$entity-number', 'properties' => ['class' => 'font-semibold uppercase text-yellow-600']], - ]], - ['element' => 'div', 'content' => '', 'properties' => ['class' => 'space-x-4'], 'elements' => [ - ['element' => 'span', 'content' => '$entity-date-label', 'properties' => ['class' => 'uppercase']], - ['element' => 'span', 'content' => '$entity-date'], - ]], - ['element' => 'div', 'content' => '', 'properties' => ['class' => 'space-x-4'], 'elements' => [ - ['element' => 'span', 'content' => '$balance-due-label', 'properties' => ['class' => 'uppercase']], - ['element' => 'span', 'content' => '$balance-due'], - ]], - ], - ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left'], 'elements' => [ - ['element' => 'th', 'content' => 'Item', 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 uppercase']], - ['element' => 'th', 'content' => 'Description', 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 uppercase']], - ['element' => 'th', 'content' => 'Unit cost', 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 uppercase']], - ['element' => 'th', 'content' => 'Quantity', 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 uppercase']], - ['element' => 'th', 'content' => 'Line total', 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 uppercase']], - ]], - ['element' => 'tbody', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'border-l-2 border-black px-4 py-4']], - ]], - ]], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '2']], - ['element' => 'td', 'content' => 'Subtotal', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$0', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Paid to date', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$0.00', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Discount %20', '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']], - ]], - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2 bg-black text-white'], 'elements' => [ - ['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']], - ]], - ]], - ], - ], - ], - 'variables' => array_merge([], $this->state['variables']), - ]; - - $maker = new PdfMaker($state); - - $maker - ->design(Hipster::class) - ->build(); - - info($maker->getCompiledHTML(true)); - - $this->assertTrue(true); - } - - public function testElegant() - { - $state = [ - 'template' => [ - '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' => '', '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']], - ]], - ], - ], - 'company-details' => [ - 'id' => 'company-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Ninja Sample'], - ['element' => 'p', 'content' => 'contact@invoiceninja.com'], - ['element' => 'p', 'content' => '1-800-555-Ninja'], - ], - ], - 'company-address' => [ - 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '123 Ninja Blvd.'], - ['element' => 'p', 'content' => 'NinjaLand, 97315'], - ['element' => 'p', 'content' => 'United States'], - ], - ], - 'client-details' => [ - 'id' => 'client-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Winterfield Medical Supply', 'properties' => ['class' => 'font-medium']], - ['element' => 'p', 'content' => '65 Medical Complex Rd., D98'], - ['element' => 'p', 'content' => 'Atlanta, GA 22546'], - ['element' => 'p', 'content' => 'United States'], - ['element' => 'p', 'content' => 'demo@invoiceninja.com'], - ], - ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left border-dashed border-b border-black'], 'elements' => [ - ['element' => 'th', 'content' => 'Item', 'properties' => ['class' => 'font-normal text-green-700 px-4 py-2']], - ['element' => 'th', 'content' => 'Description', 'properties' => ['class' => 'font-normal text-green-700 px-4 py-2']], - ['element' => 'th', 'content' => 'Unit cost', 'properties' => ['class' => 'font-normal text-green-700 px-4 py-2']], - ['element' => 'th', 'content' => 'Quantity', 'properties' => ['class' => 'font-normal text-green-700 px-4 py-2']], - ['element' => 'th', 'content' => 'Line total', 'properties' => ['class' => 'font-normal text-green-700 px-4 py-2']], - ]], - ['element' => 'tbody', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'border-dashed border-b border-black'], 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'px-4 py-3']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'px-4 py-3']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'px-4 py-3']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'px-4 py-3']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'px-4 py-3']], - ]], - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'border-dashed border-b border-black'], 'elements' => [ - ['element' => 'td', 'content' => 'Painting service', 'properties' => ['class' => 'px-4 py-3']], - ['element' => 'td', 'content' => '25 hours of painting', 'properties' => ['class' => 'px-4 py-3']], - ['element' => 'td', 'content' => '885.00', 'properties' => ['class' => 'px-4 py-3']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'px-4 py-3']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'px-4 py-3']], - ]], - ]], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '2']], - ['element' => 'td', 'content' => 'Subtotal', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$0', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Paid to date', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$0.00', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Discount %20', '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']], - ]], - ['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' => '$2.00', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ]], - ], - ], - ], - 'variables' => array_merge([], $this->state['variables']), - ]; - - $maker = new PdfMaker($state); - - $maker - ->design(Elegant::class) - ->build(); - - info($maker->getCompiledHTML(true)); - - $this->assertTrue(true); - } - - public function testCreative() - { - $state = [ - 'template' => [ - 'company-details' => [ - 'id' => 'company-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Ninja Sample'], - ['element' => 'p', 'content' => 'contact@invoiceninja.com'], - ['element' => 'p', 'content' => '1-800-555-Ninja'], - ], - ], - 'company-address' => [ - 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '123 Ninja Blvd.'], - ['element' => 'p', 'content' => 'NinjaLand, 97315'], - ['element' => 'p', 'content' => 'United States'], - ], - ], - 'client-details' => [ - 'id' => 'client-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Winterfield Medical Supply', 'properties' => ['class' => 'font-medium']], - ['element' => 'p', 'content' => '65 Medical Complex Rd., D98'], - ['element' => 'p', 'content' => 'Atlanta, GA 22546'], - ['element' => 'p', 'content' => 'United States'], - ['element' => 'p', 'content' => 'demo@invoiceninja.com'], - ], - ], - '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' => '', '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']], - ]], - ], - ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left'], 'elements' => [ - ['element' => 'th', 'content' => 'Item', 'properties' => ['class' => 'font-medium uppercase text-pink-700 text-xl px-4 py-5']], - ['element' => 'th', 'content' => 'Description', 'properties' => ['class' => 'font-medium uppercase text-pink-700 text-xl px-4 py-5']], - ['element' => 'th', 'content' => 'Unit cost', 'properties' => ['class' => 'font-medium uppercase text-pink-700 text-xl px-4 py-5']], - ['element' => 'th', 'content' => 'Quantity', 'properties' => ['class' => 'font-medium uppercase text-pink-700 text-xl px-4 py-5']], - ['element' => 'th', 'content' => 'Line total', 'properties' => ['class' => 'font-medium uppercase text-pink-700 text-xl px-4 py-5']], - ]], - ['element' => 'tbody', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', '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']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'px-4 py-4']], - ]], - ['element' => 'tr', 'content' => '', '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']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'px-4 py-4']], - ]], - ]], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '2']], - ['element' => 'td', 'content' => 'Subtotal', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$0', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Paid to date', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$0.00', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Discount %20', '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']], - ]], - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2 border-t-4 border-pink-700'], 'elements' => [ - ['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 font-semibold text-pink-700']], - ]], - ]], - ], - ], - ], - 'variables' => array_merge([], $this->state['variables']), - ]; - - $maker = new PdfMaker($state); - - $maker - ->design(Creative::class) - ->build(); - - - info($maker->getCompiledHTML(true)); - - $this->assertTrue(true); - } - - public function testPlayful() - { - $state = [ - 'template' => [ - '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' => '', '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', - 'elements' => [ - ['element' => 'p', 'content' => 'Winterfield Medical Supply', 'properties' => ['class' => 'text-red-700']], - ['element' => 'p', 'content' => '65 Medical Complex Rd., D98'], - ['element' => 'p', 'content' => 'Atlanta, GA 22546'], - ['element' => 'p', 'content' => 'United States'], - ['element' => 'p', 'content' => 'demo@invoiceninja.com'], - ], - ], - 'company-details' => [ - 'id' => 'company-details', - 'elements' => [ - ['element' => 'p', 'content' => 'Ninja Sample', 'properties' => ['class' => 'text-red-700']], - ['element' => 'p', 'content' => 'contact@invoiceninja.com'], - ['element' => 'p', 'content' => '1-800-555-Ninja'], - ], - ], - 'company-address' => [ - 'id' => 'company-address', - 'elements' => [ - ['element' => 'p', 'content' => '123 Ninja Blvd.'], - ['element' => 'p', 'content' => 'NinjaLand, 97315'], - ['element' => 'p', 'content' => 'United States'], - ], - ], - 'product-table' => [ - 'id' => 'product-table', - 'elements' => [ - ['element' => 'thead', 'content' => '', 'properties' => ['class' => 'text-left bg-teal-600'], 'elements' => [ - ['element' => 'th', 'content' => 'Item', 'properties' => ['class' => 'font-semibold text-white px-4 py-3']], - ['element' => 'th', 'content' => 'Description', 'properties' => ['class' => 'font-semibold text-white px-4 py-3']], - ['element' => 'th', 'content' => 'Unit cost', 'properties' => ['class' => 'font-semibold text-white px-4 py-3']], - ['element' => 'th', 'content' => 'Quantity', 'properties' => ['class' => 'font-semibold text-white px-4 py-3']], - ['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' => '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']], - ['element' => 'td', 'content' => '1', 'properties' => ['class' => 'px-4 py-4']], - ['element' => 'td', 'content' => '$885.00', 'properties' => ['class' => 'px-4 py-4']], - ]], - ]], - ['element' => 'tfoot', 'content' => '', 'elements' => [ - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Trend and SEO report has been sent via email. This is really long text just to test the width of the elements.', 'properties' => ['class' => 'border-l-4 border-white px-4 py-4', 'colspan' => '2']], - ['element' => 'td', 'content' => 'Subtotal', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '2']], - ['element' => 'td', 'content' => '$0', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Paid to date', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$0.00', 'properties' => ['class' => 'px-4 py-2 text-right']], - ]], - ['element' => 'tr', 'content' => '', 'elements' => [ - ['element' => 'td', 'content' => 'Discount %20', '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']], - ]], - ['element' => 'tr', 'content' => '', 'properties' => ['class' => 'mt-8 px-4 py-2'], 'elements' => [ - ['element' => 'td', 'content' => 'Balance due', 'properties' => ['class' => 'px-4 text-right', 'colspan' => '4']], - ['element' => 'td', 'content' => '$2.00', 'properties' => ['class' => 'px-4 py-2 text-right font-semibold text-teal-600']], - ]], - ]], - ], - ], - ], - 'variables' => array_merge([], $this->state['variables']), - ]; - - $maker = new PdfMaker($state); - - $maker - ->design(Playful::class) - ->build(); - - info($maker->getCompiledHTML(true)); - - $this->assertTrue(true); - } -} diff --git a/tests/Feature/PdfMaker/PdfMakerTest.php b/tests/Feature/PdfMaker/PdfMakerTest.php index 147d36dd1472..76af729733c1 100644 --- a/tests/Feature/PdfMaker/PdfMakerTest.php +++ b/tests/Feature/PdfMaker/PdfMakerTest.php @@ -2,7 +2,7 @@ namespace Tests\Feature\PdfMaker; -use App\Services\PdfMaker\Designs\Plain; +use App\Services\PdfMaker\Design; use App\Services\PdfMaker\PdfMaker; use Tests\TestCase; @@ -18,30 +18,35 @@ class PdfMakerTest extends TestCase public function testDesignLoadsCorrectly() { + $design = new Design('example.html', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); $maker = new PdfMaker($this->state); - $maker->design(ExampleDesign::class); + $maker->design($design); - $this->assertInstanceOf(ExampleDesign::class, $maker->design); + $this->assertInstanceOf(Design::class, $maker->design); } public function testHtmlDesignLoadsCorrectly() { + $design = new Design('example.html', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); + $maker = new PdfMaker($this->state); $maker - ->design(ExampleDesign::class) + ->design($design) ->build(); - $this->assertStringContainsString('', $maker->getCompiledHTML()); + $this->assertStringContainsString('Template: Example', $maker->getCompiledHTML()); } public function testGetSectionUtility() { + $design = new Design('example.html', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); + $maker = new PdfMaker($this->state); $maker - ->design(ExampleDesign::class) + ->design($design) ->build(); $this->assertEquals('table', $maker->getSectionNode('product-table')->nodeName); @@ -59,12 +64,6 @@ class PdfMakerTest extends TestCase 'script' => 'console.log(1)', ], ], - 'header' => [ - 'id' => 'header', - 'properties' => [ - 'class' => 'header-class', - ], - ], ], 'variables' => [ 'labels' => [], @@ -72,10 +71,11 @@ class PdfMakerTest extends TestCase ], ]; + $design = new Design('example.html', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); $maker = new PdfMaker($state); $maker - ->design(ExampleDesign::class) + ->design($design) ->build(); $this->assertStringContainsString('my-awesome-class', $maker->getSection('product-table', 'class')); @@ -85,36 +85,25 @@ class PdfMakerTest extends TestCase public function testVariablesAreReplaced() { - $state = [ 'template' => [ 'product-table' => [ 'id' => 'product-table', - 'properties' => [ - 'class' => 'my-awesome-class', - 'style' => 'margin-top: 10px;', - 'script' => 'console.log(1)', - ], - ], - 'header' => [ - 'id' => 'header', - 'properties' => [ - 'class' => 'header-class', - ], ], ], 'variables' => [ 'labels' => [], 'values' => [ - '$title' => 'Invoice Ninja', + '$company.name' => 'Invoice Ninja', ], ], ]; + $design = new Design('example.html', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); $maker = new PdfMaker($state); $maker - ->design(ExampleDesign::class) + ->design($design) ->build(); $this->assertStringContainsString('Invoice Ninja', $maker->getCompiledHTML()); @@ -123,7 +112,6 @@ class PdfMakerTest extends TestCase public function testElementContentIsGenerated() { - $state = [ 'template' => [ 'product-table' => [ @@ -159,10 +147,11 @@ class PdfMakerTest extends TestCase ], ]; + $design = new Design('example.html', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); $maker = new PdfMaker($state); $maker - ->design(ExampleDesign::class) + ->design($design) ->build(); $compiled = 'contact@invoiceninja.com'; @@ -172,6 +161,7 @@ class PdfMakerTest extends TestCase public function testConditionalRenderingOfElements() { + $design1 = new Design('example.html', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); $maker1 = new PdfMaker([ 'template' => [ @@ -183,13 +173,14 @@ class PdfMakerTest extends TestCase ]); $maker1 - ->design(ExampleDesign::class) + ->design($design1) ->build(); $output1 = $maker1->getCompiledHTML(); - $this->assertStringContainsString('', $output1); + $this->assertStringContainsString('