add refund logic and fix books inventory logic
This commit is contained in:
+130
-45
@@ -3,6 +3,41 @@
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<h2 class="text-center mt-4 mb-3">Refunds</h2>
|
||||
<?php
|
||||
$withdrawalReviews = $withdrawalReviews ?? [];
|
||||
$refunds = $refunds ?? [];
|
||||
$moneyFromCents = static fn($cents): string => '$' . number_format(((int) $cents) / 100, 2);
|
||||
$dateOnly = static function($dt) {
|
||||
if (empty($dt) || $dt === '0000-00-00 00:00:00') return '-';
|
||||
return local_date($dt, 'm-d-Y');
|
||||
};
|
||||
$normalizeRefundStatus = static function($status): string {
|
||||
$key = strtolower(str_replace(' ', '_', trim((string) $status)));
|
||||
if ($key === 'requested') return 'pending';
|
||||
if ($key === 'partially_paid') return 'partial';
|
||||
return $key !== '' ? $key : 'pending';
|
||||
};
|
||||
$summary = [
|
||||
'reviews' => count($withdrawalReviews),
|
||||
'approval' => 0,
|
||||
'payment' => 0,
|
||||
'complete' => 0,
|
||||
];
|
||||
foreach ($refunds as $refund) {
|
||||
$key = $normalizeRefundStatus($refund['status'] ?? '');
|
||||
$isWithdrawalRefund = (string)($refund['source_type'] ?? '') === 'tuition_withdrawal';
|
||||
$amount = (float) ($refund['refund_amount'] ?? 0);
|
||||
$paid = (float) ($refund['refund_paid_amount'] ?? 0);
|
||||
$remaining = max(0, $amount - $paid);
|
||||
if ($key === 'pending' && !$isWithdrawalRefund) {
|
||||
$summary['approval']++;
|
||||
} elseif (in_array($key, ['approved', 'partial'], true) && $remaining > 0) {
|
||||
$summary['payment']++;
|
||||
} elseif (in_array($key, ['paid', 'rejected'], true)) {
|
||||
$summary['complete']++;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- Flash messages -->
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
@@ -15,34 +50,78 @@
|
||||
<div class="alert alert-info mb-3 d-inline-block"><?= session()->getFlashdata('info') ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- (Optional) Bulk calculation form kept for future use -->
|
||||
<form method="post" action="/refunds/processRefunds">
|
||||
<?= csrf_field() ?>
|
||||
<?php
|
||||
$submitted = [];
|
||||
foreach ($refunds as $refund):
|
||||
if (!empty($refund['request']) && !in_array($refund['parent_id'], $submitted, true)):
|
||||
$submitted[] = $refund['parent_id'];
|
||||
?>
|
||||
<input type="hidden" name="parent_ids[]" value="<?= esc($refund['parent_id']) ?>">
|
||||
<?php
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
<?php if (empty($submitted)): ?>
|
||||
<div class="alert alert-info mb-3 d-inline-block">No eligible parents for refund calculation.</div>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-3"><div class="card h-100"><div class="card-body"><div class="text-muted small">Withdrawal reviews</div><div class="fs-4 fw-semibold"><?= (int) $summary['reviews'] ?></div></div></div></div>
|
||||
<div class="col-md-3"><div class="card h-100"><div class="card-body"><div class="text-muted small">Need approval</div><div class="fs-4 fw-semibold"><?= (int) $summary['approval'] ?></div></div></div></div>
|
||||
<div class="col-md-3"><div class="card h-100"><div class="card-body"><div class="text-muted small">Ready to pay</div><div class="fs-4 fw-semibold"><?= (int) $summary['payment'] ?></div></div></div></div>
|
||||
<div class="col-md-3"><div class="card h-100"><div class="card-body"><div class="text-muted small">Closed</div><div class="fs-4 fw-semibold"><?= (int) $summary['complete'] ?></div></div></div></div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($withdrawalReviews)): ?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<strong>Withdrawal Review Queue</strong>
|
||||
<span class="badge bg-warning text-dark"><?= count($withdrawalReviews) ?> pending</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-striped align-middle w-100 mb-0 no-mgmt-sticky no-dt-fixedheader" data-no-mgmt-sticky data-no-dt-fixedheader>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Parent</th>
|
||||
<th>Student</th>
|
||||
<th>Invoice #</th>
|
||||
<th>Requested</th>
|
||||
<th>Expected Refund</th>
|
||||
<th>Balance Due</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($withdrawalReviews as $review): ?>
|
||||
<?php
|
||||
$reviewStatus = (string) ($review['status'] ?? '');
|
||||
$reviewStatusClass = $reviewStatus === 'requires_review' ? 'danger' : 'warning text-dark';
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc(trim(($review['parent_firstname'] ?? '') . ' ' . ($review['parent_lastname'] ?? '')) ?: '-') ?></td>
|
||||
<td><?= esc(trim(($review['student_firstname'] ?? '') . ' ' . ($review['student_lastname'] ?? '')) ?: '-') ?></td>
|
||||
<td><?= esc($review['invoice_number'] ?? '-') ?></td>
|
||||
<td>
|
||||
<div><?= esc($dateOnly($review['withdrawal_request_date'] ?? null)) ?></div>
|
||||
<div class="text-muted small">Calculated <?= esc($dateOnly($review['calculated_at'] ?? null)) ?></div>
|
||||
</td>
|
||||
<td class="fw-semibold"><?= esc($moneyFromCents($review['new_refund_request_cents'] ?? 0)) ?></td>
|
||||
<td><?= esc($moneyFromCents($review['balance_due_cents'] ?? 0)) ?></td>
|
||||
<td><span class="badge bg-<?= esc($reviewStatusClass) ?>"><?= esc($reviewStatus ?: 'preview') ?></span></td>
|
||||
<td>
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<a class="btn btn-primary btn-sm" href="<?= site_url('administrator/withdrawals/' . (int) $review['enrollment_id'] . '/review') ?>">Open Review</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h4 class="mb-0">Refund Queue</h4>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="refundsTable" class="table table-bordered table-striped align-middle w-100">
|
||||
<table id="refundsTable" class="table table-bordered table-striped align-middle w-100 no-mgmt-sticky no-dt-fixedheader" data-no-mgmt-sticky data-no-dt-fixedheader>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Parent</th>
|
||||
<th>Invoice #</th>
|
||||
<th>Requested</th>
|
||||
<th>Amount</th>
|
||||
<th>Status</th>
|
||||
<th>Refund Details</th>
|
||||
<th>Payment</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -56,12 +135,7 @@
|
||||
return local_date($dt, 'm-d-Y');
|
||||
};
|
||||
$statusRaw = (string)($r['status'] ?? '');
|
||||
$statusKey = strtolower(str_replace(' ', '_', trim($statusRaw)));
|
||||
if ($statusKey === 'requested') {
|
||||
$statusKey = 'pending';
|
||||
} elseif ($statusKey === 'partially_paid') {
|
||||
$statusKey = 'partial';
|
||||
}
|
||||
$statusKey = $normalizeRefundStatus($statusRaw);
|
||||
$statusLabel = [
|
||||
'pending' => 'Pending',
|
||||
'approved' => 'Approved',
|
||||
@@ -80,9 +154,20 @@
|
||||
$paidAmount = (float)($r['refund_paid_amount'] ?? 0);
|
||||
$remainingAmount = max(0, $refundAmount - $paidAmount);
|
||||
$hasSource = !empty($r['source_type']) && !empty($r['source_id']);
|
||||
$canApprove = $statusKey === 'pending' && $refundAmount > 0 && $hasSource;
|
||||
$canReject = $statusKey === 'pending';
|
||||
$isWithdrawalRefund = (string)($r['source_type'] ?? '') === 'tuition_withdrawal';
|
||||
$canApprove = !$isWithdrawalRefund && $statusKey === 'pending' && $refundAmount > 0 && $hasSource;
|
||||
$canReject = !$isWithdrawalRefund && $statusKey === 'pending';
|
||||
$canRecord = in_array($statusKey, ['approved', 'partial'], true) && $remainingAmount > 0;
|
||||
$nextStep = 'Closed';
|
||||
if ($statusKey === 'pending') {
|
||||
$nextStep = $isWithdrawalRefund ? 'Approved by withdrawal review' : ($canApprove ? 'Needs approval' : 'Needs review');
|
||||
} elseif ($canRecord) {
|
||||
$nextStep = 'Ready to pay';
|
||||
} elseif ($statusKey === 'paid') {
|
||||
$nextStep = 'Paid';
|
||||
} elseif ($statusKey === 'rejected') {
|
||||
$nextStep = 'Rejected';
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc(($r['firstname'] ?? '').' '.($r['lastname'] ?? '')) ?></td>
|
||||
@@ -93,6 +178,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<div><span class="badge bg-<?= esc($statusClass) ?>"><?= esc($statusLabel) ?></span></div>
|
||||
<div class="text-muted small mt-1"><?= esc($nextStep) ?></div>
|
||||
<?php if (!empty($r['approved_at']) && $r['approved_at'] !== '0000-00-00 00:00:00'): ?>
|
||||
<div class="text-muted small mt-1">
|
||||
<?= esc($fmt($r['approved_at'])) ?>
|
||||
@@ -103,6 +189,8 @@
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div><span class="text-muted small">Paid:</span> $<?= esc(number_format($paidAmount, 2)) ?></div>
|
||||
<div><span class="text-muted small">Remaining:</span> $<?= esc(number_format($remainingAmount, 2)) ?></div>
|
||||
<div><span class="text-muted small">Check #:</span> <?= esc($r['check_nbr'] ?? '-') ?></div>
|
||||
<div>
|
||||
<span class="text-muted small">Check File:</span>
|
||||
@@ -112,25 +200,21 @@
|
||||
-
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div><span class="text-muted small">Paid:</span> $<?= esc(number_format($paidAmount, 2)) ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<button class="btn btn-success btn-sm"
|
||||
<?= $canRecord ? '' : 'disabled' ?>
|
||||
onclick="handleRecordRefundClick(<?= (int)$r['id'] ?>, '<?= esc($statusLabel) ?>', <?= $remainingAmount ?>)">
|
||||
Record
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm"
|
||||
<?= $canApprove ? '' : 'disabled' ?>
|
||||
onclick="handleStatusClick(<?= (int)$r['id'] ?>, 'Approved', <?= $refundAmount ?>)">
|
||||
Approve
|
||||
</button>
|
||||
<button class="btn btn-danger btn-sm"
|
||||
<?= $canReject ? '' : 'disabled' ?>
|
||||
onclick="handleStatusClick(<?= (int)$r['id'] ?>, 'Rejected', <?= max($refundAmount, 0.01) ?>)">
|
||||
Reject
|
||||
</button>
|
||||
<?php if ($canRecord): ?>
|
||||
<button class="btn btn-success btn-sm" onclick="handleRecordRefundClick(<?= (int)$r['id'] ?>, '<?= esc($statusLabel) ?>', <?= $remainingAmount ?>)">Pay</button>
|
||||
<?php endif; ?>
|
||||
<?php if ($canApprove): ?>
|
||||
<button class="btn btn-primary btn-sm" onclick="handleStatusClick(<?= (int)$r['id'] ?>, 'Approved', <?= $refundAmount ?>)">Approve</button>
|
||||
<?php endif; ?>
|
||||
<?php if ($canReject): ?>
|
||||
<button class="btn btn-outline-danger btn-sm" onclick="handleStatusClick(<?= (int)$r['id'] ?>, 'Rejected', <?= max($refundAmount, 0.01) ?>)">Reject</button>
|
||||
<?php endif; ?>
|
||||
<?php if (!$canRecord && !$canApprove && !$canReject): ?>
|
||||
<span class="text-muted small">No action</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -226,6 +310,7 @@ $(function () {
|
||||
order: [[2, 'desc']], // order by Requested desc
|
||||
scrollX: true,
|
||||
autoWidth: false,
|
||||
fixedHeader: false,
|
||||
});
|
||||
|
||||
// Status form (approve/reject)
|
||||
|
||||
Reference in New Issue
Block a user