false, 'error' => 'Missing school year for refund processing.']; } $semester = $semester ?? (string) (Configuration::getConfig('semester') ?? ''); $invoice = $invoiceId ? Invoice::query()->find($invoiceId) : Invoice::query() ->where('parent_id', $parentId) ->where('school_year', $schoolYear) ->orderByDesc('created_at') ->first(); if (!$invoice) { return ['ok' => false, 'error' => 'No invoice found for refund processing.']; } $students = Enrollment::query() ->where('parent_id', $parentId) ->where('school_year', $schoolYear) ->get() ->map(fn ($row) => $row->toArray()) ->all(); if (empty($students)) { return ['ok' => false, 'error' => 'No enrollments found for refund processing.']; } $details = $this->refundDetails->calculateRefundDetails($students, $parentId); return DB::transaction(function () use ( $details, $invoice, $parentId, $schoolYear, $semester, $actorId, $students ) { if (empty($details['ok'])) { $reason = $details['error'] ?? 'Refund calculation failed.'; $note = json_encode([ 'parent_id' => $parentId, 'invoice_id' => (int) ($invoice->id ?? 0), 'error' => $reason, ]); $existingRefund = Refund::query()->where('invoice_id', (int) $invoice->id)->first(); if ($existingRefund) { $existingRefund->update([ 'refund_amount' => 0.0, 'status' => Refund::STATUS_REJECTED, 'reason' => $reason, 'request' => 'tuition', 'note' => $note, 'updated_at' => utc_now(), 'updated_by' => $actorId, ]); } else { Refund::query()->create([ 'parent_id' => $parentId, 'school_year' => $schoolYear, 'semester' => $semester, 'invoice_id' => (int) $invoice->id, 'refund_amount' => 0.0, 'refund_paid_amount' => 0.00, 'status' => Refund::STATUS_REJECTED, 'reason' => $reason, 'request' => 'tuition', 'note' => $note, 'requested_at' => utc_now(), 'created_at' => utc_now(), 'updated_at' => utc_now(), 'updated_by' => $actorId, ]); } return ['ok' => false, 'error' => $reason]; } $invoiceUpdate = $this->invoiceAdjustments->applyBookChargeAndUpdateInvoice( $invoice, $parentId, $details, $semester, $actorId ); $refundAmount = (float) ($details['refund_amount'] ?? 0.0); $debitAmount = (float) ($details['debit_amount'] ?? 0.0); $eligible = !empty($details['eligible']); $status = $refundAmount > 0 ? Refund::STATUS_PENDING : Refund::STATUS_REJECTED; $reason = null; if ($refundAmount <= 0) { if (!$eligible) { $reason = 'No refund due to late withdrawal.'; } elseif (!empty($details['full_discount'])) { $reason = 'No refund due to full discount.'; } elseif ($debitAmount > 0) { $reason = 'No refund due; book fee balance remains.'; } else { $reason = 'No refund due after book fee deduction.'; } } $auditPayload = [ 'student_ids' => array_map('intval', array_column($students, 'student_id')), 'parent_id' => $parentId, 'withdraw_date' => $details['withdraw_date'] ?? null, 'refund_deadline' => $details['refund_deadline'] ?? null, 'eligible' => $details['eligible'] ?? null, 'paid_amount' => $details['paid_amount'] ?? null, 'book_price' => $details['book_price'] ?? null, 'invoice_total' => $details['invoice_total'] ?? null, 'discount_total' => $details['discount_total'] ?? null, 'full_discount' => $details['full_discount'] ?? null, 'refundable_tuition' => $details['refundable_tuition'] ?? null, 'withdrawn_eligible_count' => $details['withdrawn_eligible_count'] ?? null, 'refund_amount' => $refundAmount, 'debit_amount' => $debitAmount, 'invoice_id' => (int) ($invoice->id ?? 0), ]; $auditPayload = array_merge($auditPayload, $invoiceUpdate); $existingRefund = Refund::query()->where('invoice_id', (int) $invoice->id)->first(); if ($existingRefund) { $existingRefund->update([ 'refund_amount' => $refundAmount, 'status' => $status, 'reason' => $reason, 'request' => 'tuition', 'note' => json_encode($auditPayload), 'updated_at' => utc_now(), 'updated_by' => $actorId, ]); return [ 'ok' => true, 'refund_id' => (int) $existingRefund->id, 'refund_amount' => $refundAmount, 'status' => $status, ]; } $created = Refund::query()->create([ 'parent_id' => $parentId, 'school_year' => $schoolYear, 'semester' => $semester, 'invoice_id' => (int) $invoice->id, 'refund_amount' => $refundAmount, 'refund_paid_amount' => 0.00, 'status' => $status, 'reason' => $reason, 'request' => 'tuition', 'note' => json_encode($auditPayload), 'requested_at' => utc_now(), 'created_at' => utc_now(), 'updated_at' => utc_now(), 'updated_by' => $actorId, ]); if (!$created) { return ['ok' => false, 'error' => 'Failed to create refund record.']; } return [ 'ok' => true, 'refund_id' => (int) $created->id, 'refund_amount' => $refundAmount, 'status' => $status, ]; }); } }