seedParent(); $otherParentId = $this->seedParent('other@example.com'); DB::table('invoices')->insert([ 'parent_id' => $parentId, 'invoice_number' => 'INV-1', 'total_amount' => 100, 'paid_amount' => 0, 'balance' => 100, 'issue_date' => '2025-09-01', ]); DB::table('invoices')->insert([ 'parent_id' => $otherParentId, 'invoice_number' => 'INV-2', 'total_amount' => 50, 'paid_amount' => 0, 'balance' => 50, 'issue_date' => '2025-09-02', ]); $service = new ParentInvoiceService; $rows = $service->listInvoices($parentId); $this->assertCount(1, $rows); $this->assertSame('INV-1', $rows[0]['invoice_number']); } public function test_list_invoices_derives_payment_totals_from_payments_table(): void { $parentId = $this->seedParent(); $invoiceId = DB::table('invoices')->insertGetId([ 'parent_id' => $parentId, 'invoice_number' => 'INV-PAY', 'total_amount' => 100, 'paid_amount' => 0, 'balance' => 100, 'issue_date' => '2025-09-01', 'due_date' => '2025-10-01', 'status' => 'Unpaid', 'school_year' => '2025-2026', 'semester' => 'Fall', 'created_at' => now(), 'updated_at' => now(), ]); DB::table('payments')->insert([ [ 'parent_id' => $parentId, 'invoice_id' => $invoiceId, 'total_amount' => 100, 'paid_amount' => 40, 'balance' => 60, 'number_of_installments' => 1, 'payment_method' => 'Check', 'payment_date' => '2025-09-15', 'transaction_id' => 'CHK-1', 'status' => 'Paid', 'school_year' => '2025-2026', 'semester' => 'Fall', 'created_at' => now(), 'updated_at' => now(), ], [ 'parent_id' => $parentId, 'invoice_id' => $invoiceId, 'total_amount' => 100, 'paid_amount' => 25, 'balance' => 35, 'number_of_installments' => 1, 'payment_method' => 'Online', 'payment_date' => '2025-09-16', 'transaction_id' => 'PENDING-1', 'status' => 'Pending', 'school_year' => '2025-2026', 'semester' => 'Fall', 'created_at' => now(), 'updated_at' => now(), ], ]); $service = new ParentInvoiceService; $rows = $service->listInvoices($parentId, '2025-2026'); $this->assertCount(1, $rows); $this->assertSame(40.0, $rows[0]['paid_amount']); $this->assertSame(60.0, $rows[0]['balance']); $this->assertSame('Partially Paid', $rows[0]['status']); $this->assertCount(1, $rows[0]['payments']); $this->assertSame('CHK-1', $rows[0]['payments'][0]['transaction_id']); } public function test_list_invoices_applies_discounts_to_balance(): void { $parentId = $this->seedParent(); $invoiceId = DB::table('invoices')->insertGetId([ 'parent_id' => $parentId, 'invoice_number' => 'INV-DISCOUNT', 'total_amount' => 380, 'paid_amount' => 10, 'balance' => 370, 'has_discount' => 1, 'issue_date' => '2025-09-06', 'due_date' => '2025-09-21', 'status' => 'Paid', 'school_year' => '2025-2026', 'semester' => 'Fall', 'created_at' => now(), 'updated_at' => now(), ]); DB::table('payments')->insert([ 'parent_id' => $parentId, 'invoice_id' => $invoiceId, 'total_amount' => 380, 'paid_amount' => 10, 'balance' => 370, 'number_of_installments' => 1, 'payment_method' => 'Cash', 'payment_date' => '2025-09-10', 'status' => 'Paid', 'school_year' => '2025-2026', 'semester' => 'Fall', 'created_at' => now(), 'updated_at' => now(), ]); DB::table('discount_usages')->insert([ 'voucher_id' => 1, 'parent_id' => $parentId, 'invoice_id' => $invoiceId, 'discount_amount' => 370, 'description' => 'Tuition discount', 'school_year' => '2025-2026', 'semester' => 'Fall', ]); $service = new ParentInvoiceService; $rows = $service->listInvoices($parentId, '2025-2026'); $this->assertSame(10.0, $rows[0]['paid_amount']); $this->assertSame(370.0, $rows[0]['discount']); $this->assertSame(0.0, $rows[0]['balance']); $this->assertSame('Paid', $rows[0]['status']); } public function test_statement_derives_current_balance_from_computed_invoice_lines(): void { $parentId = $this->seedParent(); $invoiceId = DB::table('invoices')->insertGetId([ 'parent_id' => $parentId, 'invoice_number' => 'INV-STMT-DISCOUNT', 'total_amount' => 380, 'paid_amount' => 10, 'balance' => 370, 'has_discount' => 1, 'issue_date' => '2025-09-06', 'due_date' => '2025-09-21', 'status' => 'Paid', 'school_year' => '2025-2026', 'semester' => 'Fall', 'created_at' => now(), 'updated_at' => now(), ]); DB::table('parent_accounts')->insert([ 'parent_id' => $parentId, 'school_year' => '2025-2026', 'opening_balance' => 0, 'current_balance' => 370, 'created_at' => now(), 'updated_at' => now(), ]); DB::table('payments')->insert([ 'parent_id' => $parentId, 'invoice_id' => $invoiceId, 'total_amount' => 380, 'paid_amount' => 10, 'balance' => 370, 'number_of_installments' => 1, 'payment_method' => 'Cash', 'payment_date' => '2025-09-10', 'status' => 'Paid', 'school_year' => '2025-2026', 'semester' => 'Fall', 'created_at' => now(), 'updated_at' => now(), ]); DB::table('discount_usages')->insert([ 'voucher_id' => 1, 'parent_id' => $parentId, 'invoice_id' => $invoiceId, 'discount_amount' => 370, 'description' => 'Tuition discount', 'school_year' => '2025-2026', 'semester' => 'Fall', ]); $service = new ParentInvoiceService; $statement = $service->statement($parentId, '2025-2026'); $this->assertSame(0.0, $statement['lines'][0]['amount']); $this->assertSame(0.0, $statement['current_balance']); } private function seedParent(string $email = 'parent@example.com'): int { return DB::table('users')->insertGetId([ 'firstname' => 'Parent', 'lastname' => 'User', 'cellphone' => '1234567890', 'email' => $email, 'address_street' => '123 Street', 'city' => 'City', 'state' => 'ST', 'zip' => '12345', 'accept_school_policy' => 1, 'password' => bcrypt('password'), 'user_type' => 'primary', 'semester' => 'Fall', 'school_year' => '2025-2026', 'status' => 'Active', ]); } }