Improve ability for adjustments to be made between reporting periods
This commit is contained in:
parent
2903ac539c
commit
0d991036f4
|
|
@ -19,7 +19,7 @@ class TaxSummary
|
||||||
{
|
{
|
||||||
public float $total_taxes; // Tax collected and confirmed (ie. Invoice Paid)
|
public float $total_taxes; // Tax collected and confirmed (ie. Invoice Paid)
|
||||||
public float $total_paid; // Tax pending collection (Outstanding tax of balance owing)
|
public float $total_paid; // Tax pending collection (Outstanding tax of balance owing)
|
||||||
public string $status;
|
public string $status; // updated, deleted, cancelled
|
||||||
public float $adjustment;
|
public float $adjustment;
|
||||||
public function __construct(array $attributes = [])
|
public function __construct(array $attributes = [])
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -137,11 +137,23 @@ class InvoiceTaxSummary implements ShouldQueue
|
||||||
$todayStart = now()->subHours(15)->timestamp;
|
$todayStart = now()->subHours(15)->timestamp;
|
||||||
$todayEnd = now()->endOfDay()->timestamp;
|
$todayEnd = now()->endOfDay()->timestamp;
|
||||||
|
|
||||||
|
// Convert company timezone dates to UTC for database query
|
||||||
|
// $startDate and $endDate are in Y-m-d format (e.g., "2024-01-01")
|
||||||
|
$timezone = $company->timezone()->name ?? 'UTC';
|
||||||
|
$startDateUtc = Carbon::createFromFormat('Y-m-d', $startDate, $timezone)
|
||||||
|
->startOfDay()
|
||||||
|
->setTimezone('UTC')
|
||||||
|
->format('Y-m-d H:i:s');
|
||||||
|
$endDateUtc = Carbon::createFromFormat('Y-m-d', $endDate, $timezone)
|
||||||
|
->endOfDay()
|
||||||
|
->setTimezone('UTC')
|
||||||
|
->format('Y-m-d H:i:s');
|
||||||
|
|
||||||
Invoice::withTrashed()
|
Invoice::withTrashed()
|
||||||
->with('payments')
|
->with('payments',)
|
||||||
->where('company_id', $company->id)
|
->where('company_id', $company->id)
|
||||||
->whereIn('status_id', [2,3,4,5])
|
->whereIn('status_id', [2,3,4,5])
|
||||||
->where('is_deleted', 0)
|
// ->where('is_deleted', 0) I still need to assess deleted invoices, and ensure if there is an entry present, we reverse it!!!
|
||||||
->whereHas('client', function ($query) {
|
->whereHas('client', function ($query) {
|
||||||
$query->where('is_deleted', false);
|
$query->where('is_deleted', false);
|
||||||
})
|
})
|
||||||
|
|
@ -151,12 +163,13 @@ class InvoiceTaxSummary implements ShouldQueue
|
||||||
$q->where('is_flagged', false);
|
$q->where('is_flagged', false);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
->whereBetween('date', [$startDate, $endDate])
|
// ->whereBetween('date', [$startDate, $endDate])
|
||||||
->whereDoesntHave('transaction_events', function ($query) use ($todayStart, $todayEnd) {
|
// ->whereDoesntHave('transaction_events', function ($query) use ($todayStart, $todayEnd) {
|
||||||
$query->where('timestamp', '>=', $todayStart)
|
// $query->where('timestamp', '>=', $todayStart)
|
||||||
->where('timestamp', '<=', $todayEnd)
|
// ->where('timestamp', '<=', $todayEnd)
|
||||||
->where('event_id', TransactionEvent::INVOICE_UPDATED);
|
// ->where('event_id', TransactionEvent::INVOICE_UPDATED);
|
||||||
})
|
// })
|
||||||
|
->whereBetween('updated_at', [$startDateUtc, $endDateUtc])
|
||||||
->cursor()
|
->cursor()
|
||||||
->each(function (Invoice $invoice) {
|
->each(function (Invoice $invoice) {
|
||||||
(new InvoiceTransactionEventEntry())->run($invoice);
|
(new InvoiceTransactionEventEntry())->run($invoice);
|
||||||
|
|
@ -177,10 +190,10 @@ class InvoiceTaxSummary implements ShouldQueue
|
||||||
$q->where('is_flagged', false);
|
$q->where('is_flagged', false);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
->whereHas('payments', function ($query) use ($startDate, $endDate) {
|
->whereHas('payments', function ($query) use ($startDateUtc, $endDateUtc) {
|
||||||
$query->whereHas('paymentables', function ($subQuery) use ($startDate, $endDate) {
|
$query->whereHas('paymentables', function ($subQuery) use ($startDateUtc, $endDateUtc) {
|
||||||
$subQuery->where('paymentable_type', Invoice::class)
|
$subQuery->where('paymentable_type', Invoice::class)
|
||||||
->whereBetween('created_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59']);
|
->whereBetween('created_at', [$startDateUtc, $endDateUtc]);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
->whereDoesntHave('transaction_events', function ($q) use ($todayStart, $todayEnd) {
|
->whereDoesntHave('transaction_events', function ($q) use ($todayStart, $todayEnd) {
|
||||||
|
|
|
||||||
|
|
@ -12,18 +12,11 @@
|
||||||
|
|
||||||
namespace App\Listeners\Invoice;
|
namespace App\Listeners\Invoice;
|
||||||
|
|
||||||
|
use App\Utils\BcMath;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Activity;
|
|
||||||
use App\Models\TransactionEvent;
|
use App\Models\TransactionEvent;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use App\DataMapper\TaxReport\TaxDetail;
|
|
||||||
use App\DataMapper\TaxReport\TaxReport;
|
|
||||||
use App\DataMapper\TaxReport\TaxSummary;
|
|
||||||
use App\Repositories\ActivityRepository;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use App\DataMapper\TransactionEventMetadata;
|
use App\DataMapper\TransactionEventMetadata;
|
||||||
use Illuminate\Queue\Middleware\WithoutOverlapping;
|
|
||||||
|
|
||||||
class InvoiceTransactionEventEntry
|
class InvoiceTransactionEventEntry
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -31,6 +24,8 @@ class InvoiceTransactionEventEntry
|
||||||
|
|
||||||
private float $paid_ratio;
|
private float $paid_ratio;
|
||||||
|
|
||||||
|
private string $entry_type = 'updated';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the event.
|
* Handle the event.
|
||||||
*
|
*
|
||||||
|
|
@ -44,7 +39,37 @@ class InvoiceTransactionEventEntry
|
||||||
|
|
||||||
$this->setPaidRatio($invoice);
|
$this->setPaidRatio($invoice);
|
||||||
|
|
||||||
$period = $force_period ?? now()->endOfMonth()->format('Y-m-d');
|
$event = $invoice->transaction_events()
|
||||||
|
->where('event_id', TransactionEvent::INVOICE_UPDATED)
|
||||||
|
->orderBy('timestamp', 'desc')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
|
||||||
|
if($event){
|
||||||
|
|
||||||
|
$this->entry_type = 'delta';
|
||||||
|
|
||||||
|
if($invoice->is_deleted && $event->metadata->tax_report->tax_summary->status == 'deleted'){
|
||||||
|
// Invoice was previously deleted, and is still deleted... return early!!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(in_array($invoice->status_id,[Invoice::STATUS_CANCELLED]) && $event->metadata->tax_report->tax_summary->status == 'cancelled'){
|
||||||
|
// Invoice was previously cancelled, and is still cancelled... return early!!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!$invoice->is_deleted && $event->metadata->tax_report->tax_summary->status == 'deleted'){
|
||||||
|
//restored invoice must be reported!!!! _do not return early!!
|
||||||
|
$this->entry_type = 'restored';
|
||||||
|
}
|
||||||
|
/** If the invoice hasn't changed its state... return early!! */
|
||||||
|
else if(BcMath::comp($invoice->amount, $event->invoice_amount) == 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Long running tasks may spill over into the next day therefore month!
|
||||||
|
$period = $force_period ?? now()->endOfMonth()->subHours(5)->format('Y-m-d');
|
||||||
|
|
||||||
$this->payments = $invoice->payments->flatMap(function ($payment) {
|
$this->payments = $invoice->payments->flatMap(function ($payment) {
|
||||||
return $payment->invoices()->get()->map(function ($invoice) use ($payment) {
|
return $payment->invoices()->get()->map(function ($invoice) use ($payment) {
|
||||||
|
|
@ -91,6 +116,53 @@ class InvoiceTransactionEventEntry
|
||||||
{
|
{
|
||||||
return round($amount * $this->paid_ratio, 2);
|
return round($amount * $this->paid_ratio, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculateDeltaMetaData
|
||||||
|
*
|
||||||
|
* Calculates the differential between this period and the previous period.
|
||||||
|
*
|
||||||
|
* @param mixed $invoice
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function calculateDeltaMetaData($invoice)
|
||||||
|
{
|
||||||
|
$calc = $invoice->calc();
|
||||||
|
|
||||||
|
$details = [];
|
||||||
|
|
||||||
|
$taxes = array_merge($calc->getTaxMap()->merge($calc->getTotalTaxMap())->toArray());
|
||||||
|
|
||||||
|
$previous_transaction_event = TransactionEvent::where('event_id', TransactionEvent::INVOICE_UPDATED)
|
||||||
|
->where('invoice_id', $invoice->id)
|
||||||
|
->orderBy('timestamp', 'desc')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
foreach ($taxes as $tax) {
|
||||||
|
$tax_detail = [
|
||||||
|
'tax_name' => $tax['name'],
|
||||||
|
'tax_rate' => $tax['tax_rate'],
|
||||||
|
'taxable_amount' => $tax['base_amount'] ?? $calc->getNetSubtotal(),
|
||||||
|
'tax_amount' => $this->calculateRatio($tax['total']),
|
||||||
|
'tax_amount_paid' => $this->calculateRatio($tax['total']),
|
||||||
|
'tax_amount_remaining' => 0,
|
||||||
|
];
|
||||||
|
$details[] = $tax_detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TransactionEventMetadata([
|
||||||
|
'tax_report' => [
|
||||||
|
'tax_details' => $details,
|
||||||
|
'payment_history' => $this->payments->toArray() ?? [], //@phpstan-ignore-line
|
||||||
|
'tax_summary' => [
|
||||||
|
'total_taxes' => $invoice->total_taxes,
|
||||||
|
'total_paid' => $this->getTotalTaxPaid($invoice),
|
||||||
|
'status' => 'updated',
|
||||||
|
'adjustment' => round($invoice->amount - $previous_transaction_event->invoice_amount,2)
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Existing tax details are not deleted, but pending taxes are set to 0
|
* Existing tax details are not deleted, but pending taxes are set to 0
|
||||||
|
|
@ -164,7 +236,7 @@ class InvoiceTransactionEventEntry
|
||||||
'payment_history' => $this->payments->toArray(),
|
'payment_history' => $this->payments->toArray(),
|
||||||
'tax_summary' => [
|
'tax_summary' => [
|
||||||
'total_taxes' => $invoice->total_taxes,
|
'total_taxes' => $invoice->total_taxes,
|
||||||
'total_paid' => $this->getTotalTaxPaid($invoice),0,
|
'total_paid' => $this->getTotalTaxPaid($invoice),
|
||||||
'status' => 'deleted',
|
'status' => 'deleted',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
@ -179,6 +251,8 @@ class InvoiceTransactionEventEntry
|
||||||
return $this->getCancelledMetaData($invoice);
|
return $this->getCancelledMetaData($invoice);
|
||||||
} elseif ($invoice->is_deleted) {
|
} elseif ($invoice->is_deleted) {
|
||||||
return $this->getDeletedMetaData($invoice);
|
return $this->getDeletedMetaData($invoice);
|
||||||
|
} elseif ($this->entry_type == 'delta') {
|
||||||
|
return $this->calculateDeltaMetaData($invoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
$calc = $invoice->calc();
|
$calc = $invoice->calc();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue