mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 13:17:35 -04:00 
			
		
		
		
	Merge pull request #4005 from beganovich/v2-pdfmaker-design-improvements
Update DesignSeeders with new designs
This commit is contained in:
		
						commit
						ad6ae61996
					
				| @ -16,6 +16,9 @@ use App\Designs\Designer; | ||||
| use App\Factory\InvoiceFactory; | ||||
| use App\Jobs\Invoice\CreateInvoicePdf; | ||||
| use App\Jobs\Util\PreviewPdf; | ||||
| use App\Services\PdfMaker\Design; | ||||
| use App\Services\PdfMaker\PdfMaker; | ||||
| use App\Utils\HtmlEngine; | ||||
| use App\Utils\Traits\MakesHash; | ||||
| use App\Utils\Traits\MakesInvoiceHtml; | ||||
| use Illuminate\Support\Facades\DB; | ||||
| @ -92,11 +95,32 @@ class PreviewController extends BaseController | ||||
| 
 | ||||
|             $entity_obj->load('client'); | ||||
| 
 | ||||
|             $designer = new Designer($entity_obj, $design_object, $entity_obj->client->getSetting('pdf_variables'), lcfirst($entity)); | ||||
|             $html = new HtmlEngine(null, $entity_obj->invitations()->first(), request()->entity_type); | ||||
| 
 | ||||
|             $html = $this->generateEntityHtml($designer, $entity_obj); | ||||
|             $design_namespace = 'App\Services\PdfMaker\Designs\\' . request()->design['name']; | ||||
| 
 | ||||
|             $file_path = PreviewPdf::dispatchNow($html, auth()->user()->company()); | ||||
|             $design_class = new $design_namespace(); | ||||
| 
 | ||||
|             // $designer = new Designer($entity_obj, $design_object, $entity_obj->client->getSetting('pdf_variables'), lcfirst($entity));
 | ||||
|             // $html = $this->generateEntityHtml($designer, $entity_obj);
 | ||||
| 
 | ||||
|             $state = [ | ||||
|                 'template' => $design_class->elements([ | ||||
|                     'client' => $entity_obj->client, | ||||
|                     'entity' => $entity_obj, | ||||
|                     'pdf_variables' => (array) $entity_obj->company->settings->pdf_variables, | ||||
|                 ]), | ||||
|                 'variables' => $html->generateLabelsAndValues(), | ||||
|             ]; | ||||
| 
 | ||||
|             $design = new Design(request()->design['name']); | ||||
|             $maker = new PdfMaker($state); | ||||
| 
 | ||||
|             $maker | ||||
|                 ->design($design) | ||||
|                 ->build(); | ||||
| 
 | ||||
|             $file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company()); | ||||
| 
 | ||||
|             return response()->download($file_path)->deleteFileAfterSend(true); | ||||
|         } | ||||
| @ -147,17 +171,37 @@ class PreviewController extends BaseController | ||||
|             return response()->json(['message' => 'Invalid custom design object'], 400); | ||||
|         } | ||||
| 
 | ||||
|         $designer = new Designer($invoice, $design_object, auth()->user()->company()->settings->pdf_variables, lcfirst(request()->input('entity'))); | ||||
|         $html = new HtmlEngine(null, $invoice->invitations()->first(), 'invoice'); | ||||
| 
 | ||||
|         $html = $this->generateEntityHtml($designer, $invoice, $contact); | ||||
| info($html); | ||||
|         $file_path = PreviewPdf::dispatchNow($html, auth()->user()->company()); | ||||
|         $design = new Design(strtolower(request()->design['name'])); | ||||
| 
 | ||||
|         // $designer = new Designer($entity_obj, $design_object, $entity_obj->client->getSetting('pdf_variables'), lcfirst($entity));
 | ||||
|         // $html = $this->generateEntityHtml($designer, $entity_obj);
 | ||||
| 
 | ||||
|         $state = [ | ||||
|             'template' => $design->elements([ | ||||
|                 'client' => $invoice->client, | ||||
|                 'entity' => $invoice, | ||||
|                 'pdf_variables' => (array) $invoice->company->settings->pdf_variables, | ||||
|             ]), | ||||
|             'variables' => $html->generateLabelsAndValues(), | ||||
|         ]; | ||||
| 
 | ||||
|         $maker = new PdfMaker($state); | ||||
| 
 | ||||
|         $maker | ||||
|             ->design($design) | ||||
|             ->build(); | ||||
| 
 | ||||
|         info($maker->getCompiledHTML(true)); | ||||
| 
 | ||||
|         $file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company()); | ||||
| 
 | ||||
|         DB::rollBack(); | ||||
| 
 | ||||
|         $response = Response::make($file_path, 200); | ||||
|         $response->header('Content-Type', 'application/pdf'); | ||||
|         return $response; | ||||
| 
 | ||||
|         return $response; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -20,6 +20,7 @@ use App\Models\ClientContact; | ||||
| use App\Models\Company; | ||||
| use App\Models\Design; | ||||
| use App\Models\Invoice; | ||||
| use App\Services\PdfMaker\Design as PdfMakerDesign; | ||||
| use App\Services\PdfMaker\PdfMaker as PdfMakerService; | ||||
| use App\Utils\HtmlEngine; | ||||
| use App\Utils\PhantomJS\Phantom; | ||||
| @ -86,17 +87,13 @@ class CreateInvoicePdf implements ShouldQueue | ||||
| 
 | ||||
|         $html = new HtmlEngine(null, $this->invitation, 'invoice'); | ||||
| 
 | ||||
|         $design_namespace = 'App\Services\PdfMaker\Designs\\' . $design->name; | ||||
| 
 | ||||
|         $design_class = new $design_namespace(); | ||||
| 
 | ||||
|         $pdf_variables = json_decode(json_encode($this->invoice->company->settings->pdf_variables), 1); | ||||
|         $template = new PdfMakerDesign(strtolower($design->name)); | ||||
| 
 | ||||
|         $state = [ | ||||
|             'template' => $design_class->elements([ | ||||
|             'template' => $template->elements([ | ||||
|                 'client' => $this->invoice->client, | ||||
|                 'entity' => $this->invoice, | ||||
|                 'product-table-columns' => $pdf_variables['product_columns'], | ||||
|                 'pdf_variables' => (array)$this->invoice->company->settings->pdf_variables, | ||||
|             ]), | ||||
|             'variables' => $html->generateLabelsAndValues(), | ||||
|             'options' => [ | ||||
| @ -108,15 +105,15 @@ class CreateInvoicePdf implements ShouldQueue | ||||
|         $maker = new PdfMakerService($state); | ||||
| 
 | ||||
|         $maker | ||||
|             ->design($design_namespace) | ||||
|             ->design($template) | ||||
|             ->build(); | ||||
| 
 | ||||
|         //todo - move this to the client creation stage so we don't keep hitting this unnecessarily
 | ||||
|         Storage::makeDirectory($path, 0775); | ||||
| 
 | ||||
|         info($maker->getCompiledHTML()); | ||||
|         info($maker->getCompiledHTML(true)); | ||||
| 
 | ||||
|         $pdf       = $this->makePdf(null, null, $maker->getCompiledHTML()); | ||||
|         $pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true)); | ||||
| 
 | ||||
|         $instance  = Storage::disk($this->disk)->put($file_path, $pdf); | ||||
| 
 | ||||
|  | ||||
| @ -94,7 +94,7 @@ class CreateQuotePdf implements ShouldQueue | ||||
|             'template' => $design_class->elements([ | ||||
|                 'client' => $this->quote->client, | ||||
|                 'entity' => $this->quote, | ||||
|                 'product-table-columns' => $pdf_variables['product_columns'], | ||||
|                 'pdf_variables' => (array)$this->quote->company->settings->pdf_variables, | ||||
|             ]), | ||||
|             'variables' => $html->generateLabelsAndValues(), | ||||
|             'options' => [ | ||||
|  | ||||
| @ -10,22 +10,17 @@ | ||||
|  * @license https://opensource.org/licenses/AAL | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Services\PdfMaker\Designs; | ||||
| namespace App\Services\PdfMaker; | ||||
| 
 | ||||
| use Illuminate\Support\Str; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| use App\Services\PdfMaker\Designs\Utilities\BaseDesign; | ||||
| use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| 
 | ||||
| class Modern extends BaseDesign | ||||
| class Design extends BaseDesign | ||||
| { | ||||
|     use MakesInvoiceValues, DesignHelpers; | ||||
| 
 | ||||
|     /** 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; | ||||
| 
 | ||||
| @ -35,10 +30,37 @@ class Modern extends BaseDesign | ||||
|     /** Type of entity => product||task */ | ||||
|     public $type; | ||||
| 
 | ||||
|     public function html() | ||||
|     /** Design string */ | ||||
|     public $design; | ||||
| 
 | ||||
|     /** Construct options */ | ||||
|     public $options; | ||||
| 
 | ||||
|     const BOLD = 'bold'; | ||||
|     const BUSINESS = 'business'; | ||||
|     const CLEAN = 'clean'; | ||||
|     const CREATIVE = 'creative'; | ||||
|     const ELEGANT = 'elegant'; | ||||
|     const HIPSTER = 'hipster'; | ||||
|     const MODERN = 'modern'; | ||||
|     const PLAIN = 'plain'; | ||||
|     const PLAYFUL = 'playful'; | ||||
| 
 | ||||
|     public function __construct(string $design = null, array $options = []) | ||||
|     { | ||||
|         Str::endsWith('.html', $design) ? $this->design = $design : $this->design = "{$design}.html"; | ||||
| 
 | ||||
|         $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( | ||||
|             base_path('resources/views/pdf-designs/modern.html') | ||||
|             $path . $this->design | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
| @ -51,18 +73,6 @@ class Modern extends BaseDesign | ||||
|         $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(), | ||||
| @ -71,6 +81,18 @@ class Modern extends BaseDesign | ||||
|                 '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' => [ | ||||
| @ -80,29 +102,9 @@ class Modern extends BaseDesign | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     public function entityDetails(): array | ||||
|     public function companyDetails() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->invoice_details; | ||||
| 
 | ||||
|         if ($this->entity instanceof \App\Models\Quote) { | ||||
|             $variables = $this->entity->company->settings->pdf_variables->quote_details; | ||||
|         } | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'tr', 'properties' => ['hidden' => $this->entityVariableCheck($variable)], '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; | ||||
|         $variables = $this->context['pdf_variables']['company_details']; | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
| @ -113,12 +115,58 @@ class Modern extends BaseDesign | ||||
|         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', 'content' => '', 'properties' => ['class' => 'text-left text-white bg-gray-900'], 'elements' => $this->buildTableHeader()], | ||||
|             ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], | ||||
|             ['element' => 'tfoot', 'content' => '', 'elements' => $this->tableFooter()], | ||||
|             ['element' => 'thead', 'elements' => $this->buildTableHeader()], | ||||
|             ['element' => 'tbody', 'elements' => $this->buildTableBody()], | ||||
|             ['element' => 'tfoot', 'elements' => $this->tableFooter()], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
| @ -128,8 +176,8 @@ class Modern extends BaseDesign | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($this->context['product-table-columns'] as $column) { | ||||
|             $elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['class' => 'px-4 py-2']]; | ||||
|         foreach ($this->context['pdf_variables']["{$this->type}_columns"] as $column) { | ||||
|             $elements[] = ['element' => 'th', 'content' => $column . '_label']; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
| @ -146,10 +194,10 @@ class Modern extends BaseDesign | ||||
|         } | ||||
| 
 | ||||
|         foreach ($items as $row) { | ||||
|             $element = ['element' => 'tr', 'properties' => ['class' => 'border-t border-b border-gray-900'], 'content' => '', 'elements' => []]; | ||||
|             $element = ['element' => 'tr', 'elements' => []]; | ||||
| 
 | ||||
|             foreach ($this->context['product-table-columns'] as $key => $cell) { | ||||
|                 $element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['class' => 'px-4 py-4']]; | ||||
|             foreach ($this->context['pdf_variables']["{$this->type}_columns"] as $key => $cell) { | ||||
|                 $element['elements'][] = ['element' => 'td', 'content' => $row[$cell]]; | ||||
|             } | ||||
| 
 | ||||
|             $elements[] = $element; | ||||
| @ -160,47 +208,26 @@ class Modern extends BaseDesign | ||||
| 
 | ||||
|     public function tableFooter() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->total_columns; | ||||
|         $variables = $this->context['pdf_variables']['total_columns']; | ||||
| 
 | ||||
|         $elements = [ | ||||
|             ['element' => 'tr', 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '100%']], | ||||
|             ['element' => 'tr', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['colspan' => '100%']], | ||||
|             ]], | ||||
|         ]; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             ['element' => 'tr', 'properties' => ['hidden' => 'false'], 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => $this->calculateColspan(1)]], | ||||
|                 ['element' => 'td', 'content' => $variable, 'properties' => ['class' => 'px-4 py-2 text-right']], | ||||
|             if ($variable == '$total_taxes' || $variable == '$line_taxes') { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             $elements[] = ['element' => 'tr', 'elements' => [ | ||||
|                 ['element' => 'td', 'properties' => ['colspan' => $this->calculateColspan(2)]], | ||||
|                 ['element' => 'td', 'content' => $variable . '_label'], | ||||
|                 ['element' => 'td', 'content' => $variable], | ||||
|             ]]; | ||||
|         } | ||||
| 
 | ||||
|         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; | ||||
|     } | ||||
| } | ||||
| @ -1,206 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com) | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://opensource.org/licenses/AAL | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Services\PdfMaker\Designs; | ||||
| 
 | ||||
