config->getSchoolYear(); $schoolYears = DB::table('invoices') ->select('school_year') ->distinct() ->where('parent_id', $parentId) ->orderBy('school_year', 'DESC') ->get() ->map(fn ($r) => (array) $r) ->all(); $selectedYear = $schoolYear ?: null; if (! $selectedYear) { $hasCurrentYear = in_array($currentSchoolYear, array_column($schoolYears, 'school_year'), true); $selectedYear = $hasCurrentYear ? $currentSchoolYear : (! empty($schoolYears) ? $schoolYears[0]['school_year'] : null); } $invoices = []; if ($selectedYear) { $invoices = Invoice::getInvoicesByParentId($parentId, $selectedYear); } $invoiceIds = array_column($invoices, 'id'); $payments = []; $discounts = []; $refunds = []; if (! empty($invoiceIds)) { $paymentTotals = DB::table('payments') ->selectRaw('invoice_id, COALESCE(SUM(paid_amount),0) as paid_amount') ->whereIn('invoice_id', $invoiceIds) ->where(function ($query) { $query->whereNotIn(DB::raw('LOWER(status)'), [ 'pending', 'void', 'voided', 'cancelled', 'canceled', 'failed', 'rejected', 'refunded', 'chargeback', 'declined', 'reversed', ])->orWhereNull('status'); }) ->groupBy('invoice_id') ->get() ->map(fn ($r) => (array) $r) ->all(); foreach ($paymentTotals as $row) { $payments[$row['invoice_id']] = (float) ($row['paid_amount'] ?? 0); } $discountResults = DB::table('discount_usages') ->selectRaw('invoice_id, COALESCE(SUM(discount_amount),0) as discount_amount') ->whereIn('invoice_id', $invoiceIds) ->groupBy('invoice_id') ->get() ->map(fn ($r) => (array) $r) ->all(); foreach ($discountResults as $row) { $discounts[$row['invoice_id']] = (float) ($row['discount_amount'] ?? 0); } $refundResults = DB::table('refunds') ->selectRaw('invoice_id, COALESCE(SUM(refund_paid_amount),0) as refund_paid_amount') ->whereIn('invoice_id', $invoiceIds) ->whereIn('status', ['Partial', 'Paid']) ->groupBy('invoice_id') ->get() ->map(fn ($r) => (array) $r) ->all(); foreach ($refundResults as $row) { $refunds[$row['invoice_id']] = (float) ($row['refund_paid_amount'] ?? 0); } } $lastPayments = []; if (! empty($invoiceIds)) { $paymentResults = Payment::getPaymentsByInvoice($invoiceIds); foreach ($paymentResults as $payment) { $lastPayments[$payment['invoice_id']] = [ 'last_paid_amount' => (float) ($payment['last_paid_amount'] ?? 0), 'last_payment_date' => $payment['last_payment_date'] ?? null, ]; } } foreach ($invoices as &$invoice) { $invoiceId = (int) ($invoice['id'] ?? 0); $totalAmount = round((float) ($invoice['total_amount'] ?? 0), 2); $paidAmount = round((float) ($payments[$invoiceId] ?? $invoice['paid_amount'] ?? 0), 2); $discountAmount = round((float) ($discounts[$invoiceId] ?? $invoice['discount'] ?? 0), 2); $refundAmount = round((float) ($refunds[$invoiceId] ?? 0), 2); $balance = max(0.0, round($totalAmount - $paidAmount - $discountAmount - $refundAmount, 2)); $invoice['paid_amount'] = $paidAmount; $invoice['discount'] = $discountAmount; $invoice['refund_amount'] = $refundAmount; $invoice['balance'] = $balance; $invoice['status'] = $this->deriveInvoiceStatus($invoice['status'] ?? null, $paidAmount, $balance); $invoice['last_paid_amount'] = $lastPayments[$invoiceId]['last_paid_amount'] ?? 0.0; $invoice['last_payment_date'] = $lastPayments[$invoiceId]['last_payment_date'] ?? null; } unset($invoice); return [ 'invoices' => $invoices, 'schoolYears' => $schoolYears, 'selectedYear' => $selectedYear, 'currentSchoolYear' => $currentSchoolYear, 'dueDate' => $this->config->getDueDate(), ]; } private function deriveInvoiceStatus(?string $storedStatus, float $paidAmount, float $balance): string { if ($balance <= 0.00001) { return 'Paid'; } if ($paidAmount > 0) { return 'Partially Paid'; } return $storedStatus ?: 'Unpaid'; } }