Fixes for rounding

This commit is contained in:
David Bomba 2023-11-14 10:57:02 +11:00
parent d7362c6bbe
commit ea3c5236c6
3 changed files with 159 additions and 50 deletions

View File

@ -633,9 +633,7 @@ class PdfBuilder
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'product_table-product.tax2-td']];
} elseif ($cell == '$product.tax_rate3') {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'product_table-product.tax3-td']];
}
elseif ($cell == '$task.discount' && !$this->service->company->enable_product_discount) {
} elseif ($cell == '$task.discount' && !$this->service->company->enable_product_discount) {
$element['elements'][] = ['element' => 'td', 'content' => $row['$task.discount'], 'properties' => ['data-ref' => 'task_table-task.discount-td', 'style' => 'display: none;']];
} elseif ($cell == '$task.tax_rate1') {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'task_table-task.tax1-td']];
@ -643,10 +641,7 @@ class PdfBuilder
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'task_table-task.tax2-td']];
} elseif ($cell == '$task.tax_rate3') {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => 'task_table-task.tax3-td']];
}
elseif ($cell == '$product.unit_cost' || $cell == '$task.rate') {
} elseif ($cell == '$product.unit_cost' || $cell == '$task.rate') {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['style' => 'white-space: nowrap;', 'data-ref' => "{$_type}_table-" . substr($cell, 1) . '-td']];
} else {
$element['elements'][] = ['element' => 'td', 'content' => $row[$cell], 'properties' => ['data-ref' => "{$_type}_table-" . substr($cell, 1) . '-td']];
@ -712,9 +707,9 @@ class PdfBuilder
$data[$key][$table_type.".{$_table_type}4"] = strlen($item->custom_value4) >= 1 ? $helpers->formatCustomFieldValue($this->service->company->custom_fields, "{$_table_type}4", $item->custom_value4, $this->service->config->currency_entity) : '';
if ($item->quantity > 0 || $item->cost > 0) {
$data[$key][$table_type.'.quantity'] = $item->quantity;
$data[$key][$table_type.'.quantity'] = $this->service->config->formatValueNoTrailingZeroes($item->quantity);
$data[$key][$table_type.'.unit_cost'] = $this->service->config->formatMoney($item->cost);
$data[$key][$table_type.'.unit_cost'] = $this->service->config->formatMoneyNoRounding($item->cost);
$data[$key][$table_type.'.cost'] = $this->service->config->formatMoney($item->cost);
@ -820,9 +815,7 @@ class PdfBuilder
$elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-product.tax2-th", 'hidden' => $this->service->config->settings->hide_empty_columns_on_pdf]];
} elseif ($column == '$product.tax_rate3') {
$elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-product.tax3-th", 'hidden' => $this->service->config->settings->hide_empty_columns_on_pdf]];
}
elseif ($column == '$task.discount' && !$this->service->company->enable_product_discount) {
} elseif ($column == '$task.discount' && !$this->service->company->enable_product_discount) {
$elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-" . substr($column, 1) . '-th', 'style' => 'display: none;']];
} elseif ($column == '$task.tax_rate1') {
$elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-task.tax1-th", 'hidden' => $this->service->config->settings->hide_empty_columns_on_pdf]];
@ -830,9 +823,7 @@ class PdfBuilder
$elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-task.tax2-th", 'hidden' => $this->service->config->settings->hide_empty_columns_on_pdf]];
} elseif ($column == '$task.tax_rate3') {
$elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-task.tax3-th", 'hidden' => $this->service->config->settings->hide_empty_columns_on_pdf]];
}
else {
} else {
$elements[] = ['element' => 'th', 'content' => $column . '_label', 'properties' => ['data-ref' => "{$type}_table-" . substr($column, 1) . '-th', 'hidden' => $this->service->config->settings->hide_empty_columns_on_pdf]];
}
}

View File

