applyPaymentFilters($this->buildPaymentQuery($schoolYear, $dateFrom, $dateTo)); return $query ->selectRaw('invoice_id, SUM(paid_amount) AS paid_amount') ->whereNotNull('invoice_id') ->groupBy('invoice_id') ->get() ->map(fn ($row) => (array) $row) ->all(); } public function paymentBreakdown(?string $schoolYear, ?string $dateFrom, ?string $dateTo): array { $query = $this->applyPaymentFilters($this->buildPaymentQuery($schoolYear, $dateFrom, $dateTo)); $rows = $query ->selectRaw(" invoice_id, CASE WHEN LOWER(TRIM(payment_method)) = 'cash' THEN 'cash' WHEN LOWER(TRIM(payment_method)) IN ('check','cheque') THEN 'check' WHEN LOWER(TRIM(payment_method)) IN ('credit','card','credit card','debit','debit card','visa','mastercard') THEN 'credit' ELSE 'other' END AS method, SUM(paid_amount) AS amount ") ->whereNotNull('invoice_id') ->groupBy('invoice_id', 'method') ->get() ->map(fn ($row) => (array) $row) ->all(); $breakdown = []; foreach ($rows as $row) { $invoiceId = (int) ($row['invoice_id'] ?? 0); if ($invoiceId <= 0) { continue; } $method = (string) ($row['method'] ?? ''); $amount = (float) ($row['amount'] ?? 0); if (! isset($breakdown[$invoiceId])) { $breakdown[$invoiceId] = []; } $breakdown[$invoiceId][$method] = $amount; } return $breakdown; } public function paymentTotals(?string $schoolYear, ?string $dateFrom, ?string $dateTo): array { $query = $this->applyPaymentFilters($this->buildPaymentQuery($schoolYear, $dateFrom, $dateTo)); $row = (array) $query ->selectRaw(" SUM(paid_amount) AS total_all, SUM(CASE WHEN LOWER(TRIM(payment_method)) = 'cash' THEN paid_amount ELSE 0 END) AS total_cash, SUM(CASE WHEN LOWER(TRIM(payment_method)) IN ('check','cheque') THEN paid_amount ELSE 0 END) AS total_check, SUM(CASE WHEN LOWER(TRIM(payment_method)) IN ('credit','card','credit card','debit','debit card','visa','mastercard') THEN paid_amount ELSE 0 END) AS total_credit ") ->whereNotNull('invoice_id') ->first(); return [ 'total_all' => (float) ($row['total_all'] ?? 0), 'total_cash' => (float) ($row['total_cash'] ?? 0), 'total_check' => (float) ($row['total_check'] ?? 0), 'total_credit' => (float) ($row['total_credit'] ?? 0), ]; } private function buildPaymentQuery(?string $schoolYear, ?string $dateFrom, ?string $dateTo): Builder { $query = DB::table('payments'); if (! empty($schoolYear)) { $query->where('school_year', $schoolYear); } if (! empty($dateFrom)) { $query->whereRaw('DATE(payment_date) >= ?', [$dateFrom]); } if (! empty($dateTo)) { $query->whereRaw('DATE(payment_date) <= ?', [$dateTo]); } return $query; } private function applyPaymentFilters(Builder $query): Builder { $exclude = ['void', 'voided', 'refunded', 'failed', 'chargeback', 'declined', 'reversed', 'canceled', 'cancelled']; if (Schema::hasColumn('payments', 'status')) { $query->where(function ($q) use ($exclude) { $q->whereNotIn('status', $exclude)->orWhereNull('status'); }); } if (Schema::hasColumn('payments', 'is_void')) { $query->where(function ($q) { $q->where('is_void', 0)->orWhereNull('is_void'); }); } return $query; } }