invoice = $invoice; $this->paidTotal = $paidTotal; } protected function loadInvoice(int $invoiceId): ?array { return $invoiceId === (int) ($this->invoice['id'] ?? 0) ? $this->invoice : null; } protected function calculateTuitionTotal(array $invoice): float { return 0.0; } protected function calculateEventTotal(array $invoice): float { return 0.0; } protected function calculateAdditionalCharges(int $invoiceId): float { return 0.0; } protected function calculateDiscounts(int $invoiceId): float { return 0.0; } protected function calculateValidPayments(int $invoiceId): float { return $this->paidTotal; } protected function calculatePaidRefunds(int $invoiceId): float { return 0.0; } } class InvoiceLedgerServiceTest extends CIUnitTestCase { public function testCarryForwardInvoiceUsesStoredOpeningBalance(): void { $service = new InvoiceLedgerServiceHarness([ 'id' => 10, 'invoice_number' => 'CF-20252026-20262027-P8-I4', 'total_amount' => '90.00', 'semester' => 'Opening Balance', 'description' => 'Balance carried over from previous school year 2025-2026.', ]); $calculation = $service->calculateInvoice(10); $this->assertSame('90.00', $calculation['total_amount']); $this->assertSame('90.00', $calculation['balance']); $this->assertSame(FinancialStatus::INVOICE_UNPAID, $calculation['status']); } public function testCarryForwardInvoiceIsPaidAfterFullPayment(): void { $service = new InvoiceLedgerServiceHarness([ 'id' => 10, 'invoice_number' => 'CF-20252026-20262027-P8-I4', 'total_amount' => '90.00', 'semester' => 'Opening Balance', 'description' => 'Balance carried over from previous school year 2025-2026.', ], 90.0); $calculation = $service->calculateInvoice(10); $this->assertSame('90.00', $calculation['total_amount']); $this->assertSame('0.00', $calculation['balance']); $this->assertSame(FinancialStatus::INVOICE_PAID, $calculation['status']); } }