add waiver column to event table
This commit is contained in:
@@ -537,6 +537,7 @@ $routes->post('payment/event_charges', 'View\EventController::eventUpdate');
|
||||
$routes->get('administrator/event-charges', 'View\EventController::eventShow');
|
||||
$routes->post('administrator/event-charges/remove/(:num)', 'View\EventController::removeCharge/$1');
|
||||
$routes->post('administrator/event-charges/payment/(:num)', 'View\EventController::toggleEventPayment/$1');
|
||||
$routes->post('administrator/event-charges/waiver/(:num)', 'View\EventController::toggleWaiverStatus/$1');
|
||||
$routes->get('administrator/get-students-with-charges', 'View\EventController::getStudentsWithCharges');
|
||||
|
||||
$routes->get('parent/events', 'View\ParentController::parentEventPage', ['filter' => 'auth:parent']);
|
||||
|
||||
@@ -41,6 +41,7 @@ class EventController extends ResourceController
|
||||
protected $categories;
|
||||
protected $enrollmentModel;
|
||||
private ?bool $eventChargesHasCreatedBy = null;
|
||||
private ?bool $eventChargesHasWaiverSigned = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -85,6 +86,41 @@ class EventController extends ResourceController
|
||||
return $this->eventChargesHasCreatedBy;
|
||||
}
|
||||
|
||||
private function eventChargesSupportsWaiverSigned(): bool
|
||||
{
|
||||
if ($this->eventChargesHasWaiverSigned !== null) {
|
||||
return $this->eventChargesHasWaiverSigned;
|
||||
}
|
||||
|
||||
try {
|
||||
$db = Database::connect();
|
||||
$this->eventChargesHasWaiverSigned = $db->fieldExists('waiver_signed', 'event_charges');
|
||||
} catch (\Throwable $e) {
|
||||
$this->eventChargesHasWaiverSigned = false;
|
||||
}
|
||||
|
||||
return $this->eventChargesHasWaiverSigned;
|
||||
}
|
||||
|
||||
private function getEventChargesReturnTo(): string
|
||||
{
|
||||
$fallback = site_url('administrator/event-charges');
|
||||
$returnTo = trim((string) ($this->request->getPost('return_to') ?? ''));
|
||||
if ($returnTo === '') {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$base = rtrim((string) base_url(), '/');
|
||||
if (str_starts_with($returnTo, '/')) {
|
||||
return $returnTo;
|
||||
}
|
||||
if ($base !== '' && str_starts_with($returnTo, $base)) {
|
||||
return $returnTo;
|
||||
}
|
||||
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$eventModel = new EventModel();
|
||||
@@ -570,6 +606,7 @@ class EventController extends ResourceController
|
||||
|
||||
$parentsForInvoice = [];
|
||||
$supportsCreatedBy = $this->eventChargesSupportsCreatedBy();
|
||||
$supportsWaiverSigned = $this->eventChargesSupportsWaiverSigned();
|
||||
|
||||
foreach ($participations as $studentId => $value) {
|
||||
$existing = $this->eventChargesModel->where([
|
||||
@@ -596,6 +633,9 @@ class EventController extends ResourceController
|
||||
'updated_by' => $userId,
|
||||
'class_section_id'=> $classSectionId,
|
||||
];
|
||||
if ($supportsWaiverSigned) {
|
||||
$updateData['waiver_signed'] = (int) ($existing['waiver_signed'] ?? 0);
|
||||
}
|
||||
if (isset($event['amount']) && ((float)$event['amount'] !== (float)($existing['charged'] ?? 0))) {
|
||||
$updateData['charged'] = $event['amount'];
|
||||
}
|
||||
@@ -614,6 +654,9 @@ class EventController extends ResourceController
|
||||
'semester' => $semester,
|
||||
'updated_by' => $userId
|
||||
];
|
||||
if ($supportsWaiverSigned) {
|
||||
$insertData['waiver_signed'] = 0;
|
||||
}
|
||||
if ($supportsCreatedBy) {
|
||||
$insertData['created_by'] = $userId;
|
||||
}
|
||||
@@ -630,6 +673,7 @@ class EventController extends ResourceController
|
||||
$parentPhone = trim($pieces['parent_phone'] ?? '');
|
||||
$parentEmail = trim((string)($pieces['parent_email'] ?? ''));
|
||||
$markPaid = (string)($pieces['paid'] ?? '0') === '1';
|
||||
$waiverSigned = (string)($pieces['waiver_signed'] ?? '0') === '1';
|
||||
|
||||
if (!$firstname && !$lastname) {
|
||||
continue;
|
||||
@@ -664,7 +708,7 @@ class EventController extends ResourceController
|
||||
$existingExternal = $this->eventChargesModel->where($matchConditions)->first();
|
||||
|
||||
if ($existingExternal) {
|
||||
$this->eventChargesModel->update($existingExternal['id'], [
|
||||
$updateData = [
|
||||
'participation' => 'yes',
|
||||
'charged' => $event['amount'],
|
||||
'updated_by' => $userId,
|
||||
@@ -674,7 +718,11 @@ class EventController extends ResourceController
|
||||
'external_parent_lastname' => $parentLast !== '' ? $parentLast : ($existingExternal['external_parent_lastname'] ?? null),
|
||||
'external_parent_phone' => $parentPhone !== '' ? $parentPhone : ($existingExternal['external_parent_phone'] ?? null),
|
||||
'external_parent_email' => $parentEmail !== '' ? $parentEmail : ($existingExternal['external_parent_email'] ?? null),
|
||||
]);
|
||||
];
|
||||
if ($supportsWaiverSigned) {
|
||||
$updateData['waiver_signed'] = $waiverSigned ? 1 : 0;
|
||||
}
|
||||
$this->eventChargesModel->update($existingExternal['id'], $updateData);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -696,6 +744,9 @@ class EventController extends ResourceController
|
||||
'semester' => $semester,
|
||||
'updated_by' => $userId,
|
||||
];
|
||||
if ($supportsWaiverSigned) {
|
||||
$insertData['waiver_signed'] = $waiverSigned ? 1 : 0;
|
||||
}
|
||||
if ($supportsCreatedBy) {
|
||||
$insertData['created_by'] = $userId;
|
||||
}
|
||||
@@ -725,13 +776,14 @@ class EventController extends ResourceController
|
||||
|
||||
public function removeCharge($chargeId = null)
|
||||
{
|
||||
$returnTo = $this->getEventChargesReturnTo();
|
||||
if (!$chargeId) {
|
||||
return redirect()->back()->with('error', 'Invalid charge.');
|
||||
return redirect()->to($returnTo)->with('error', 'Invalid charge.');
|
||||
}
|
||||
|
||||
$charge = $this->eventChargesModel->find($chargeId);
|
||||
if (!$charge) {
|
||||
return redirect()->back()->with('error', 'Charge not found.');
|
||||
return redirect()->to($returnTo)->with('error', 'Charge not found.');
|
||||
}
|
||||
|
||||
$paymentId = (int)($charge['event_payment_id'] ?? 0);
|
||||
@@ -744,19 +796,20 @@ class EventController extends ResourceController
|
||||
$this->invoiceController->generateInvoice((string)$charge['parent_id'], (string)($charge['school_year'] ?? $this->schoolYear), (string)($charge['semester'] ?? $this->semester), false);
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success', 'Participation removed, invoices updated.');
|
||||
return redirect()->to($returnTo)->with('success', 'Participation removed, invoices updated.');
|
||||
}
|
||||
|
||||
public function toggleEventPayment($chargeId = null)
|
||||
{
|
||||
$returnTo = $this->getEventChargesReturnTo();
|
||||
if (!$chargeId) {
|
||||
return redirect()->back()->with('error', 'Invalid charge.');
|
||||
return redirect()->to($returnTo)->with('error', 'Invalid charge.');
|
||||
}
|
||||
|
||||
$isPaid = $this->request->getPost('paid') === '1';
|
||||
$meta = $this->applyEventPaymentStatus((int)$chargeId, $isPaid);
|
||||
if (!$meta) {
|
||||
return redirect()->back()->with('error', 'Charge not found.');
|
||||
return redirect()->to($returnTo)->with('error', 'Charge not found.');
|
||||
}
|
||||
|
||||
if (!empty($meta['invoice_id'])) {
|
||||
@@ -764,7 +817,33 @@ class EventController extends ResourceController
|
||||
$this->fixInvoiceStatusAfterCharge((int)$meta['parent_id'], (string)$meta['school_year']);
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success', 'Event payment status updated.');
|
||||
return redirect()->to($returnTo)->with('success', 'Event payment status updated.');
|
||||
}
|
||||
|
||||
public function toggleWaiverStatus($chargeId = null)
|
||||
{
|
||||
$returnTo = $this->getEventChargesReturnTo();
|
||||
if (!$chargeId) {
|
||||
return redirect()->to($returnTo)->with('error', 'Invalid charge.');
|
||||
}
|
||||
|
||||
if (!$this->eventChargesSupportsWaiverSigned()) {
|
||||
return redirect()->to($returnTo)->with('error', 'Waiver tracking is not available until the database migration is applied.');
|
||||
}
|
||||
|
||||
$charge = $this->eventChargesModel->find($chargeId);
|
||||
if (!$charge) {
|
||||
return redirect()->to($returnTo)->with('error', 'Charge not found.');
|
||||
}
|
||||
|
||||
$signed = $this->request->getPost('waiver_signed') === '1';
|
||||
|
||||
$this->eventChargesModel->update((int) $chargeId, [
|
||||
'waiver_signed' => $signed ? 1 : 0,
|
||||
'updated_by' => session()->get('user_id'),
|
||||
]);
|
||||
|
||||
return redirect()->to($returnTo)->with('success', $signed ? 'Waiver marked as signed.' : 'Waiver marked as unsigned.');
|
||||
}
|
||||
|
||||
private function parentHasEnrollment(int $parentId, string $schoolYear): bool
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddWaiverSignedToEventCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$fields = [
|
||||
'waiver_signed' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 0,
|
||||
'after' => 'charged',
|
||||
],
|
||||
];
|
||||
|
||||
if (! $this->db->fieldExists('waiver_signed', 'event_charges')) {
|
||||
$this->forge->addColumn('event_charges', $fields);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->fieldExists('waiver_signed', 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', 'waiver_signed');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ class EventChargesModel extends Model
|
||||
'student_id',
|
||||
'participation',
|
||||
'charged',
|
||||
'waiver_signed',
|
||||
'event_paid',
|
||||
'event_payment_id',
|
||||
'class_section_id',
|
||||
|
||||
@@ -183,6 +183,7 @@
|
||||
<th>Class Section</th>
|
||||
<th>Charged Amount</th>
|
||||
<th>Created</th>
|
||||
<th>Waiver</th>
|
||||
<th>Fees Paid</th>
|
||||
<th>Payment</th>
|
||||
<th>Actions</th>
|
||||
@@ -193,6 +194,22 @@
|
||||
<?php
|
||||
$isParticipating = ($charge['participation'] === 'yes');
|
||||
$isEventPaid = !empty($charge['event_paid']);
|
||||
$returnParams = [];
|
||||
if (!empty($semester)) {
|
||||
$returnParams['semester'] = $semester;
|
||||
}
|
||||
if (!empty($school_year)) {
|
||||
$returnParams['school_year'] = $school_year;
|
||||
}
|
||||
if (!empty($filterEventId)) {
|
||||
$returnParams['event_id'] = $filterEventId;
|
||||
}
|
||||
if (!empty($filterParentId)) {
|
||||
$returnParams['parent_id'] = $filterParentId;
|
||||
}
|
||||
$returnTo = site_url('administrator/event-charges')
|
||||
. (!empty($returnParams) ? '?' . http_build_query($returnParams) : '')
|
||||
. '#eventTable_' . (int) ($charge['event_id'] ?? 0);
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc($charge['id']) ?></td>
|
||||
@@ -237,8 +254,22 @@
|
||||
$feeAmount = (float) ($charge['event_amount'] ?? 0);
|
||||
$hasBalanceRecord = array_key_exists((int)$charge['parent_id'], $parentBalances);
|
||||
$parentBalance = $hasBalanceRecord ? (float)$parentBalances[$charge['parent_id']] : null;
|
||||
$waiverSigned = !empty($charge['waiver_signed']);
|
||||
$feeIsPaid = $isParticipating && ($isEventPaid || ($hasBalanceRecord && $parentBalance <= 0));
|
||||
?>
|
||||
<td class="text-center">
|
||||
<form method="post" action="<?= site_url('administrator/event-charges/waiver/' . esc($charge['id'])) ?>" class="d-inline-flex align-items-center">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="return_to" value="<?= esc($returnTo) ?>">
|
||||
<input type="hidden" name="waiver_signed" value="<?= $waiverSigned ? '1' : '0' ?>">
|
||||
<input type="checkbox" class="form-check-input" id="eventWaiver_<?= esc($charge['id']) ?>"
|
||||
<?= $waiverSigned ? 'checked' : '' ?>
|
||||
onchange="this.form.waiver_signed.value = this.checked ? 1 : 0; this.form.submit();">
|
||||
<label class="form-check-label ms-2" for="eventWaiver_<?= esc($charge['id']) ?>" aria-hidden="true">
|
||||
<?= $waiverSigned ? 'Signed' : 'Unsigned' ?>
|
||||
</label>
|
||||
</form>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<?php if ($feeIsPaid): ?>
|
||||
<span class="badge bg-success">Paid</span>
|
||||
@@ -249,6 +280,7 @@
|
||||
<td class="text-center">
|
||||
<form method="post" action="<?= site_url('administrator/event-charges/payment/' . esc($charge['id'])) ?>" class="d-inline-flex align-items-center">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="return_to" value="<?= esc($returnTo) ?>">
|
||||
<input type="hidden" name="paid" value="<?= $feeIsPaid ? '1' : '0' ?>">
|
||||
<input type="checkbox" class="form-check-input" id="eventPayment_<?= esc($charge['id']) ?>"
|
||||
<?= $isEventPaid ? 'checked' : '' ?>
|
||||
@@ -263,6 +295,7 @@
|
||||
</a>
|
||||
<form action="<?= site_url('administrator/event-charges/remove/' . esc($charge['id'])) ?>" method="post" onsubmit="return confirm('Remove this participation and update the charge?');">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="return_to" value="<?= esc($returnTo) ?>">
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm">Remove</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -280,7 +313,7 @@
|
||||
<tr>
|
||||
<th colspan="4">Totals</th>
|
||||
<th>$<?= esc(number_format($totalCharged, 2)) ?></th>
|
||||
<th colspan="5">
|
||||
<th colspan="6">
|
||||
<span class="badge bg-secondary">
|
||||
<?= esc($totalParticipants) ?> participating
|
||||
</span>
|
||||
@@ -444,6 +477,7 @@ function loadStudentsWithCharges() {
|
||||
function buildExternalRow(entry) {
|
||||
const key = entry.key;
|
||||
const isPaid = !!entry.paid;
|
||||
const waiverSigned = !!entry.waiverSigned;
|
||||
const firstEsc = escapeHtml(entry.firstname);
|
||||
const lastEsc = escapeHtml(entry.lastname);
|
||||
const noteEsc = escapeHtml(entry.note);
|
||||
@@ -472,6 +506,7 @@ function loadStudentsWithCharges() {
|
||||
<input type="hidden" name="external_participants[${key}][parent_lastname]" value="${parentLastEsc}">
|
||||
<input type="hidden" name="external_participants[${key}][parent_phone]" value="${parentPhoneEsc}">
|
||||
<input type="hidden" name="external_participants[${key}][parent_email]" value="${parentEmailEsc}">
|
||||
<input type="hidden" name="external_participants[${key}][waiver_signed]" value="${waiverSigned ? '1' : '0'}">
|
||||
<input type="hidden" name="external_participants[${key}][paid]" value="${isPaid ? '1' : '0'}">
|
||||
</div>
|
||||
`);
|
||||
@@ -497,6 +532,12 @@ function loadStudentsWithCharges() {
|
||||
<td>External</td>
|
||||
<td>$${amountDisplay}</td>
|
||||
<td>${createdDisplay}</td>
|
||||
<td class="text-center">
|
||||
<div class="form-check d-inline-flex align-items-center gap-2 justify-content-center m-0">
|
||||
<input class="form-check-input external-waiver-toggle" type="checkbox" data-key="${key}" ${waiverSigned ? 'checked' : ''}>
|
||||
<span class="small text-muted external-waiver-label">${waiverSigned ? 'Signed' : 'Unsigned'}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="badge ${isPaid ? 'bg-success' : 'bg-danger'} external-paid-badge">${isPaid ? 'Paid' : 'Unpaid'}</span>
|
||||
</td>
|
||||
@@ -526,6 +567,7 @@ function loadStudentsWithCharges() {
|
||||
function saveExternalDraft(entry) {
|
||||
entry.key = entry.key ?? `${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
||||
entry.paid = !!entry.paid;
|
||||
entry.waiverSigned = !!entry.waiverSigned;
|
||||
removeExternalEntryFromDom(entry.key);
|
||||
externalDrafts = externalDrafts.filter((existing) => existing.key !== entry.key);
|
||||
externalDrafts.push(entry);
|
||||
@@ -646,6 +688,7 @@ function loadStudentsWithCharges() {
|
||||
eventId: (draftEntry && draftEntry.eventId) ? draftEntry.eventId : eventId,
|
||||
eventAmount: (draftEntry && draftEntry.eventAmount) ? draftEntry.eventAmount : eventAmount,
|
||||
parentDisplayName: (draftEntry && draftEntry.parentDisplayName) ? draftEntry.parentDisplayName : parentName,
|
||||
waiverSigned: (draftEntry && typeof draftEntry.waiverSigned !== 'undefined') ? !!draftEntry.waiverSigned : false,
|
||||
paid: (draftEntry && typeof draftEntry.paid !== 'undefined') ? !!draftEntry.paid : false,
|
||||
};
|
||||
if (editingKey) {
|
||||
@@ -695,6 +738,27 @@ function loadStudentsWithCharges() {
|
||||
$badge.removeClass('bg-success').addClass('bg-danger').text('Unpaid');
|
||||
}
|
||||
});
|
||||
$(document).on('change', '.external-waiver-toggle', function() {
|
||||
const key = $(this).data('key');
|
||||
const signed = !!this.checked;
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
const entry = getDraftByKey(key);
|
||||
if (entry) {
|
||||
entry.waiverSigned = signed;
|
||||
persistDrafts();
|
||||
}
|
||||
$externalHidden
|
||||
.find(`div[data-key="${key}"] input[name="external_participants[${key}][waiver_signed]"]`)
|
||||
.val(signed ? '1' : '0');
|
||||
const $label = $(`tr.external-preview[data-key="${key}"] .external-waiver-label`);
|
||||
if (signed) {
|
||||
$label.text('Signed');
|
||||
} else {
|
||||
$label.text('Unsigned');
|
||||
}
|
||||
});
|
||||
$('#event-participant-form').on('submit', function() {
|
||||
localStorage.removeItem(storageKey);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user