Invoice report improvements to include tax breakdowns per invoice

This commit is contained in:
David Bomba 2025-04-11 11:00:17 +10:00
parent 0a98b75b26
commit 5d3d0c24de
4 changed files with 77 additions and 11 deletions

View File

@ -39,6 +39,7 @@ use App\Transformers\TaskTransformer;
use App\Transformers\PaymentTransformer;
use Illuminate\Database\Eloquent\Builder;
use League\Fractal\Serializer\ArraySerializer;
use Str;
class BaseExport
{
@ -1367,7 +1368,7 @@ class BaseExport
$header = [];
// nlog("header");
foreach ($this->input['report_keys'] as $value) {
foreach ($this->input['report_keys'] as &$value) {
$key = array_search($value, $this->entity_keys);
$original_key = $key;
@ -1460,7 +1461,11 @@ class BaseExport
$key = str_replace('product.', '', $key);
$key = str_replace('task.', '', $key);
if (stripos($value, 'custom_value') !== false) {
if (stripos($value, 'tax.') !== false) {
$value = Str::after($value, 'tax.');
$header[] = $value;
}
elseif (stripos($value, 'custom_value') !== false) {
$parts = explode(".", $value);
if (count($parts) == 2 && in_array($parts[0], ['credit','quote','invoice','purchase_order','recurring_invoice'])) {

View File

@ -31,6 +31,8 @@ class InvoiceExport extends BaseExport
private Decorator $decorator;
private array $tax_names = [];
public function __construct(Company $company, array $input)
{
$this->company = $company;
@ -119,6 +121,53 @@ class InvoiceExport extends BaseExport
//load the CSV document from a string
$this->csv = Writer::createFromString();
\League\Csv\CharsetConverter::addTo($this->csv, 'UTF-8', 'UTF-8');
if ($tax_amount_position = array_search('invoice.total_taxes', $this->input['report_keys'])) {
$first_part = array_slice($this->input['report_keys'], 0, $tax_amount_position + 1);
$second_part = array_slice($this->input['report_keys'], $tax_amount_position + 1);
$this->tax_names = $query->get()
->flatMap(function ($invoice) {
$taxes = [];
// Invoice level taxes
if (!empty($invoice->tax_name1) && !empty($invoice->tax_rate1)) {
$taxes[] = trim($invoice->tax_name1) . ' ' . \App\Utils\Number::formatValueNoTrailingZeroes(floatval($invoice->tax_rate1), $invoice->client) . '%';
}
if (!empty($invoice->tax_name2) && !empty($invoice->tax_rate2)) {
$taxes[] = trim($invoice->tax_name2) . ' ' . \App\Utils\Number::formatValueNoTrailingZeroes(floatval($invoice->tax_rate2), $invoice->client) . '%';
}
if (!empty($invoice->tax_name3) && !empty($invoice->tax_rate3)) {
$taxes[] = trim($invoice->tax_name3) . ' ' . \App\Utils\Number::formatValueNoTrailingZeroes(floatval($invoice->tax_rate3), $invoice->client) . '%';
}
// Line item taxes
$line_taxes = collect($invoice->line_items)->flatMap(function ($item) use($invoice){
$taxes = [];
if (!empty($item->tax_name1) && !empty($item->tax_rate1)) {
$taxes[] = trim($item->tax_name1) . ' ' . \App\Utils\Number::formatValueNoTrailingZeroes(floatval($item->tax_rate1), $invoice->client) . '%';
}
if (!empty($item->tax_name2) && !empty($item->tax_rate2)) {
$taxes[] = trim($item->tax_name2) . ' ' . \App\Utils\Number::formatValueNoTrailingZeroes(floatval($item->tax_rate2), $invoice->client) . '%';
}
if (!empty($item->tax_name3) && !empty($item->tax_rate3)) {
$taxes[] = trim($item->tax_name3) . ' ' . \App\Utils\Number::formatValueNoTrailingZeroes(floatval($item->tax_rate3), $invoice->client) . '%';
}
return $taxes;
});
return array_merge($taxes, $line_taxes->toArray());
})
->unique()
->toArray();
foreach ($this->tax_names as $tax_name) {
$labels[] = 'tax.'.$tax_name;
}
$this->input['report_keys'] = array_merge($first_part, $labels, $second_part);
}
//insert the header
$this->csv->insertOne($this->buildHeader());
@ -145,8 +194,20 @@ class InvoiceExport extends BaseExport
if (is_array($parts) && $parts[0] == 'invoice' && array_key_exists($parts[1], $transformed_invoice)) {
$entity[$key] = $transformed_invoice[$parts[1]];
} else {
$entity[$key] = $this->decorator->transform($key, $invoice);
} elseif($decorated_value = $this->decorator->transform($key, $invoice)) {
$entity[$key] = $decorated_value;
} elseif(count($this->tax_names) > 0) {
$calc = $invoice->calc();
$taxes = $calc->getTaxMap()->merge($calc->getTotalTaxMap())->toArray();
nlog($this->tax_names);
foreach ($this->tax_names as $tax_name) {
$entity[$tax_name] = 0;
}
foreach ($taxes as $tax) {
$entity[$tax['name']] += $tax['total'];
}
}
}

View File

@ -169,10 +169,6 @@ class InvoiceItemExport extends BaseExport
$tmp_key = str_replace("item.", "", $key);
// if ($tmp_key == 'type_id') {
// $tmp_key = 'type';
// }
if ($tmp_key == 'tax_id') {
$tmp_key = 'tax_category';
}

View File

@ -22,7 +22,11 @@ class Decorator implements DecoratorInterface
$index = $this->getKeyPart(0, $key);
$column = $this->getKeyPart(1, $key);
return $this->{$index}()->transform($column, $entity);
if (method_exists($this, $index)) {
return $this->{$index}()->transform($column, $entity);
}
return null;
}
@ -96,10 +100,10 @@ class Decorator implements DecoratorInterface
return new PurchaseOrderDecorator();
}
public function getKeyPart(int $index, string $key): string
public function getKeyPart(int $index, string $key): ?string
{
$parts = explode('.', $key);
return $parts[$index];
return $parts[$index] ?? null;
}
}