| use App\Services\PdfMaker\Designs\Utilities\BaseDesign; | ||||
| use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| 
 | ||||
| class Bold extends BaseDesign | ||||
| { | ||||
|     use MakesInvoiceValues, DesignHelpers; | ||||
| 
 | ||||
|     /** 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 => product||task */ | ||||
|     public $type; | ||||
| 
 | ||||
|     public function html() | ||||
|     { | ||||
|         return file_get_contents( | ||||
|             base_path('resources/views/pdf-designs/bold.html') | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     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->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; | ||||
| 
 | ||||
|         if ($this->entity instanceof \App\Models\Quote) { | ||||
|             $variables = $this->entity->company->settings->pdf_variables->quote_details; | ||||
|         } | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'tr', 'properties' => ['hidden' => $this->entityVariableCheck($variable)], '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' => $this->tableFooter()], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     public function buildTableHeader(): array | ||||
|     { | ||||
|         $this->processTaxColumns(); | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($this->context["{$this->type}-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; | ||||
|     } | ||||
| 
 | ||||
|     public function tableFooter() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->total_columns; | ||||
| 
 | ||||
|         $elements = [ | ||||
|             ['element' => 'tr', 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '100%']], | ||||
|             ]], | ||||
|         ]; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             ['element' => 'tr', 'properties' => ['hidden' => 'false'], 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => $this->calculateColspan(1)]], | ||||
|                 ['element' => 'td', 'content' => $variable, 'properties' => ['class' => 'px-4 py-2 text-right']], | ||||
|             ]]; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
|     } | ||||
| } | ||||
| @ -1,206 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com) | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://opensource.org/licenses/AAL | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Services\PdfMaker\Designs; | ||||
| 
 | ||||
| use App\Services\PdfMaker\Designs\Utilities\BaseDesign; | ||||
| use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| 
 | ||||
| class Business extends BaseDesign | ||||
| { | ||||
|     use MakesInvoiceValues, DesignHelpers; | ||||
| 
 | ||||
|     /** 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 => product||task */ | ||||
|     public $type; | ||||
| 
 | ||||
|     public function html() | ||||
|     { | ||||
|         return file_get_contents( | ||||
|             base_path('resources/views/pdf-designs/business.html') | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     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->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; | ||||
| 
 | ||||
|         if ($this->entity instanceof \App\Models\Quote) { | ||||
|             $variables = $this->entity->company->settings->pdf_variables->quote_details; | ||||
|         } | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'tr', 'properties' => ['hidden' => $this->entityVariableCheck($variable)], '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' => $this->tableFooter()], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     public function tableFooter() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->total_columns; | ||||
| 
 | ||||
|         $elements = [ | ||||
|             ['element' => 'tr', 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '100%']], | ||||
|             ]], | ||||
|         ]; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             ['element' => 'tr', 'properties' => ['hidden' => 'false'], 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => $this->calculateColspan(1)]], | ||||
|                 ['element' => 'td', 'content' => $variable, 'properties' => ['class' => 'px-4 py-2 text-right']], | ||||
|             ]]; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
|     } | ||||
| } | ||||
| @ -1,206 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com) | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://opensource.org/licenses/AAL | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Services\PdfMaker\Designs; | ||||
| 
 | ||||
| use App\Services\PdfMaker\Designs\Utilities\BaseDesign; | ||||
| use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| 
 | ||||
| class Clean extends BaseDesign | ||||
| { | ||||
|     use MakesInvoiceValues, DesignHelpers; | ||||
| 
 | ||||
|     /** 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 => product||task */ | ||||
|     public $type; | ||||
| 
 | ||||
|     public function html() | ||||
|     { | ||||
|         return file_get_contents( | ||||
|             base_path('resources/views/pdf-designs/clean.html') | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     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(), | ||||
|             ], | ||||
|             'entity-details' => [ | ||||
|                 'id' => 'entity-details', | ||||
|                 'elements' => $this->entityDetails(), | ||||
|             ], | ||||
|             'client-details' => [ | ||||
|                 'id' => 'client-details', | ||||
|                 'elements' => $this->clientDetails(), | ||||
|             ], | ||||
|             'product-table' => [ | ||||
|                 'id' => 'product-table', | ||||
|                 'elements' => $this->productTable(), | ||||
|             ], | ||||
|             'footer-elements' => [ | ||||
|                 'id' => 'footer', | ||||
|                 'elements' => [ | ||||
|                     $this->sharedFooterElements(), | ||||
|                 ], | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|         if ($this->entity instanceof \App\Models\Quote) { | ||||
|             $variables = $this->entity->company->settings->pdf_variables->quote_details; | ||||
|         } | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'tr', 'properties' => ['hidden' => $this->entityVariableCheck($variable)], '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' => $this->tableFooter()], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     public function tableFooter() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->total_columns; | ||||
| 
 | ||||
|         $elements = [ | ||||
|             ['element' => 'tr', 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '100%']], | ||||
|             ]], | ||||
|         ]; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             ['element' => 'tr', 'properties' => ['hidden' => 'false'], 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => $this->calculateColspan(1)]], | ||||
|                 ['element' => 'td', 'content' => $variable, 'properties' => ['class' => 'px-4 py-2 text-right']], | ||||
|             ]]; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
|     } | ||||
| } | ||||
| @ -1,206 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com) | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://opensource.org/licenses/AAL | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Services\PdfMaker\Designs; | ||||
| 
 | ||||
| use App\Services\PdfMaker\Designs\Utilities\BaseDesign; | ||||
| use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| 
 | ||||
| class Creative extends BaseDesign | ||||
| { | ||||
|     use MakesInvoiceValues, DesignHelpers; | ||||
| 
 | ||||
|     /** 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 => product||task */ | ||||
|     public $type; | ||||
| 
 | ||||
|     public function html() | ||||
|     { | ||||
|         return file_get_contents( | ||||
|             base_path('resources/views/pdf-designs/creative.html') | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     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->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; | ||||
| 
 | ||||
|         if ($this->entity instanceof \App\Models\Quote) { | ||||
|             $variables = $this->entity->company->settings->pdf_variables->quote_details; | ||||
|         } | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'tr', 'properties' => ['hidden' => $this->entityVariableCheck($variable)], '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' => $this->tableFooter()], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     public function tableFooter() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->total_columns; | ||||
|          | ||||
|         $elements = [ | ||||
|             ['element' => 'tr', 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '100%']], | ||||
|             ]], | ||||
|         ]; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             ['element' => 'tr', 'properties' => ['hidden' => 'false'], 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => $this->calculateColspan(1)]], | ||||
|                 ['element' => 'td', 'content' => $variable, 'properties' => ['class' => 'px-4 py-2 text-right']], | ||||
|             ]]; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
|     } | ||||
| } | ||||
| @ -1,207 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com) | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://opensource.org/licenses/AAL | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Services\PdfMaker\Designs; | ||||
| 
 | ||||
| use App\Services\PdfMaker\Designs\Utilities\BaseDesign; | ||||
| use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| 
 | ||||
| class Elegant extends BaseDesign | ||||
| { | ||||
|     use MakesInvoiceValues, DesignHelpers; | ||||
| 
 | ||||
|     /** 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 => product||task */ | ||||
|     public $type; | ||||
| 
 | ||||
|     public function html() | ||||
|     { | ||||
|         return file_get_contents( | ||||
|             base_path('resources/views/pdf-designs/elegant.html') | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function elements(array $context, string $type = 'product'): 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(), | ||||
|             ], | ||||
|             'footer-elements' => [ | ||||
|                 'id' => 'footer', | ||||
|                 'elements' => [ | ||||
|                     $this->sharedFooterElements(), | ||||
|                 ], | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     public function entityDetails(): array | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->invoice_details; | ||||
| 
 | ||||
|         if ($this->entity instanceof \App\Models\Quote) { | ||||
|             $variables = $this->entity->company->settings->pdf_variables->quote_details; | ||||
|         } | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'tr', 'properties' => ['hidden' => $this->entityVariableCheck($variable)], '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' => $this->tableFooter()], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     public function tableFooter() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->total_columns; | ||||
| 
 | ||||
|         $elements = [ | ||||
|             ['element' => 'tr', 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '100%']], | ||||
|             ]], | ||||
|         ]; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             ['element' => 'tr', 'properties' => ['hidden' => 'false'], 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => $this->calculateColspan(1)]], | ||||
|                 ['element' => 'td', 'content' => $variable, 'properties' => ['class' => 'px-4 py-2 text-right']], | ||||
|             ]]; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
|     } | ||||
| } | ||||
| @ -1,206 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com) | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://opensource.org/licenses/AAL | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Services\PdfMaker\Designs; | ||||
| 
 | ||||
| use App\Services\PdfMaker\Designs\Utilities\BaseDesign; | ||||
| use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| 
 | ||||
| class Hipster extends BaseDesign | ||||
| { | ||||
|     use MakesInvoiceValues, DesignHelpers; | ||||
| 
 | ||||
|     /** 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 => product||task */ | ||||
|     public $type; | ||||
| 
 | ||||
|     public function html() | ||||
|     { | ||||
|         return file_get_contents( | ||||
|             base_path('resources/views/pdf-designs/hipster.html') | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     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->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; | ||||
| 
 | ||||
|         if ($this->entity instanceof \App\Models\Quote) { | ||||
|             $variables = $this->entity->company->settings->pdf_variables->quote_details; | ||||
|         } | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'div', 'properties' => ['hidden' => $this->entityVariableCheck($variable), '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' => $this->tableFooter()], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     public function tableFooter() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->total_columns; | ||||
| 
 | ||||
|         $elements = [ | ||||
|             ['element' => 'tr', 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'px-4 py-4 text-right', 'colspan' => '100%']], | ||||
|             ]], | ||||
|         ]; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             ['element' => 'tr', 'properties' => ['hidden' => 'false'], 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => $this->calculateColspan(1)]], | ||||
|                 ['element' => 'td', 'content' => $variable, 'properties' => ['class' => 'border-l-2 border-black px-4 py-2 text-right']], | ||||
|             ]]; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
|     } | ||||
| } | ||||
| @ -1,191 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com) | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://opensource.org/licenses/AAL | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Services\PdfMaker\Designs; | ||||
| 
 | ||||
| use App\Services\PdfMaker\Designs\Utilities\BaseDesign; | ||||
| use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| 
 | ||||
| class Plain extends BaseDesign | ||||
| { | ||||
|     use MakesInvoiceValues, DesignHelpers; | ||||
| 
 | ||||
|     /** 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 => product||task */ | ||||
|     public $type; | ||||
| 
 | ||||
|     public function html(): ?string | ||||
|     { | ||||
|         return file_get_contents( | ||||
|             base_path('resources/views/pdf-designs/plain.html') | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function elements(array $context, string $type = 'product'): array | ||||
|     { | ||||
|         $this->context = $context; | ||||
| 
 | ||||
|         $this->type = $type; | ||||
| 
 | ||||
|         $this->setup(); | ||||
| 
 | ||||
|         return [ | ||||
|             '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(), | ||||
|             ], | ||||
|             'footer-elements' => [ | ||||
|                 'id' => 'footer', | ||||
|                 'elements' => [ | ||||
|                     $this->sharedFooterElements(), | ||||
|                 ], | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|         if ($this->entity instanceof \App\Models\Quote) { | ||||
|             $variables = $this->entity->company->settings->pdf_variables->quote_details; | ||||
|         } | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $element = ['element' => 'tr', 'properties' => ['hidden' => $this->entityVariableCheck($variable)], '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']], | ||||
|             ]]; | ||||
| 
 | ||||
|             $elements[] = $element; | ||||
|         } | ||||
| 
 | ||||
|         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-gray-200'], 'elements' => $this->buildTableHeader()], | ||||
|             ['element' => 'tbody', 'content' => '', 'elements' => $this->buildTableBody()], | ||||
|             ['element' => 'tfoot', 'content' => '', 'elements' => $this->tableFooter()], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     public function tableFooter() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->total_columns; | ||||
| 
 | ||||
|         $elements = [ | ||||
|             ['element' => 'tr', 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '100%']], | ||||
|             ]], | ||||
|         ]; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'tr', 'properties' => ['hidden' => 'false'], 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => $this->calculateColspan(1)]], | ||||
|                 ['element' => 'td', 'content' => $variable, 'properties' => ['class' => 'px-4 py-2 text-right']], | ||||
|             ]]; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
|     } | ||||
| 
 | ||||
|     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', 'content' => '', 'elements' => []]; | ||||
| 
 | ||||
|             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']]; | ||||
|             } | ||||
| 
 | ||||
|             $elements[] = $element; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
|     } | ||||
| } | ||||
| @ -1,206 +0,0 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com) | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://opensource.org/licenses/AAL | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Services\PdfMaker\Designs; | ||||
| 
 | ||||
| use App\Services\PdfMaker\Designs\Utilities\BaseDesign; | ||||
| use App\Services\PdfMaker\Designs\Utilities\DesignHelpers; | ||||
| use App\Utils\Traits\MakesInvoiceValues; | ||||
| 
 | ||||
