add refund logic and fix books inventory logic
This commit is contained in:
+3
-3
@@ -474,7 +474,7 @@
|
||||
<img src="images/carousel-0.png" class="d-block w-100" alt="Faith and Knowledge Hand in Hand">
|
||||
<div class="carousel-caption">
|
||||
<h1>Faith and Knowledge Hand in Hand</h1>
|
||||
<p>Our Sunday School program (Grades 1-9, Youth) is evenly divided between Islamic Studies in English—exploring topics about Allah, Islamic values, Muslim life and lessons from the Prophets—and Quran/Arabic studies focused on recitation, memorization and language. This balanced approach nurtures both understanding and practice of Islam.</p>
|
||||
<p>Our Sunday School program (Grades 1-10, Youth) is evenly divided between Islamic Studies in English—exploring topics about Allah, Islamic values, Muslim life and lessons from the Prophets—and Quran/Arabic studies focused on recitation, memorization and language. This balanced approach nurtures both understanding and practice of Islam.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -662,8 +662,8 @@
|
||||
<div class="h-100 d-flex flex-column justify-content-center p-5">
|
||||
<h1 class="mb-4">Our Curriculum and Grade Structure</h1>
|
||||
<p>Our program spans nine structured grade levels, each building upon the previous year's knowledge to ensure a solid foundation in faith, character, and Islamic learning.</p>
|
||||
<p>Upon completing the 9th grade, students transition into our three-year Youth Program, which emphasizes deeper community engagement, personal development and practical application of Islamic principles. Participation in the Youth Program requires students to be at least 15 years old, ensuring they are mature enough to benefit from its advanced content.</p>
|
||||
<p>Starting this academic year, children must be at least 6 years old by 09-01-2025 to enroll in Grade 1. For younger learners, we are pleased to offer our newly established Kindergarten class, welcoming children who are at least 5 years old by 12-31-2025. This early education program is designed to introduce young minds to the basics of Islamic teachings in a warm, age-appropriate environment.</p>
|
||||
<p>Upon completing the 10th grade, students transition into our two-year Youth Program, which emphasizes deeper community engagement, personal development and practical application of Islamic principles. Participation in the Youth Program requires students to be at least 16 years old, ensuring they are mature enough to benefit from its advanced content.</p>
|
||||
<p>Starting this academic year, children must be at least 6 years old by 09-01-2026 to enroll in Grade 1. For younger learners, we are pleased to offer our newly established Kindergarten class, welcoming children who are at least 5 years old by 12-31-2026. This early education program is designed to introduce young minds to the basics of Islamic teachings in a warm, age-appropriate environment.</p>
|
||||
<a class="btn btn-success py-3 px-5 mt-3" href="/register">Get Started Now<i class="fa fa-arrow-right ms-2"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -121,7 +121,6 @@ $selectedClasses = array_values(array_intersect(range(1,13), $selectedClasses));
|
||||
<label class="form-label">Unit</label>
|
||||
<input class="form-control" name="unit" placeholder="pcs, set" value="<?= esc($item['unit'] ?? '') ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">SKU</label>
|
||||
<input class="form-control" name="sku" value="<?= esc($item['sku'] ?? '') ?>">
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
<div class="d-flex justify-content-between align-items-center mb-3 px-3">
|
||||
<h3 class="mb-0">Books</h3>
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-outline-primary" href="<?= site_url('inventory/book-prices') ?>">Book Prices</a>
|
||||
<a class="btn btn-primary" href="<?= site_url('inventory/create/book') ?>">Add Book</a>
|
||||
<button class="btn btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#addCategoryModal">Add Category</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= view('partials/flash_messages') ?>
|
||||
<div class="px-3 mb-2"><?= $this->include('partials/academic_filter') ?></div>
|
||||
|
||||
<?php
|
||||
// Helper to render a compact grade label from a category row
|
||||
@@ -50,7 +50,7 @@
|
||||
<th>Grade Range</th> <!-- NEW -->
|
||||
<th>Qty</th><th>Unit</th>
|
||||
<th>Updated By</th><th>Updated Date</th>
|
||||
<th>SKU</th><th style="width:110px">Actions</th>
|
||||
<th>SKU</th><th style="width:150px">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -72,7 +72,7 @@
|
||||
<td><?= esc($i['updated_at'] ? local_datetime($i['updated_at'], 'm-d-Y H:i') : '—') ?></td>
|
||||
<td><?= esc($i['sku']) ?></td>
|
||||
<td>
|
||||
<a class="btn btn-sm btn-outline-primary" href="<?= site_url('inventory/edit/'.$i['id']) ?>">Edit</a>
|
||||
<a class="btn btn-sm btn-outline-primary" href="<?= site_url('inventory/edit/'.$i['id']) ?>">Edit Book</a>
|
||||
<form action="<?= site_url('inventory/delete/'.$i['id']) ?>" method="post" class="d-inline">
|
||||
<?= csrf_field() ?>
|
||||
<button class="btn btn-sm btn-outline-danger" onclick="return confirm('Delete this item?')">Del</button>
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?php
|
||||
$categoryById = [];
|
||||
foreach (($categories ?? []) as $category) {
|
||||
$categoryById[(int) ($category['id'] ?? 0)] = $category;
|
||||
}
|
||||
|
||||
$gradeLabel = static function (?array $category): string {
|
||||
if (! $category) {
|
||||
return '-';
|
||||
}
|
||||
$gmin = $category['grade_min'] ?? null;
|
||||
$gmax = $category['grade_max'] ?? null;
|
||||
if ($gmin === null && $gmax === null) {
|
||||
return '-';
|
||||
}
|
||||
if ($gmin !== null && $gmax !== null) {
|
||||
return 'G' . (int) $gmin . '-G' . (int) $gmax;
|
||||
}
|
||||
if ($gmin !== null) {
|
||||
return 'G' . (int) $gmin . '+';
|
||||
}
|
||||
return '<=G' . (int) $gmax;
|
||||
};
|
||||
?>
|
||||
|
||||
<div class="container-fluid px-0 mt-3">
|
||||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3 px-3">
|
||||
<div>
|
||||
<h3 class="mb-0">Book Prices</h3>
|
||||
<div class="text-muted small">School year: <?= esc($schoolYear ?? '') ?></div>
|
||||
</div>
|
||||
<a class="btn btn-outline-secondary" href="<?= site_url('inventory/book') ?>">Back to Books</a>
|
||||
</div>
|
||||
|
||||
<?= view('partials/flash_messages') ?>
|
||||
|
||||
<form method="post" action="<?= site_url('inventory/book-prices') ?>">
|
||||
<?= csrf_field() ?>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex flex-wrap justify-content-between align-items-center gap-2">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<input class="form-control form-control-sm" id="bookPriceSearch" type="search" placeholder="Search title, ISBN, SKU" style="width: 260px;">
|
||||
<select class="form-select form-select-sm" id="bookPriceCategoryFilter" style="width: 240px;">
|
||||
<option value="">All Categories</option>
|
||||
<?php foreach (($categories ?? []) as $category): ?>
|
||||
<option value="<?= (int) ($category['id'] ?? 0) ?>"><?= esc($category['name'] ?? '') ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm">Save Prices</button>
|
||||
</div>
|
||||
<div class="card-body table-responsive">
|
||||
<table class="table table-striped align-middle mb-0 no-mgmt-sticky no-dt-fixedheader" data-no-mgmt-sticky data-no-dt-fixedheader id="bookPriceTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Book</th>
|
||||
<th>ISBN / Edition / SKU</th>
|
||||
<th>Category</th>
|
||||
<th>Grade Range</th>
|
||||
<th class="text-end">Qty</th>
|
||||
<th style="width: 170px;">Price</th>
|
||||
<th style="width: 130px;">Confirmed</th>
|
||||
<th style="width: 120px;">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach (($books ?? []) as $book): ?>
|
||||
<?php
|
||||
$bookId = (int) ($book['id'] ?? 0);
|
||||
$category = $categoryById[(int) ($book['category_id'] ?? 0)] ?? null;
|
||||
$priceCents = (int) ($book['charge_price_cents'] ?? 0);
|
||||
$isConfirmed = $priceCents > 0 && (int) ($book['price_confirmed'] ?? 0) === 1;
|
||||
$search = strtolower(trim(implode(' ', [
|
||||
$book['name'] ?? '',
|
||||
$book['isbn'] ?? '',
|
||||
$book['edition'] ?? '',
|
||||
$book['sku'] ?? '',
|
||||
$category['name'] ?? '',
|
||||
])));
|
||||
?>
|
||||
<tr data-category="<?= esc($book['category_id'] ?? '') ?>" data-search="<?= esc($search) ?>">
|
||||
<td>
|
||||
<div class="fw-semibold"><?= esc($book['name'] ?? '') ?></div>
|
||||
<div class="small text-muted">ID #<?= $bookId ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<div><?= esc(($book['isbn'] ?? '') ?: '-') ?></div>
|
||||
<div class="small text-muted">
|
||||
<?= esc(($book['edition'] ?? '') ?: '-') ?> / <?= esc(($book['sku'] ?? '') ?: '-') ?>
|
||||
</div>
|
||||
</td>
|
||||
<td><?= esc($category['name'] ?? 'Uncategorized') ?></td>
|
||||
<td><?= esc($gradeLabel($category)) ?></td>
|
||||
<td class="text-end"><?= (int) ($book['quantity'] ?? 0) ?></td>
|
||||
<td>
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">$</span>
|
||||
<input class="form-control" name="prices[<?= $bookId ?>]" inputmode="decimal" pattern="^\d+(\.\d{1,2})?$" value="<?= esc(number_format($priceCents / 100, 2, '.', '')) ?>">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="confirmed[<?= $bookId ?>]" value="1" id="confirmed<?= $bookId ?>" <?= $isConfirmed ? 'checked' : '' ?>>
|
||||
<label class="form-check-label" for="confirmed<?= $bookId ?>">Confirm</label>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($isConfirmed): ?>
|
||||
<span class="badge bg-success">Ready</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-warning text-dark">Needs price</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer text-end">
|
||||
<button class="btn btn-primary">Save Prices</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const search = document.getElementById('bookPriceSearch');
|
||||
const category = document.getElementById('bookPriceCategoryFilter');
|
||||
const rows = Array.from(document.querySelectorAll('#bookPriceTable tbody tr'));
|
||||
|
||||
function applyFilters() {
|
||||
const term = (search?.value || '').trim().toLowerCase();
|
||||
const categoryId = category?.value || '';
|
||||
rows.forEach(row => {
|
||||
const matchesText = !term || (row.getAttribute('data-search') || '').includes(term);
|
||||
const matchesCategory = !categoryId || row.getAttribute('data-category') === categoryId;
|
||||
row.style.display = matchesText && matchesCategory ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
search?.addEventListener('input', applyFilters);
|
||||
category?.addEventListener('change', applyFilters);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<div class="container py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3"><div><h2 class="mb-1">Book Issue History</h2><div class="text-muted"><?= esc(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')) ?> · <?= esc($student['school_id'] ?? '') ?></div></div><a class="btn btn-outline-secondary" href="<?= previous_url() ?>">Back</a></div>
|
||||
<div class="alert alert-info">Issued books are not returnable. A reversed row means an administrator corrected an issue that was entered in error; it is not a parent return.</div>
|
||||
<div class="table-responsive"><table class="table table-striped align-middle"><thead><tr><th>Year</th><th>Book</th><th>Issued</th><th>Qty</th><th>Status</th><th>Issued by</th><th>Correction audit</th></tr></thead><tbody>
|
||||
<?php foreach ($issues as $issue): ?><tr><td><?= esc($issue['school_year'] ?? '') ?></td><td><?= esc($issue['book_name'] ?? '') ?><div class="small text-muted"><?= esc($issue['isbn'] ?? '') ?> <?= esc($issue['edition'] ?? '') ?></div></td><td><?= esc($issue['issued_at'] ?? '') ?></td><td><?= (int) ($issue['quantity'] ?? 0) ?></td><td><span class="badge bg-<?= ($issue['status'] ?? '') === 'issued' ? 'success' : 'secondary' ?>"><?= esc($issue['status'] ?? '') ?></span></td><td><?= esc(trim(($issue['issued_by_firstname'] ?? '') . ' ' . ($issue['issued_by_lastname'] ?? ''))) ?></td><td><?php if (($issue['status'] ?? '') === 'reversed'): ?><?= esc($issue['reversal_reason'] ?? '') ?><div class="small text-muted"><?= esc($issue['reversed_at'] ?? '') ?> by <?= esc(trim(($issue['reversed_by_firstname'] ?? '') . ' ' . ($issue['reversed_by_lastname'] ?? ''))) ?></div><?php else: ?>—<?php endif; ?></td></tr><?php endforeach; ?>
|
||||
<?php if (empty($issues)): ?><tr><td colspan="7" class="text-muted">No book issues found.</td></tr><?php endif; ?>
|
||||
</tbody></table></div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -47,8 +47,13 @@
|
||||
<strong>School Year:</strong> <?= esc($schoolYear) ?>,
|
||||
<strong>Semester:</strong> <?= esc($semester) ?>
|
||||
</div>
|
||||
<div><strong>On Hand:</strong> <?= (int)$onHand ?></div>
|
||||
<div>
|
||||
<strong>On Hand:</strong> <?= (int)$onHand ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ((int)($priceConfirmed ?? 0) !== 1 || (int)($unitChargeCents ?? 0) <= 0): ?>
|
||||
<div class="mt-2 text-danger">This book cannot be distributed until its active-year charge price is confirmed.</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Submission form (POST) -->
|
||||
@@ -57,6 +62,7 @@
|
||||
<!-- Keep class section hidden -->
|
||||
<input type="hidden" name="class_section_id" value="<?= esc($class_section_id) ?>">
|
||||
<input type="hidden" name="item_id" value="<?= esc($item_id) ?>">
|
||||
<input type="hidden" name="idempotency_key" value="<?= esc(hash('sha256', (string) microtime(true) . ':' . (string) random_int(1, PHP_INT_MAX))) ?>">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
@@ -96,7 +102,7 @@
|
||||
class="form-check-input student-box"
|
||||
name="student_ids[]"
|
||||
value="<?= esc($sid) ?>"
|
||||
<?= $given ? 'checked' : '' ?><?= $disabledAttr ?>>
|
||||
<?= $given ? 'checked disabled' : $disabledAttr ?>>
|
||||
</td>
|
||||
<td><?= esc($student['school_id'] ?? '-') ?></td>
|
||||
<td><?= esc($student['firstname'] ?? '') ?></td>
|
||||
@@ -123,7 +129,7 @@
|
||||
<textarea class="form-control" rows="2" name="note" placeholder="e.g., Distributed in class today"<?= $disabledAttr ?>></textarea>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="button" class="btn btn-success"<?= $disabledAttr ?>>Deduct & Save</button>
|
||||
<button type="submit" class="btn btn-success"<?= $disabledAttr ?><?= ((int)($priceConfirmed ?? 0) !== 1 || (int)($unitChargeCents ?? 0) <= 0) ? ' disabled' : '' ?>>Deduct & Save</button>
|
||||
<button type="button" class="btn btn-secondary" id="clearSelectionBtn"<?= $disabledAttr ?>>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -148,34 +154,18 @@
|
||||
|
||||
document.getElementById('checkAllBtn')?.addEventListener('click', () => {
|
||||
if (distributeReadonly) return;
|
||||
document.querySelectorAll('.student-box').forEach(cb => cb.checked = true);
|
||||
});
|
||||
document.getElementById('uncheckAllBtn')?.addEventListener('click', () => {
|
||||
if (distributeReadonly) return;
|
||||
document.querySelectorAll('.student-box').forEach(cb => cb.checked = false);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Auto-submit filter when book changes
|
||||
document.getElementById('bookSelect')?.addEventListener('change', () => {
|
||||
document.getElementById('filterForm').submit();
|
||||
});
|
||||
|
||||
document.getElementById('checkAllBtn')?.addEventListener('click', () => {
|
||||
if (distributeReadonly) return;
|
||||
document.querySelectorAll('.student-box').forEach(cb => cb.checked = true);
|
||||
document.querySelectorAll('.student-box:not(:disabled)').forEach(cb => cb.checked = true);
|
||||
});
|
||||
|
||||
document.getElementById('uncheckAllBtn')?.addEventListener('click', () => {
|
||||
if (distributeReadonly) return;
|
||||
document.querySelectorAll('.student-box').forEach(cb => cb.checked = false);
|
||||
document.querySelectorAll('.student-box:not(:disabled)').forEach(cb => cb.checked = false);
|
||||
});
|
||||
|
||||
// Cancel button clears all checkboxes
|
||||
document.getElementById('clearSelectionBtn')?.addEventListener('click', () => {
|
||||
if (distributeReadonly) return;
|
||||
document.querySelectorAll('.student-box').forEach(cb => cb.checked = false);
|
||||
document.querySelectorAll('.student-box:not(:disabled)').forEach(cb => cb.checked = false);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
+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)
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
$blockers = $preview['blockers'] ?? [];
|
||||
$warnings = $preview['warnings'] ?? [];
|
||||
$carryForward = $preview['carry_forward'] ?? [];
|
||||
$inventory = $preview['inventory'] ?? ['rows' => [], 'summary' => []];
|
||||
$inventoryRows = $inventory['rows'] ?? [];
|
||||
$carryForwardTotal = array_reduce(
|
||||
$carryForward,
|
||||
static fn (float $total, array $row): float => $total + (float) ($row['carry_forward_amount'] ?? 0),
|
||||
@@ -344,6 +346,44 @@
|
||||
</div>
|
||||
|
||||
<div class="border rounded bg-white p-3 mb-4" id="carry-forward-table">
|
||||
<h5>Book Inventory Reconciliation</h5>
|
||||
<div class="table-responsive mb-4">
|
||||
<table class="table table-sm align-middle no-mgmt-sticky" data-no-mgmt-sticky>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Book</th>
|
||||
<th class="text-end">Opening</th>
|
||||
<th class="text-end">Net Movements</th>
|
||||
<th class="text-end">System Closing</th>
|
||||
<th class="text-end">Physical Count</th>
|
||||
<th class="text-end">Variance</th>
|
||||
<th class="text-end">Charge Price</th>
|
||||
<th class="text-end">Target Opening</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($inventoryRows as $row): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<div><?= esc($row['item_name'] ?? '') ?></div>
|
||||
<div class="text-muted small"><?= esc(trim((string)($row['isbn'] ?? '') . ' ' . (string)($row['edition'] ?? ''))) ?></div>
|
||||
</td>
|
||||
<td class="text-end"><?= (int) ($row['opening_quantity'] ?? 0) ?></td>
|
||||
<td class="text-end"><?= (int) ($row['movement_total'] ?? 0) ?></td>
|
||||
<td class="text-end"><?= (int) ($row['system_closing_quantity'] ?? 0) ?></td>
|
||||
<td class="text-end"><?= ($row['counted_closing_quantity'] ?? null) === null ? 'Missing' : (int) $row['counted_closing_quantity'] ?></td>
|
||||
<td class="text-end"><?= ($row['variance_quantity'] ?? null) === null ? '-' : (int) $row['variance_quantity'] ?></td>
|
||||
<td class="text-end">$<?= number_format(((int) ($row['charge_price_cents'] ?? 0)) / 100, 2) ?></td>
|
||||
<td class="text-end"><?= (int) ($row['target_opening_quantity'] ?? 0) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if ($inventoryRows === []): ?>
|
||||
<tr><td colspan="8" class="text-muted">No book inventory item-year rows found for this source year.</td></tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h5>Carry-Forward Families</h5>
|
||||
<div class="table-responsive">
|
||||
<table id="carryForwardFamiliesTable" class="table table-sm align-middle no-mgmt-sticky" data-no-mgmt-sticky>
|
||||
|
||||
@@ -93,6 +93,12 @@
|
||||
required
|
||||
>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label" for="new_total_instructional_weeks">Instructional Weeks</label>
|
||||
<input class="form-control" id="new_total_instructional_weeks" name="total_instructional_weeks" type="number" min="1" step="1" required>
|
||||
<input type="hidden" name="annual_fee_includes_books" value="1">
|
||||
<input type="hidden" name="withdrawal_policy_version" value="studied_weeks_v1">
|
||||
</div>
|
||||
<div class="col-md-3 d-flex gap-2">
|
||||
<button class="btn btn-primary" type="submit">Save Draft</button>
|
||||
<button class="btn btn-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#schoolYearCreateForm">Cancel</button>
|
||||
@@ -320,6 +326,12 @@
|
||||
<label class="form-label" for="fall_makeup_exam_on_<?= $id ?>">Fall Makeup Exam</label>
|
||||
<input class="form-control" id="fall_makeup_exam_on_<?= $id ?>" name="fall_makeup_exam_on" type="date" value="<?= esc($year['fall_makeup_exam_on'] ?? '') ?>">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label" for="total_instructional_weeks_<?= $id ?>">Instructional Weeks</label>
|
||||
<input class="form-control" id="total_instructional_weeks_<?= $id ?>" name="total_instructional_weeks" type="number" min="1" step="1" value="<?= esc($totalInstructionalWeeks ?? '') ?>" required>
|
||||
<input type="hidden" name="annual_fee_includes_books" value="1">
|
||||
<input type="hidden" name="withdrawal_policy_version" value="<?= esc($year['withdrawal_policy_version'] ?? 'studied_weeks_v1') ?>">
|
||||
</div>
|
||||
</div>
|
||||
<label class="form-label" for="description_<?= $id ?>">Description</label>
|
||||
<textarea class="form-control" id="description_<?= $id ?>" name="description" rows="3"><?= esc($year['description'] ?? '') ?></textarea>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<?php $c = $calculation ?? []; $money = static fn ($v): string => '$' . number_format(((int) $v) / 100, 2); ?>
|
||||
<div class="container py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3"><div><h2 class="mb-1">Withdrawal Calculation #<?= (int) ($c['id'] ?? 0) ?></h2><div class="text-muted">Version <?= (int) ($c['version'] ?? 0) ?> · <?= esc($c['status'] ?? '') ?> · <?= esc($c['student_firstname'] ?? '') ?> <?= esc($c['student_lastname'] ?? '') ?></div></div><a class="btn btn-outline-secondary" href="<?= site_url('administrator/withdrawals/' . (int) ($c['enrollment_id'] ?? 0) . '/review') ?>">Review</a></div>
|
||||
<?php if (session()->getFlashdata('success')): ?><div class="alert alert-success"><?= esc(session()->getFlashdata('success')) ?></div><?php endif; ?>
|
||||
<?php if (!empty($c['blockers'])): ?><div class="alert alert-danger"><ul class="mb-0"><?php foreach ($c['blockers'] as $b): ?><li><?= esc($b) ?></li><?php endforeach; ?></ul></div><?php endif; ?>
|
||||
<div class="card mb-3"><div class="card-body"><div class="row g-3">
|
||||
<?php foreach ([
|
||||
'Annual allocation'=>'annual_fee_allocation_cents','Issued books'=>'issued_book_charge_cents','Instruction component'=>'annual_instruction_cents','Earned tuition'=>'earned_tuition_cents','Retained charge'=>'retained_charge_cents','Original invoice charge'=>'original_invoice_charge_cents','Invoice adjustment'=>'invoice_adjustment_cents','Adjusted invoice charge'=>'adjusted_invoice_charge_cents','Valid payments'=>'valid_payment_cents','Completed payouts'=>'completed_payout_cents','Open reservations'=>'open_reservation_cents','Refundable credit'=>'refundable_credit_cents','New refund request'=>'new_refund_request_cents','Balance due'=>'balance_due_cents'
|
||||
] as $label=>$field): ?><div class="col-md-3"><div class="text-muted small"><?= esc($label) ?></div><div class="fw-semibold"><?= $money($c[$field] ?? 0) ?></div></div><?php endforeach; ?>
|
||||
</div></div></div>
|
||||
<div class="card mb-3"><div class="card-header fw-semibold">Policy snapshot</div><div class="card-body"><dl class="row mb-0"><dt class="col-sm-4">Dates</dt><dd class="col-sm-8"><?= esc($c['school_year_start_date'] ?? '') ?> / <?= esc($c['enrollment_date'] ?? '') ?> / <?= esc($c['withdrawal_request_date'] ?? '') ?></dd><dt class="col-sm-4">Studied</dt><dd class="col-sm-8"><?= (int) ($c['studied_calendar_days'] ?? 0) ?> calendar day(s), rounded to <?= (int) ($c['studied_weeks'] ?? 0) ?> week(s), of <?= (int) ($c['total_instructional_weeks'] ?? 0) ?></dd><dt class="col-sm-4">Policy</dt><dd class="col-sm-8"><?= esc($c['policy_version'] ?? '') ?>; annual tuition includes books; no no-school subtraction; no book returns</dd><dt class="col-sm-4">Override reason</dt><dd class="col-sm-8"><?= esc($c['override_reason'] ?? '—') ?></dd></dl></div></div>
|
||||
<div class="card"><div class="card-header fw-semibold">Book price snapshots</div><div class="table-responsive"><table class="table table-sm mb-0"><thead><tr><th>Issue</th><th>Book</th><th>Date</th><th>Status</th><th>Price</th><th>Total</th></tr></thead><tbody><?php foreach ((array) ($c['books'] ?? []) as $book): ?><tr><td>#<?= (int) ($book['id'] ?? 0) ?></td><td><?= esc($book['book_name'] ?? '') ?></td><td><?= esc($book['issued_at'] ?? '') ?></td><td><?= esc($book['status'] ?? '') ?></td><td><?= $money($book['unit_charge_price_cents'] ?? 0) ?></td><td><?= $money($book['total_charge_cents'] ?? 0) ?></td></tr><?php endforeach; ?></tbody></table></div></div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<?php $money = static fn ($v): string => '$' . number_format(((int) $v) / 100, 2); ?>
|
||||
<div class="container py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3"><h2>Invoice #<?= (int) $invoiceId ?> Withdrawal Breakdown</h2><a class="btn btn-outline-secondary" href="<?= site_url('refunds/list') ?>">Back to refunds</a></div>
|
||||
<?php foreach ($calculations as $c): ?>
|
||||
<div class="card mb-3"><div class="card-header d-flex justify-content-between"><strong><?= esc(trim(($c['student_firstname'] ?? '') . ' ' . ($c['student_lastname'] ?? ''))) ?></strong><span class="badge bg-<?= ($c['status'] ?? '') === 'posted' ? 'success' : 'danger' ?>"><?= esc($c['status'] ?? '') ?></span></div><div class="card-body"><div class="row g-2"><div class="col-md-3">Studied: <strong><?= (int) ($c['studied_weeks'] ?? 0) ?> week(s)</strong></div><div class="col-md-3">Books: <strong><?= $money($c['issued_book_charge_cents'] ?? 0) ?></strong></div><div class="col-md-3">Earned tuition: <strong><?= $money($c['earned_tuition_cents'] ?? 0) ?></strong></div><div class="col-md-3">Retained: <strong><?= $money($c['retained_charge_cents'] ?? 0) ?></strong></div></div><div class="mt-2"><a href="<?= site_url('administrator/withdrawal-calculations/' . (int) $c['id']) ?>">Calculation #<?= (int) $c['id'] ?> version <?= (int) $c['version'] ?></a></div></div></div>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($calculations)): ?><div class="alert alert-warning">No posted withdrawal calculations were found for this invoice.</div><?php endif; ?>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
@@ -0,0 +1,82 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
<?php
|
||||
$c = $calculation ?? [];
|
||||
$money = static fn ($cents): string => '$' . number_format(((int) $cents) / 100, 2);
|
||||
$blockers = (array) ($c['blockers'] ?? []);
|
||||
$discountProjection = (array) (($c['explanation']['discount_projection'] ?? []));
|
||||
?>
|
||||
<div class="container py-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<h2 class="mb-1">Withdrawal Refund Review</h2>
|
||||
<div class="text-muted">
|
||||
<?= esc(trim((string) ($c['student_firstname'] ?? '') . ' ' . (string) ($c['student_lastname'] ?? ''))) ?>
|
||||
· <?= esc($c['school_year'] ?? '') ?> · calculation v<?= (int) ($c['version'] ?? 0) ?>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-outline-secondary" href="<?= site_url('refunds/list') ?>">Back</a>
|
||||
</div>
|
||||
|
||||
<?php if (session()->getFlashdata('success')): ?><div class="alert alert-success"><?= esc(session()->getFlashdata('success')) ?></div><?php endif; ?>
|
||||
<?php if (session()->getFlashdata('error')): ?><div class="alert alert-danger"><?= esc(session()->getFlashdata('error')) ?></div><?php endif; ?>
|
||||
<?php if ($blockers !== []): ?>
|
||||
<div class="alert alert-danger">
|
||||
<strong>Cannot post this refund yet.</strong>
|
||||
<ul class="mb-0 mt-2"><?php foreach ($blockers as $blocker): ?><li><?= esc($blocker) ?></li><?php endforeach; ?></ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<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">Studied period</div><div class="fs-5 fw-semibold"><?= (int) ($c['studied_calendar_days'] ?? 0) ?> day(s) / <?= (int) ($c['studied_weeks'] ?? 0) ?> week(s)</div><div class="small">of <?= (int) ($c['total_instructional_weeks'] ?? 0) ?> instructional weeks</div></div></div></div>
|
||||
<div class="col-md-3"><div class="card h-100"><div class="card-body"><div class="text-muted small">Annual allocation</div><div class="fs-5 fw-semibold"><?= $money($c['annual_fee_allocation_cents'] ?? 0) ?></div><div class="small">Includes books</div></div></div></div>
|
||||
<div class="col-md-3"><div class="card h-100"><div class="card-body"><div class="text-muted small">Retained charge</div><div class="fs-5 fw-semibold"><?= $money($c['retained_charge_cents'] ?? 0) ?></div><div class="small">Books + earned tuition</div></div></div></div>
|
||||
<div class="col-md-3"><div class="card h-100"><div class="card-body"><div class="text-muted small"><?= ((int) ($c['new_refund_request_cents'] ?? 0)) > 0 ? 'Expected refund' : 'Expected balance' ?></div><div class="fs-5 fw-semibold"><?= $money(((int) ($c['new_refund_request_cents'] ?? 0)) > 0 ? ($c['new_refund_request_cents'] ?? 0) : ($c['balance_due_cents'] ?? 0)) ?></div><div class="small">Payments: <?= $money($c['valid_payment_cents'] ?? 0) ?></div></div></div></div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header fw-semibold">Books Kept by Student</div>
|
||||
<div class="table-responsive"><table class="table table-sm mb-0 no-mgmt-sticky no-dt-fixedheader" data-no-mgmt-sticky data-no-dt-fixedheader><thead><tr><th>Book</th><th>Issued</th><th>Status</th><th>Qty</th><th>Snapshot price</th><th>Total</th><th>Correction</th></tr></thead><tbody>
|
||||
<?php foreach ((array) ($c['books'] ?? []) as $book): ?>
|
||||
<tr><td><?= esc($book['book_name'] ?? ('Issue #' . ($book['id'] ?? ''))) ?></td><td><?= esc($book['issued_at'] ?? '') ?></td><td><?= esc($book['status'] ?? '') ?></td><td><?= (int) ($book['quantity'] ?? 0) ?></td><td><?= $money($book['unit_charge_price_cents'] ?? 0) ?></td><td><?= $money($book['total_charge_cents'] ?? 0) ?></td><td><?= esc($book['reversal_reason'] ?? '—') ?></td></tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($c['books'])): ?><tr><td colspan="7" class="text-muted">No book issues were recorded by the withdrawal date.</td></tr><?php endif; ?>
|
||||
</tbody></table></div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header fw-semibold">Refund Calculation</div>
|
||||
<div class="card-body row g-2">
|
||||
<div class="col-md-4">Issued books: <strong><?= $money($c['issued_book_charge_cents'] ?? 0) ?></strong></div>
|
||||
<div class="col-md-4">Instruction component: <strong><?= $money($c['annual_instruction_cents'] ?? 0) ?></strong></div>
|
||||
<div class="col-md-4">Earned tuition: <strong><?= $money($c['earned_tuition_cents'] ?? 0) ?></strong></div>
|
||||
<div class="col-md-4">Invoice adjustment: <strong><?= $money($c['invoice_adjustment_cents'] ?? 0) ?></strong></div>
|
||||
<div class="col-md-4">Adjusted invoice charge: <strong><?= $money($c['adjusted_invoice_charge_cents'] ?? 0) ?></strong></div>
|
||||
<div class="col-md-4">Open reservations: <strong><?= $money($c['open_reservation_cents'] ?? 0) ?></strong></div>
|
||||
<div class="col-md-4">Completed prior payouts: <strong><?= $money($c['completed_payout_cents'] ?? 0) ?></strong></div>
|
||||
<div class="col-md-4">Projected applied discount: <strong><?= $money($discountProjection['adjusted_discount_cents'] ?? 0) ?></strong></div>
|
||||
<div class="col-md-4">Refundable invoice credit: <strong><?= $money($c['refundable_credit_cents'] ?? 0) ?></strong></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" action="<?= site_url('administrator/withdrawals/' . (int) $c['enrollment_id'] . '/recalculate') ?>" class="card mb-3">
|
||||
<?= csrf_field() ?>
|
||||
<div class="card-header fw-semibold">Review Inputs</div>
|
||||
<div class="card-body row g-3">
|
||||
<div class="col-md-3"><label class="form-label">Enrollment date</label><input class="form-control" type="date" name="enrollment_date" value="<?= esc($c['enrollment_date'] ?? '') ?>" required></div>
|
||||
<div class="col-md-3"><label class="form-label">Withdrawal request date</label><input class="form-control" type="date" name="withdrawal_request_date" value="<?= esc($c['withdrawal_request_date'] ?? '') ?>" required></div>
|
||||
<div class="col-md-3"><label class="form-label">Legacy invoice</label><div class="form-check mt-2"><input class="form-check-input" type="checkbox" value="1" name="legacy_invoice_confirmed" id="legacyConfirmed"><label class="form-check-label" for="legacyConfirmed">I reconciled the aggregate invoice</label></div></div>
|
||||
<div class="col-md-12"><label class="form-label">Required audit reason when changing dates or confirming legacy data</label><textarea class="form-control" name="override_reason" rows="2"><?= esc($c['override_reason'] ?? '') ?></textarea></div>
|
||||
</div>
|
||||
<div class="card-footer"><button class="btn btn-outline-primary" type="submit">Update Preview</button></div>
|
||||
</form>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<a class="btn btn-outline-secondary" href="<?= site_url('administrator/withdrawal-calculations/' . (int) $c['id']) ?>">Detailed Breakdown</a>
|
||||
<form method="post" action="<?= site_url('administrator/withdrawal-calculations/' . (int) $c['id'] . '/confirm') ?>" onsubmit="return confirm('Post these invoice adjustments and finalize the withdrawal calculation?');">
|
||||
<?= csrf_field() ?>
|
||||
<button class="btn btn-success" type="submit" <?= $blockers !== [] || ($c['status'] ?? '') === 'posted' ? 'disabled' : '' ?>>Confirm and Post</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
Reference in New Issue
Block a user