update event charge at the invoice
This commit is contained in:
@@ -535,6 +535,8 @@ $routes->post('payment/event_charges', 'View\EventController::eventUpdate');
|
||||
|
||||
// Parent event participation
|
||||
$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->get('administrator/get-students-with-charges', 'View\EventController::getStudentsWithCharges');
|
||||
|
||||
$routes->get('parent/events', 'View\ParentController::parentEventPage');
|
||||
|
||||
@@ -750,7 +750,9 @@ class DiscountController extends BaseController
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
|
||||
$newTotal = round($tuitionSubtotal + $eventSubtotal + $additionalSubtotal, 2);
|
||||
$discountableTotal = $tuitionSubtotal + $additionalSubtotal;
|
||||
$nonDiscountableTotal = $eventSubtotal;
|
||||
$newTotal = round($discountableTotal + $nonDiscountableTotal, 2);
|
||||
|
||||
// ---- Payments / Discounts / Refunds ----
|
||||
$db = $this->db;
|
||||
@@ -794,7 +796,8 @@ class DiscountController extends BaseController
|
||||
->get()->getRowArray();
|
||||
$totalRefundPaid = (float)($refundRow['total_refund_paid'] ?? 0);
|
||||
|
||||
$newBalance = max(0.0, $newTotal - $totalDisc - $totalPaid - $totalRefundPaid);
|
||||
$appliedDiscount = min($totalDisc, $discountableTotal);
|
||||
$newBalance = max(0.0, $newTotal - $appliedDiscount - $totalPaid - $totalRefundPaid);
|
||||
$newStatus = ($newBalance <= 0.00001) ? 'Paid' : (($totalPaid > 0) ? 'Partially Paid' : 'Unpaid');
|
||||
|
||||
$updateData = [
|
||||
|
||||
@@ -6,8 +6,14 @@ use App\Models\EventModel;
|
||||
use App\Models\EventChargesModel;
|
||||
use App\Models\UserModel;
|
||||
use App\Models\StudentModel;
|
||||
use App\Models\StudentClassModel;
|
||||
use App\Models\ConfigurationModel;
|
||||
use App\Models\EnrollmentModel;
|
||||
use App\Models\InvoiceModel;
|
||||
use App\Models\InvoiceEventModel;
|
||||
use App\Models\ClassSectionModel;
|
||||
use App\Models\PaymentModel;
|
||||
#use ???
|
||||
use App\Controllers\View\InvoiceController;
|
||||
use CodeIgniter\RESTful\ResourceController;
|
||||
|
||||
@@ -19,6 +25,11 @@ class EventController extends ResourceController
|
||||
protected $configModel;
|
||||
protected $eventModel;
|
||||
protected $invoiceController;
|
||||
protected $invoiceModel;
|
||||
protected $invoiceEventModel;
|
||||
protected $studentClassModel;
|
||||
protected $classSectionModel;
|
||||
protected $paymentModel;
|
||||
protected $schoolYear;
|
||||
protected $semester;
|
||||
protected $categories;
|
||||
@@ -32,6 +43,11 @@ class EventController extends ResourceController
|
||||
$this->userModel = new UserModel(); // Add this
|
||||
$this->eventModel = new EventModel();
|
||||
$this->invoiceController = new InvoiceController();
|
||||
$this->invoiceModel = new InvoiceModel();
|
||||
$this->invoiceEventModel = new InvoiceEventModel();
|
||||
$this->studentClassModel = new StudentClassModel();
|
||||
$this->classSectionModel = new ClassSectionModel();
|
||||
$this->paymentModel = new PaymentModel();
|
||||
$this->enrollmentModel = new EnrollmentModel();
|
||||
|
||||
$this->schoolYear = $this->configModel->getConfig('school_year');
|
||||
@@ -166,6 +182,19 @@ class EventController extends ResourceController
|
||||
$parentIds[] = $charge['parent_id'];
|
||||
}
|
||||
|
||||
// Also remove any invoice_event rows tied to this event
|
||||
$eventName = $event['event_name'] ?? null;
|
||||
if ($eventName) {
|
||||
$builder = $this->invoiceEventModel->where('event_name', $eventName);
|
||||
if (!empty($event['school_year'])) {
|
||||
$builder->where('school_year', $event['school_year']);
|
||||
}
|
||||
if (!empty($event['semester'])) {
|
||||
$builder->where('semester', $event['semester']);
|
||||
}
|
||||
$builder->delete();
|
||||
}
|
||||
|
||||
// Delete event
|
||||
$this->eventModel->delete($id);
|
||||
|
||||
@@ -189,6 +218,7 @@ class EventController extends ResourceController
|
||||
$parents = $this->userModel->getParents();
|
||||
$events = $this->eventModel->getActiveEvents($this->schoolYear);
|
||||
$filterEventId = (int) ($this->request->getGet('event_id') ?? 0);
|
||||
$filterParentId = (int) ($this->request->getGet('parent_id') ?? 0);
|
||||
|
||||
$chargesBuilder = $this->eventChargesModel
|
||||
->select('event_charges.*,
|
||||
@@ -209,6 +239,67 @@ class EventController extends ResourceController
|
||||
->orderBy('event_charges.created_at', 'DESC')
|
||||
->findAll();
|
||||
|
||||
foreach ($charges as &$charge) {
|
||||
if (empty($charge['class_section_id']) && !empty($charge['student_id'])) {
|
||||
$sections = $this->studentClassModel->getClassSectionIdsByStudentId(
|
||||
(int)$charge['student_id'],
|
||||
$schoolYear
|
||||
);
|
||||
if (!empty($sections)) {
|
||||
$charge['class_section_id'] = $sections[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($charge);
|
||||
|
||||
$parentBalances = [];
|
||||
try {
|
||||
$balanceRows = $this->invoiceModel
|
||||
->select('parent_id, COALESCE(SUM(balance),0) AS total_balance')
|
||||
->where('school_year', $schoolYear)
|
||||
->where('semester', $semester)
|
||||
->groupBy('parent_id')
|
||||
->findAll();
|
||||
|
||||
foreach ($balanceRows as $row) {
|
||||
$parentBalances[(int)($row['parent_id'] ?? 0)] = (float)($row['total_balance'] ?? 0.0);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
log_message('error', 'Failed to load parent balances: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$sectionIds = array_unique(array_filter(array_column($charges, 'class_section_id')));
|
||||
$classSectionNames = [];
|
||||
if (!empty($sectionIds)) {
|
||||
$sections = $this->classSectionModel
|
||||
->select('class_section_id, class_section_name')
|
||||
->whereIn('class_section_id', $sectionIds)
|
||||
->findAll();
|
||||
foreach ($sections as $section) {
|
||||
$classSectionNames[(int)($section['class_section_id'] ?? 0)] = $section['class_section_name'] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
$semesterOptions = (new EventChargesModel())
|
||||
->select('semester')
|
||||
->distinct()
|
||||
->orderBy('semester', 'ASC')
|
||||
->findColumn('semester');
|
||||
$semesterOptions = array_values(array_filter(array_unique($semesterOptions ?? [])));
|
||||
if (empty($semesterOptions)) {
|
||||
$semesterOptions = [$this->semester];
|
||||
}
|
||||
|
||||
$schoolYearOptions = (new EventChargesModel())
|
||||
->select('school_year')
|
||||
->distinct()
|
||||
->orderBy('school_year', 'ASC')
|
||||
->findColumn('school_year');
|
||||
$schoolYearOptions = array_values(array_filter(array_unique($schoolYearOptions ?? [])));
|
||||
if (empty($schoolYearOptions)) {
|
||||
$schoolYearOptions = [$this->schoolYear];
|
||||
}
|
||||
|
||||
return view('administrator/events/event_charges', [
|
||||
'charges' => $charges,
|
||||
'parents' => $parents,
|
||||
@@ -216,6 +307,11 @@ class EventController extends ResourceController
|
||||
'school_year' => $schoolYear,
|
||||
'semester' => $semester,
|
||||
'filterEventId' => $filterEventId,
|
||||
'filterParentId' => $filterParentId,
|
||||
'parentBalances' => $parentBalances,
|
||||
'classSectionNames' => $classSectionNames,
|
||||
'semesterOptions' => $semesterOptions,
|
||||
'schoolYearOptions' => $schoolYearOptions,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -252,13 +348,20 @@ class EventController extends ResourceController
|
||||
continue;
|
||||
}
|
||||
|
||||
// value is 'yes'
|
||||
$sectionIds = $this->studentClassModel->getClassSectionIdsByStudentId($studentId, $schoolYear);
|
||||
$classSectionId = !empty($sectionIds) ? $sectionIds[0] : null;
|
||||
|
||||
if ($existing) {
|
||||
$this->eventChargesModel->update($existing['id'], [
|
||||
'participation' => 'yes',
|
||||
'charged' => $event['amount'],
|
||||
'updated_by' => $userId
|
||||
]);
|
||||
$updateData = [
|
||||
'participation' => 'yes',
|
||||
'updated_by' => $userId,
|
||||
'class_section_id'=> $classSectionId,
|
||||
];
|
||||
if (isset($event['amount']) && ((float)$event['amount'] !== (float)($existing['charged'] ?? 0))) {
|
||||
$updateData['charged'] = $event['amount'];
|
||||
}
|
||||
$this->eventChargesModel->update($existing['id'], $updateData);
|
||||
continue;
|
||||
} else {
|
||||
$this->eventChargesModel->insert([
|
||||
'parent_id' => $parentId,
|
||||
@@ -266,6 +369,8 @@ class EventController extends ResourceController
|
||||
'event_id' => $eventId,
|
||||
'participation' => 'yes',
|
||||
'charged' => $event['amount'],
|
||||
'event_paid' => 0,
|
||||
'class_section_id' => $classSectionId,
|
||||
'school_year' => $schoolYear,
|
||||
'semester' => $semester,
|
||||
'created_by' => $userId,
|
||||
@@ -276,9 +381,90 @@ class EventController extends ResourceController
|
||||
|
||||
$this->invoiceController->generateInvoice($parentId);
|
||||
|
||||
$this->fixInvoiceStatusAfterCharge($parentId, $schoolYear);
|
||||
|
||||
return redirect()->back()->with('success', 'Event charges updated successfully.');
|
||||
}
|
||||
|
||||
public function removeCharge($chargeId = null)
|
||||
{
|
||||
if (!$chargeId) {
|
||||
return redirect()->back()->with('error', 'Invalid charge.');
|
||||
}
|
||||
|
||||
$charge = $this->eventChargesModel->find($chargeId);
|
||||
if (!$charge) {
|
||||
return redirect()->back()->with('error', 'Charge not found.');
|
||||
}
|
||||
|
||||
$paymentId = (int)($charge['event_payment_id'] ?? 0);
|
||||
if ($paymentId > 0) {
|
||||
$this->paymentModel->delete($paymentId);
|
||||
}
|
||||
|
||||
$this->eventChargesModel->delete($chargeId);
|
||||
$this->invoiceController->generateInvoice($charge['parent_id']);
|
||||
|
||||
return redirect()->back()->with('success', 'Participation removed, invoices updated.');
|
||||
}
|
||||
|
||||
public function toggleEventPayment($chargeId = null)
|
||||
{
|
||||
if (!$chargeId) {
|
||||
return redirect()->back()->with('error', 'Invalid charge.');
|
||||
}
|
||||
|
||||
$charge = $this->eventChargesModel->find($chargeId);
|
||||
if (!$charge) {
|
||||
return redirect()->back()->with('error', 'Charge not found.');
|
||||
}
|
||||
|
||||
$isPaid = $this->request->getPost('paid') === '1';
|
||||
$event = $this->eventModel->find($charge['event_id']);
|
||||
$eventAmount = max(0.0, (float)($event['amount'] ?? 0));
|
||||
$paymentId = (int)($charge['event_payment_id'] ?? 0);
|
||||
|
||||
$parentId = $charge['parent_id'];
|
||||
$schoolYear = $charge['school_year'] ?? $this->schoolYear;
|
||||
|
||||
if (!empty($eventAmount)) {
|
||||
$invoice = $this->invoiceModel
|
||||
->where('parent_id', $parentId)
|
||||
->where('school_year', $schoolYear)
|
||||
->orderBy('id', 'DESC')
|
||||
->first();
|
||||
|
||||
if (!$invoice) {
|
||||
$this->invoiceController->generateInvoice($parentId);
|
||||
$invoice = $this->invoiceModel
|
||||
->where('parent_id', $parentId)
|
||||
->where('school_year', $schoolYear)
|
||||
->orderBy('id', 'DESC')
|
||||
->first();
|
||||
}
|
||||
|
||||
if ($invoice) {
|
||||
if ($isPaid && !$paymentId) {
|
||||
$paymentId = $this->createEventPayment($parentId, (int)$invoice['id'], $eventAmount, $schoolYear, $charge['semester'] ?? $this->semester);
|
||||
} elseif (!$isPaid && $paymentId > 0) {
|
||||
$this->paymentModel->delete($paymentId);
|
||||
$paymentId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->eventChargesModel->update($chargeId, [
|
||||
'event_paid' => $isPaid ? 1 : 0,
|
||||
'charged' => $eventAmount,
|
||||
'event_payment_id' => $paymentId > 0 ? $paymentId : null,
|
||||
]);
|
||||
|
||||
$this->invoiceController->generateInvoice($parentId);
|
||||
$this->fixInvoiceStatusAfterCharge($parentId, $schoolYear);
|
||||
|
||||
return redirect()->back()->with('success', 'Event payment status updated.');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -292,10 +478,18 @@ class EventController extends ResourceController
|
||||
$students = $this->studentModel->where('parent_id', $parentId)->findAll();
|
||||
|
||||
// Get student_ids that already have charges
|
||||
$chargedStudentIds = $this->eventChargesModel
|
||||
$eventId = $this->request->getGet('event_id');
|
||||
|
||||
$chargesBuilder = $this->eventChargesModel
|
||||
->where('parent_id', $parentId)
|
||||
->where('semester', $semester)
|
||||
->where('school_year', $schoolYear)
|
||||
->where('school_year', $schoolYear);
|
||||
|
||||
if (!empty($eventId)) {
|
||||
$chargesBuilder->where('event_id', $eventId);
|
||||
}
|
||||
|
||||
$chargedStudentIds = $chargesBuilder
|
||||
->groupBy('student_id')
|
||||
->select('student_id')
|
||||
->findColumn('student_id');
|
||||
@@ -312,5 +506,58 @@ class EventController extends ResourceController
|
||||
return $this->response->setJSON($data);
|
||||
}
|
||||
|
||||
private function createEventPayment(int $parentId, int $invoiceId, float $amount, string $schoolYear, ?string $semester): ?int
|
||||
{
|
||||
if ($amount <= 0 || $invoiceId <= 0 || $parentId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$monthSemester = $semester ?: $this->semester;
|
||||
$data = [
|
||||
'parent_id' => $parentId,
|
||||
'invoice_id' => $invoiceId,
|
||||
'total_amount' => $amount,
|
||||
'paid_amount' => $amount,
|
||||
'balance' => 0.0,
|
||||
'number_of_installments' => 1,
|
||||
'payment_method' => 'Event charge',
|
||||
'payment_date' => utc_now(),
|
||||
'school_year' => $schoolYear,
|
||||
'semester' => $monthSemester,
|
||||
'status' => 'Paid',
|
||||
'transaction_id' => $this->paymentModel->generateNewTransactionId(),
|
||||
'updated_by' => session()->get('user_id'),
|
||||
];
|
||||
|
||||
if (!$this->paymentModel->insert($data)) {
|
||||
log_message('error', 'Failed to insert event payment: ' . json_encode($this->paymentModel->errors()));
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int)$this->paymentModel->getInsertID();
|
||||
}
|
||||
|
||||
private function fixInvoiceStatusAfterCharge($parentId, $schoolYear)
|
||||
{
|
||||
if (!$parentId || !$schoolYear) {
|
||||
return;
|
||||
}
|
||||
|
||||
$invoices = $this->invoiceModel
|
||||
->where('parent_id', $parentId)
|
||||
->where('school_year', $schoolYear)
|
||||
->findAll();
|
||||
|
||||
foreach ($invoices as $invoice) {
|
||||
$status = strtolower(trim($invoice['status'] ?? ''));
|
||||
$balance = (float)($invoice['balance'] ?? 0.0);
|
||||
|
||||
if ($balance <= 0.00001 && $status !== 'paid') {
|
||||
$this->invoiceModel->update($invoice['id'], ['status' => 'Paid']);
|
||||
} elseif ($status === 'paid' && $balance > 0) {
|
||||
$this->invoiceModel->update($invoice['id'], ['status' => 'Unpaid']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -678,7 +678,7 @@ class InvoiceController extends ResourceController
|
||||
log_message('error', 'additional_charges sum failed for discount recalculation invoice ' . (int)$invoice['id'] . ': ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$baseTotal = round($tuitionFee + $eventchargeTotal + $extrasSum, 2);
|
||||
$baseTotal = round($tuitionFee + $extrasSum, 2);
|
||||
|
||||
// Recalculate discount
|
||||
if ($discountUsage['discount_type'] === 'percent') {
|
||||
@@ -1612,12 +1612,24 @@ private function getGradeLevel($grade): array
|
||||
$invoice['last_payment_date'] = $lastPayments[$invoice['id']]['last_payment_date'] ?? null;
|
||||
}
|
||||
|
||||
$invoiceEventCharges = [];
|
||||
foreach ($invoices as $invoice) {
|
||||
$year = $invoice['school_year'] ?? $this->schoolYear;
|
||||
$sem = $invoice['semester'] ?? $this->semester;
|
||||
$invoiceEventCharges[(int)$invoice['id']] = $this->chargesModel->getChargesWithEventInfo(
|
||||
$invoice['parent_id'],
|
||||
$year,
|
||||
$sem
|
||||
);
|
||||
}
|
||||
|
||||
return view('/parent/invoice_payment', [
|
||||
'invoices' => $invoices,
|
||||
'schoolYears' => $schoolYears,
|
||||
'selectedYear' => $selectedYear,
|
||||
'currentSchoolYear' => $currentSchoolYear,
|
||||
'dueDate' => $this->dueDate
|
||||
'dueDate' => $this->dueDate,
|
||||
'invoiceEventCharges' => $invoiceEventCharges,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddEventPaidFlagToCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$fields = [
|
||||
'event_paid' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 0,
|
||||
'after' => 'charged',
|
||||
],
|
||||
];
|
||||
|
||||
$this->forge->addColumn('event_charges', $fields);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropColumn('event_charges', 'event_paid');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddClassSectionToEventCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$fields = [
|
||||
'class_section_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
'after' => 'event_paid',
|
||||
],
|
||||
];
|
||||
|
||||
if (! $this->db->fieldExists('class_section_id', 'event_charges')) {
|
||||
$this->forge->addColumn('event_charges', $fields);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->fieldExists('class_section_id', 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', 'class_section_id');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddEventPaymentRefToEventCharges extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$fields = [
|
||||
'event_payment_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
'after' => 'class_section_id',
|
||||
],
|
||||
];
|
||||
|
||||
if (! $this->db->fieldExists('event_payment_id', 'event_charges')) {
|
||||
$this->forge->addColumn('event_charges', $fields);
|
||||
}
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->fieldExists('event_payment_id', 'event_charges')) {
|
||||
$this->forge->dropColumn('event_charges', 'event_payment_id');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,9 @@ class EventChargesModel extends Model
|
||||
'student_id',
|
||||
'participation',
|
||||
'charged',
|
||||
'event_paid',
|
||||
'event_payment_id',
|
||||
'class_section_id',
|
||||
'semester',
|
||||
'school_year',
|
||||
'updated_by',
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
$classSectionNames = $classSectionNames ?? [];
|
||||
$semesterOptions = $semesterOptions ?? [];
|
||||
$schoolYearOptions = $schoolYearOptions ?? [];
|
||||
?>
|
||||
|
||||
<?php
|
||||
$filterParentId = $filterParentId ?? 0;
|
||||
$parentBalances = $parentBalances ?? [];
|
||||
$selectedEvent = null;
|
||||
if (!empty($filterEventId)) {
|
||||
foreach ($events as $event) {
|
||||
@@ -22,10 +30,48 @@
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form method="get" action="<?= site_url('administrator/event-charges') ?>" class="row g-3 align-items-end">
|
||||
<?php if ($filterEventId > 0): ?>
|
||||
<input type="hidden" name="event_id" value="<?= esc($filterEventId) ?>">
|
||||
<?php endif; ?>
|
||||
<?php if ($filterParentId > 0): ?>
|
||||
<input type="hidden" name="parent_id" value="<?= esc($filterParentId) ?>">
|
||||
<?php endif; ?>
|
||||
<div class="col-md-4">
|
||||
<label for="semester_filter" class="form-label">Semester</label>
|
||||
<select id="semester_filter" name="semester" class="form-select">
|
||||
<option value="">-- All semesters --</option>
|
||||
<?php foreach ($semesterOptions as $option): ?>
|
||||
<option value="<?= esc($option) ?>" <?= $semester === $option ? 'selected' : '' ?>>
|
||||
<?= esc($option) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="school_year_filter" class="form-label">School Year</label>
|
||||
<select id="school_year_filter" name="school_year" class="form-select">
|
||||
<option value="">-- All school years --</option>
|
||||
<?php foreach ($schoolYearOptions as $option): ?>
|
||||
<option value="<?= esc($option) ?>" <?= $school_year === $option ? 'selected' : '' ?>>
|
||||
<?= esc($option) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-outline-primary">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add New Charge Form -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form action="<?= site_url('payment/event_charges') ?>" method="post">
|
||||
<form id="event-participant-form" action="<?= site_url('payment/event_charges') ?>" method="post">
|
||||
<?= csrf_field() ?>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
@@ -60,16 +106,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row g-3 mt-2">
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="parent_id" class="form-label">Parents List</label>
|
||||
<select id="parent_id" name="parent_id" class="form-select" required>
|
||||
<option value="">-- Select Parent --</option>
|
||||
<?php foreach ($parents as $parent): ?>
|
||||
<option value="<?= $parent['id'] ?>">
|
||||
<option value="<?= esc($parent['id']) ?>" <?= $filterParentId && $filterParentId == $parent['id'] ? 'selected' : '' ?>>
|
||||
<?= esc($parent['firstname'] . ' ' . $parent['lastname']) ?> (<?= esc($parent['school_id']) ?>)
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
@@ -89,7 +132,6 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Charge Tables grouped by event -->
|
||||
<?php
|
||||
$grouped = [];
|
||||
@@ -108,6 +150,10 @@
|
||||
<?= esc($eventLabel) ?>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<?php
|
||||
$totalParticipants = 0;
|
||||
$totalCharged = 0.0;
|
||||
?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-striped mb-0 no-mgmt-sticky">
|
||||
<thead class="table-light">
|
||||
@@ -115,17 +161,20 @@
|
||||
<th>ID</th>
|
||||
<th>Parent Name</th>
|
||||
<th>Student Name</th>
|
||||
<th>Class Section</th>
|
||||
<th>Charged Amount</th>
|
||||
<th>Is Participating</th>
|
||||
<th>Semester</th>
|
||||
<th>Year</th>
|
||||
<th>Created</th>
|
||||
<th>Description</th>
|
||||
<th>Event Fees</th>
|
||||
<th>Fees Paid</th>
|
||||
<th>Payment</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $charge): ?>
|
||||
<?php
|
||||
$isParticipating = ($charge['participation'] === 'yes');
|
||||
$isEventPaid = !empty($charge['event_paid']);
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc($charge['id']) ?></td>
|
||||
<td><?= esc($charge['parent_firstname'] . ' ' . $charge['parent_lastname']) ?></td>
|
||||
@@ -134,20 +183,65 @@
|
||||
? esc($charge['student_firstname'] . ' ' . $charge['student_lastname'])
|
||||
: '-' ?>
|
||||
</td>
|
||||
<td>$<?= esc(number_format($charge['charged'] ?? 0, 2)) ?></td>
|
||||
<td>
|
||||
<?= $charge['participation']
|
||||
? '<span class="badge bg-success">Yes</span>'
|
||||
: '<span class="badge bg-warning">No</span>' ?>
|
||||
<?= esc($classSectionNames[$charge['class_section_id'] ?? ''] ?? '—') ?>
|
||||
</td>
|
||||
<td><?= esc($charge['semester'] ?? '-') ?></td>
|
||||
<td><?= esc($charge['school_year'] ?? '-') ?></td>
|
||||
<td><?= esc(!empty($charge['created_at']) ? local_datetime($charge['created_at'], 'm-d-Y H:i') : '') ?></td>
|
||||
<td><?= esc($charge['event_description'] ?? '—') ?></td>
|
||||
<td>$<?= esc(number_format($charge['event_amount'] ?? 0, 2)) ?></td>
|
||||
<td><?= esc(!empty($charge['created_at']) ? local_datetime($charge['created_at'], 'm-d-Y H:i') : '') ?></td>
|
||||
<?php
|
||||
$feeAmount = (float) ($charge['event_amount'] ?? 0);
|
||||
$hasBalanceRecord = array_key_exists((int)$charge['parent_id'], $parentBalances);
|
||||
$parentBalance = $hasBalanceRecord ? (float)$parentBalances[$charge['parent_id']] : null;
|
||||
$feeIsPaid = $isParticipating && ($isEventPaid || ($hasBalanceRecord && $parentBalance <= 0));
|
||||
?>
|
||||
<td class="text-center">
|
||||
<?php if ($feeIsPaid): ?>
|
||||
<span class="badge bg-success">Paid</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger">Unpaid</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<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="paid" value="<?= $feeIsPaid ? '1' : '0' ?>">
|
||||
<input type="checkbox" class="form-check-input" id="eventPayment_<?= esc($charge['id']) ?>"
|
||||
<?= $isEventPaid ? 'checked' : '' ?>
|
||||
onchange="this.form.paid.value = this.checked ? 1 : 0; this.form.submit();">
|
||||
<label class="form-check-label ms-2" for="eventPayment_<?= esc($charge['id']) ?>" aria-hidden="true">Paid</label>
|
||||
</form>
|
||||
</td>
|
||||
<td class="text-nowrap">
|
||||
<div class="d-flex gap-1 align-items-center">
|
||||
<a href="<?= site_url('administrator/event-charges') ?>?event_id=<?= esc($charge['event_id']) ?>&parent_id=<?= esc($charge['parent_id']) ?>#event-participant-form" class="btn btn-outline-primary btn-sm">
|
||||
Edit
|
||||
</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() ?>
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm">Remove</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
if ($isParticipating) {
|
||||
$totalParticipants++;
|
||||
$totalCharged += (float) ($charge['event_amount'] ?? 0);
|
||||
}
|
||||
?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
<tfoot class="table-light">
|
||||
<tr>
|
||||
<th colspan="4">Totals</th>
|
||||
<th>$<?= esc(number_format($totalCharged, 2)) ?></th>
|
||||
<th colspan="5">
|
||||
<span class="badge bg-secondary">
|
||||
<?= esc($totalParticipants) ?> participating
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -214,6 +308,10 @@ $(function() {
|
||||
}
|
||||
window.location.href = url.toString();
|
||||
});
|
||||
|
||||
if ($('#event_id').val() && $('#parent_id').val()) {
|
||||
loadStudentsWithCharges();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
@@ -143,12 +143,61 @@ $deadline = parseDbDateTime($dueDate, 'UTC', $displayTz); // format either DATE
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php if (!empty($invoiceEventCharges)): ?>
|
||||
<?php foreach ($invoices as $invoice): ?>
|
||||
<?php $charges = $invoiceEventCharges[(int)($invoice['id'] ?? 0)] ?? []; ?>
|
||||
<?php if (empty($charges)): ?>
|
||||
<?php continue; ?>
|
||||
<?php endif; ?>
|
||||
<div class="card mb-3 shadow-sm">
|
||||
<div class="card-header">
|
||||
<strong>Event charges for Invoice #<?= esc($invoice['invoice_number'] ?? '#'.$invoice['id']) ?></strong>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive mb-0">
|
||||
<table class="table table-sm table-bordered mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Event</th>
|
||||
<th>Student</th>
|
||||
<th>Fee</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($charges as $charge): ?>
|
||||
<?php
|
||||
$studentName = trim(($charge['student_firstname'] ?? '') . ' ' . ($charge['student_lastname'] ?? ''));
|
||||
$eventName = $charge['event_name'] ?? '—';
|
||||
$paid = !empty($charge['event_paid']) || ((float)($charge['charged'] ?? 0) <= 0);
|
||||
$badgeClass = $paid ? 'success' : 'danger';
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc($eventName) ?></td>
|
||||
<td><?= esc($studentName ?: '—') ?></td>
|
||||
<td>$<?= number_format((float)($charge['event_amount'] ?? 0), 2) ?></td>
|
||||
<td>
|
||||
<span class="badge bg-<?= $badgeClass ?>">
|
||||
<?= $paid ? 'Paid' : 'Unpaid' ?>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info mb-3 d-inline-block">
|
||||
No invoice found for the selected school year.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php $invoiceEventCharges = $invoiceEventCharges ?? []; ?>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
Reference in New Issue
Block a user