| class Playful extends BaseDesign | ||||
| { | ||||
|     use MakesInvoiceValues, DesignHelpers; | ||||
| 
 | ||||
|     /** 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 => product||task */ | ||||
|     public $type; | ||||
| 
 | ||||
|     public function html() | ||||
|     { | ||||
|         return file_get_contents( | ||||
|             base_path('resources/views/pdf-designs/playful.html') | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function elements(array $context, string $type = 'product'): 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(), | ||||
|             ], | ||||
|             'footer-elements' => [ | ||||
|                 'id' => 'footer', | ||||
|                 'elements' => [ | ||||
|                     $this->sharedFooterElements(), | ||||
|                 ], | ||||
|             ], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     public function entityDetails(): array | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->invoice_details; | ||||
| 
 | ||||
|         if ($this->entity instanceof \App\Models\Quote) { | ||||
|             $variables = $this->entity->company->settings->pdf_variables->quote_details; | ||||
|         } | ||||
| 
 | ||||
|         $elements = []; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'tr', 'properties' => ['hidden' => $this->entityVariableCheck($variable)],  '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' => $this->tableFooter()], | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     public function tableFooter() | ||||
|     { | ||||
|         $variables = $this->entity->company->settings->pdf_variables->total_columns; | ||||
| 
 | ||||
|         $elements = [ | ||||
|             ['element' => 'tr', 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => '$entity.public_notes', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => '100%']], | ||||
|             ]], | ||||
|         ]; | ||||
| 
 | ||||
|         foreach ($variables as $variable) { | ||||
|             $elements[] = ['element' => 'tr', 'properties' => ['hidden' => $this->toggleHiddenProperty($this->entity->calc()->getTotalDiscount())], 'content' => '', 'elements' => [ | ||||
|                 ['element' => 'td', 'content' => $variable . '_label', 'properties' => ['class' => 'border-l-4 border-white px-4 text-right', 'colspan' => $this->calculateColspan(1)]], | ||||
|                 ['element' => 'td', 'content' => $variable, 'properties' => ['class' => 'px-4 py-2 text-right']], | ||||
|             ]]; | ||||
|         } | ||||
| 
 | ||||
|         return $elements; | ||||
|     } | ||||
| } | ||||
| @ -79,10 +79,10 @@ trait DesignHelpers | ||||
|                 $document->importNode($element, true) | ||||
|             ); | ||||
| 
 | ||||
|             return $document->saveHTML(); | ||||
|             return $document->saveXML(); | ||||
|         } | ||||
| 
 | ||||
|         return null; | ||||
|         return ''; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -96,7 +96,7 @@ trait DesignHelpers | ||||
|      */ | ||||
|     public function processTaxColumns(): void | ||||
|     { | ||||
|         if (in_array('$product.tax', $this->context['product-table-columns'])) { | ||||
|         if (in_array('$product.tax', (array)$this->context['pdf_variables']['product_columns'])) { | ||||
|             $line_items = collect($this->entity->line_items); | ||||
| 
 | ||||
|             $tax1 = $line_items->where('tax_name1', '<>', '')->where('type_id', 1)->count(); | ||||
| @ -116,10 +116,10 @@ trait DesignHelpers | ||||
|                 array_push($taxes, '$product.tax_rate3'); | ||||
|             } | ||||
| 
 | ||||
|             $key = array_search('$product.tax', $this->context['product-table-columns'], true); | ||||
|             $key = array_search('$product.tax', $this->context['pdf_variables']['product_columns'], true); | ||||
| 
 | ||||
|             if ($key) { | ||||
|                 array_splice($this->context['product-table-columns'], $key, 1, $taxes); | ||||
|                 array_splice($this->context['pdf_variables']['product_columns'], $key, 1, $taxes); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -132,7 +132,7 @@ trait DesignHelpers | ||||
|      */ | ||||
|     public function calculateColspan(int $taken): int | ||||
|     { | ||||
|         $total = (int) count($this->context['product-table-columns']); | ||||
|         $total = (int) count($this->context['pdf_variables']['product_columns']); | ||||
| 
 | ||||
|         return (int)$total - $taken; | ||||
|     } | ||||
| @ -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; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -28,6 +28,8 @@ class PdfMaker | ||||
| 
 | ||||
|     private $filters = [ | ||||
|         '<![CDATA[' => '', | ||||
|         '<![CDATA[<![CDATA[' => '', | ||||
|         ']]]]><![CDATA[>]]>' => '', | ||||
|         ']]>' => '', | ||||
|         '<?xml version="1.0" encoding="utf-8" standalone="yes"??>' => '', | ||||
|     ]; | ||||
| @ -43,9 +45,9 @@ class PdfMaker | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public function design(string $design) | ||||
|     public function design(Design $design) | ||||
|     { | ||||
|         $this->design = new $design(); | ||||
|         $this->design = $design; | ||||
| 
 | ||||
|         $this->initializeDomDocument(); | ||||
| 
 | ||||
| @ -71,12 +73,12 @@ class PdfMaker | ||||
|     { | ||||
|         if ($final) { | ||||
|             $html = $this->document->saveXML(); | ||||
|              | ||||
| 
 | ||||
|             $filtered = strtr($html, $this->filters); | ||||
|              | ||||
| 
 | ||||
|             return $filtered; | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         return $this->document->saveXML(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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'] | ||||
|         ) { | ||||
|  | ||||
| @ -483,7 +483,8 @@ class HtmlEngine | ||||
|         } | ||||
| 
 | ||||
|         foreach ($this->entity_calc->getTotalTaxMap() as $tax) { | ||||
|             $data .= '<tr class="total_taxes">'; | ||||
|             $data .= '<tr>'; | ||||
|             $data .= '<td colspan="{ count($this->entity->company->settings->pdf_variables->total_columns) - 2 }"></td>'; | ||||
|             $data .= '<td>'. $tax['name'] .'</td>'; | ||||
|             $data .= '<td>'. Number::formatMoney($tax['total'], $this->client) .'</td></tr>'; | ||||
|         } | ||||
|  | ||||
| @ -128,5 +128,8 @@ return [ | ||||
|     'system' => [ | ||||
|         'node_path' => env('NODE_PATH', false), | ||||
|         'npm_path' => env('NPM_PATH', false) | ||||
|     ] | ||||
|     ], | ||||
|     'designs' => [ | ||||
|         'base_path' => resource_path('views/pdf-designs/'), | ||||
|     ], | ||||
| ]; | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| 
 | ||||
| use App\Models\Bank; | ||||
| use App\Models\Design; | ||||
| use App\Services\PdfMaker\Design as PdfMakerDesign; | ||||
| use Illuminate\Database\Seeder; | ||||
| 
 | ||||
| class DesignSeeder extends Seeder | ||||
| @ -36,16 +37,16 @@ class DesignSeeder extends Seeder | ||||
|         } | ||||
| 
 | ||||
|         foreach (Design::all() as $design) { | ||||
|             $class = 'App\Designs\\'.$design->name; | ||||
|             $invoice_design = new $class(); | ||||
|             $template =  new PdfMakerDesign(strtolower($design->name)); | ||||
|             $template->document(); | ||||
| 
 | ||||
|             $design_object = new \stdClass; | ||||
|             $design_object->includes = $invoice_design->includes() ?: ''; | ||||
|             $design_object->header = $invoice_design->header() ?: ''; | ||||
|             $design_object->body = $invoice_design->body() ?: ''; | ||||
|             $design_object->product = $invoice_design->product() ?: ''; | ||||
|             $design_object->task = $invoice_design->task() ?: ''; | ||||
|             $design_object->footer = $invoice_design->footer() ?: ''; | ||||
|             $design_object->includes = $template->getSectionHTML('includes'); | ||||
|             $design_object->header = $template->getSectionHTML('head', false); | ||||
|             $design_object->body = $template->getSectionHTML('body', false); | ||||
|             $design_object->product = $template->getSectionHTML('product-table'); | ||||
|             $design_object->task = $template->getSectionHTML('task-table'); | ||||
|             $design_object->footer = $template->getSectionHTML('footer', false); | ||||
| 
 | ||||
|             $design->design = $design_object; | ||||
|             $design->save(); | ||||
|  | ||||
| @ -1,77 +1,140 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8" /> | ||||
|         <meta | ||||
|             name="viewport" | ||||
|             content="width=device-width, initial-scale=1, shrink-to-fit=no" | ||||
|         /> | ||||
|         <meta http-equiv="x-ua-compatible" content="ie=edge" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="$app_url/css/tailwindcss@1.4.6.css" /> | ||||
| <html lang="en"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
|     </head> | ||||
| 
 | ||||
|     <style> | ||||
|         tbody > tr:nth-child(even) { | ||||
|             background-color: #edf2f7; | ||||
|     <style id="style"> | ||||
|         * { | ||||
|             margin: 0; | ||||
|             padding: 0; | ||||
|             font-size: 14px; | ||||
|         } | ||||
| 
 | ||||
|         /** Required for proper margins on print **/ | ||||
|         @page { | ||||
|             margin-bottom: 8.5mm; | ||||
|         body { | ||||
|             -webkit-font-smoothing: antialiased; | ||||
|             -moz-osx-font-smoothing: grayscale; | ||||
|             font-family: Arial, Helvetica, sans-serif; | ||||
|         } | ||||
| 
 | ||||
|         /** Custom CSS goes here.. */ | ||||
|         @media print { | ||||
|             body { | ||||
|                 margin-top: 0; | ||||
|                 margin-right: 0; | ||||
|             } | ||||
|         } | ||||
|         .header-wrapper { | ||||
|             display: grid; | ||||
|             grid-template-columns: 1.5fr 1fr 1fr; | ||||
|             background-color: #2d2c2a; | ||||
|             padding: 3rem; | ||||
|             color: white; | ||||
|         } | ||||
| 
 | ||||
|         .company-logo { | ||||
|             height: 6rem; | ||||
|             padding: 2rem; | ||||
|             background-color: white; | ||||
|             margin: 2rem; | ||||
|             margin-top: -4rem; | ||||
|         } | ||||
| 
 | ||||
|         #company-details, | ||||
|         #company-address { | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
|         } | ||||
| 
 | ||||
|         #client-details { | ||||
|             margin: 2rem; | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
|         } | ||||
|         #client-details > :first-child { | ||||
|             font-weight: bold; | ||||
|         } | ||||
| 
 | ||||
|         .client-entity-wrapper { | ||||
|             display: grid; | ||||
|             grid-template-columns: 1.5fr 1fr; | ||||
|         } | ||||
| 
 | ||||
|         .entity-details-wrapper { | ||||
|             background-color: #35a39a; | ||||
|             padding: 1rem; | ||||
|         } | ||||
| 
 | ||||
|         #entity-details { | ||||
|             width: 100%; | ||||
|             text-align: left; | ||||
|             color: white !important; | ||||
|         } | ||||
|         #entity-details > tr, | ||||
|         #entity-details th { | ||||
|             font-weight: normal; | ||||
|             padding-bottom: 0.5rem; | ||||
|         } | ||||
| 
 | ||||
|         #product-table { | ||||
|             min-width: 100%; | ||||
|             table-layout: fixed; | ||||
|             overflow-wrap: break-word; | ||||
|             margin-top: 3rem; | ||||
|         } | ||||
|         #product-table > thead { | ||||
|             text-align: left; | ||||
|         } | ||||
|         #product-table > thead > tr > th { | ||||
|             padding: 2rem; | ||||
|             font-size: 1.5rem; | ||||
|         } | ||||
|         #product-table > tbody > tr > td { | ||||
|             padding: 1.5rem; | ||||
|         } | ||||
|         #product-table > tbody > tr > td:first-child { | ||||
|             font-weight: bold; | ||||
|         } | ||||
|         #product-table > tbody > tr:nth-child(odd) { | ||||
|             background-color: #ebebeb; | ||||
|         } | ||||
|         #product-table > tfoot > tr > td { | ||||
|             padding: 1.5rem; | ||||
|         } | ||||
|         #product-table > tfoot [data-element='balance-due-label'], | ||||
|         #product-table > tfoot [data-element='balance-due'] { | ||||
|             font-weight: bold; | ||||
|             font-size: 1.4rem; | ||||
|         } | ||||
|         #product-table > tfoot [data-element='balance-due'] { | ||||
|             color: #35a39a; | ||||
|         } | ||||
|     </style> | ||||
| 
 | ||||
|     <body class="antialiased break-words bg-white"> | ||||
|         <!-- Company logo, company details --> | ||||
|         <div class="$global-padding static bg-gray-800" id="header"> | ||||
|             <div class="grid grid-cols-12"> | ||||
|                 <div class="absolute col-span-4 p-6 pb-10 bg-white"> | ||||
|                     <img | ||||
|                         src="$company.logo" | ||||
|                         alt="$company.name logo" | ||||
|                         class="w-24 col-span-4 sm:w-32" | ||||
|                     /> | ||||
|                 </div> | ||||
|                 <div | ||||
|                     class="flex justify-between col-span-8 col-start-6 lg:col-span-6 lg:col-start-8" | ||||
|                 > | ||||
|                     <div id="company-details" class="text-white"></div> | ||||
|                     <div id="company-address" class="text-white"></div> | ||||
|                 </div> | ||||
|     <body id="body"> | ||||
|         <div class="header-wrapper" id="header"> | ||||
|             <div> <!-- Empty space placeholder--> </div> | ||||
| 
 | ||||
|             <div id="company-details"></div> | ||||
|             <div id="company-address"></div> | ||||
|         </div> | ||||
| 
 | ||||
|         <img | ||||
|             class="company-logo" | ||||
|             src="$company.logo" | ||||
|             alt="$company.name logo" | ||||
|         /> | ||||
| 
 | ||||
|         <div class="client-entity-wrapper"> | ||||
|             <div id="client-details" cellspacing="0"></div> | ||||
| 
 | ||||
