fix the enrollement-carryover balance
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 49s
Tests / PHPUnit (push) Successful in 1m21s

This commit is contained in:
root
2026-09-09 21:40:01 -04:00
parent 2d5b151234
commit 36e8ffe56d
12 changed files with 1365 additions and 39 deletions
+45 -3
View File
@@ -452,6 +452,29 @@ class InvoiceLedgerService
protected function calculateTuitionTotal(array $invoice): float
{
$invoiceId = (int) ($invoice['id'] ?? 0);
if (
$invoiceId > 0
&& $this->invoiceStudentListModel->db->tableExists('invoice_students_list')
&& $this->invoiceStudentListModel->db->fieldExists('tuition_fee', 'invoice_students_list')
) {
$snapshot = $this->invoiceStudentListModel
->select(
'COALESCE(SUM(tuition_fee),0) AS total_amount, '
. 'COALESCE(SUM(CASE WHEN ABS(tuition_fee) > 0 THEN 1 ELSE 0 END),0) AS priced_rows',
false
)
->where('invoice_id', $invoiceId)
->first();
// A priced snapshot is the amount actually issued to the family. It
// intentionally excludes later live configuration changes (including
// book fees that were not part of this invoice).
if ((int) ($snapshot['priced_rows'] ?? 0) > 0) {
return (float) ($snapshot['total_amount'] ?? 0);
}
}
$parentId = (int) ($invoice['parent_id'] ?? 0);
$schoolYear = (string) ($invoice['school_year'] ?? '');
if ($parentId <= 0 || $schoolYear === '') {
@@ -480,11 +503,14 @@ class InvoiceLedgerService
}
}
// InvoiceController enforces one invoice per parent and school year, and
// invoice generation includes the full year's event charges. Keep the
// ledger on that same scope so recalculation cannot drop another term's
// event charges from the invoice total.
$rows = $this->eventChargesModel
->select('COALESCE(SUM(charged),0) AS total_amount')
->where('parent_id', (int) ($invoice['parent_id'] ?? 0))
->where('school_year', (string) ($invoice['school_year'] ?? ''))
->where('semester', (string) ($invoice['semester'] ?? ''))
->findAll();
return (float) ($rows[0]['total_amount'] ?? 0);
@@ -493,12 +519,28 @@ class InvoiceLedgerService
protected function calculateAdditionalCharges(int $invoiceId): float
{
$rows = $this->additionalChargeModel
->select("COALESCE(SUM(CASE WHEN charge_type = 'deduct' THEN -ABS(amount) ELSE ABS(amount) END),0) AS total_amount", false)
->select('charge_type, amount')
->where('invoice_id', $invoiceId)
->where('status', FinancialStatus::ADDITIONAL_CHARGE_APPLIED)
->findAll();
return (float) ($rows[0]['total_amount'] ?? 0);
return array_reduce(
$rows,
static fn (float $sum, array $charge): float => $sum + self::signedAdditionalChargeAmount($charge),
0.0
);
}
public static function signedAdditionalChargeAmount(array $charge): float
{
$amount = (float) ($charge['amount'] ?? 0.0);
if ($amount < 0) {
return $amount;
}
return (string) ($charge['charge_type'] ?? '') === 'deduct'
? -abs($amount)
: $amount;
}
protected function calculateDiscounts(int $invoiceId): float