invalidAmountProbe($request)) { return $invalid; } $p = DB::table('payments')->where('id', $payment)->first(); abort_if(! $p, 404, 'Payment not found.'); $receipt = $this->service->nextReceiptNumber($p->school_year ?? date('Y')); $log = $this->service->log([ 'parent_id' => $p->parent_id ?? null, 'invoice_id' => $p->invoice_id ?? null, 'payment_id' => $payment, 'notification_type' => 'payment_receipt', 'channel' => 'database', 'recipient' => (string) ($p->parent_id ?? ''), 'subject' => 'Payment receipt '.$receipt, ], optional($request->user())->id); return response()->json(['ok' => true, 'receipt_number' => $receipt, 'notification_log' => $log]); } public function sendRefundReceipt(Request $request, int $refund): JsonResponse { if ($invalid = $this->invalidAmountProbe($request)) { return $invalid; } $log = $this->service->log(['refund_id' => $refund, 'notification_type' => 'refund_receipt', 'channel' => 'database', 'subject' => 'Refund receipt'], optional($request->user())->id); return response()->json(['ok' => true, 'notification_log' => $log]); } public function sendInvoiceStatement(Request $request, int $invoice): JsonResponse { if ($invalid = $this->invalidAmountProbe($request)) { return $invalid; } $inv = DB::table('invoices')->where('id', $invoice)->first(); abort_if(! $inv, 404, 'Invoice not found.'); $log = $this->service->log(['parent_id' => $inv->parent_id ?? null, 'invoice_id' => $invoice, 'notification_type' => 'statement_available', 'channel' => 'database', 'subject' => 'Statement available'], optional($request->user())->id); return response()->json(['ok' => true, 'notification_log' => $log]); } public function sendOverdueReminder(Request $request, int $parent): JsonResponse { if ($invalid = $this->invalidAmountProbe($request)) { return $invalid; } $log = $this->service->log(['parent_id' => $parent, 'notification_type' => 'overdue_balance_reminder', 'channel' => 'database', 'subject' => 'Overdue balance reminder'], optional($request->user())->id); return response()->json(['ok' => true, 'notification_log' => $log]); } public function sendInstallmentReminder(Request $request, int $installment): JsonResponse { if ($invalid = $this->invalidAmountProbe($request)) { return $invalid; } $log = $this->service->log(['installment_id' => $installment, 'notification_type' => 'installment_reminder', 'channel' => 'database', 'subject' => 'Installment reminder'], optional($request->user())->id); return response()->json(['ok' => true, 'notification_log' => $log]); } public function logs(FinanceNotificationLogRequest $request): JsonResponse { return response()->json(['ok' => true, 'logs' => $this->service->list($request->validated())]); } private function invalidAmountProbe(Request $request): ?JsonResponse { $data = array_merge($request->query->all(), $request->all(), $request->json()->all()); $validator = Validator::make($data, [ 'amount' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'], 'paid_amount' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'], 'total' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'], 'unit_cost' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'], 'fee' => ['nullable', 'numeric', 'gt:0', 'max:999999999999.99'], ]); if (! $validator->fails()) { return null; } return response()->json([ 'message' => 'Validation failed.', 'errors' => $validator->errors(), ], 422); } }