|             <div class="entity-details-wrapper"> | ||||
|                 <table id="entity-details"></table> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Client details, entity details --> | ||||
|         <div class="grid grid-cols-12 gap-4 my-12 ml-12"> | ||||
|             <div class="col-span-6"> | ||||
|                 <h2 | ||||
|                     class="text-2xl font-semibold tracking-tight text-teal-600 uppercase" | ||||
|                 > | ||||
|                     $your_entity_label | ||||
|                 </h2> | ||||
|                 <div id="client-details" class="mt-4"></div> | ||||
|             </div> | ||||
|             <div class="col-span-6"> | ||||
|                 <div class="h-auto px-4 py-4 bg-teal-600"> | ||||
|                     <table | ||||
|                         class="flex justify-between text-white" | ||||
|                         id="entity-details" | ||||
|                     ></table> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|         <table id="product-table" cellspacing="0"></table> | ||||
| 
 | ||||
|         <!-- Product table --> | ||||
|         <div class="$global-margin"> | ||||
|             <table | ||||
|                 id="product-table" | ||||
|                 class="w-full table-auto mt-8 $table-padding" | ||||
|             ></table> | ||||
|         </div> | ||||
|         <footer id="footer"></footer> | ||||
|     </body> | ||||
| 
 | ||||
|     <footer id="footer"></footer> | ||||
| </html> | ||||
|  | ||||
| @ -1,84 +1,165 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8" /> | ||||
|         <meta | ||||
|             name="viewport" | ||||
|             content="width=device-width, initial-scale=1, shrink-to-fit=no" | ||||
|         /> | ||||
|         <meta http-equiv="x-ua-compatible" content="ie=edge" /> | ||||
| <html lang="en"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="$app_url/css/tailwindcss@1.4.6.css" /> | ||||
|         <style> | ||||
|             body { | ||||
|                 margin: 2rem; | ||||
|                 -webkit-font-smoothing: antialiased; | ||||
|                 -moz-osx-font-smoothing: grayscale; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
| 
 | ||||
|             .header-container { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1.8fr 1fr 1fr; | ||||
|                 grid-gap: 20px; | ||||
|             } | ||||
|             .header-container > span { | ||||
|                 display: block; | ||||
|             } | ||||
| 
 | ||||
|             .company-logo { | ||||
|                 height: 4rem; | ||||
|             } | ||||
| 
 | ||||
|             #company-details { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|                 color: #b1b1b1; | ||||
|             } | ||||
|             #company-details > * { | ||||
|                 margin-bottom: 0.8rem; | ||||
|             } | ||||
| 
 | ||||
|             #company-address { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|                 color: #b1b1b1; | ||||
|             } | ||||
|             #company-address > * { | ||||
|                 margin-bottom: 0.8rem; | ||||
|             } | ||||
| 
 | ||||
|             .entity-issued-to { | ||||
|                 margin-top: 3rem; | ||||
|                 font-weight: bold; | ||||
|             } | ||||
| 
 | ||||
|             .client-and-entity-wrapper { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 2fr 1.5fr; | ||||
|                 gap: 20px; | ||||
|             } | ||||
| 
 | ||||
|             #client-details { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|                 color: #ec782f; | ||||
|             } | ||||
|             #client-details > * { | ||||
|                 margin-bottom: 0.5rem; | ||||
|             } | ||||
|             #client-details > span:nth-child(1) { | ||||
|                 font-weight: bold; | ||||
|             } | ||||
| 
 | ||||
|             #entity-details { | ||||
|                 background-color: #ec782f; | ||||
|                 padding: 0.8rem; | ||||
|                 border-radius: 1rem; | ||||
|                 width: 100%; | ||||
|                 color: white; | ||||
|                 text-align: left; | ||||
|             } | ||||
|             #entity-details th { | ||||
|                 font-weight: normal; | ||||
|             } | ||||
| 
 | ||||
|             #product-table { | ||||
|                 margin-top: 3.5rem; | ||||
|                 min-width: 100%; | ||||
|                 table-layout: fixed; | ||||
|                 overflow-wrap: break-word; | ||||
|             } | ||||
|             #product-table > thead { | ||||
|                 text-align: left; | ||||
|                 background: #394e6b; | ||||
|             } | ||||
|             #product-table > thead > tr > th { | ||||
|                 padding: 1rem; | ||||
|                 color: white; | ||||
|                 font-weight: semibold; | ||||
|             } | ||||
|             #product-table > thead > tr > th:first-child { | ||||
|                 border-top-left-radius: 1rem; | ||||
|             } | ||||
|             #product-table > thead > tr > th:last-child { | ||||
|                 border-top-right-radius: 1rem; | ||||
|             } | ||||
|             #product-table > tbody > tr > td { | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tbody > tr:nth-child(odd) > td { | ||||
|                 background: #e8e8e8; | ||||
|             } | ||||
|             #product-table > tbody > tr:nth-child(even) > td { | ||||
|                 background: #f7f7f7; | ||||
|             } | ||||
|             #product-table > tfoot > tr > td { | ||||
|                 padding: 1rem; | ||||
|                 background: #e8e8e8; | ||||
|             } | ||||
|             #product-table > tfoot > tr:nth-last-child(1) > td:first-child { | ||||
|                 border-bottom-left-radius: 1rem; | ||||
|             } | ||||
|             #product-table > tfoot > tr:nth-last-child(1) > td:last-child { | ||||
|                 border-bottom-right-radius: 1rem; | ||||
|             } | ||||
|             #product-table > tfoot > td { | ||||
|                 border: none !important; | ||||
|             } | ||||
| 
 | ||||
|             [data-element='product-table-balance-due-label'], | ||||
|             [data-element='product-table-balance-due'] { | ||||
|                 color: #394e6b !important; | ||||
|                 font-weight: bold !important; | ||||
|             } | ||||
| 
 | ||||
|             @media print { | ||||
|                 body { | ||||
|                     margin-top: 0; | ||||
|                     margin-right: 0; | ||||
|                 } | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|     <style> | ||||
|         thead th:first-child { | ||||
|             border-top-left-radius: 0.5rem; | ||||
|             border-bottom-left-radius: 0.3rem; | ||||
|         } | ||||
| 
 | ||||
|         thead th:last-child { | ||||
|             border-top-right-radius: 0.5rem; | ||||
|             border-bottom-right-radius: 0.3rem; | ||||
|         } | ||||
| 
 | ||||
|         tbody > tr > td:first-child { | ||||
|             color: #d03801; | ||||
|         } | ||||
| 
 | ||||
|         /** Required for proper margins on print **/ | ||||
|         @page { | ||||
|             margin-top: 8.5mm; | ||||
|             margin-bottom: 8.5mm; | ||||
|         } | ||||
| 
 | ||||
|         /** Custom CSS goes here.. */ | ||||
|     </style> | ||||
| 
 | ||||
|     <body class="$global-margin bg-white break-words antialiased"> | ||||
|         <!-- Logo, company details & company address --> | ||||
|         <div class="flex grid items-start grid-cols-12 gap-4" id="header"> | ||||
|     <body id="body"> | ||||
|         <div class="header-container" id="header"> | ||||
|             <img | ||||
|                 src="$company.logo" | ||||
|                 alt="$company.name" | ||||
|                 class="grid w-24 col-span-4 sm:w-32" | ||||
|                 class="company-logo" | ||||
|                 alt="$company.name logo" | ||||
|             /> | ||||
|             <div | ||||
|                 class="grid grid-cols-2 col-span-8 space-x-10 text-gray-700 lg:col-start-8" | ||||
|             > | ||||
|                 <div | ||||
|                     id="company-details" | ||||
|                     class="col-span-1 text-gray-500" | ||||
|                 ></div> | ||||
|                 <div | ||||
|                     id="company-address" | ||||
|                     class="col-span-1 text-gray-500" | ||||
|                 ></div> | ||||
| 
 | ||||
|             <div id="company-details"></div> | ||||
|             <div id="company-address"></div> | ||||
|         </div> | ||||
| 
 | ||||
|         <p class="entity-issued-to">$entity_issued_to_label:</p> | ||||
|         <div class="client-and-entity-wrapper"> | ||||
|             <div id="client-details"></div> | ||||
| 
 | ||||
|             <div class="entity-details-wrapper"> | ||||
|                 <table id="entity-details" cellspacing="0"></table> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Client details, entity details --> | ||||
|         <div class="grid grid-cols-12 gap-4 my-12"> | ||||
|             <div class="col-span-6"> | ||||
|                 <p>$entity_issued_to_label</p> | ||||
|                 <div id="client-details" class="mt-4 text-orange-600"></div> | ||||
|             </div> | ||||
|             <div class="col-span-6"> | ||||
|                 <div class="h-auto px-4 py-4 bg-orange-600 rounded-lg"> | ||||
|                     <table | ||||
|                         class="flex justify-between text-white" | ||||
|                         id="entity-details" | ||||
|                     ></table> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|         <table id="product-table" cellspacing="0"></table> | ||||
| 
 | ||||
|         <!-- Product table --> | ||||
|         <table | ||||
|             id="product-table" | ||||
|             class="w-full mt-20 rounded table-auto $table-padding" | ||||
|         ></table> | ||||
|         <footer id="footer"></footer> | ||||
|     </body> | ||||
| 
 | ||||
|     <footer id="footer"></footer> | ||||
| </html> | ||||
|  | ||||
| @ -1,61 +1,138 @@ | ||||
| <!-- Template: Clean --> | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8" /> | ||||
|         <meta | ||||
|             name="viewport" | ||||
|             content="width=device-width, initial-scale=1, shrink-to-fit=no" | ||||
|         /> | ||||
|         <meta http-equiv="x-ua-compatible" content="ie=edge" /> | ||||
| <html lang="en"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="$app_url/css/tailwindcss@1.4.6.css" /> | ||||
|         <style id="style"> | ||||
|             body { | ||||
|                 margin: 2rem; | ||||
|                 -webkit-font-smoothing: antialiased; | ||||
|                 -moz-osx-font-smoothing: grayscale; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
| 
 | ||||
|             @media print { | ||||
|                 body { | ||||
|                     margin-top: 0; | ||||
|                     margin-right: 0; | ||||
|                 } | ||||
|             } | ||||
|             .header-container { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1fr 1fr 1fr; | ||||
|                 gap: 20px; | ||||
|             } | ||||
|             .header-container .company-logo { | ||||
|                 height: 4rem; | ||||
|             } | ||||
| 
 | ||||
|             #company-details { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|                 color: #9f9f9f; | ||||
|             } | ||||
|             #company-details > span:first-child { | ||||
|                 color: #67b1cc; | ||||
|             } | ||||
| 
 | ||||
|             #company-address { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|                 color: #9f9f9f; | ||||
|             } | ||||
| 
 | ||||
|             .entity-label { | ||||
|                 text-transform: uppercase; | ||||
|                 margin-top: 3.5rem; | ||||
|                 font-weight: semibold; | ||||
|                 color: #67b1cc; | ||||
|             } | ||||
| 
 | ||||
|             .client-and-entity-wrapper { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1fr 1fr; | ||||
|                 padding-left: 1rem; | ||||
|                 padding-right: 1rem; | ||||
|                 padding-top: 1rem; | ||||
|                 padding-bottom: 1rem; | ||||
|                 border-top: 1px solid #9f9f9f; | ||||
|                 border-bottom: 1px solid #9f9f9f; | ||||
|             } | ||||
| 
 | ||||
|             #entity-details { | ||||
|                 text-align: left; | ||||
|             } | ||||
|             #entity-details > tr, | ||||
|             #entity-details th { | ||||
|                 font-weight: normal; | ||||
|             } | ||||
| 
 | ||||
|             #client-details { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|             } | ||||
|             #client-details > :first-child { | ||||
|                 font-weight: bold; | ||||
|             } | ||||
| 
 | ||||
|             #product-table { | ||||
|                 margin-top: 3rem; | ||||
|                 min-width: 100%; | ||||
|                 table-layout: fixed; | ||||
|                 overflow-wrap: break-word; | ||||
|             } | ||||
|             #product-table > thead { | ||||
|                 text-align: left; | ||||
|             } | ||||
|             #product-table > thead > tr > th { | ||||
|                 font-size: 1.1rem; | ||||
|                 padding-bottom: 1.5rem; | ||||
|                 padding-left: 1rem; | ||||
|             } | ||||
|             #product-table > tbody > tr > td { | ||||
|                 border-bottom: 1px solid #9f9f9f; | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tbody > tr > td:first-child { | ||||
|                 color: #67b1cc; | ||||
|             } | ||||
|             #product-table > tbody > tr:nth-child(odd) { | ||||
|                 background-color: #f5f5f5; | ||||
|             } | ||||
|             #product-table > tfoot > tr > td { | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tfoot [data-element='balance-due'] { | ||||
|                 color: #67b1cc; | ||||
|                 font-weight: bold; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|     <style> | ||||
|         #product-table tbody > tr:nth-child(even) { | ||||
|             background-color: #f7fafc; | ||||
|         } | ||||
| 
 | ||||
|         /** Required for proper margins on print **/ | ||||
|         @page { | ||||
|             margin-top: 8.5mm; | ||||
|             margin-bottom: 8.5mm; | ||||
|         } | ||||
| 
 | ||||
|         /** Custom CSS goes here.. */ | ||||
|     </style> | ||||
| 
 | ||||
