Additional Templates

This commit is contained in:
David Bomba 2024-04-04 15:04:50 +11:00
parent 7a8fb8f486
commit 2957227422
7 changed files with 474 additions and 17 deletions

View File

@ -64,7 +64,9 @@ class Statement
$variables = []; $variables = [];
$variables = $html->generateLabelsAndValues(); $variables = $html->generateLabelsAndValues();
if($this->client->getSetting('statement_design_id') != '') { $option_template = &$this->options['template'];
if($this->client->getSetting('statement_design_id') != '' || $option_template && $option_template != '') {
$variables['values']['$start_date'] = $this->translateDate($this->options['start_date'], $this->client->date_format(), $this->client->locale()); $variables['values']['$start_date'] = $this->translateDate($this->options['start_date'], $this->client->date_format(), $this->client->locale());
$variables['values']['$end_date'] = $this->translateDate($this->options['end_date'], $this->client->date_format(), $this->client->locale()); $variables['values']['$end_date'] = $this->translateDate($this->options['end_date'], $this->client->date_format(), $this->client->locale());

View File

@ -11,33 +11,34 @@
namespace App\Services\Template; namespace App\Services\Template;
use App\Libraries\MultiDB; use App\Models\Task;
use App\Models\User;
use App\Models\Quote;
use App\Models\Client; use App\Models\Client;
use App\Models\Company;
use App\Models\Credit; use App\Models\Credit;
use App\Models\Design; use App\Models\Design;
use App\Models\Vendor;
use App\Models\Company;
use App\Models\Expense; use App\Models\Expense;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Payment; use App\Models\Payment;
use App\Models\Product; use App\Models\Product;
use App\Models\Project; use App\Models\Project;
use App\Libraries\MultiDB;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Models\Quote; use Illuminate\Bus\Queueable;
use App\Utils\Traits\MakesHash;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\Models\Task;
use App\Models\User;
use App\Models\Vendor;
use App\Services\Email\AdminEmail; use App\Services\Email\AdminEmail;
use App\Services\Email\EmailObject; use App\Services\Email\EmailObject;
use App\Utils\Traits\MakesHash; use App\Services\PdfMaker\PdfMerge;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Mail\Mailables\Address; use Illuminate\Mail\Mailables\Address;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\Middleware\WithoutOverlapping;
class TemplateAction implements ShouldQueue class TemplateAction implements ShouldQueue
{ {
@ -111,6 +112,39 @@ class TemplateAction implements ShouldQueue
/** Set a global currency_code */ /** Set a global currency_code */
$first_entity = $result->first(); $first_entity = $result->first();
/** Lets be clever and sniff out Statements */
if($first_entity instanceof Client && stripos(json_encode($template->design), '##statement##') !== false) {
$options = [
'show_payments_table' => true,
'show_aging_table' => true,
'status' => 'all',
'show_credits_table' => false,
'template' => $this->template,
];
$pdfs = [];
foreach($result as $client) {
$pdfs[] = $client->service()->statement($options);
}
if(count($pdfs) == 1) {
$pdf = $pdfs[0];
} else {
$pdf = (new PdfMerge($pdfs))->run();
}
if($this->send_email) {
$this->sendEmail($pdf, $template);
} else {
$filename = "templates/{$this->hash}.pdf";
Storage::disk(config('filesystems.default'))->put($filename, $pdf);
return $pdf;
}
}
if($first_entity instanceof Client) if($first_entity instanceof Client)
$currency_code = $first_entity->currency()->code; $currency_code = $first_entity->currency()->code;
elseif($first_entity->client) elseif($first_entity->client)

View File

@ -0,0 +1,205 @@
<!doctype html>
<!-- Delivery Note Design 4 - MONO - TemplateID #TD13 -->
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
html {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif;
}
table {
margin-top: 2rem;
min-width: 100%;
table-layout: fixed;
overflow-wrap: break-word;
}
.table-header>tr>th {
border-bottom: solid 1px #efefef;
}
.table-body>tr>td {
border-bottom: solid 1px #efefef;
}
th {
text-align: left;
padding-left: 6px;
padding-right: 6px;
padding-top: 6px;
padding-bottom: 6px;
}
td {
padding-left: 6px;
padding-right: 6px;
padding-top: 1rem;
padding-bottom: 1rem;
}
.item-row {
border-bottom: 1px #000 dotted;
}
.totals-row-label {
text-align: right;
white-space: nowrap;
}
.totals-row-value {
text-align: right;
white-space: nowrap;
}
.table-totals {
display: grid;
grid-template-columns: 2fr 1fr;
}
.centered {
text-align: center;
}
.doc-title {
font-size: 32px;
}
p {
margin: 0;
padding: 0;
}
span {
padding-right: 5px;
width: 100%;
}
div .label {
text-align: right;
padding-right: 10px;
}
div .value {
text-align: left;
padding-left: 5px;
}
.two-col-grid {
display: grid;
grid-template-columns: 1fr 1fr;
}
.client-details {
padding-top: 0.2rem;
padding-bottom: 0.1rem;
}
.container {
padding-top: 2rem;
}
.bottom-margin {
padding-bottom: 2rem;
}
.section-title {
font-style: italic;
color: #454545
}
</style>
</head>
<body>
<ninja>
<table width="100%" cellspacing="0" cellpadding="0" class="" border="0">
<tr>
<td align="left" class="doc-title">Delivery Note</td>
<td align="right">{{ img('$company.logo') }}</td>
</tr>
</table>
</ninja>
<table width="100%" cellspacing="0" cellpadding="0" class="" border="0">
<tr>
<td align="left" class="">
<div class="">
<div class="client-details">
<p class="section-title">Bill To:</p>
</div>
<div class="client-details">
<p>$client.name</p>
</div>
<div class="client-details">
<p>$client.shipping_address</p>
</div>
</div>
</td>
<td align="left">
<div class="">
<div class="client-details">
<p class="section-title">Ship To:</p>
</div>
<div class="client-details">
<p>$client.name</p>
</div>
<div class="client-details">
<p>$client.shipping_address</p>
</div>
</div>
</td>
</tr>
</table>
<table width="100%" cellspacing="0" cellpadding="0" class="">
<tr>
<td align="left" class="">
<div class="">
<p>Order # $invoice.po_number</p>
</div>
</td>
<td align="left">
<div class="">
<p>Order Date: $invoice.date</p>
</div>
</td>
</tr>
</table>
<ninja>
{% set invoice = invoices|first %}
<table width="100%" cellspacing="0" cellpadding="0" class="">
<thead class="table-header">
<tr class="table-header">
<th class="">Item #</th>
<th class="" width="50%">Description</th>
<th class="totals-row-label centered">Delivered</th>
</tr>
</thead>
<tbody class="table-body">
{% for item in invoice.line_items|filter(item => item.type_id == 1) %}
<tr class="item-row">
<td class="">{{ item.product_key }}</td>
<td class="">{{ item.notes }}</td>
<td class="centered">{{ item.quantity }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</ninja>
<table width="100%" cellspacing="0" cellpadding="0" class="">
<div class="container">
<p class="bottom-margin">Notes:</p>
$invoice.public_notes
</div>
</table>
</body>
</html>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- Plain Statement - TemplateID #TS1 --> <!-- Plain Statement - TemplateID #TS1 ##statement##-->
<html> <html>
<head> <head>
@ -13,7 +13,7 @@
} }
@page { @page {
margin: 0 !important; //removes top and bottom default headers margin: 0 !important;
size: $page_size $page_layout; size: $page_size $page_layout;
} }

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- Color Statement - TemplateID #TS2 --> <!-- Color Statement - TemplateID #TS2 ##statement##-->
<html> <html>
<head> <head>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- Vertial Statement - TemplateID #TS3 --> <!-- Vertial Statement - TemplateID #TS3 ##statement##-->
<html> <html>
<head> <head>

View File

@ -0,0 +1,216 @@
<!doctype html>
<!-- Statement - TemplateID #TS4 ##statement##-->
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url($font_url);
@page {
margin: 50 0 50 0 !important;
}
body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: $font_name, Helvetica, sans-serif;
font-size: $font_size !important;
zoom: 80%;
}
#logo-container {
width: 100%;
margin-top: 1rem;
margin-bottom: 1rem;
}
img {
display: block;
margin-left: auto;
margin-right: auto;
}
.two-col-grid {
display: grid;
grid-template-columns: 1fr 1fr;
border: 0px solid #000;
}
.body-margin {
margin-left: 2rem;
margin-right: 2rem;
}
.aging-table {
border: 0px dashed $primary_color;
text-align: center;
}
#client-wrapper {
width: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
border: 0px solid #000;
}
#client-details {}
#company-details {}
#company-address {}
#company-wrapper {
margin-left: auto;
margin-right: 0;
}
#statement-details {
margin-top: 1rem;
}
#statement-details>h2 {
font-style: italic;
font-size: 1.3rem;
}
#date-range {
font-size: 1rem;
font-weight: bold;
}
</style>
</head>
<body>
<div class="repeating-header" id="header"></div>
<table style="min-width: 100%">
<thead>
<tr>
<td>
<!-- repeating header -->
</td>
</tr>
</thead>
<tbody>
<tr>
<td>
<!-- body -->
<div id="logo-container">
<img src="$company.logo">
</div>
<div class="two-col-grid body-margin">
<div id="client-details"></div>
<div id="company-wrapper">
<div id="company-details"></div>
<div id="company-address"></div>
<div id="statement-details">
<h2>$statement_label</h2>
<p id="date-range">$start_date - $end_date</p>
</div>
</div>
</div>
<ninja>
<table class="min-w-full text-left text-sm font-light">
<thead class="border-b font-medium dark:border-neutral-500">
<tr class="text-sm leading-normal">
<th scope="col" class="px-6 py-4">Doc #</th>
<th scope="col" class="px-6 py-4">Date</th>
<th scope="col" class="px-6 py-4">Due Date</th>
<th scope="col" class="px-6 py-4">Total</th>
<th scope="col" class="px-6 py-4">Transaction</th>
<th scope="col" class="px-6 py-4">Outstanding</th>
</tr>
</thead>
<tbody>
{% for invoice in invoices %}
<tr class="border-b dark:border-neutral-500">
<td class="whitespace-nowrap px-6 py-4 font-medium">Invoice - {{ invoice.number }}
</td>
<td class="whitespace-nowrap px-6 py-4 font-medium">{{ invoice.date }}</td>
<td class="whitespace-nowrap px-6 py-4 font-medium">{{ invoice.due_date }}</td>
<td class="whitespace-nowrap px-6 py-4 font-medium">{{
invoice.amount_raw|format_currency(invoice.client.currency) }}</td>
<td class="whitespace-nowrap px-6 py-4 font-medium"></td>
<td class="whitespace-nowrap px-6 py-4 font-medium">{{
invoice.balance_raw|format_currency(invoice.client.currency) }}</td>
</tr>
{% for payment in invoice.payments|filter(payment => payment.is_deleted == false) %}
{% for pivot in payment.paymentables %}
<tr class="border-b dark:border-neutral-500">
<td class="whitespace-nowrap px-6 py-4 font-medium">Payment - {{ payment.number }}
</td>
<td class="whitespace-nowrap px-6 py-4 font-medium">{{ payment.date }}</td>
<td class="whitespace-nowrap px-6 py-4 font-medium"></td>
<td class="whitespace-nowrap px-6 py-4 font-medium">
{% if pivot.amount > 0 %}
{{ pivot.amount_raw|format_currency(payment.currency) }} - {{ payment.type.name
}}
{% else %}
({{ pivot.refunded_raw|format_currency(payment.currency) }})
{% endif %}
</td>
<td class="whitespace-nowrap px-6 py-4 font-medium">{{ payment.transaction_reference
}}</td>
<td class="whitespace-nowrap px-6 py-4 font-medium"></td>
</tr>
{% endfor %}
{% endfor %}
{% endfor%}
</tbody>
</table>
</ninja>
<ninja>
{% if aging and show_aging %}
<div id="entity-container" style="break-inside: avoid;">
<table width="100%" cellspacing="0" cellpadding="0" class="">
<thead class="">
<tr class="item-row border-bottom">
{% for key, age in aging %}
<th class="">{{ key }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr class="item-row">
{% for key, age in aging %}
<td class="aging-table">{{ age }}</td>
{% endfor %}
</tr>
</tbody>
</table>
</div>
{% endif %}
</ninja>
</div>
</div>
</div>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<!-- repeating header -->
</td>
</tr>
</tfoot>
</table>
</div>
<div id="footer">
</div>
</body>
</html>