Merge pull request #6496 from beganovich/v5-statements

(v5) Statements implementation
This commit is contained in:
David Bomba 2021-08-25 09:41:57 +10:00 committed by GitHub
commit 9c11e5fc4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 739 additions and 350 deletions

View File

@ -594,7 +594,7 @@ class CompanySettings extends BaseSettings
*
* @return stdClass The stdClass of PDF variables
*/
private static function getEntityVariableDefaults() :stdClass
public static function getEntityVariableDefaults() :stdClass
{
$variables = [
'client_details' => [
@ -676,6 +676,19 @@ class CompanySettings extends BaseSettings
'$paid_to_date',
'$outstanding',
],
'statement_invoice_columns' => [
'$invoice.number',
'$invoice.date',
'$due_date',
'$total',
'$outstanding',
],
'statement_payment_columns' => [
'$invoice.number',
'$payment.date',
'$method',
'$outstanding',
],
];
return json_decode(json_encode($variables));

View File

@ -521,16 +521,6 @@ class ClientController extends BaseController
return $this->listResponse(Client::withTrashed()->whereIn('id', $this->transformKeys($ids)));
}
/**
* Returns a client statement.
*
* @return void [type] [description]
*/
public function statement()
{
//todo
}
/**
* Update the specified resource in storage.
*

View File

@ -11,31 +11,118 @@
namespace App\Http\Controllers;
/**
* Class ClientStatementController.
*/
use App\Http\Requests\Statements\CreateStatementRequest;
use App\Models\Design;
use App\Models\InvoiceInvitation;
use App\Services\PdfMaker\Design as PdfDesignModel;
use App\Services\PdfMaker\Design as PdfMakerDesign;
use App\Services\PdfMaker\PdfMaker as PdfMakerService;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\HtmlEngine;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Pdf\PdfMaker;
class ClientStatementController extends BaseController
{
use MakesHash, PdfMaker;
/** @var \App\Models\Invoice|\App\Models\Payment */
protected $entity;
public function __construct()
{
parent::__construct();
}
/**
* Displays a client statement view for a given
* client_id.
* @return void
*/
public function show()
public function statement(CreateStatementRequest $request)
{
$pdf = $this->createStatement($request);
if ($pdf) {
return response()->streamDownload(function () use ($pdf) {
echo $pdf;
}, 'statement.pdf', ['Content-Type' => 'application/pdf']);
}
return response()->json(['message' => 'Something went wrong. Please check logs.']);
}
/**
* Updates the show view data dependent on
* configured variables.
* @return void
*/
public function update()
protected function createStatement(CreateStatementRequest $request): ?string
{
$invitation = InvoiceInvitation::first();
if (count($request->getInvoices()) >= 1) {
$this->entity = $request->getInvoices()->first();
}
if (count($request->getPayments()) >= 1) {
$this->entity = $request->getPayments()->first();
}
$entity_design_id = 1;
$entity_design_id = $this->entity->design_id
? $this->entity->design_id
: $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id));
$design = Design::find($entity_design_id);
if (!$design) {
$design = Design::find($entity_design_id);
}
$html = new HtmlEngine($invitation);
$options = [
'start_date' => $request->start_date,
'end_date' => $request->end_date,
'show_payments_table' => $request->show_payments_table,
'show_aging_table' => $request->show_aging_table,
];
if ($design->is_custom) {
$options['custom_partials'] = \json_decode(\json_encode($design->design), true);
$template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options);
} else {
$template = new PdfMakerDesign(strtolower($design->name), $options);
}
$variables = $html->generateLabelsAndValues();
$state = [
'template' => $template->elements([
'client' => $this->entity->client,
'entity' => $this->entity,
'pdf_variables' => (array)$this->entity->company->settings->pdf_variables,
'$product' => $design->design->product,
'variables' => $variables,
'invoices' => $request->getInvoices(),
'payments' => $request->getPayments(),
'aging' => $request->getAging(),
], \App\Services\PdfMaker\Design::STATEMENT),
'variables' => $variables,
'options' => [],
'process_markdown' => $this->entity->client->company->markdown_enabled,
];
$maker = new PdfMakerService($state);
$maker
->design($template)
->build();
$pdf = null;
try {
if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') {
$pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
} else {
$pdf = $this->makePdf(null, null, $maker->getCompiledHTML(true));
}
} catch (\Exception $e) {
nlog(print_r($e->getMessage(), 1));
}
return $pdf;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\Http\Requests\Statements;
use App\Models\Invoice;
use App\Models\Payment;
use Illuminate\Foundation\Http\FormRequest;
class CreateStatementRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(): bool
{
return auth()->user()->isAdmin();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'start_date' => ['required'],
'end_date' => ['required'],
];
}
/**
* The collection of invoices for the statement.
*
* @return Invoice[]|\Illuminate\Database\Eloquent\Collection
*/
public function getInvoices()
{
// $this->request->start_date & $this->request->end_date are available.
return Invoice::all();
}
/**
* The collection of payments for the statement.
*
* @return Payment[]|\Illuminate\Database\Eloquent\Collection
*/
public function getPayments()
{
// $this->request->start_date & $this->request->end_date are available.
return Payment::all();
}
/**
* The array of aging data.
*/
public function getAging(): array
{
return [
'0-30' => 1000,
'30-60' => 2000,
'60-90' => 3000,
'90-120' => 4000,
'120+' => 5000,
];
}
}