|     <body class="$global-margin bg-white break-words antialiased"> | ||||
|         <!-- Company logo, company details --> | ||||
|         <div class="grid grid-cols-12 px-2" id="header"> | ||||
|     <body id="body"> | ||||
|         <div class="header-container" id="header"> | ||||
|             <img | ||||
|                 src="$company_logo" | ||||
|                 alt="$company_name logo" | ||||
|                 class="grid w-24 col-span-4 sm:w-32" | ||||
|                 class="company-logo" | ||||
|                 src="$company.logo" | ||||
|                 alt="$company.name logo" | ||||
|             /> | ||||
|             <div | ||||
|                 class="grid grid-cols-2 col-span-8 text-gray-700 lg:col-span-6" | ||||
|             > | ||||
|                 <div id="company-details" class="col-span-1"></div> | ||||
|                 <div id="company-address" class="col-span-1"></div> | ||||
|             </div> | ||||
| 
 | ||||
|             <div id="company-details"></div> | ||||
|             <div id="company-address"></div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Entity labels, client details --> | ||||
|         <p class="px-2 mt-10 text-xl text-blue-500 uppercase">$entity_label</p> | ||||
|         <div class="grid grid-cols-12 px-2 py-3 mt-4 border-t border-b"> | ||||
|             <div class="col-span-6"> | ||||
|                 <table id="entity-details"></table> | ||||
|             </div> | ||||
|             <div id="client-details" class="col-span-6"></div> | ||||
|         <p class="entity-label">$entity_label</p> | ||||
|         <div class="client-and-entity-wrapper"> | ||||
|             <table id="entity-details" cellspacing="0"></table> | ||||
| 
 | ||||
|             <div id="client-details"></div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Product table --> | ||||
|         <table | ||||
|             id="product-table" | ||||
|             class="table-auto w-full mt-12 $table-padding" | ||||
|         ></table> | ||||
|         <!-- product_table --> | ||||
|         <table id="product-table" cellspacing="0"></table> | ||||
| 
 | ||||
|         <footer id="footer"></footer> | ||||
|     </body> | ||||
| 
 | ||||
|     <footer id="footer"></footer> | ||||
| </html> | ||||
|  | ||||
| @ -1,77 +1,136 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8" /> | ||||
|         <meta | ||||
|             name="viewport" | ||||
|             content="width=device-width, initial-scale=1, shrink-to-fit=no" | ||||
|         /> | ||||
|         <meta http-equiv="x-ua-compatible" content="ie=edge" /> | ||||
| <html lang="en"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="$app_url/css/tailwindcss@1.4.6.css" /> | ||||
|         <style id="style"> | ||||
|             * { | ||||
|                 margin: 0; | ||||
|                 padding: 0; | ||||
|                 font-size: 14px; | ||||
|             } | ||||
| 
 | ||||
|             body { | ||||
|                 -webkit-font-smoothing: antialiased; | ||||
|                 -moz-osx-font-smoothing: grayscale; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
| 
 | ||||
|             @media print { | ||||
|                 body { | ||||
|                     margin: 0; | ||||
|                     padding: 0; | ||||
|                 } | ||||
|             } | ||||
|             body { | ||||
|                 margin: 2rem; | ||||
|             } | ||||
| 
 | ||||
|             .header-wrapper { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1fr 1fr 1fr; | ||||
|                 gap: 20px; | ||||
|             } | ||||
|             .header-wrapper .company-logo { | ||||
|                 height: 5rem; | ||||
|             } | ||||
|             .header-wrapper #client-details, | ||||
|             .header-wrapper #company-details, | ||||
|             .header-wrapper #company-address { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|             } | ||||
|             .header-wrapper #client-details > *:first-child { | ||||
|                 font-weight: bold; | ||||
|             } | ||||
|             .header-wrapper .company-info-wrapper > * { | ||||
|                 margin-bottom: 1rem; | ||||
|             } | ||||
| 
 | ||||
|             .entity-label-wrapper { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 2fr 1fr; | ||||
|                 margin-top: 3rem; | ||||
|             } | ||||
|             .entity-label-wrapper .entity-label > * { | ||||
|                 font-size: 3rem; | ||||
|             } | ||||
|             .entity-label-wrapper .entity-label > *:first-child { | ||||
|                 text-transform: uppercase; | ||||
|             } | ||||
|             .entity-label-wrapper .entity-label > *:last-child { | ||||
|                 color: #b21c53; | ||||
|                 font-style: italic; | ||||
|             } | ||||
|             .entity-label-wrapper #entity-details { | ||||
|                 text-align: left; | ||||
|             } | ||||
|             .entity-label-wrapper #entity-details > tr, | ||||
|             .entity-label-wrapper #entity-details th { | ||||
|                 font-weight: normal; | ||||
|             } | ||||
| 
 | ||||
|             #product-table { | ||||
|                 margin-top: 3rem; | ||||
|                 min-width: 100%; | ||||
|                 table-layout: fixed; | ||||
|                 overflow-wrap: break-word; | ||||
|                 border-top: 5px solid #b21c53; | ||||
|             } | ||||
|             #product-table > thead { | ||||
|                 text-align: left; | ||||
|             } | ||||
|             #product-table > thead > tr > th { | ||||
|                 font-size: 1.1rem; | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tbody > tr > td { | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tbody > tr:nth-child(odd) { | ||||
|                 background-color: #e8e8e8; | ||||
|             } | ||||
|             #product-table > tfoot > tr > td { | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tfoot > tr:last-child > td { | ||||
|                 border-top: 5px solid #b21c53; | ||||
|             } | ||||
|             #product-table > tfoot [data-element='product-table-balance-due'] { | ||||
|                 color: #b21c53; | ||||
|                 font-weight: bold; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|     <style> | ||||
|         #product-table tbody > tr:nth-child(even) { | ||||
|             background-color: #edf2f7; | ||||
|         } | ||||
|     <body id="body"> | ||||
|         <div class="header-wrapper" id="header"> | ||||
|             <div id="client-details"></div> | ||||
| 
 | ||||
|         #product-table tbody > tr:nth-child(odd) { | ||||
|             background-color: #f7fafc; | ||||
|         } | ||||
| 
 | ||||
|         /** Required for proper margins on print **/ | ||||
|         @page { | ||||
|             margin-top: 8.5mm; | ||||
|             margin-bottom: 8.5mm; | ||||
|         } | ||||
| 
 | ||||
|         /** Custom CSS goes here.. */ | ||||
|     </style> | ||||
| 
 | ||||
|     <body class="$global-margin antialiased bg-white break-words"> | ||||
|         <!-- Client details, company details, company logo --> | ||||
|         <div class="grid grid-cols-12 gap-4" id="header"> | ||||
|             <!-- Client details --> | ||||
|             <div class="col-span-4"> | ||||
|                 <div id="client-details"></div> | ||||
|             </div> | ||||
| 
 | ||||
|             <!-- Company details --> | ||||
|             <div class="flex flex-col col-span-4 space-y-4"> | ||||
|             <div class="company-info-wrapper"> | ||||
|                 <div id="company-details"></div> | ||||
|                 <div id="company-address"></div> | ||||
|             </div> | ||||
| 
 | ||||
|             <!-- Logo --> | ||||
|             <div class="flex flex-col items-end col-span-4"> | ||||
|                 <img | ||||
|                     src="$company.logo" | ||||
|                     alt="$company.name logo" | ||||
|                     class="w-24 col-span-4 sm:w-32" | ||||
|                 /> | ||||
|             </div> | ||||
|             <img | ||||
|                 class="company-logo" | ||||
|                 src="$company.logo" | ||||
|                 alt="$company.name logo" | ||||
|             /> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Entity label, entity details --> | ||||
|         <div class="grid grid-cols-12 mt-10"> | ||||
|             <!-- Entity number --> | ||||
|             <div class="col-span-4 text-3xl font-semibold uppercase"> | ||||
|                 <span>$entity_label</span> | ||||
|                 <i class="text-pink-700">#$entity_number</i> | ||||
|             </div> | ||||
|         <div class="entity-label-wrapper"> | ||||
|             <h1 class="entity-label"> | ||||
|                 <span>$entity_label</span>  | ||||
|                 <span>#$entity_number</span> | ||||
|             </h1> | ||||
| 
 | ||||
|             <!-- Entity labels --> | ||||
|             <div class="flex flex-col items-end col-span-8"> | ||||
|                 <table id="entity-details"></table> | ||||
|             </div> | ||||
|             <table id="entity-details" cellspacing="0"></table> | ||||
|         </div> | ||||
| 
 | ||||
|         <table | ||||
|             id="product-table" | ||||
|             class="w-full mt-10 border-t-4 border-pink-700 table-auto $table-padding" | ||||
|         ></table> | ||||
|         <table id="product-table" cellspacing="0"></table> | ||||
| 
 | ||||
|         <footer id="footer"></footer> | ||||
|     </body> | ||||
| 
 | ||||
|     <footer id="footer"></footer> | ||||
| </html> | ||||
|  | ||||
| @ -1,75 +1,162 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8" /> | ||||
|         <meta | ||||
|             name="viewport" | ||||
|             content="width=device-width, initial-scale=1, shrink-to-fit=no" | ||||
|         /> | ||||
|         <meta http-equiv="x-ua-compatible" content="ie=edge" /> | ||||
| <html lang="en"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="$app_url/css/tailwindcss@1.4.6.css" /> | ||||
|         <style id="style"> | ||||
|             * { | ||||
|                 margin: 0; | ||||
|                 padding: 0; | ||||
|                 font-size: 14px; | ||||
|             } | ||||
| 
 | ||||
|             body { | ||||
|                 -webkit-font-smoothing: antialiased; | ||||
|                 -moz-osx-font-smoothing: grayscale; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
| 
 | ||||
|             @media print { | ||||
|                 body { | ||||
|                     margin: 0; | ||||
|                     padding: 0; | ||||
|                 } | ||||
|             } | ||||
|             body { | ||||
|                 margin: 2rem; | ||||
|             } | ||||
| 
 | ||||
|             .company-logo-wrapper { | ||||
|                 display: flex; | ||||
|                 flex-direction: row; | ||||
|                 justify-content: center; | ||||
|                 padding-bottom: 2.5rem; | ||||
|                 border-bottom: 4px solid; | ||||
|             } | ||||
|             .company-logo-wrapper .company-logo { | ||||
|                 height: 5rem; | ||||
|             } | ||||
| 
 | ||||
|             .double-border { | ||||
|                 margin-top: 3px; | ||||
|                 border-color: black; | ||||
|             } | ||||
| 
 | ||||
|             .client-entity-wrapper { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1.8fr 1.2fr; | ||||
|                 margin-top: 3rem; | ||||
|                 gap: 10px; | ||||
|             } | ||||
|             .client-entity-wrapper .wrapper-info-text { | ||||
|                 display: block; | ||||
|                 font-size: 1.5rem; | ||||
|                 font-weight: normal; | ||||
|             } | ||||
|             .client-entity-wrapper .wrapper-left-side { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1fr 1fr; | ||||
|             } | ||||
|             .client-entity-wrapper .wrapper-left-side #client-details, | ||||
|             .client-entity-wrapper .wrapper-left-side #company-details, | ||||
|             .client-entity-wrapper .wrapper-left-side #company-address { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|                 margin-top: 0.5rem; | ||||
|             } | ||||
|             .client-entity-wrapper .wrapper-left-side .company-info { | ||||
|                 border-left: 1px solid; | ||||
|                 padding-left: 1rem; | ||||
|             } | ||||
|             .client-entity-wrapper #entity-details { | ||||
|                 text-align: left; | ||||
|                 margin-top: 0.5rem; | ||||
|                 min-width: 100%; | ||||
|             } | ||||
|             .client-entity-wrapper #entity-details > tr, | ||||
|             .client-entity-wrapper #entity-details th { | ||||
|                 font-weight: normal; | ||||
|             } | ||||
| 
 | ||||
|             #product-table { | ||||
|                 margin-top: 3rem; | ||||
|                 min-width: 100%; | ||||
|                 table-layout: fixed; | ||||
|                 overflow-wrap: break-word; | ||||
|             } | ||||
|             #product-table > thead { | ||||
|                 text-align: left; | ||||
|             } | ||||
|             #product-table > thead > tr > th { | ||||
|                 font-size: 1.1rem; | ||||
|                 padding-bottom: 1.5rem; | ||||
|                 padding-left: 1rem; | ||||
|                 color: #396d49; | ||||
|                 font-weight: medium; | ||||
|             } | ||||
|             #product-table > tbody > tr > td { | ||||
|                 border-bottom: 1px solid; | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tfoot > tr > td { | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table | ||||
|                 > tfoot | ||||
|                 [data-element='product-table-balance-due-label'], | ||||
|             #product-table > tfoot [data-element='product-table-balance-due'] { | ||||
|                 border-top: 1px solid; | ||||
|                 border-bottom: 1px solid; | ||||
|             } | ||||
| 
 | ||||
