Tax Reporting

This commit is contained in:
David Bomba 2025-11-18 14:31:13 +11:00
parent 392a7c7736
commit 226c881eef
4 changed files with 141 additions and 24 deletions

View File

@ -17,6 +17,7 @@ namespace App\DataMapper\TaxReport;
*/
class TaxSummary
{
public float $taxable_amount;
public float $total_taxes; // Tax collected and confirmed (ie. Invoice Paid)
public float $total_paid; // Tax pending collection (Outstanding tax of balance owing)
public string $status; // updated, deleted, cancelled, adjustment
@ -25,6 +26,7 @@ class TaxSummary
public function __construct(array $attributes = [])
{
$this->taxable_amount = $attributes['taxable_amount'] ?? 0.0;
$this->total_taxes = $attributes['total_taxes'] ?? 0.0;
$this->total_paid = $attributes['total_paid'] ?? 0.0;
$this->status = $attributes['status'] ?? 'updated';
@ -35,6 +37,7 @@ class TaxSummary
public function toArray(): array
{
return [
'taxable_amount' => $this->taxable_amount,
'total_taxes' => $this->total_taxes,
'total_paid' => $this->total_paid,
'status' => $this->status,

View File

@ -129,6 +129,8 @@ class InvoiceTransactionEventEntry
*/
private function calculateDeltaMetaData($invoice)
{
$this->paid_ratio = 1;
$calc = $invoice->calc();
$details = [];
@ -144,7 +146,7 @@ class InvoiceTransactionEventEntry
$previous_tax_details = $previous_transaction_event->metadata->tax_report->tax_details;
foreach ($taxes as $tax) {
$previousLine = $previous_tax_details[$tax['name']] ?? null;
$previousLine = collect($previous_tax_details)->where('tax_name', $tax['name'])->first() ?? null;
$tax_detail = [
'tax_name' => $tax['name'],
@ -153,28 +155,32 @@ class InvoiceTransactionEventEntry
'tax_amount' => $this->calculateRatio($tax['total']),
'tax_amount_paid' => $this->calculateRatio($tax['total']),
'tax_amount_remaining' => 0,
'taxable_amount_adjustment' => ($tax['base_amount'] ?? $calc->getNetSubtotal()) - ($previousLine['taxable_amount'] ?? 0),
'tax_amount_adjustment' => $this->calculateRatio($tax['total']) - ($previousLine['tax_amount'] ?? 0),
'tax_amount_paid_adjustment' => $this->calculateRatio($tax['total']) - ($previousLine['tax_amount_paid'] ?? 0),
'taxable_amount_adjustment' => ($tax['base_amount'] ?? $calc->getNetSubtotal()) - ($previousLine->taxable_amount ?? 0),
'tax_amount_adjustment' => $tax['total'] - ($previousLine->tax_amount ?? 0),
'tax_amount_paid_adjustment' => $this->calculateRatio($tax['total']) - ($previousLine->tax_amount_paid ?? 0),
'tax_amount_remaining_adjustment' => 0,
];
$details[] = $tax_detail;
}
$this->setPaidRatio($invoice);
return new TransactionEventMetadata([
'tax_report' => [
'tax_details' => $details,
'payment_history' => $this->payments->toArray() ?? [], //@phpstan-ignore-line
'tax_summary' => [
'total_taxes' => $invoice->total_taxes,
'taxable_amount' => $calc->getNetSubtotal(),
'total_taxes' => $calc->getTotalTaxes(),
'total_paid' => $this->getTotalTaxPaid($invoice),
'status' => 'delta',
'adjustment' => round($invoice->amount - $previous_transaction_event->invoice_amount, 2),
'tax_adjustment' => round($invoice->total_taxes - $previous_transaction_event->metadata->tax_report->tax_summary->total_taxes,2)
'adjustment' => round($calc->getNetSubtotal() - $previous_transaction_event->metadata->tax_report->tax_summary->taxable_amount, 2),
'tax_adjustment' => round($calc->getTotalTaxes() - $previous_transaction_event->metadata->tax_report->tax_summary->total_taxes,2)
],
],
]);
}
/**
@ -203,14 +209,18 @@ class InvoiceTransactionEventEntry
$details[] = $tax_detail;
}
//@todo what happens if this is triggered in the "NEXT FINANCIAL PERIOD?
return new TransactionEventMetadata([
'tax_report' => [
'tax_details' => $details,
'payment_history' => $this->payments->toArray() ?? [], //@phpstan-ignore-line
'tax_summary' => [
'total_taxes' => $invoice->total_taxes,
'taxable_amount' => $calc->getNetSubtotal(),
'total_taxes' => $calc->getTotalTaxes(),
'total_paid' => $this->getTotalTaxPaid($invoice),
'status' => 'cancelled',
// 'adjustment' => round($calc->getNetSubtotal() - $previous_transaction_event->metadata->tax_report->tax_summary->taxable_amount, 2),
// 'tax_adjustment' => round($calc->getTotalTaxes() - $previous_transaction_event->metadata->tax_report->tax_summary->total_taxes,2)
],
],
]);
@ -248,7 +258,8 @@ class InvoiceTransactionEventEntry
'tax_details' => $details,
'payment_history' => $this->payments->toArray(),
'tax_summary' => [
'total_taxes' => $invoice->total_taxes,
'taxable_amount' => $calc->getNetSubtotal(),
'total_taxes' => $calc->getTotalTaxes(),
'total_paid' => $this->getTotalTaxPaid($invoice),
'status' => 'deleted',
],
@ -291,7 +302,8 @@ class InvoiceTransactionEventEntry
'tax_details' => $details,
'payment_history' => $this->payments->toArray(),
'tax_summary' => [
'total_taxes' => $invoice->total_taxes,
'taxable_amount' => $calc->getNetSubtotal(),
'total_taxes' => $calc->getTotalTaxes(),
'total_paid' => $this->getTotalTaxPaid($invoice),
'status' => 'updated',
],

View File

@ -22,25 +22,25 @@ use App\DataMapper\TransactionEventMetadata;
* @property int $invoice_id
* @property int $payment_id
* @property int $credit_id
* @property string $client_balance
* @property string $client_paid_to_date
* @property string $client_credit_balance
* @property string $invoice_balance
* @property string $invoice_amount
* @property string $invoice_partial
* @property string $invoice_paid_to_date
* @property float $client_balance
* @property float $client_paid_to_date
* @property float $client_credit_balance
* @property float $invoice_balance
* @property float $invoice_amount
* @property float $invoice_partial
* @property float $invoice_paid_to_date
* @property int|null $invoice_status
* @property string $payment_amount
* @property string $payment_applied
* @property string $payment_refunded
* @property float $payment_amount
* @property float $payment_applied
* @property float $payment_refunded
* @property int|null $payment_status
* @property array|null $paymentables
* @property int $event_id
* @property int $timestamp
* @property array|null $payment_request
* @property TransactionEventMetadata|null $metadata
* @property string $credit_balance
* @property string $credit_amount
* @property float $credit_balance
* @property float $credit_amount
* @property int|null $credit_status
* @property Carbon|null $period
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel company()

View File

@ -199,6 +199,7 @@ class TaxPeriodReportTest extends TestCase
$transaction_event = $invoice->transaction_events()->first();
nlog($transaction_event->metadata->toArray());
$this->assertNotNull($transaction_event);
$this->assertEquals(330, $transaction_event->invoice_amount);
$this->assertEquals('2025-10-01', $invoice->date);
@ -248,12 +249,113 @@ class TaxPeriodReportTest extends TestCase
$pl = new TaxPeriodReport($this->company, $payload);
$data = $pl->boot()->getData();
nlog($invoice->transaction_events->toArray());
$this->assertCount(2, $invoice->transaction_events);
$this->assertCount(2, $data['invoices']);
$this->assertCount(2, $data['invoice_items']);
$this->travelBack();
}
/**
* Test that we adjust appropriately across reporting period where an invoice amount has been both
* increased and decreased, and assess that the adjustments are correct.
*
* @return void
*/
public function testInvoiceReportingOverMultiplePeriodsWithAccrualAccountingCheckAdjustments()
{
$this->buildData();
$this->travelTo(\Carbon\Carbon::createFromDate(2025, 10, 1)->startOfDay());
$line_items = [];
$item = InvoiceItemFactory::create();
$item->quantity = 1;
$item->cost = 300;
$item->type_id = 1;
$item->tax_name1 = 'GST';
$item->tax_rate1 = 10;
$line_items[] = $item;
$invoice = Invoice::factory()->create([
'client_id' => $this->client->id,
'company_id' => $this->company->id,
'user_id' => $this->user->id,
'line_items' => $line_items,
'status_id' => Invoice::STATUS_DRAFT,
'discount' => 0,
'is_amount_discount' => false,
'uses_inclusive_taxes' => false,
'tax_name1' => '',
'tax_rate1' => 0,
'tax_name2' => '',
'tax_rate2' => 0,
'tax_name3' => '',
'tax_rate3' => 0,
'custom_surcharge1' => 0,
'custom_surcharge2' => 0,
'custom_surcharge3' => 0,
'custom_surcharge4' => 0,
'date' => now()->format('Y-m-d'),
'due_date' => now()->addDays(30)->format('Y-m-d'),
]);
$invoice = $invoice->calc()->getInvoice();
$invoice->service()->markSent()->createInvitations()->save();
$invoice->fresh();
(new InvoiceTransactionEventEntry())->run($invoice);
$invoice->fresh();
$transaction_event = $invoice->transaction_events()->first();
$this->assertEquals('2025-10-31', $transaction_event->period->format('Y-m-d'));
$this->assertEquals(330, $transaction_event->invoice_amount);
$this->assertEquals(30, $transaction_event->metadata->tax_report->tax_summary->total_taxes);
$this->assertEquals(0, $transaction_event->invoice_paid_to_date);
$this->travelTo(\Carbon\Carbon::createFromDate(2025, 11, 5)->startOfDay());
$line_items = [];
$item = InvoiceItemFactory::create();
$item->quantity = 1;
$item->cost = 400;
$item->type_id = 1;
$item->tax_name1 = 'GST';
$item->tax_rate1 = 10;
$line_items[] = $item;
$invoice->line_items = $line_items;
$invoice = $invoice->calc()->getInvoice();
$invoice->fresh();
(new InvoiceTransactionEventEntry())->run($invoice);
$transaction_event = $invoice->transaction_events()->orderBy('timestamp', 'desc')->first();
nlog($transaction_event->metadata);
$this->assertEquals('2025-11-30', $transaction_event->period->format('Y-m-d'));
$this->assertEquals(440, $transaction_event->invoice_amount);
$this->assertEquals("delta", $transaction_event->metadata->tax_report->tax_summary->status);
$this->assertEquals(40, $transaction_event->metadata->tax_report->tax_summary->total_taxes);
$this->assertEquals(100, $transaction_event->metadata->tax_report->tax_summary->adjustment);
$this->assertEquals(10, $transaction_event->metadata->tax_report->tax_summary->tax_adjustment);
}
public function invoiceReportingOverMultiplePeriodsWithCashAccountingCheckAdjustments()
{
}
}