validated(); $report = $this->reportService->getReport( $payload['date_from'] ?? null, $payload['date_to'] ?? null, $payload['school_year'] ?? null ); return response()->json([ 'ok' => true, 'report' => new FinancialReportResource($report), ]); } public function summary(FinancialSummaryRequest $request): JsonResponse { $payload = $request->validated(); $summary = $this->summaryService->getSummary( $payload['date_from'] ?? null, $payload['date_to'] ?? null, $payload['school_year'] ?? null ); $schoolYears = $this->schoolYears->listYears($summary['schoolYear'] ?? null); return response()->json([ 'ok' => true, 'summary' => new FinancialSummaryResource($summary), 'schoolYears' => $schoolYears, ]); } public function unpaidParents(FinancialUnpaidParentsRequest $request): JsonResponse { $payload = $request->validated(); $data = $this->unpaidParentsService->getUnpaidParents($payload['school_year'] ?? null); return response()->json([ 'ok' => true, 'schoolYear' => $data['schoolYear'] ?? null, 'schoolYears' => $data['schoolYears'] ?? [], 'results' => FinancialUnpaidParentResource::collection($data['results'] ?? []), ]); } public function parentPaymentFollowups(ParentPaymentFollowUpRequest $request): JsonResponse { return response()->json([ 'ok' => true, 'followups' => $this->parentPaymentFollowUpService->report($request->validated()), ]); } public function parentPaymentFollowupsCsv(ParentPaymentFollowUpRequest $request): StreamedResponse { $report = $this->parentPaymentFollowUpService->report($request->validated()); $rows = $this->parentPaymentFollowUpService->csvRows($report); return response()->streamDownload(function () use ($rows) { $out = fopen('php://output', 'w'); foreach ($rows as $row) { fputcsv($out, $row); } fclose($out); }, 'parent_payment_followups_' . ($report['schoolYear'] ?? 'report') . '_' . date('Ymd_His') . '.csv', ['Content-Type' => 'text/csv']); } public function storeParentFollowUpNote(FollowUpNoteRequest $request, int $parent): JsonResponse { return response()->json([ 'ok' => true, 'note' => $this->parentPaymentFollowUpService->storeNote($parent, $request->validated(), optional($request->user())->id), ], 201); } public function markParentContacted(FollowUpNoteRequest $request, int $parent): JsonResponse { $payload = array_merge($request->validated(), ['status' => $request->input('status', 'contacted')]); return response()->json(['ok' => true, 'note' => $this->parentPaymentFollowUpService->storeNote($parent, $payload, optional($request->user())->id)], 201); } public function storePromiseToPay(FollowUpNoteRequest $request, int $parent): JsonResponse { $payload = array_merge($request->validated(), ['status' => 'promise_to_pay']); return response()->json(['ok' => true, 'note' => $this->parentPaymentFollowUpService->storeNote($parent, $payload, optional($request->user())->id)], 201); } public function resolveParentFollowUp(FollowUpNoteRequest $request, int $parent): JsonResponse { $payload = array_merge($request->validated(), ['status' => 'resolved']); return response()->json(['ok' => true, 'note' => $this->parentPaymentFollowUpService->storeNote($parent, $payload, optional($request->user())->id)], 201); } public function stakeholderAnalysis(StakeholderFinancialAnalysisRequest $request): JsonResponse { $payload = $request->validated(); $analysis = $this->stakeholderAnalysisService->analyze( $payload['date_from'] ?? null, $payload['date_to'] ?? null, $payload['school_year'] ?? null, $payload['compare_school_year'] ?? null ); return response()->json([ 'ok' => true, 'analysis' => $analysis, ]); } public function stakeholderAnalysisCsv(StakeholderFinancialAnalysisRequest $request): StreamedResponse { $payload = $request->validated(); $analysis = $this->stakeholderAnalysisService->analyze( $payload['date_from'] ?? null, $payload['date_to'] ?? null, $payload['school_year'] ?? null, $payload['compare_school_year'] ?? null ); $rows = $this->stakeholderAnalysisService->csvRows($analysis); $schoolYear = $analysis['schoolYear'] ?? 'report'; return response()->streamDownload(function () use ($rows) { $out = fopen('php://output', 'w'); foreach ($rows as $row) { fputcsv($out, $row); } fclose($out); }, 'stakeholder_financial_analysis_' . $schoolYear . '_' . date('Ymd_His') . '.csv', ['Content-Type' => 'text/csv']); } public function downloadCsv(FinancialReportRequest $request): StreamedResponse { $payload = $request->validated(); $report = $this->reportService->getReport( $payload['date_from'] ?? null, $payload['date_to'] ?? null, $payload['school_year'] ?? null ); $paymentsMap = []; foreach ($report['payments'] as $payment) { $invoiceId = (int) ($payment['invoice_id'] ?? 0); $paymentsMap[$invoiceId] = (float) ($payment['paid_amount'] ?? 0); } $refundsMap = []; foreach ($report['refunds'] as $refund) { $invoiceId = (int) ($refund['invoice_id'] ?? 0); $refundsMap[$invoiceId] = (float) ($refund['total_refunded'] ?? 0); } $discountsMap = []; foreach ($report['discounts'] as $discount) { $invoiceId = (int) ($discount['invoice_id'] ?? 0); $discountsMap[$invoiceId] = (float) ($discount['discount_amount'] ?? 0); } $breakdown = $report['paymentBreakdown'] ?? []; $filename = 'financial_report_' . date('Ymd_His') . '.csv'; return response()->streamDownload(function () use ($report, $paymentsMap, $refundsMap, $discountsMap, $breakdown) { $out = fopen('php://output', 'w'); fputcsv($out, ['Invoice #', 'Parent', 'School Year', 'Total', 'Paid', 'Cash', 'Credit', 'Check', 'Balance', 'Refund', 'Discount', 'Status']); $sumTotal = 0.0; $sumPaid = 0.0; $sumCash = 0.0; $sumCredit = 0.0; $sumCheck = 0.0; $sumBalance = 0.0; $sumRefund = 0.0; $sumDiscount = 0.0; foreach ($report['invoices'] as $inv) { $invoiceId = (int) ($inv['id'] ?? 0); $paid = (float) ($paymentsMap[$invoiceId] ?? 0); $bd = $breakdown[$invoiceId] ?? []; $cash = (float) ($bd['cash'] ?? 0); $credit = (float) ($bd['credit'] ?? 0); $check = (float) ($bd['check'] ?? 0); $refunded = (float) ($refundsMap[$invoiceId] ?? 0); $discount = (float) ($discountsMap[$invoiceId] ?? 0); $total = (float) ($inv['total_amount'] ?? 0); $balance = $total - $paid - $discount - $refunded; if ($balance < 0) { $balance = 0.0; } $status = $balance === 0.0 ? 'Paid' : 'Unpaid'; fputcsv($out, [ $inv['invoice_number'] ?? '', $inv['parent_name'] ?? '', $inv['school_year'] ?? '', $total, $paid, $cash, $credit, $check, $balance, $refunded, $discount, $status, ]); $sumTotal += $total; $sumPaid += $paid; $sumCash += $cash; $sumCredit += $credit; $sumCheck += $check; $sumBalance += $balance; $sumRefund += $refunded; $sumDiscount += $discount; } fputcsv($out, [ 'TOTALS', '', '', $sumTotal, $sumPaid, $sumCash, $sumCredit, $sumCheck, $sumBalance, $sumRefund, $sumDiscount, '', ]); fputcsv($out, []); fputcsv($out, ['Expenses Summary']); fputcsv($out, ['Category', 'Total Amount']); foreach ($report['expenses'] as $exp) { fputcsv($out, [ $exp['category'] ?? '', $exp['total_amount'] ?? 0, ]); } fputcsv($out, []); fputcsv($out, ['Reimbursements Summary']); fputcsv($out, ['Status', 'Total Amount']); foreach ($report['reimbursements'] as $row) { fputcsv($out, [ $row['status'] ?? '', $row['total_amount'] ?? 0, ]); } fclose($out); }, $filename, ['Content-Type' => 'text/csv']); } public function downloadPdf(FinancialReportRequest $request): StreamedResponse { $payload = $request->validated(); $summary = $this->summaryService->getSummary( $payload['date_from'] ?? null, $payload['date_to'] ?? null, $payload['school_year'] ?? null ); $pdfBytes = $this->pdfService->buildPdf($summary); $schoolYear = $summary['schoolYear'] ?? 'report'; return response()->streamDownload(function () use ($pdfBytes) { echo $pdfBytes; }, 'Financial_Report_' . $schoolYear . '.pdf', ['Content-Type' => 'application/pdf']); } }