@ -330,6 +330,125 @@ class PdfConfiguration
}
}
/**
* Formats a given value based on the clients currency.
*
* @param float $value The number to be formatted
*
* @return string The formatted value
*/
public function formatValueNoTrailingZeroes($value) :string
{
$value = floatval($value);
$thousand = $this->currency->thousand_separator;
$decimal = $this->currency->decimal_separator;
/* Country settings override client settings */
if (isset($this->country->thousand_separator) && strlen($this->country->thousand_separator) >= 1) {
$thousand = $this->country->thousand_separator;
}
if (isset($this->country->decimal_separator) && strlen($this->country->decimal_separator) >= 1) {
$decimal = $this->country->decimal_separator;
}
$precision = 10;
return rtrim(rtrim(number_format($value, $precision, $decimal, $thousand), '0'), $decimal);
}
/**
* Formats a given value based on the clients currency AND country.
*
* @param float $value The number to be formatted
* @return string The formatted value
*/
public function formatMoneyNoRounding($value) :string
{
$_value = $value;
$thousand = $this->currency->thousand_separator;
$decimal = $this->currency->decimal_separator;
$precision = $this->currency->precision;
$code = $this->currency->code;
$swapSymbol = $this->currency->swap_currency_symbol;
/* Country settings override client settings */
if (isset($this->country->thousand_separator) && strlen($this->country->thousand_separator) >= 1) {
$thousand = $this->country->thousand_separator;
}
if (isset($this->country->decimal_separator) && strlen($this->country->decimal_separator) >= 1) {
$decimal = $this->country->decimal_separator;
}
if (isset($this->country->swap_currency_symbol) && strlen($this->country->swap_currency_symbol) >= 1) {
$swapSymbol = $this->country->swap_currency_symbol;
}
/* 08-01-2022 allow increased precision for unit price*/
$v = rtrim(sprintf('%f', $value), '0');
$parts = explode('.', $v);
/* 08-02-2023 special if block to render $0.5 to $0.50*/
if ($v < 1 && strlen($v) == 3) {
$precision = 2;
} elseif ($v < 1) {
$precision = strlen($v) - strrpos($v, '.') - 1;
}
if (is_array($parts) && $parts[0] != 0) {
$precision = 2;
}
//04-04-2023 if currency = JPY override precision to 0
if($this->currency->code == 'JPY') {
$precision = 0;
}
$value = number_format($v, $precision, $decimal, $thousand);
$symbol = $this->currency->symbol;
if ($this->settings->show_currency_code === true && $this->currency->code == 'CHF') {
return "{$code} {$value}";
} elseif ($this->settings->show_currency_code === true) {
return "{$value} {$code}";
} elseif ($swapSymbol) {
return "{$value} ".trim($symbol);
} elseif ($this->settings->show_currency_code === false) {
if ($_value < 0) {
$value = substr($value, 1);
$symbol = "-{$symbol}";
}
return "{$symbol}{$value}";
} else {
return $this->formatValue($value);
}
}
/**
* Formats a given value based on the clients currency.
*
* @param float $value The number to be formatted
*
* @return string The formatted value
*/
public function formatValue($value) :string
{
$value = floatval($value);
$thousand = $this->currency->thousand_separator;
$decimal = $this->currency->decimal_separator;
$precision = $this->currency->precision;
return number_format($value, $precision, $decimal, $thousand);
}
/**
* date_format
*

View File

@ -11,35 +11,31 @@
namespace App\Services\Template;
use Twig\TwigFilter;
use App\Models\Quote;
use App\Utils\Number;
use Twig\Environment;
use Twig\Error\Error;
use App\Models\Client;
use App\Models\Company;
use App\Models\Credit;
use App\Models\Design;
use App\Models\Vendor;
use Twig\TwigFunction;
use App\Models\Company;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Project;
use App\Utils\HtmlEngine;
use Twig\Error\LoaderError;
use Twig\Error\SyntaxError;
use Twig\Error\RuntimeError;
use App\Models\PurchaseOrder;
use App\Utils\VendorHtmlEngine;
use Twig\Sandbox\SecurityError;
use App\Models\Quote;
use App\Models\RecurringInvoice;
use App\Models\Vendor;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\HtmlEngine;
use App\Utils\Number;
use App\Utils\PaymentHtmlEngine;
use App\Utils\Traits\MakesDates;
use App\Utils\HostedPDF\NinjaPdf;
use Twig\Loader\FilesystemLoader;
use App\Utils\Traits\Pdf\PdfMaker;
use Twig\Extra\Intl\IntlExtension;
use App\Utils\VendorHtmlEngine;
use League\CommonMark\CommonMarkConverter;
use Twig\Error\Error;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Extra\Intl\IntlExtension;
use Twig\Sandbox\SecurityError;
class TemplateService
{
@ -88,8 +84,9 @@ class TemplateService
$this->document = new \DOMDocument();
$this->document->validateOnParse = true;
$loader = new FilesystemLoader(storage_path());
$this->twig = new Environment($loader, [
$loader = new \Twig\Loader\FilesystemLoader(storage_path());
$this->twig = new \Twig\Environment($loader, [
'debug' => true,
]);
$string_extension = new \Twig\Extension\StringLoaderExtension();
@ -97,8 +94,8 @@ class TemplateService
$this->twig->addExtension(new IntlExtension());
$this->twig->addExtension(new \Twig\Extension\DebugExtension());
$function = new TwigFunction('img', function ($string, $style = '') {
return '<img src="'.$string.'" style="'.$style.'"></img>';
$function = new \Twig\TwigFunction('img', function ($string, $style = '') {
return '<img src="' . $string . '" style="' . $style . '"></img>';
});
$this->twig->addFunction($function);
@ -236,16 +233,16 @@ class TemplateService
$template = $this->twig->createTemplate(html_entity_decode($template));
} catch(SyntaxError $e) {
nlog($e->getMessage());
continue;
throw ($e);
} catch(Error $e) {
nlog("error = " .$e->getMessage());
continue;
nlog("error = " . $e->getMessage());
throw ($e);
} catch(RuntimeError $e) {
nlog("runtime = " .$e->getMessage());
continue;
nlog("runtime = " . $e->getMessage());
throw ($e);
} catch(LoaderError $e) {
nlog("loader = " . $e->getMessage());
continue;
throw ($e);
} catch(SecurityError $e) {
nlog("security = " . $e->getMessage());
throw ($e);
@ -281,7 +278,6 @@ class TemplateService
$html = $this->getHtml();
foreach($this->variables as $key => $variable) {
if(isset($variable['labels']) && isset($variable['values'])) {
$html = strtr($html, $variable['labels']);
$html = strtr($html, $variable['values']);
@ -363,7 +359,7 @@ class TemplateService
$processed = [];
if(in_array($key, ['tasks','projects','aging']) || !$value->first()) {
if(in_array($key, ['tasks', 'projects', 'aging']) || !$value->first()) {
return $processed;
}
@ -428,6 +424,7 @@ class TemplateService
->map(function ($invoice) {
$payments = [];
$this->entity = $invoice;
if($invoice->payments ?? false) {
$payments = $invoice->payments->map(function ($payment) {
@ -438,6 +435,8 @@ class TemplateService
return [
'amount' => Number::formatMoney($invoice->amount, $invoice->client),
'balance' => Number::formatMoney($invoice->balance, $invoice->client),
'status_id' => $invoice->status_id,
'status' => Invoice::stringStatus($invoice->status_id),
'balance_raw' => $invoice->balance,
'number' => $invoice->number ?: '',
'discount' => $invoice->discount,
@ -475,7 +474,7 @@ class TemplateService
'custom_surcharge_tax2' => (bool) $invoice->custom_surcharge_tax2,
'custom_surcharge_tax3' => (bool) $invoice->custom_surcharge_tax3,
'custom_surcharge_tax4' => (bool) $invoice->custom_surcharge_tax4,
'line_items' => $invoice->line_items ? $this->padLineItems($invoice->line_items, $invoice->client): (array) [],
'line_items' => $invoice->line_items ? $this->padLineItems($invoice->line_items, $invoice->client) : (array) [],
'reminder1_sent' => $this->translateDate($invoice->reminder1_sent, $invoice->client->date_format(), $invoice->client->locale()),
'reminder2_sent' => $this->translateDate($invoice->reminder2_sent, $invoice->client->date_format(), $invoice->client->locale()),
'reminder3_sent' => $this->translateDate($invoice->reminder3_sent, $invoice->client->date_format(), $invoice->client->locale()),
@ -791,7 +790,7 @@ class TemplateService
'custom_surcharge_tax2' => (bool) $credit->custom_surcharge_tax2,
'custom_surcharge_tax3' => (bool) $credit->custom_surcharge_tax3,
'custom_surcharge_tax4' => (bool) $credit->custom_surcharge_tax4,
'line_items' => $credit->line_items ? $this->padLineItems($credit->line_items, $credit->client): (array) [],
'line_items' => $credit->line_items ? $this->padLineItems($credit->line_items, $credit->client) : (array) [],
'reminder1_sent' => $this->translateDate($credit->reminder1_sent, $credit->client->date_format(), $credit->client->locale()),
'reminder2_sent' => $this->translateDate($credit->reminder2_sent, $credit->client->date_format(), $credit->client->locale()),
'reminder3_sent' => $this->translateDate($credit->reminder3_sent, $credit->client->date_format(), $credit->client->locale()),