|             .thanks-label { | ||||
|                 text-align: center; | ||||
|                 margin-top: 6rem; | ||||
|                 font-size: 1.5rem; | ||||
|                 font-weight: bold; | ||||
|                 padding-bottom: 1rem; | ||||
|                 border-bottom: 4px solid; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|     <style> | ||||
|         /** Required for proper margins on print **/ | ||||
|         @page { | ||||
|             margin-top: 8.5mm; | ||||
|             margin-bottom: 8.5mm; | ||||
|         } | ||||
|     <body id="body"> | ||||
|         <div class="company-logo-wrapper" id="header"> | ||||
|             <img | ||||
|                 class="company-logo" | ||||
|                 src="$company.logo" | ||||
|                 alt="$company.name logo" | ||||
|             /> | ||||
|         </div> | ||||
| 
 | ||||
|         /** Custom CSS goes here.. */ | ||||
|     </style> | ||||
|         <hr class="double-border" /> | ||||
| 
 | ||||
|     <body class="$global-margin antialiased bg-white break-words"> | ||||
|         <!-- Company logo, entity details --> | ||||
|         <div class="grid grid-cols-12 gap-4 pb-6 border-b-4 border-black" id="header"> | ||||
|             <div class="col-span-6"> | ||||
|                 <img | ||||
|                     src="$company.logo" | ||||
|                     alt="$company.name logo" | ||||
|                     class="w-24 col-span-4 sm:w-32" | ||||
|                 /> | ||||
|         <div class="client-entity-wrapper"> | ||||
|             <div class="wrapper-left-side"> | ||||
|                 <div class="text-with-client"> | ||||
|                     <h2 class="wrapper-info-text">$balance_due_label</h2> | ||||
| 
 | ||||
|                     <div id="client-details"></div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="company-info"> | ||||
|                     <div id="company-details"></div> | ||||
|                     <div id="company-address"></div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div class="flex flex-col items-end col-span-6"> | ||||
|                 <table id="entity-details"></table> | ||||
| 
 | ||||
|             <div class="wrapper-right-side"> | ||||
|                 <h2 class="wrapper-info-text">$details_label</h2> | ||||
|                 <table id="entity-details" cellspacing="0"></table> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="grid grid-cols-12"> | ||||
|             <div class="col-span-6 py-6"> | ||||
|                 <p class="text-xl font-semibold uppercase"> | ||||
|                     $your_entity_label | ||||
|                 </p> | ||||
|             </div> | ||||
|         </div> | ||||
|         <table id="product-table" cellspacing="0"></table> | ||||
| 
 | ||||
|         <!-- Client details, company details --> | ||||
|         <div class="grid grid-cols-12 gap-4 pt-6 mt-1 border-t border-black"> | ||||
|             <div | ||||
|                 class="col-span-5 border-r border-black border-dashed" | ||||
|                 id="client-details" | ||||
|             ></div> | ||||
|             <div class="flex col-span-7 space-x-8"> | ||||
|                 <div id="company-details"></div> | ||||
|                 <div id="company-address"></div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Product table --> | ||||
|         <table | ||||
|             id="product-table" | ||||
|             class="w-full mt-10 table-auto $table-padding" | ||||
|         ></table> | ||||
| 
 | ||||
|         <!-- Thanks label --> | ||||
|         <div id="footer"> | ||||
|             <p | ||||
|                 class="w-full pb-4 mt-10 text-2xl font-semibold text-center border-b-4 border-black" | ||||
|             > | ||||
|                 $thanks_label | ||||
|             </p> | ||||
|             <div class="w-full border-black order-b wpy-1"></div> | ||||
|         </div> | ||||
|         <footer id="footer"> | ||||
|             <p class="thanks-label">$thanks_label!</p> | ||||
|             <hr class="double-border" /> | ||||
|         </footer> | ||||
|     </body> | ||||
| </html> | ||||
|  | ||||
| @ -1,69 +1,186 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8" /> | ||||
|         <meta | ||||
|             name="viewport" | ||||
|             content="width=device-width, initial-scale=1, shrink-to-fit=no" | ||||
|         /> | ||||
|         <meta http-equiv="x-ua-compatible" content="ie=edge" /> | ||||
| <html lang="en"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="$app_url/css/tailwindcss@1.4.6.css" /> | ||||
|         <style id="style"> | ||||
|             * { | ||||
|                 margin: 0; | ||||
|                 padding: 0; | ||||
|                 font-size: 14px; | ||||
|             } | ||||
| 
 | ||||
|             body { | ||||
|                 -webkit-font-smoothing: antialiased; | ||||
|                 -moz-osx-font-smoothing: grayscale; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
| 
 | ||||
|             @media print { | ||||
|                 body { | ||||
|                     margin: 0; | ||||
|                     padding: 0; | ||||
|                 } | ||||
|             } | ||||
|             body { | ||||
|                 margin: 2rem; | ||||
|             } | ||||
| 
 | ||||
|             .header-wrapper { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1.2fr 1.8fr; | ||||
|                 gap: 20px; | ||||
|             } | ||||
|             .header-wrapper .header-text-label { | ||||
|                 font-size: 1.1rem; | ||||
|                 color: #bba238; | ||||
|                 text-transform: uppercase; | ||||
|                 font-weight: bold; | ||||
|             } | ||||
|             .header-wrapper .header-left-side-wrapper { | ||||
|                 grid-template-columns: 1fr 1fr; | ||||
|                 gap: 10px; | ||||
|                 border-left: 1px solid #303030; | ||||
|                 padding-left: 1rem; | ||||
|             } | ||||
|             .header-wrapper .header-left-side-wrapper > * { | ||||
|                 margin-bottom: 0.8rem; | ||||
|             } | ||||
|             .header-wrapper .header-left-side-wrapper #company-details, | ||||
|             .header-wrapper .header-left-side-wrapper #company-address { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|             } | ||||
|             .header-wrapper .header-right-side-wrapper { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1fr 1fr; | ||||
|                 gap: 10px; | ||||
|                 border-left: 1px solid #303030; | ||||
|                 padding-left: 1rem; | ||||
|             } | ||||
|             .header-wrapper .header-right-side-wrapper #client-details { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|                 margin-top: 0.8rem; | ||||
|             } | ||||
|             .header-wrapper .company-logo { | ||||
|                 height: 5rem; | ||||
|             } | ||||
| 
 | ||||
|             .entity-label { | ||||
|                 font-size: 3rem; | ||||
|                 text-transform: uppercase; | ||||
|                 margin: 2rem 1rem; | ||||
|             } | ||||
| 
 | ||||
|             .entity-details-wrapper { | ||||
|                 margin: 1rem; | ||||
|             } | ||||
|             .entity-details-wrapper > * { | ||||
|                 margin-right: 1.5rem; | ||||
|             } | ||||
|             .entity-details-wrapper .entity-property-label { | ||||
|                 text-transform: uppercase; | ||||
|             } | ||||
|             .entity-details-wrapper | ||||
|                 [data-element='entity-details-wrapper-invoice-number-label'], | ||||
|             .entity-details-wrapper | ||||
|                 [data-element='entity-details-wrapper-amount-due'] { | ||||
|                 color: #bba238; | ||||
|                 font-weight: bold; | ||||
|             } | ||||
| 
 | ||||
|             #product-table { | ||||
|                 margin-top: 3rem; | ||||
|                 min-width: 100%; | ||||
|                 table-layout: fixed; | ||||
|                 overflow-wrap: break-word; | ||||
|             } | ||||
|             #product-table > thead { | ||||
|                 text-align: left; | ||||
|                 text-transform: uppercase; | ||||
|                 font-weight: bold; | ||||
|             } | ||||
|             #product-table > thead > tr > th { | ||||
|                 font-size: 1.1rem; | ||||
|                 padding-bottom: 1.5rem; | ||||
|                 padding-left: 1rem; | ||||
|                 border-left: 1px solid; | ||||
|             } | ||||
|             #product-table > tbody > tr > td { | ||||
|                 padding: 1rem; | ||||
|                 border-left: 1px solid; | ||||
|             } | ||||
|             #product-table > tfoot > tr > td { | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tfoot > tr > td:nth-last-child(1), | ||||
|             #product-table > tfoot > tr td:nth-last-child(2) { | ||||
|                 border-left: 1px solid; | ||||
|             } | ||||
|             #product-table | ||||
|                 > tfoot | ||||
|                 [data-element='product-table-balance-due-label'], | ||||
|             #product-table > tfoot [data-element='product-table-balance-due'] { | ||||
|                 font-weight: bold; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|     <style> | ||||
|         /** Required for proper margins on print **/ | ||||
|         @page { | ||||
|             margin-top: 8.5mm; | ||||
|             margin-bottom: 8.5mm; | ||||
|         } | ||||
|     <body id="body"> | ||||
|         <div class="header-wrapper" id="header"> | ||||
|             <div class="header-left-side-wrapper"> | ||||
|                 <p class="header-text-label">$from_label:</p> | ||||
| 
 | ||||
|         /** Custom CSS goes here.. */ | ||||
|     </style> | ||||
|                 <div id="company-details"></div> | ||||
|                 <div id="company-address"></div> | ||||
|             </div> | ||||
| 
 | ||||
|     <body class="$global-margin antialiased break-words bg-white"> | ||||
|         <!-- Company details, address, client details, company logo --> | ||||
|         <div class="grid grid-cols-12 gap-4" id="header"> | ||||
|             <div class="col-span-4 pl-4 border-l border-black"> | ||||
|                 <div id="company-details"> | ||||
|                     <p class="font-semibold text-yellow-600 uppercase"> | ||||
|                         $from_label: | ||||
|                     </p> | ||||
|             <div class="header-right-side-wrapper"> | ||||
|                 <div> | ||||
|                     <p class="header-text-label">$to_label:</p> | ||||
|                     <div id="client-details"></div> | ||||
|                 </div> | ||||
|                 <div id="company-address" class="mt-4"></div> | ||||
|             </div> | ||||
|             <div | ||||
|                 class="col-span-5 pl-4 border-l border-black" | ||||
|                 id="client-details" | ||||
|             > | ||||
|                 <p class="font-semibold text-yellow-600 uppercase"> | ||||
|                     $to_label: | ||||
|                 </p> | ||||
|             </div> | ||||
|             <div class="col-span-3"> | ||||
| 
 | ||||
|                 <img | ||||
|                     class="company-logo" | ||||
|                     src="$company.logo" | ||||
|                     alt="$company.name logo" | ||||
|                     class="w-24 col-span-4 sm:w-32" | ||||
|                 /> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Entity details --> | ||||
|         <h1 class="mt-6 text-4xl font-semibold uppercase lg:text-5xl"> | ||||
|             $entity_label | ||||
|         </h1> | ||||
|         <div | ||||
|             id="entity-details" | ||||
|             class="flex flex-wrap items-center space-x-4" | ||||
|         ></div> | ||||
|         <h1 class="entity-label">$entity_label</h1> | ||||
|         <div class="entity-details-wrapper"> | ||||
|             <span> | ||||
|                 <span | ||||
|                     class="entity-property-label" | ||||
|                     data-element="entity-details-wrapper-invoice-number-label" | ||||
|                     >$entity_number_label:</span | ||||
|                 > | ||||
|                 <span class="entity-property-value">$entity_number</span> | ||||
|             </span> | ||||
|             <span> | ||||
|                 <span class="entity-property-label">$entity_date_label:</span> | ||||
|                 <span class="entity-property-value">$entity_date</span> | ||||
|             </span> | ||||
|             <span> | ||||
|                 <span class="entity-property-label">$payment_due_label:</span> | ||||
|                 <span class="entity-property-value">$payment_due</span> | ||||
|             </span> | ||||
|             <span> | ||||
|                 <span class="entity-property-label">$amount_due_label:</span> | ||||
|                 <span | ||||
|                     class="entity-property-value" | ||||
|                     data-element="entity-details-wrapper-amount-due" | ||||
|                     >$amount_due</span | ||||
|                 > | ||||
|             </span> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Product table --> | ||||
|         <table | ||||
|             id="product-table" | ||||
|             class="w-full mt-10 table-auto $table-padding" | ||||
|         ></table> | ||||
|         <table id="product-table" cellspacing="0"></table> | ||||
| 
 | ||||
|         <footer id="footer"></footer> | ||||
|     </body> | ||||
| 
 | ||||
|     <footer id="footer"></footer> | ||||
| </html> | ||||
|  | ||||
| @ -1,68 +1,159 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8" /> | ||||
|         <meta | ||||
|             name="viewport" | ||||
|             content="width=device-width, initial-scale=1, shrink-to-fit=no" | ||||
|         /> | ||||
|         <meta http-equiv="x-ua-compatible" content="ie=edge" /> | ||||
| <html lang="en"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="$app_url/css/tailwindcss@1.4.6.css" /> | ||||
|         <style id="style"> | ||||
|             * { | ||||
|                 margin: 0; | ||||
|                 padding: 0; | ||||
|                 font-size: 14px; | ||||
|             } | ||||
| 
 | ||||
|             body { | ||||
|                 -webkit-font-smoothing: antialiased; | ||||
|                 -moz-osx-font-smoothing: grayscale; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
| 
 | ||||
|             @media print { | ||||
|                 body { | ||||
|                     margin: 0; | ||||
|                     padding: 0; | ||||
|                 } | ||||
|             } | ||||
|             .header-container { | ||||
|                 background-color: #f46521; | ||||
|                 color: white; | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1.5fr 1fr; | ||||
|                 padding: 1.5rem; | ||||
|             } | ||||
|             .header-container .company-name { | ||||
|                 font-size: 2.5rem; | ||||
|             } | ||||
| 
 | ||||
|             #entity-details { | ||||
|                 text-align: left; | ||||
|                 color: #fff4e9 !important; | ||||
|             } | ||||
|             #entity-details > tr, | ||||
|             #entity-details th { | ||||
|                 font-weight: normal; | ||||
|                 padding-bottom: 0.5rem; | ||||
|             } | ||||
| 
 | ||||
|             .company-logo { | ||||
|                 height: 5rem; | ||||
|             } | ||||
| 
 | ||||
|             .logo-client-wrapper { | ||||
|                 margin: 3rem 1.5rem; | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1.5fr 1fr; | ||||
|             } | ||||
| 
 | ||||
|             #client-details { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|             } | ||||
|             #client-details > * { | ||||
|                 margin-bottom: 0.5rem; | ||||
|             } | ||||
| 
 | ||||
|             .table-wrapper { | ||||
|                 margin: 3rem 1.5rem; | ||||
|             } | ||||
| 
 | ||||
