Fix semester context, attendance rosters, and billing workflows
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 31s
Tests / PHPUnit (push) Failing after 55s

- load global semester helpers consistently and use date-based semester defaults
- fix grading and daily attendance duplicate student/section rows
- keep attendance violations scoped to the current semester by default
- update invoice, refund, discount, payment, and financial aid flows
- add configuration cleanup migrations for duplicate calendar/semester keys
- refresh parent registration/report-card and print request handling
- update related models, services, views, cron notes, and test coverage
This commit is contained in:
root
2026-08-16 17:41:11 -04:00
parent 36c7e3fc6d
commit 0ac3a8375e
99 changed files with 1598 additions and 814 deletions
+33 -6
View File
@@ -45,12 +45,14 @@ class DiscountController extends BaseController
$this->classSectionModel = new ClassSectionModel();
$this->invoiceLedgerService = new InvoiceLedgerService();
$this->schoolYear = $this->configModel->getConfig('school_year');
$this->semester = $this->configModel->getConfig('semester');
$this->schoolYear = $this->activeSchoolYearName();
$this->semester = getSemester();
}
public function applyVoucher()
{
$this->schoolYear = $this->activeSchoolYearName();
if (strtolower($this->request->getMethod()) === 'post') {
$voucherId = $this->request->getPost('voucher_id');
$parentIds = $this->request->getPost('parent_ids') ?? [];
@@ -402,7 +404,10 @@ class DiscountController extends BaseController
unset($parent);
return view('discounts/apply_voucher', [
'vouchers' => $this->voucherModel->where('is_active', 1)->findAll(),
'vouchers' => $this->voucherModel
->where('is_active', 1)
->where('school_year', $this->schoolYear)
->findAll(),
'parents' => $parents,
]);
}
@@ -464,7 +469,7 @@ class DiscountController extends BaseController
->orWhere('enrollment_status', 'Payment pending')
->orWhere('enrollment_status', 'Payment Pending')
->orWhere('enrollment_status', 'PAYMENT PENDING')
->orWhere("LOWER(TRIM(REPLACE(enrollment_status, CHAR(160), ' '))) = 'payment pending'", null, false)
->orWhere("LOWER(TRIM(REPLACE(enrollment_status, CONVERT(0xC2A0 USING utf8mb4), ' '))) = 'payment pending'", null, false)
->groupEnd();
if (!empty($paidEnrollmentIds)) {
@@ -524,13 +529,20 @@ class DiscountController extends BaseController
public function listVouchers()
{
$this->schoolYear = $this->activeSchoolYearName();
$vouchers = $this->voucherModel
->where('school_year', $this->schoolYear)
->orderBy('code', 'ASC')
->findAll();
$vouchers = $this->voucherModel->findAll();
return view('discounts/list', ['vouchers' => $vouchers]);
}
public function createVoucher()
{
$this->schoolYear = $this->activeSchoolYearName();
if (strtolower($this->request->getMethod()) === 'post') {
// -------- Gather & normalize inputs --------
@@ -606,6 +618,7 @@ class DiscountController extends BaseController
'valid_until' => $validUntil,
'is_active' => $isActive,
'description' => $description, // <-- NEW
'school_year' => $this->schoolYear,
];
if ($this->voucherModel->save($data)) {
@@ -624,7 +637,11 @@ class DiscountController extends BaseController
public function editVoucher($id)
{
$voucher = $this->voucherModel->find($id);
$this->schoolYear = $this->activeSchoolYearName();
$voucher = $this->voucherModel
->where('school_year', $this->schoolYear)
->find($id);
if (!$voucher) {
return redirect()->to('discounts/list')->with('error', 'Voucher not found');
@@ -640,6 +657,7 @@ class DiscountController extends BaseController
'valid_from' => $this->request->getPost('valid_from') ?: null,
'valid_until' => $this->request->getPost('valid_until') ?: null,
'is_active' => $this->request->getPost('is_active') ? 1 : 0,
'school_year' => $this->schoolYear,
];
$this->voucherModel->save($data);
@@ -649,6 +667,15 @@ class DiscountController extends BaseController
return view('discounts/edit', ['voucher' => $voucher]);
}
private function activeSchoolYearName(): string
{
try {
return service('schoolYearContext')->active()->yearName();
} catch (\Throwable) {
return (string) ($this->configModel->getConfig('school_year') ?? '');
}
}
/**
* 🔄 Helper: Current invoice balance (school-year scoped) = total - payments - discounts - refundsPaid
*/