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
+61 -1
View File
@@ -51,6 +51,7 @@ class PrintRequests extends BaseController
$schoolYear = $context->yearName();
$printRequestsQuery = $this->printRequestModel
->distinct()
->select('print_requests.*, admins.firstname as admin_firstname, admins.lastname as admin_lastname')
->join('users as admins', 'admins.id = print_requests.admin_id', 'left')
->join('classSection cs', 'cs.class_section_id = print_requests.class_id', 'left')
@@ -67,6 +68,8 @@ class PrintRequests extends BaseController
$data['sundays'] = $dateOptions['sundays'];
$data['times'] = $dateOptions['times'];
$data['isSchoolYearReadonly'] = $context->isReadonly();
$data['printRequestToken'] = $this->issuePrintRequestToken('print');
$data['copyRequestToken'] = $this->issuePrintRequestToken('copy');
return view('print_requests/teacher_index', $data);
}
@@ -77,6 +80,7 @@ class PrintRequests extends BaseController
$schoolYear = $context->yearName();
$printRequestsQuery = $this->printRequestModel
->distinct()
->select('
print_requests.*,
u.firstname,
@@ -125,6 +129,10 @@ class PrintRequests extends BaseController
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
}
if (! $this->consumePrintRequestToken('print')) {
return redirect()->to('teacher/print-requests')->with('error', 'This print request was already submitted. Please refresh the page before submitting another request.');
}
$teacher_id = session()->get('user_id');
$file = $this->request->getFile('file');
@@ -346,6 +354,10 @@ class PrintRequests extends BaseController
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
}
if (! $this->consumePrintRequestToken('copy')) {
return redirect()->to('teacher/print-requests')->with('error', 'This copy request was already submitted. Please refresh the page before submitting another request.');
}
$teacher_id = session()->get('user_id');
$data = [
@@ -402,6 +414,54 @@ class PrintRequests extends BaseController
];
}
private function issuePrintRequestToken(string $type): string
{
$key = $this->printRequestTokenSessionKey($type);
$tokens = session()->get($key);
if (! is_array($tokens)) {
$tokens = [];
}
$token = bin2hex(random_bytes(16));
$tokens[$token] = time();
if (count($tokens) > 20) {
asort($tokens);
$tokens = array_slice($tokens, -20, null, true);
}
session()->set($key, $tokens);
return $token;
}
private function consumePrintRequestToken(string $type): bool
{
$token = (string) $this->request->getPost('request_token');
if ($token === '') {
return false;
}
$key = $this->printRequestTokenSessionKey($type);
$tokens = session()->get($key);
if (! is_array($tokens) || ! array_key_exists($token, $tokens)) {
return false;
}
unset($tokens[$token]);
session()->set($key, $tokens);
return true;
}
private function printRequestTokenSessionKey(string $type): string
{
return 'print_request_' . $type . '_tokens';
}
private function applyPrintRequestSchoolYearScope($query, string $schoolYear): void
{
if ($schoolYear === '') {
@@ -620,7 +680,7 @@ class PrintRequests extends BaseController
'action_url' => $isCopyRequest ? '' : $actionUrl,
'scheduled_at' => utc_now(),
'school_year' => $this->configModel->getConfig('school_year'),
'semester' => $this->configModel->getConfig('semester'),
'semester' => getSemester(),
];
$notificationFields = $db->getFieldNames('notifications');