|             #product-table { | ||||
|                 min-width: 100%; | ||||
|                 table-layout: fixed; | ||||
|                 overflow-wrap: break-word; | ||||
|             } | ||||
|             #product-table > thead { | ||||
|                 text-align: left; | ||||
|             } | ||||
|             #product-table > thead > tr > th { | ||||
|                 padding: 0.8rem; | ||||
|                 background-color: #3f3e3c; | ||||
|                 color: white; | ||||
|             } | ||||
|             #product-table > tbody > tr > td { | ||||
|                 border-bottom: 1px solid #3f3e3c; | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tbody > tr > td:first-child { | ||||
|                 font-weight: bold; | ||||
|             } | ||||
|             #product-table > tfoot > tr > td { | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tfoot [data-element='balance-due-row'] > td { | ||||
|                 background-color: #3f3e3c; | ||||
|                 color: white; | ||||
|             } | ||||
|             #product-table > tfoot [data-element='balance-due-label'] { | ||||
|                 font-weight: bold; | ||||
|                 font-size: 1.2rem; | ||||
|             } | ||||
|             #product-table > tfoot [data-element='balance-due'] { | ||||
|                 font-size: 1.2rem; | ||||
|             } | ||||
| 
 | ||||
|             .footer-wrapper { | ||||
|                 display: grid; | ||||
|                 position: fixed; | ||||
|                 bottom: 0; | ||||
|                 width: 100%; | ||||
|                 padding: 1.5rem; | ||||
|                 grid-template-columns: 2fr 1fr 1fr; | ||||
|                 background-color: #f46521; | ||||
|                 color: #fff4e9; | ||||
|             } | ||||
| 
 | ||||
|             #company-address, | ||||
|             #company-details { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|             } | ||||
|             #company-address > *, | ||||
|             #company-details > * { | ||||
|                 margin-bottom: 0.5rem; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|     <body class="antialiased break-words bg-white"> | ||||
|         <!-- Company name, entity details --> | ||||
|         <div class="bg-orange-600" id="header"> | ||||
|             <div class="$global-padding"> | ||||
|                 <div class="grid grid-cols-12"> | ||||
|                     <div class="col-span-4"> | ||||
|                         <h1 class="text-3xl font-bold text-white lg:text-4xl"> | ||||
|                             $company.name | ||||
|                         </h1> | ||||
|                     </div> | ||||
|                     <div class="col-span-7 col-start-6 lg:col-start-7"> | ||||
|                         <table id="entity-details" class="text-white"></table> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|     <body id="body"> | ||||
|         <div class="header-container" id="header"> | ||||
|             <h1 class="company-name">$company.name</h1> | ||||
| 
 | ||||
|             <table id="entity-details" cellspacing="0"></table> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="$global-margin"> | ||||
|             <!-- Company logo, client details --> | ||||
|             <div class="col-span-12 mt-6 mb-10"> | ||||
|                 <p class="text-xl font-semibold text-orange-600 uppercase"> | ||||
|                     $your_entity_label | ||||
|                 </p> | ||||
|             </div> | ||||
|             <div class="grid grid-cols-12"> | ||||
|                 <img | ||||
|                     src="$company.logo" | ||||
|                     alt="$company.name logo" | ||||
|                     class="grid w-24 col-span-4 sm:w-32" | ||||
|                 /> | ||||
|                 <div id="client-details" class="col-span-8 col-start-6"></div> | ||||
|             </div> | ||||
|         <div class="logo-client-wrapper"> | ||||
|             <img | ||||
|                 class="company-logo" | ||||
|                 src="$company.logo" | ||||
|                 alt="$company.name logo" | ||||
|             /> | ||||
| 
 | ||||
|             <!-- Product table --> | ||||
|             <table | ||||
|                 id="product-table" | ||||
|                 class="w-full mt-8 mb-10 table-auto $table-padding" | ||||
|             ></table> | ||||
|             <div id="client-details"></div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Company details --> | ||||
|         <footer id="footer" class="fixed bottom-0 w-full bg-orange-600"> | ||||
|             <div class="$global-padding"> | ||||
|                 <div class="grid grid-cols-12"> | ||||
|                     <div | ||||
|                         class="flex justify-between col-span-8 col-start-6 lg:col-span-6 lg:col-start-8" | ||||
|                     > | ||||
|                         <div id="company-details" class="text-white"></div> | ||||
|                         <div id="company-address" class="text-white"></div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|         <div class="table-wrapper"> | ||||
|             <table id="product-table" cellspacing="0"></table> | ||||
|         </div> | ||||
|          | ||||
|         <div class="footer-wrapper"> | ||||
|             <div> | ||||
|                 <!-- Placeholder for offset --> | ||||
|             </div> | ||||
|         </footer> | ||||
|              | ||||
|             <div id="company-details"></div> | ||||
|             <div id="company-address"></div> | ||||
|         </div> | ||||
|          | ||||
|         <footer id="footer"></footer> | ||||
|     </body> | ||||
| </html> | ||||
|  | ||||
| @ -1,63 +1,119 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8" /> | ||||
|         <meta | ||||
|             name="viewport" | ||||
|             content="width=device-width, initial-scale=1, shrink-to-fit=no" | ||||
|         /> | ||||
|         <meta http-equiv="x-ua-compatible" content="ie=edge" /> | ||||
| <html lang="en"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="$app_url/css/tailwindcss@1.4.6.css" /> | ||||
|         <style id="style"> | ||||
|             * { | ||||
|                 margin: 0; | ||||
|                 padding: 0; | ||||
|                 font-size: 14px; | ||||
|             } | ||||
| 
 | ||||
|             body { | ||||
|                 -webkit-font-smoothing: antialiased; | ||||
|                 -moz-osx-font-smoothing: grayscale; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
| 
 | ||||
|             @media print { | ||||
|                 body { | ||||
|                     margin: 0; | ||||
|                     padding: 0; | ||||
|                 } | ||||
|             } | ||||
|             body { | ||||
|                 margin: 2rem; | ||||
|             } | ||||
| 
 | ||||
|             .header-wrapper { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1fr 1fr 1fr; | ||||
|             } | ||||
|             .header-wrapper .company-logo { | ||||
|                 height: 5rem; | ||||
|             } | ||||
|             .header-wrapper #company-address { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|             } | ||||
|             .header-wrapper #entity-details { | ||||
|                 margin-top: 1.5rem; | ||||
|                 text-align: left; | ||||
|                 width: 100%; | ||||
|             } | ||||
|             .header-wrapper #entity-details > tr, | ||||
|             .header-wrapper #entity-details th { | ||||
|                 font-weight: normal; | ||||
|                 padding-left: 0.9rem; | ||||
|                 padding-top: 0.3rem; | ||||
|                 padding-bottom: 0.3rem; | ||||
|             } | ||||
|             .header-wrapper | ||||
|                 #entity-details | ||||
|                 [data-element='entity-balance-due-label'], | ||||
|             .header-wrapper | ||||
|                 #entity-details | ||||
|                 [data-element='entity-balance-due'] { | ||||
|                 background-color: #e6e6e6; | ||||
|             } | ||||
| 
 | ||||
|             #client-details { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|             } | ||||
| 
 | ||||
|             #product-table { | ||||
|                 min-width: 100%; | ||||
|                 table-layout: fixed; | ||||
|                 overflow-wrap: break-word; | ||||
|                 margin-top: 3rem; | ||||
|             } | ||||
|             #product-table > thead { | ||||
|                 text-align: left; | ||||
|             } | ||||
|             #product-table > thead > tr > th { | ||||
|                 padding: 1rem; | ||||
|                 background-color: #e6e6e6; | ||||
|             } | ||||
|             #product-table > tbody > tr > td { | ||||
|                 border-bottom: 1px solid #e6e6e6; | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tfoot > tr > td { | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table | ||||
|                 > tfoot | ||||
|                 [data-element='product-table-balance-due-label'], | ||||
|             #product-table > tfoot [data-element='product-table-balance-due'] { | ||||
|                 background-color: #e6e6e6; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|     <style> | ||||
|         /** Required for proper margins on print **/ | ||||
|         @page { | ||||
|             margin-top: 8.5mm; | ||||
|             margin-bottom: 8.5mm; | ||||
|         } | ||||
|     <body id="body"> | ||||
|         <div class="header-wrapper" id="header"> | ||||
|             <p>$company.name</p> | ||||
| 
 | ||||
|         /** Custom CSS goes here.. */ | ||||
|     </style> | ||||
|             <div id="company-address"></div> | ||||
| 
 | ||||
|     <body class="$global-margin antialiased break-words bg-white"> | ||||
|         <!-- Company name, company address, company logo --> | ||||
|         <div class="grid grid-cols-12 gap-4" id="header"> | ||||
|             <div class="col-span-4">$company.name</div> | ||||
|             <div class="col-span-4" id="company-address"></div> | ||||
|             <div class="col-span-4"> | ||||
|             <div> | ||||
|                 <img | ||||
|                     class="company-logo" | ||||
|                     src="$company.logo" | ||||
|                     alt="$company.name logo" | ||||
|                     class="block w-24 col-span-4 sm:w-32" | ||||
|                 /> | ||||
| 
 | ||||
|                 <table id="entity-details" cellspacing="0"></table> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Entity details --> | ||||
|         <div class="grid grid-cols-12"> | ||||
|             <div class="col-span-6 col-start-6 mt-12"> | ||||
|                 <table class="flex justify-between" id="entity-details"></table> | ||||
|             </div> | ||||
|         </div> | ||||
|         <div id="client-details"></div> | ||||
|          | ||||
|         <table id="product-table" cellspacing="0"></table> | ||||
| 
 | ||||
|         <!-- Client details --> | ||||
|         <div class="grid grid-cols-12 mt-12"> | ||||
|             <div class="col-span-12 mb-10"> | ||||
|                 <p class="text-xl font-semibold text-black uppercase"> | ||||
|                     $your_entity_label | ||||
|                 </p> | ||||
|             </div> | ||||
|             <div class="col-span-6" id="client-details"></div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Product table --> | ||||
|         <table | ||||
|             id="product-table" | ||||
|             class="w-full mt-8 table-auto $table-padding" | ||||
|         ></table> | ||||
|         <footer id="footer"></footer> | ||||
|     </body> | ||||
| 
 | ||||
|     <footer id="footer"></footer> | ||||
| </html> | ||||
|  | ||||
| @ -1,82 +1,173 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <meta charset="utf-8" /> | ||||
|         <meta | ||||
|             name="viewport" | ||||
|             content="width=device-width, initial-scale=1, shrink-to-fit=no" | ||||
|         /> | ||||
|         <meta http-equiv="x-ua-compatible" content="ie=edge" /> | ||||
| <html lang="en"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="$app_url/css/tailwindcss@1.4.6.css" /> | ||||
|         <style id="style"> | ||||
|             * { | ||||
|                 margin: 0; | ||||
|                 padding: 0; | ||||
|                 font-size: 14px; | ||||
|             } | ||||
| 
 | ||||
|             body { | ||||
|                 -webkit-font-smoothing: antialiased; | ||||
|                 -moz-osx-font-smoothing: grayscale; | ||||
|                 font-family: Arial, Helvetica, sans-serif; | ||||
|             } | ||||
| 
 | ||||
|             @media print { | ||||
|                 body { | ||||
|                     margin: 0; | ||||
|                     padding: 0; | ||||
|                 } | ||||
|             } | ||||
|             body { | ||||
|                 margin: 2rem; | ||||
|             } | ||||
| 
 | ||||
|             .header-wrapper { | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1fr 1fr 1fr; | ||||
|             } | ||||
|             .header-wrapper .company-logo { | ||||
|                 height: 5rem; | ||||
|             } | ||||
|             .header-wrapper .entity-details-wrapper { | ||||
|                 background-color: #009e90; | ||||
|                 padding: 1rem; | ||||
|                 border-radius: 10px; | ||||
|             } | ||||
|             .header-wrapper #entity-details { | ||||
|                 width: 100%; | ||||
|                 color: white; | ||||
|                 text-align: left; | ||||
|             } | ||||
|             .header-wrapper #entity-details > tr, | ||||
|             .header-wrapper #entity-details th { | ||||
|                 font-weight: normal; | ||||
|             } | ||||
| 
 | ||||
|             .contacts-wrapper { | ||||
|                 margin-top: 3rem; | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1fr 1fr; | ||||
|                 gap: 40px; | ||||
|             } | ||||
|             .contacts-wrapper .contact-label { | ||||
|                 font-weight: bold; | ||||
|                 color: #009e90; | ||||
|                 margin-left: 1rem; | ||||
|             } | ||||
|             .contacts-wrapper #company-address, | ||||
|             .contacts-wrapper #company-details, | ||||
|             .contacts-wrapper #client-details { | ||||
|                 display: flex; | ||||
|                 flex-direction: column; | ||||
|                 margin-bottom: 1rem; | ||||
|             } | ||||
|             .contacts-wrapper .company-info { | ||||
|                 margin-top: 1rem; | ||||
|                 padding: 1rem; | ||||
|                 border-top: 1px solid #009e90; | ||||
|                 border-bottom: 1px solid #009e90; | ||||
|                 display: grid; | ||||
|                 grid-template-columns: 1fr 1fr; | ||||
|                 gap: 10px; | ||||
|             } | ||||
|             .contacts-wrapper #client-details { | ||||
|                 margin-top: 1rem; | ||||
|                 padding: 1rem; | ||||
|                 border-top: 1px solid #009e90; | ||||
|                 border-bottom: 1px solid #009e90; | ||||
|             } | ||||
| 
 | ||||