View File

@ -13,17 +13,21 @@
namespace App\Services\PdfMaker;
use App\Models\Credit;
use App\Models\GatewayType;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Quote;
use App\Services\PdfMaker\Designs\Utilities\BaseDesign;
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
use App\Utils\Number;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesInvoiceValues;
use DOMDocument;
use Illuminate\Support\Str;
class Design extends BaseDesign
{
use MakesInvoiceValues, DesignHelpers;
use MakesInvoiceValues, DesignHelpers, MakesDates;
/** @var App\Models\Invoice || @var App\Models\Quote */
public $entity;
@ -43,6 +47,15 @@ class Design extends BaseDesign
/** Construct options */
public $options;
/** @var Invoice[] */
public $invoices;
/** @var Payment[] */
public $payments;
/** @var array */
public $aging = [];
const BOLD = 'bold';
const BUSINESS = 'business';
const CLEAN = 'clean';
@ -54,6 +67,9 @@ class Design extends BaseDesign
const PLAYFUL = 'playful';
const CUSTOM = 'custom';
const DELIVERY_NOTE = 'delivery_note';
const STATEMENT = 'statement';
public function __construct(string $design = null, array $options = [])
{
Str::endsWith('.html', $design) ? $this->design = $design : $this->design = "{$design}.html";
@ -69,9 +85,7 @@ class Design extends BaseDesign
);
}
$path = isset($this->options['custom_path'])
? $this->options['custom_path']
: config('ninja.designs.base_path');
$path = $this->options['custom_path'] ?? config('ninja.designs.base_path');
return file_get_contents(
$path . $this->design
@ -115,6 +129,26 @@ class Design extends BaseDesign
'id' => 'task-table',
'elements' => $this->taskTable(),
],
'statement-invoice-table' => [
'id' => 'statement-invoice-table',
'elements' => $this->statementInvoiceTable(),
],
'statement-invoice-table-totals' => [
'id' => 'statement-invoice-table-totals',
'elements' => $this->statementInvoiceTableTotals(),
],
'statement-payment-table' => [
'id' => 'statement-payment-table',
'elements' => $this->statementPaymentTable(),
],
'statement-payment-table-totals' => [
'id' => 'statement-payment-table-totals',
'elements' => $this->statementPaymentTableTotals(),
],
'statement-aging-table' => [
'id' => 'statement-aging-table',
'elements' => $this->statementAgingTable(),
],
'table-totals' => [
'id' => 'table-totals',
'elements' => $this->tableTotals(),
@ -158,7 +192,7 @@ class Design extends BaseDesign
{
$elements = [];
if ($this->type == 'delivery_note') {
if ($this->type == self::DELIVERY_NOTE) {
$elements = [
['element' => 'p', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']],
['element' => 'p', 'content' => $this->entity->client->name, 'show_empty' => false, 'properties' => ['data-ref' => 'delivery_note-client.name']],
@ -190,6 +224,19 @@ class Design extends BaseDesign
public function entityDetails(): array
{
if ($this->type === 'statement') {
return [
['element' => 'tr', 'properties' => [], 'elements' => [
['element' => 'th', 'properties' => [], 'content' => ctrans('texts.statement_date')],
['element' => 'th', 'properties' => [], 'content' => $this->options['end_date'] ?? ''],
]],
['element' => 'tr', 'properties' => [], 'elements' => [
['element' => 'th', 'properties' => [], 'content' => '$balance_due_label'],
['element' => 'th', 'properties' => [], 'content' => '$balance_due'],
]],
];
}
$variables = $this->context['pdf_variables']['invoice_details'];
if ($this->entity instanceof Quote) {
@ -203,7 +250,7 @@ class Design extends BaseDesign
$elements = [];
// We don't want to show account balance or invoice total on PDF.. or any amount with currency.
if ($this->type == 'delivery_note') {
if ($this->type == self::DELIVERY_NOTE) {
$variables = array_filter($variables, function ($m) {
return !in_array($m, ['$invoice.balance_due', '$invoice.total']);
});
@ -231,7 +278,7 @@ class Design extends BaseDesign
public function deliveryNoteTable(): array
{
if ($this->type !== 'delivery_note') {
if ($this->type !== self::DELIVERY_NOTE) {
return [];
}
@ -241,7 +288,7 @@ class Design extends BaseDesign
['element' => 'th', 'content' => '$description_label', 'properties' => ['data-ref' => 'delivery_note-description_label']],
['element' => 'th', 'content' => '$product.quantity_label', 'properties' => ['data-ref' => 'delivery_note-product.quantity_label']],
]],
['element' => 'tbody', 'elements' => $this->buildTableBody('delivery_note')],
['element' => 'tbody', 'elements' => $this->buildTableBody(self::DELIVERY_NOTE)],
];
}
@ -260,7 +307,7 @@ class Design extends BaseDesign
return [];
}
if ($this->type == 'delivery_note') {
if ($this->type === self::DELIVERY_NOTE || $this->type === self::STATEMENT) {
return [];
}
@ -285,7 +332,7 @@ class Design extends BaseDesign
return [];
}
if ($this->type == 'delivery_note') {
if ($this->type === self::DELIVERY_NOTE || $this->type === self::STATEMENT) {
return [];
}
@ -295,6 +342,120 @@ class Design extends BaseDesign
];
}
/**
* Parent method for building invoices table within statement.
*
* @return array
*/
public function statementInvoiceTable(): array
{
if (is_null($this->invoices) || $this->type !== self::STATEMENT) {
return [];
}
$tbody = [];
foreach ($this->invoices as $invoice) {
$element = ['element' => 'tr', 'elements' => []];
$element['elements'][] = ['element' => 'td', 'content' => $invoice->number];
$element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()) ?: '&nbsp;'];
$element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($invoice->due_date, $invoice->client->date_format(), $invoice->client->locale()) ?: '&nbsp;'];
$element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->calc()->getTotal(), $invoice->client) ?: '&nbsp;'];
$element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($invoice->partial, $invoice->client) ?: '&nbsp;'];
$tbody[] = $element;
}
return [
['element' => 'thead', 'elements' => $this->buildTableHeader('statement_invoice')],
['element' => 'tbody', 'elements' => $tbody],
];
}
public function statementInvoiceTableTotals(): array
{
if ($this->type !== self::STATEMENT) {
return [];
}
return [
['element' => 'p', 'content' => '$outstanding_label: $outstanding'],
];
}
/**
* Parent method for building payments table within statement.
*
* @return array
*/
public function statementPaymentTable(): array
{
if (is_null($this->payments) && $this->type !== self::STATEMENT) {
return [];
}
if (\array_key_exists('show_payment_table', $this->options) && $this->options['show_payment_table'] === false) {
return [];
}
$tbody = [];
foreach ($this->payments as $payment) {
foreach ($payment->invoices as $invoice) {
$element = ['element' => 'tr', 'elements' => []];
$element['elements'][] = ['element' => 'td', 'content' => $invoice->number];
$element['elements'][] = ['element' => 'td', 'content' => $this->translateDate($payment->date, $payment->client->date_format(), $payment->client->locale()) ?: '&nbsp;'];
$element['elements'][] = ['element' => 'td', 'content' => GatewayType::getAlias($payment->gateway_type_id) ?: '&nbsp;'];
$element['elements'][] = ['element' => 'td', 'content' => Number::formatMoney($payment->amount, $payment->client) ?: '&nbsp;'];
$tbody[] = $element;
}
}
return [
['element' => 'thead', 'elements' => $this->buildTableHeader('statement_payment')],
['element' => 'tbody', 'elements' => $tbody],
];
}
public function statementPaymentTableTotals(): array
{
if ($this->type !== self::STATEMENT) {
return [];
}
return [
['element' => 'p', 'content' => \sprintf('%s: %s', ctrans('texts.amount_paid'), 1000)],
];
}
public function statementAgingTable(): array
{
if ($this->type !== self::STATEMENT) {
return [];
}
if (\array_key_exists('show_aging_table', $this->options) && $this->options['show_aging_table'] === false) {
return [];
}
$elements = [
['element' => 'thead', 'elements' => []],
['element' => 'tbody', 'elements' => [
['element' => 'tr', 'elements' => []],
]],
];
foreach ($this->aging as $column => $value) {
$elements[0]['elements'][] = ['element' => 'th', 'content' => $column];
$elements[1]['elements'][] = ['element' => 'td', 'content' => $value];
}
return $elements;
}
/**
* Generate the structure of table headers. (<thead/>)
*
@ -354,7 +515,7 @@ class Design extends BaseDesign
return [];
}
if ($type == 'delivery_note') {
if ($type == self::DELIVERY_NOTE) {
foreach ($items as $row) {
$element = ['element' => 'tr', 'elements' => []];
@ -453,7 +614,7 @@ class Design extends BaseDesign
['element' => 'div', 'properties' => ['class' => 'totals-table-right-side', 'dir' => '$dir'], 'elements' => []],
];
if ($this->type == 'delivery_note') {
if ($this->type == self::DELIVERY_NOTE || $this->type == self::STATEMENT) {
return $elements;
}

View File

@ -28,6 +28,8 @@ trait DesignHelpers
public function setup(): self
{
$this->syncPdfVariables();
if (isset($this->context['client'])) {
$this->client = $this->context['client'];
}
@ -36,11 +38,38 @@ trait DesignHelpers
$this->entity = $this->context['entity'];
}
if (isset($this->context['invoices'])) {
$this->invoices = $this->context['invoices'];
$this->entity = $this->invoices->first();
}
if (isset($this->context['payments'])) {
$this->payments = $this->context['payments'];
}
if (isset($this->context['aging'])) {
$this->aging = $this->context['aging'];
}
$this->document();
return $this;
}
protected function syncPdfVariables(): void
{
$default = (array) \App\DataMapper\CompanySettings::getEntityVariableDefaults();
$variables = $this->context['pdf_variables'];
foreach ($default as $property => $value) {
if (array_key_exists($property, $variables)) {
continue;
}
$variables[$property] = $value;
}
}
/**
* Initialize local dom document instance. Used for getting raw HTML out of template.
*

View File

@ -439,6 +439,9 @@ class HtmlEngine
$data['$dir'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'rtl' : 'ltr', 'label' => ''];
$data['$dir_text_align'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'right' : 'left', 'label' => ''];
$data['$payment.date'] = ['value' => '&nbsp;', 'label' => ctrans('texts.payment_date')];
$data['$method'] = ['value' => '&nbsp;', 'label' => ctrans('texts.method')];
$arrKeysLength = array_map('strlen', array_keys($data));
array_multisort($arrKeysLength, SORT_DESC, $data);

View File

@ -80,9 +80,7 @@
padding-bottom: 0.5rem;
}
#product-table,
#task-table,
#delivery-note-table {
[data-ref="table"] {
min-width: 100%;
table-layout: fixed;
overflow-wrap: break-word;
@ -96,46 +94,32 @@
color: grey;
}
#product-table > thead,
#delivery-note-table > thead,
#task-table > thead {
[data-ref="table"] > thead {
text-align: left;
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
padding: 1.5rem 3rem;
font-size: 1rem;
}
#product-table > thead > tr > th:last-child,
#delivery-note-table > thead > tr > th:last-child,
#task-table > thead > tr > th:last-child {
[data-ref="table"] > thead > tr > th:last-child {
text-align: right;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
padding: 1.5rem 3rem;
}
#product-table > tbody > tr > td:last-child,
#delivery-note-table > tbody > tr > td:last-child,
#task-table > tbody > tr > td:last-child {
[data-ref="table"] > tbody > tr > td:last-child {
text-align: right;
}
#product-table > tbody > tr > td:first-child,
#delivery-note-table > tbody > tr > td:first-child,
#task-table > tbody > tr > td:first-child {
[data-ref="table"] > tbody > tr > td:first-child {
font-weight: bold;
}
#product-table > tbody > tr:nth-child(odd),
#delivery-note-table > tbody > tr:nth-child(odd),
#task-table > tbody > tr:nth-child(odd) {
[data-ref="table"] > tbody > tr:nth-child(odd) {
background-color: #ebebeb;
}
@ -258,6 +242,12 @@
width: 23%;
}
[data-ref="statement-totals"] {
margin-top: 1rem;
text-align: right;
margin-right: .75rem;
}
/** Useful snippets, uncomment to enable. **/
/** Hide company logo **/
@ -318,11 +308,20 @@
</div>
<!-- Start Print Content -->
<table id="product-table" cellspacing="0" class="print-content"></table>
<table id="product-table" cellspacing="0" class="print-content" data-ref="table"></table>
<table id="task-table" cellspacing="0" class="print-content"></table>
<table id="task-table" cellspacing="0" class="print-content" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0" class="print-content"></table>
<table id="delivery-note-table" cellspacing="0" class="print-content" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" class="print-content" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" class="print-content" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" class="print-content" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
<!-- End Print Content -->
</td>
</tr>
@ -350,7 +349,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -93,9 +93,7 @@
text-align: right;
}
#product-table,
#delivery-note-table,
#task-table {
[data-ref="table"] {
margin-top: 3.5rem;
/* margin-bottom: 200px; */
min-width: 100%;
@ -109,55 +107,39 @@
color: grey;
}
#product-table > thead,
#delivery-note-table > thead,
#task-table > thead {
[data-ref="table"] > thead {
text-align: left;
background: var(--secondary-color);
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
padding: 1rem;
color: white;
font-weight: semibold;
}
#product-table > thead > tr > th:first-child,
#delivery-note-table > thead > tr > th:first-child,
#task-table > thead > tr > th:first-child {
[data-ref="table"] > thead > tr > th:first-child {
border-top-left-radius: 1rem;
}
#product-table > thead > tr > th:last-child,
#delivery-note-table > thead > tr > th:last-child,
#task-table > thead > tr > th:last-child {
[data-ref="table"] > thead > tr > th:last-child {
border-top-right-radius: 1rem;
text-align: right;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
padding: 1rem;
}
#product-table > tbody > tr > td:last-child,
#delivery-note-table > tbody > tr > td:last-child,
#task-table > tbody > tr > td:last-child {
[data-ref="table"] > tbody > tr > td:last-child {
text-align: right;
}
#product-table > tbody > tr:nth-child(odd) > td,
#delivery-note-table > tbody > tr:nth-child(odd) > td,
#task-table > tbody > tr:nth-child(odd) > td {
[data-ref="table"] > tbody > tr:nth-child(odd) > td {
background: #F7F7F7;
}
#product-table > tbody > tr:nth-child(even) > td,
#delivery-note-table > tbody > tr:nth-child(even) > td,
#task-table > tbody > tr:nth-child(even) > td {
[data-ref="table"] > tbody > tr:nth-child(even) > td {
background: #f7f7f7;
}
@ -241,9 +223,7 @@
}
/** Markdown-specific styles. **/
#product-table h3,
#task-table h3,
#delivery-note-table h3 {
[data-ref="table"] h3 {
font-size: 1rem;
margin-bottom: 0;
}
@ -257,6 +237,12 @@
padding-right: 7px;
}
[data-ref="statement-totals"] {
margin-top: 1rem;
text-align: right;
margin-right: .75rem;
}
/** Useful snippets, uncomment to enable. **/
/** Hide company logo **/
@ -310,11 +296,20 @@
</div>
</div>
<table id="product-table" cellspacing="0"></table>
<table id="product-table" cellspacing="0" data-ref="table"></table>
<table id="task-table" cellspacing="0"></table>
<table id="task-table" cellspacing="0" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0"></table>
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
<div id="table-totals" cellspacing="0"></div>
</div>
@ -325,7 +320,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -88,9 +88,7 @@
font-weight: bold;
}
#product-table,
#delivery-note-table,
#task-table {
[data-ref="table"] {
margin-top: 3rem;
/* margin-bottom: 200px; */
min-width: 100%;
@ -104,43 +102,31 @@
color: grey;
}
#product-table > thead,
#delivery-note-table > thead,
#task-table > thead {
[data-ref="table"] > thead {
text-align: left;
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
font-size: 1.1rem;
padding-bottom: 1.5rem;
padding-left: 1rem;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
border-top: 1px solid #d8d8d8;
border-bottom: 1px solid #d8d8d8;
padding: 1.5rem;
}
#product-table > tbody > tr > td:first-child,
#delivery-note-table > tbody > tr > td:first-child,
#task-table > tbody > tr > td:first-child {
[data-ref="table"] > tbody > tr > td:first-child {
color: var(--primary-color);
}
#product-table > tbody > tr > td:last-child,
#delivery-note-table > tbody > tr > td:last-child,
#task-table > tbody > tr > td:last-child {
[data-ref="table"] > tbody > tr > td:last-child {
text-align: right;
}
#product-table > tbody > tr:nth-child(odd),
#delivery-note-table > tbody > tr:nth-child(odd),
#task-table > tbody > tr:nth-child(odd) {
[data-ref="table"] > tbody > tr:nth-child(odd) {
background-color: #f5f5f5;
}
@ -215,6 +201,12 @@
justify-content: flex-end;
}
[data-ref="statement-totals"] {
margin-top: 1rem;
text-align: right;
margin-right: .75rem;
}
/** Useful snippets, uncomment to enable. **/
/** Hide company logo **/
@ -266,11 +258,20 @@
<div id="client-details"></div>
</div>
<table id="product-table" cellspacing="0"></table>
<table id="product-table" cellspacing="0" data-ref="table"></table>
<table id="task-table" cellspacing="0"></table>
<table id="task-table" cellspacing="0" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0"></table>
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
<div id="table-totals" cellspacing="0"></div>
</div>
@ -281,7 +282,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -84,18 +84,14 @@
font-weight: normal;
}
#product-table,
#delivery-note-table,
#task-table {
[data-ref="table"] {
/* margin-bottom: 200px; */
min-width: 100%;
table-layout: fixed;
overflow-wrap: break-word;
}
#product-table:not(:empty),
#delivery-note-table:not(:empty),
#task-table:not(:empty) {
[data-ref="table"]:not(:empty) {
border-top: 5px solid var(--primary-color);
margin-top: 3rem;
}
@ -106,40 +102,28 @@
color: grey;
}
#product-table > thead,
#delivery-note-table > thead,
#task-table > thead {
[data-ref="table"] > thead {
text-align: left;
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
font-size: 1.1rem;
padding: 1rem;
}
#product-table > thead > tr > th:last-child,
#delivery-note-table > thead > tr > th:last-child,
#task-table > thead > tr > th:last-child {
[data-ref="table"] > thead > tr > th:last-child {
text-align: right;
}
#product-table > tbody > tr > td:last-child,
#delivery-note-table > tbody > tr > td:last-child,
#task-table > tbody > tr > td:last-child {
[data-ref="table"] > tbody > tr > td:last-child {
text-align: right;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
padding: 1rem;
}
#product-table > tbody > tr:nth-child(odd),
#delivery-note-table > tbody > tr:nth-child(odd),
#task-table > tbody > tr:nth-child(odd) {
[data-ref="table"] > tbody > tr:nth-child(odd) {
background-color: #e8e8e8;
}
@ -201,13 +185,17 @@
}
/** Markdown-specific styles. **/
#product-table h3,
#task-table h3,
#delivery-note-table h3 {
[data-ref="table"] h3 {
font-size: 1rem;
margin-bottom: 0;
}
[data-ref="statement-totals"] {
margin-top: 1rem;
text-align: right;
margin-right: .75rem;
}
/** Useful snippets, uncomment to enable. **/
/** Hide company logo **/
@ -266,11 +254,20 @@
<table id="entity-details" cellspacing="0" dir="$dir"></table>
</div>
<table id="product-table" cellspacing="0"></table>
<table id="product-table" cellspacing="0" data-ref="table"></table>
<table id="task-table" cellspacing="0"></table>
<table id="task-table" cellspacing="0" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0"></table>
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
<div id="table-totals" cellspacing="0"></div>
</div>
@ -281,7 +278,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -86,9 +86,7 @@
font-weight: normal;
}
#product-table,
#delivery-note-table,
#task-table {
[data-ref="table"] {
margin-top: 3rem;
/* margin-bottom: 200px; */
min-width: 100%;
@ -102,15 +100,11 @@
color: grey;
}
#product-table > thead,
#delivery-note-table > thead,
#task-table > thead {
[data-ref="table"] > thead {
text-align: left;
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
font-size: 1.1rem;
padding-bottom: 1.5rem;
padding-left: 1rem;
@ -118,30 +112,21 @@
font-weight: bold;
}
#product-table > thead > tr > th:last-child,
#delivery-note-table > thead > tr > th:last-child,
#task-table > thead > tr > th:last-child {
[data-ref="table"] > thead > tr > th:last-child {
text-align: right;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
border-bottom: 1pt solid;
padding: 1rem;
}
#product-table > tbody > tr:first-child > td,
#delivery-note-table > tbody > tr:first-child > td,
#task-table > tbody > tr:first-child > td {
[data-ref="table"] > tbody > tr:first-child > td {
border-top: 1pt solid !important;
padding: 1rem;
}
#product-table > tbody > tr > td:last-child,
#delivery-note-table > tbody > tr > td:last-child,
#task-table > tbody > tr > td:last-child {
[data-ref="table"] > tbody > tr > td:last-child {
text-align: right;
}
@ -208,13 +193,17 @@
}
/** Markdown-specific styles. **/
#product-table h3,
#task-table h3,
#delivery-note-table h3 {
[data-ref="table"] h3 {
font-size: 1rem;
margin-bottom: 0;
}
[data-ref="statement-totals"] {
margin-top: 1rem;
text-align: right;
margin-right: .75rem;
}
/** Useful snippets, uncomment to enable. **/
/** Hide company logo **/
@ -275,11 +264,20 @@
</div>
</div>
<table id="product-table" cellspacing="0"></table>
<table id="product-table" cellspacing="0" data-ref="table"></table>
<table id="task-table" cellspacing="0"></table>
<table id="task-table" cellspacing="0" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0"></table>
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
<div id="table-totals" cellspacing="0"></div>
</div>
@ -290,7 +288,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -98,9 +98,7 @@
font-weight: bold;
}
#product-table,
#delivery-note-table,
#task-table {
[data-ref="table"] {
margin-top: 3rem;
/* margin-bottom: 200px; */
min-width: 100%;
@ -114,39 +112,29 @@
color: grey;
}
#product-table > thead,
#product-table > thead,
#task-table > thead {
[data-ref="table"] > thead {
text-align: left;
text-transform: uppercase;
font-weight: bold;
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
font-size: 1.1rem;
padding-bottom: 1.5rem;
padding-left: 1rem;
border-left: 1px solid;
}
#product-table > thead > tr > th:last-child,
#delivery-note-table > thead > tr > th:last-child,
#task-table > thead > tr > th:last-child {
[data-ref="table"] > thead > tr > th:last-child {
text-align: right;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
padding: 1rem;
border-left: 1px solid;
}
#product-table > tbody > tr td:last-child,
#delivery-note-table > tbody > tr td:last-child,
#task-table > tbody > tr td:last-child {
[data-ref="table"] > tbody > tr td:last-child {
text-align: right;
}
@ -208,9 +196,7 @@
}
/** Markdown-specific styles. **/
#product-table h3,
#task-table h3,
#delivery-note-table h3 {
[data-ref="table"] h3 {
font-size: 1rem;
margin-bottom: 0;
}
@ -229,6 +215,12 @@
[data-ref="totals_table-outstanding"] { color: var(--primary-color); }
[data-ref="statement-totals"] {
margin-top: 1rem;
text-align: right;
margin-right: .75rem;
}
/** Useful snippets, uncomment to enable. **/
/** Hide company logo **/
@ -315,11 +307,20 @@
</div>
</div>
<table id="product-table" cellspacing="0"></table>
<table id="product-table" cellspacing="0" data-ref="table"></table>
<table id="task-table" cellspacing="0"></table>
<table id="task-table" cellspacing="0" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0"></table>
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
<div id="table-totals" cellspacing="0"></div>
</div>
@ -330,7 +331,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -77,9 +77,7 @@
margin: 3rem 2rem;
}
#product-table,
#delivery-note-table,
#task-table {
[data-ref="table"] {
min-width: 100%;
table-layout: fixed;
overflow-wrap: break-word;
@ -91,49 +89,35 @@
color: grey;
}
#product-table > thead,
#delivery-note-table > thead,
#task-table > thead {
[data-ref="table"] > thead {
text-align: left;
width: 100%;
}
#product-table th + th,
#delivery-note-table th + th,
#task-table th + th {
[data-ref="table"] th + th {
border-left: 2px solid white;
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
padding: 0.8rem;
background-color: var(--secondary-color);
color: white;
}
#product-table > thead > tr > th:last-child,
#delivery-note-table > thead > tr > th:last-child,
#task-table > thead > tr > th:last-child {
[data-ref="table"] > thead > tr > th:last-child {
text-align: right;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
border-bottom: 1px solid var(--secondary-color);
padding: 1rem;
}
#product-table > tbody > tr > td:first-child,
#delivery-note-table > tbody > tr > td:first-child,
#task-table > tbody > tr > td:first-child {
[data-ref="table"] > tbody > tr > td:first-child {
font-weight: bold;
}
#product-table > tbody > tr > td:last-child,
#delivery-note-table > tbody > tr > td:last-child,
#task-table > tbody > tr > td:last-child {
[data-ref="table"] > tbody > tr > td:last-child {
text-align: right;
}
@ -282,6 +266,13 @@
width: 23%;
}
[data-ref="statement-totals"] {
margin-top: 1rem;
margin-bottom: 1rem;
text-align: right;
margin-right: .75rem;
}
/** Useful snippets, uncomment to enable. **/
/** Hide company logo **/
@ -339,9 +330,20 @@
<!-- Start Print Content -->
<div class="table-wrapper">
<table id="product-table" cellspacing="0" class="print-content"></table>
<table id="task-table" cellspacing="0" class="print-content"></table>
<table id="delivery-note-table" cellspacing="0" class="print-content"></table>
<table id="product-table" cellspacing="0" class="print-content" data-ref="table"></table>
<table id="task-table" cellspacing="0" class="print-content" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0" class="print-content" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" class="print-content" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" class="print-content" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" class="print-content" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
</div>
<!-- End Print Content -->
</td>
@ -371,7 +373,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -68,9 +68,7 @@
line-height: var(--line-height);
}
#product-table,
#delivery-note-table,
#task-table {
[data-ref="table"] {
min-width: 100%;
table-layout: fixed;
overflow-wrap: break-word;
@ -84,35 +82,25 @@
color: grey;
}
#product-table > thead,
#delivery-note-table > thead,
#task-table > thead {
[data-ref="table"] > thead {
text-align: left;
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
padding: 1rem;
background-color: #e6e6e6;
}
#product-table > thead > tr > th:last-child,
#delivery-note-table > thead > tr > th:last-child,
#task-table > thead > tr > th:last-child {
[data-ref="table"] > thead > tr > th:last-child {
text-align: right;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
border-bottom: 1px solid #e6e6e6;
padding: 1rem;
}
#product-table > tbody > tr > td:last-child,
#delivery-note-table > tbody > tr > td:last-child,
#task-table > tbody > tr > td:last-child {
[data-ref="table"] > tbody > tr > td:last-child {
text-align: right;
}
@ -179,9 +167,7 @@
}
/** Markdown-specific styles. **/
#product-table h3,
#task-table h3,
#delivery-note-table h3 {
[data-ref="table"] h3 {
font-size: 1rem;
margin-bottom: 0;
}
@ -195,6 +181,12 @@
padding-right: 7px;
}
[data-ref="statement-totals"] {
margin-top: 1rem;
text-align: right;
margin-right: .75rem;
}
/** Useful snippets, uncomment to enable. **/
/** Hide company logo **/
@ -245,11 +237,20 @@
<div id="client-details"></div>
<table id="product-table" cellspacing="0"></table>
<table id="product-table" cellspacing="0" data-ref="table"></table>
<table id="task-table" cellspacing="0"></table>
<table id="task-table" cellspacing="0" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0"></table>
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
<div id="table-totals" cellspacing="0"></div>
</div>
@ -260,7 +261,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -95,9 +95,7 @@
border-bottom: 1px solid var(--primary-color);
}
#product-table,
#delivery-note-table,
#task-table {
[data-ref="table"] {
padding-left: 3rem;
padding-right: 3rem;
margin-top: 3rem;
@ -113,58 +111,42 @@
color: grey;
}
#product-table > thead,
#delivery-note-table > thead,
#task-table > thead {
[data-ref="table"] > thead {
text-align: left;
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
font-size: 1.2rem;
padding: 1rem;
background: var(--primary-color);
color: white;
}
#product-table > thead tr > th:last-child,
#delivery-note-table > thead tr > th:last-child,
#task-table > thead tr > th:last-child {
[data-ref="table"] > thead tr > th:last-child {
text-align: right;
}
#product-table > thead tr > th:first-child,
#delivery-note-table > thead tr > th:first-child,
#task-table > thead tr > th:first-child {
[data-ref="table"] > thead tr > th:first-child {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
#product-table > thead tr > th:last-child,
#delivery-note-table > thead tr > th:last-child,
#task-table > thead tr > th:last-child {
[data-ref="table"] > thead tr > th:last-child {
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
background-color: #F7F7F7;
border-bottom: 1px solid var(--primary-color);
padding: 1rem;
}
#product-table > tbody > tr > td:first-child,
#delivery-note-table > tbody > tr > td:first-child,
#task-table > tbody > tr > td:first-child {
[data-ref="table"] > tbody > tr > td:first-child {
color: var(--primary-color);
}
#product-table > tbody > tr > td:last-child,
#delivery-note-table > tbody > tr > td:last-child,
#task-table > tbody > tr > td:last-child {
[data-ref="table"] > tbody > tr > td:last-child {
text-align: right;
}
@ -246,9 +228,7 @@
}
/** Markdown-specific styles. **/
#product-table h3,
#task-table h3,
#delivery-note-table h3 {
[data-ref="table"] h3 {
font-size: 1rem;
margin-bottom: 0;
}
@ -266,6 +246,13 @@
padding: 10px;
}
[data-ref="statement-totals"] {
margin-top: 1rem;
text-align: right;
padding-left: 3rem;
padding-right: 3rem;
}
/** Useful snippets, uncomment to enable. **/
/** Hide company logo **/
@ -333,11 +320,20 @@
</div>
</div>
<table id="product-table" cellspacing="0"></table>
<table id="product-table" cellspacing="0" data-ref="table"></table>
<table id="task-table" cellspacing="0"></table>
<table id="task-table" cellspacing="0" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0"></table>
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
<div id="table-totals" cellspacing="0"></div>
</div>
@ -359,7 +355,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -122,18 +122,14 @@
.body-wrapper {}
#product-table,
#delivery-note-table,
#task-table {
[data-ref="table"] {
min-width: 100%;
table-layout: fixed;
overflow-wrap: break-word;
margin-top: 3rem;
}
#product-table > thead > tr > th,
#delivery-note-table > thead > tr > th,
#task-table > thead > tr > th {
[data-ref="table"] > thead > tr > th {
text-transform: uppercase;
font-weight: normal;
padding: 1rem;
@ -142,28 +138,20 @@
font-size: 1.1rem;
}
#product-table > thead > tr > th:last-child,
#delivery-note-table > thead > tr > th:last-child,
#task-table > thead > tr > th:last-child {
[data-ref="table"] > thead > tr > th:last-child {
text-align: right;
}
#product-table > tbody > tr > td,
#delivery-note-table > tbody > tr > td,
#task-table > tbody > tr > td {
[data-ref="table"] > tbody > tr > td {
border-bottom: 1px solid #e6e6e6;
padding: 1rem;
}
#product-table > tbody > tr > td:first-child,
#delivery-note-table > tbody > tr > td:first-child,
#task-table > tbody > tr > td:first-child {
[data-ref="table"] > tbody > tr > td:first-child {
color: var(--primary-color);
}
#product-table > tbody > tr > td:last-child,
#delivery-note-table > tbody > tr > td:last-child,
#task-table > tbody > tr > td:last-child {
[data-ref="table"] > tbody > tr > td:last-child {
text-align: right;
}
@ -229,9 +217,7 @@
}
/** Markdown-specific styles. **/
#product-table h3,
#task-table h3,
#delivery-note-table h3 {
[data-ref="table"] h3 {
font-size: 1rem;
margin-bottom: 0;
}
@ -309,11 +295,20 @@
</div>
<div class="body-wrapper">
<table id="product-table" cellspacing="0"></table>
<table id="product-table" cellspacing="0" data-ref="table"></table>
<table id="task-table" cellspacing="0"></table>
<table id="task-table" cellspacing="0" data-ref="table"></table>
<table id="delivery-note-table" cellspacing="0"></table>
<table id="delivery-note-table" cellspacing="0" data-ref="table"></table>
<table id="statement-invoice-table" cellspacing="0" data-ref="table"></table>
<div id="statement-invoice-table-totals" data-ref="statement-totals"></div>
<table id="statement-payment-table" cellspacing="0" data-ref="table"></table>
<div id="statement-payment-table-totals" data-ref="statement-totals"></div>
<table id="statement-aging-table" cellspacing="0" data-ref="table"></table>
<div id="statement-aging-table-totals" data-ref="statement-totals"></div>
<div id="table-totals" cellspacing="0"></div>
</div>
@ -325,7 +320,12 @@
<script>
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
document.addEventListener('DOMContentLoaded', () => {
['product-table', 'task-table', 'delivery-note-table'].forEach((tableIdentifier) => {
let tables = [
'product-table', 'task-table', 'delivery-note-table',
'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
];
tables.forEach((tableIdentifier) => {
document.getElementById(tableIdentifier).childElementCount === 0
? document.getElementById(tableIdentifier).style.display = 'none'
: '';

View File

@ -43,7 +43,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
Route::post('connected_account', 'ConnectedAccountController@index');
Route::post('connected_account/gmail', 'ConnectedAccountController@handleGmailOauth');
Route::resource('client_statement', 'ClientStatementController@statement'); // name = (client_statement. index / create / show / update / destroy / edit
Route::post('client_statement', 'ClientStatementController@statement')->name('client.statement');
Route::post('companies/purge/{company}', 'MigrationController@purgeCompany')->middleware('password_protected');
Route::post('companies/purge_save_settings/{company}', 'MigrationController@purgeCompanySaveSettings')->middleware('password_protected');