|             #product-table { | ||||
|                 margin-top: 3rem; | ||||
|                 min-width: 100%; | ||||
|                 table-layout: fixed; | ||||
|                 overflow-wrap: break-word; | ||||
|             } | ||||
|             #product-table > thead { | ||||
|                 text-align: left; | ||||
|             } | ||||
|             #product-table > thead > tr > th { | ||||
|                 font-size: 1.2rem; | ||||
|                 padding: 1rem; | ||||
|                 background: #009e90; | ||||
|                 color: white; | ||||
|             } | ||||
|             #product-table > thead tr > th:first-child { | ||||
|                 border-top-left-radius: 10px; | ||||
|                 border-bottom-left-radius: 10px; | ||||
|             } | ||||
|             #product-table > thead tr > th:last-child { | ||||
|                 border-top-right-radius: 10px; | ||||
|                 border-bottom-right-radius: 10px; | ||||
|             } | ||||
|             #product-table > tbody > tr > td { | ||||
|                 border-bottom: 1px solid #009e90; | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table > tbody > tr > td:first-child { | ||||
|                 color: #bb3a24; | ||||
|             } | ||||
|             #product-table > tfoot > tr > td { | ||||
|                 padding: 1rem; | ||||
|             } | ||||
|             #product-table | ||||
|                 > tfoot | ||||
|                 [data-element='product-table-balance-due-label'] { | ||||
|                 background-color: #009e90; | ||||
|                 color: white; | ||||
|                 border-top-left-radius: 10px; | ||||
|                 border-bottom-left-radius: 10px; | ||||
|             } | ||||
|             #product-table > tfoot [data-element='product-table-balance-due'] { | ||||
|                 background-color: #009e90; | ||||
|                 color: white; | ||||
|                 border-top-right-radius: 10px; | ||||
|                 border-bottom-right-radius: 10px; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
| 
 | ||||
|     <style> | ||||
|         #product-table tbody > tr > td:first-child { | ||||
|             color: #9b2c2c; | ||||
|         } | ||||
|     <body id="body"> | ||||
|         <div class="header-wrapper" id="header"> | ||||
|             <img | ||||
|                 class="company-logo" | ||||
|                 src="$company.logo" | ||||
|                 alt="$company.name logo" | ||||
|             /> | ||||
| 
 | ||||
|         #product-table tbody > tr > td:last-child { | ||||
|             color: #9b2c2c; | ||||
|             font-weight: bold; | ||||
|         } | ||||
| 
 | ||||
|         /** Required for proper margins on print **/ | ||||
|         @page { | ||||
|             margin-top: 8.5mm; | ||||
|             margin-bottom: 8.5mm; | ||||
|         } | ||||
| 
 | ||||
|         /** Custom CSS goes here.. */ | ||||
|     </style> | ||||
| 
 | ||||
|     <body class="$global-margin antialiased bg-white break-words"> | ||||
|         <!-- Company logo, entity details --> | ||||
|         <div class="grid grid-cols-12 gap-4" id="header"> | ||||
|             <div class="col-span-4"> | ||||
|                 <img | ||||
|                     src="$company.logo" | ||||
|                     alt="$company.name logo" | ||||
|                     class="w-24 col-span-4 sm:w-32" | ||||
|                 /> | ||||
|             <div> | ||||
|                 <!-- Placeholder for empty space --> | ||||
|             </div> | ||||
|             <div class="col-span-6 col-start-7 p-5 bg-teal-600 rounded-lg"> | ||||
|                 <table id="entity-details" class="text-white"></table> | ||||
| 
 | ||||
|             <div class="entity-details-wrapper"> | ||||
|                 <table id="entity-details" cellspacing="0"></table> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Company details, client details --> | ||||
|         <div class="grid grid-cols-12 gap-12 mt-12"> | ||||
|             <div class="col-span-12"> | ||||
|                 <p class="text-xl font-semibold text-teal-600 uppercase"> | ||||
|                     $your_entity_label | ||||
|                 </p> | ||||
|             </div> | ||||
|             <div class="col-span-6"> | ||||
|                 <p class="px-4 font-semibold text-teal-600">$to_label:</p> | ||||
|                 <div | ||||
|                     class="p-4 mt-4 border-t-4 border-b-4 border-teal-600 border-dashed" | ||||
|                 > | ||||
|                     <div id="client-details"></div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div class="col-span-6"> | ||||
|                 <p class="px-4 font-semibold text-teal-600">$from_label:</p> | ||||
|                 <div | ||||
|                     class="flex p-4 mt-4 space-x-4 border-t-4 border-b-4 border-teal-600 border-dashed" | ||||
|                 > | ||||
|         <div class="contacts-wrapper"> | ||||
|             <div> | ||||
|                 <p class="contact-label">$to_label:</p> | ||||
|                 <div class="company-info"> | ||||
|                     <div id="company-details"></div> | ||||
|                     <div id="company-address"></div> | ||||
|                 </div> | ||||
|             </div> | ||||
| 
 | ||||
|             <div> | ||||
|                 <p class="contact-label">$from_label:</p> | ||||
| 
 | ||||
|                 <div id="client-details"></div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- Product table --> | ||||
|         <table | ||||
|             id="product-table" | ||||
|             class="w-full mt-10 table-auto $table-padding" | ||||
|         ></table> | ||||
|     </body> | ||||
|         <table id="product-table" cellspacing="0"></table> | ||||
| 
 | ||||
|     <footer id="footer"></footer> | ||||
|         <footer id="footer"></footer> | ||||
|     </body> | ||||
| </html> | ||||
|  | ||||
| @ -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; | ||||
| @ -23,22 +24,22 @@ class ExampleIntegrationTest extends TestCase | ||||
| 
 | ||||
|     public function testExample() | ||||
|     { | ||||
|         $this->markTestIncomplete(); | ||||
| 
 | ||||
|         $invoice = $this->invoice; | ||||
|         $invitation = $invoice->invitations()->first(); | ||||
| 
 | ||||
|         $engine = new HtmlEngine(null, $invitation, 'invoice'); | ||||
|         $design = new Playful(); | ||||
| 
 | ||||
|         $product_table_columns = json_decode( | ||||
|             json_encode($invoice->company->settings->pdf_variables), | ||||
|             1 | ||||
|         )['product_columns']; | ||||
|         $design = new Design( | ||||
|             Design::CLEAN | ||||
|         ); | ||||
| 
 | ||||
|         $state = [ | ||||
|             'template' => $design->elements([ | ||||
|                 'client' => $invoice->client, | ||||
|                 'entity' => $invoice, | ||||
|                 'product-table-columns' => $product_table_columns, | ||||
|                 'pdf_variables' => (array)$invoice->company->settings->pdf_variables, | ||||
|             ]), | ||||
|             'variables' => $engine->generateLabelsAndValues(), | ||||
|         ]; | ||||
| @ -46,7 +47,7 @@ class ExampleIntegrationTest extends TestCase | ||||
|         $maker = new PdfMaker($state); | ||||
| 
 | ||||
|         $maker | ||||
|             ->design(Playful::class) | ||||
|             ->design($design) | ||||
|             ->build(); | ||||
| 
 | ||||
|   //      exec('echo "" > storage/logs/laravel.log');
 | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -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', ['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', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); | ||||
| 
 | ||||
|         $maker = new PdfMaker($this->state); | ||||
| 
 | ||||
|         $maker | ||||
|             ->design(ExampleDesign::class) | ||||
|             ->design($design) | ||||
|             ->build(); | ||||
| 
 | ||||
|         $this->assertStringContainsString('<!-- Business -->', $maker->getCompiledHTML()); | ||||
|         $this->assertStringContainsString('Template: Example', $maker->getCompiledHTML()); | ||||
|     } | ||||
| 
 | ||||
|     public function testGetSectionUtility() | ||||
|     { | ||||
|         $design = new Design('example', ['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', ['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', ['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', ['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', ['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('<div id="header">$title</div>', $output1); | ||||
|         $this->assertStringContainsString('<div id="header">', $output1); | ||||
| 
 | ||||
|         $design2 = new Design('example', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); | ||||
|         $maker2 = new PdfMaker([ | ||||
|             'template' => [ | ||||
|                 'header' => [ | ||||
| @ -200,18 +191,19 @@ class PdfMakerTest extends TestCase | ||||
|         ]); | ||||
| 
 | ||||
|         $maker2 | ||||
|             ->design(ExampleDesign::class) | ||||
|             ->design($design2) | ||||
|             ->build(); | ||||
| 
 | ||||
|         $output2 = $maker2->getCompiledHTML(); | ||||
| 
 | ||||
|         $this->assertStringContainsString('<div id="header" hidden="true">$title</div>', $output2); | ||||
|         $this->assertStringContainsString('<div id="header" hidden="true">$company.name</div>', $output2); | ||||
| 
 | ||||
|         $this->assertNotSame($output1, $output2); | ||||
|     } | ||||
| 
 | ||||
|     public function testOrderingElements() | ||||
|     { | ||||
|         $design = new Design('example', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); | ||||
| 
 | ||||
|         $maker = new PdfMaker([ | ||||
|             'template' => [ | ||||
| @ -227,7 +219,7 @@ class PdfMakerTest extends TestCase | ||||
|         ]); | ||||
| 
 | ||||
|         $maker | ||||
|             ->design(ExampleDesign::class) | ||||
|             ->design($design) | ||||
|             ->build(); | ||||
| 
 | ||||
|         $node = $maker->getSectionNode('header'); | ||||
| @ -254,7 +246,7 @@ class PdfMakerTest extends TestCase | ||||
|         ]); | ||||
| 
 | ||||
|         $maker | ||||
|             ->design(ExampleDesign::class) | ||||
|             ->design($design) | ||||
|             ->build(); | ||||
| 
 | ||||
|         $node = $maker->getSectionNode('header'); | ||||
| @ -270,7 +262,6 @@ class PdfMakerTest extends TestCase | ||||
| 
 | ||||
|     public function testGeneratingPdf() | ||||
|     { | ||||
| 
 | ||||
|         $state = [ | ||||
|             'template' => [ | ||||
|                 'header' => [ | ||||
| @ -319,10 +310,11 @@ class PdfMakerTest extends TestCase | ||||
|             ] | ||||
|         ]; | ||||
| 
 | ||||
|         $design = new Design('example', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); | ||||
|         $maker = new PdfMaker($state); | ||||
| 
 | ||||
|         $maker | ||||
|             ->design(ExampleDesign::class) | ||||
|             ->design($design) | ||||
|             ->build(); | ||||
| 
 | ||||
|         $this->assertTrue(true); | ||||
| @ -330,7 +322,7 @@ class PdfMakerTest extends TestCase | ||||
| 
 | ||||
|     public function testGetSectionHTMLWorks() | ||||
|     { | ||||
|         $design = new ExampleDesign(); | ||||
|         $design = new Design('example', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); | ||||
| 
 | ||||
|         $html = $design | ||||
|             ->document() | ||||
| @ -341,7 +333,7 @@ class PdfMakerTest extends TestCase | ||||
| 
 | ||||
|     public function testWrapperHTMLWorks() | ||||
|     { | ||||
|         $design = new ExampleDesign(); | ||||
|         $design = new Design('example', ['custom_path' => base_path('tests/Feature/PdfMaker/')]); | ||||
| 
 | ||||
|         $state = [ | ||||
|             'template' => [ | ||||
| @ -357,6 +349,7 @@ class PdfMakerTest extends TestCase | ||||
|                 'values' => [], | ||||
|             ], | ||||
|             'options' => [ | ||||
|                 'all_pages_header' => true, | ||||
|                 'all_pages_footer' => true, | ||||
|             ], | ||||
|         ]; | ||||
| @ -364,7 +357,7 @@ class PdfMakerTest extends TestCase | ||||
|         $maker = new PdfMaker($state); | ||||
| 
 | ||||
|         $maker | ||||
|             ->design(ExampleDesign::class) | ||||
|             ->design($design) | ||||
|             ->build(); | ||||
| 
 | ||||
|         // exec('echo "" > storage/logs/laravel.log');
 | ||||
|  | ||||
| @ -1,8 +0,0 @@ | ||||
| <!-- Business --> | ||||
| <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"> | ||||
| 
 | ||||
| <body class="m-10"> | ||||
|     <div id="header">$title</div> | ||||
|     <table id="product-table"></table> | ||||
|     <div id="footer">My awesome footer</div> | ||||
| </body> | ||||
							
								
								
									
										31
									
								
								tests/Feature/PdfMaker/example.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								tests/Feature/PdfMaker/example.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| <!-- Template: Example --> | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|     <head> | ||||
|         <meta charset="UTF-8" /> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
|     </head> | ||||
| 
 | ||||
|     <body> | ||||
|         <div id="header">$company.name</div> | ||||
|          | ||||
|         <img | ||||
|             src="https://www.invoiceninja.com/wp-content/uploads/2015/10/logo-blk-vertical-1.png" | ||||
|             alt="Invoice Ninja logo" | ||||
|         /> | ||||
|          | ||||
|         <div id="company-details"></div> | ||||
| 
 | ||||
|         <div id="company-address"></div> | ||||
| 
 | ||||
|         <div id="client-details"></div> | ||||
| 
 | ||||
|         <table id="entity-details"></table> | ||||
| 
 | ||||
|         <table id="product-table"></table> | ||||
| 
 | ||||
|         <div id="footer"> | ||||
|             my awesome footer | ||||
|         </div> | ||||
|     </body> | ||||
| </html> | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user