apply the school year concept
Tests / PHPUnit (push) Failing after 1m19s

This commit is contained in:
root
2026-07-14 00:59:00 -04:00
parent 504c3bc9f9
commit feb1b29a32
73 changed files with 4288 additions and 620 deletions
+29
View File
@@ -77,6 +77,13 @@ class ConfigurationModel extends Model
public function getConfig($key)
{
$key = (string) $key;
if ($key === 'school_year') {
$activeSchoolYear = $this->activeSchoolYearName();
if ($activeSchoolYear !== null) {
return $activeSchoolYear;
}
}
if ($key === 'semester') {
try {
$semester = (new \App\Services\SemesterRangeService($this))->getSemesterForDate();
@@ -90,4 +97,26 @@ class ConfigurationModel extends Model
return $this->getConfigValueByKey($key);
}
private function activeSchoolYearName(): ?string
{
try {
if (! $this->db->tableExists('school_years')) {
return null;
}
$row = $this->db->table('school_years')
->select('name')
->where('status', 'active')
->orderBy('id', 'DESC')
->get(1)
->getRowArray();
$name = trim((string) ($row['name'] ?? ''));
return $name !== '' ? $name : null;
} catch (\Throwable) {
return null;
}
}
}
+46 -10
View File
@@ -39,23 +39,59 @@ class ExpenseModel extends Model
{
$db = \Config\Database::connect();
$builder = $db->table('expenses');
$builder->select('expenses.*,
r.id AS reimb_id,
r.amount AS reimb_amount, r.reimbursement_method, r.check_number,
r.receipt_path AS reimb_receipt, r.status AS reimb_status,
r.school_year, r.semester, r.created_at AS reimb_created_at,
r.reimbursed_to AS reimb_recipient_id,
reimb.firstname AS reimb_firstname, reimb.lastname AS reimb_lastname,
approver.firstname AS approver_firstname, approver.lastname AS approver_lastname');
$hasReimbursementSchoolYear = $db->fieldExists('school_year', 'reimbursements');
$hasReimbursementSemester = $db->fieldExists('semester', 'reimbursements');
$hasExpenseSchoolYear = $db->fieldExists('school_year', 'expenses');
$hasExpenseSemester = $db->fieldExists('semester', 'expenses');
$select = [
'expenses.*',
'r.id AS reimb_id',
'r.amount AS reimb_amount',
'r.reimbursement_method',
'r.check_number',
'r.receipt_path AS reimb_receipt',
'r.status AS reimb_status',
'r.created_at AS reimb_created_at',
'r.reimbursed_to AS reimb_recipient_id',
'reimb.firstname AS reimb_firstname',
'reimb.lastname AS reimb_lastname',
'approver.firstname AS approver_firstname',
'approver.lastname AS approver_lastname',
];
if ($hasReimbursementSchoolYear) {
$select[] = 'r.school_year';
} elseif ($hasExpenseSchoolYear) {
$select[] = 'expenses.school_year AS school_year';
}
if ($hasReimbursementSemester) {
$select[] = 'r.semester';
} elseif ($hasExpenseSemester) {
$select[] = 'expenses.semester AS semester';
} else {
$select[] = 'NULL AS semester';
}
$builder->select(implode(",\n", $select), false);
$builder->join('reimbursements r', 'r.expense_id = expenses.id', 'inner');
$builder->join('users reimb', 'reimb.id = r.reimbursed_to', 'left');
$builder->join('users approver', 'approver.id = r.approved_by', 'left');
if (!empty($filters['school_year'])) {
$builder->where('r.school_year', $filters['school_year']);
if ($hasReimbursementSchoolYear) {
$builder->where('r.school_year', $filters['school_year']);
} elseif ($hasExpenseSchoolYear) {
$builder->where('expenses.school_year', $filters['school_year']);
}
}
if (!empty($filters['semester'])) {
$builder->where('r.semester', $filters['semester']);
if ($hasReimbursementSemester) {
$builder->where('r.semester', $filters['semester']);
} elseif ($hasExpenseSemester) {
$builder->where('expenses.semester', $filters['semester']);
}
}
if (!empty($filters['status'])) {
$builder->where('r.status', $filters['status']);
+8 -2
View File
@@ -40,8 +40,14 @@ class SchoolYearModel extends Model
public function active(): ?array
{
return $this->where('status', 'active')
$rows = $this->where('status', 'active')
->orderBy('id', 'DESC')
->first();
->findAll(2);
if (count($rows) !== 1) {
return null;
}
return $rows[0];
}
}
+12 -3
View File
@@ -341,8 +341,17 @@ class StudentModel extends Model
return array_column($results, 'id');
}
public function getStudentsWithClassAndEnrollment()
public function getStudentsWithClassAndEnrollment(?string $schoolYear = null)
{
$schoolYear = trim((string) $schoolYear);
$studentClassJoin = 'student_class.student_id = students.id';
$enrollmentJoin = 'enrollments.student_id = students.id';
if ($schoolYear !== '') {
$studentClassJoin .= ' AND student_class.school_year = ' . $this->db->escape($schoolYear);
$enrollmentJoin .= ' AND enrollments.school_year = ' . $this->db->escape($schoolYear);
}
return $this->select('
students.*,
student_class.class_section_id,
@@ -351,8 +360,8 @@ class StudentModel extends Model
u.firstname AS parent_firstname,
u.lastname AS parent_lastname
')
->join('student_class', 'student_class.student_id = students.id', 'left')
->join('enrollments', 'enrollments.student_id = students.id', 'left')
->join('student_class', $studentClassJoin, 'left')
->join('enrollments', $enrollmentJoin, 'left')
->join('users u', 'u.id = students.parent_id', 'left')
// keep your original grouping as-is so behavior doesn't change
->groupBy('students.id, student_class.class_section_id, enrollments.enrollment_status, enrollments.admission_status')
+32 -8
View File
@@ -16,6 +16,17 @@ class WhatsappGroupLinkModel extends Model
];
protected $useTimestamps = true; // requires created_at / updated_at columns
private ?bool $hasSchoolYearColumn = null;
private function hasSchoolYearColumn(): bool
{
if ($this->hasSchoolYearColumn === null) {
$this->hasSchoolYearColumn = $this->db->fieldExists('school_year', $this->table);
}
return $this->hasSchoolYearColumn;
}
/**
* Get the link for a specific section in a specific term.
*
@@ -36,8 +47,11 @@ class WhatsappGroupLinkModel extends Model
$sem = trim($sem);
$b = $this->asArray()
->where('class_section_id', $sectionId)
->where('school_year', $year);
->where('class_section_id', $sectionId);
if ($this->hasSchoolYearColumn()) {
$b = $b->where('school_year', $year);
}
if ($onlyActive) {
$b = $b->where('active', 1);
@@ -69,8 +83,11 @@ class WhatsappGroupLinkModel extends Model
$year = trim($year);
$sem = trim($sem);
$b = $this->asArray()
->where('school_year', $year);
$b = $this->asArray();
if ($this->hasSchoolYearColumn()) {
$b = $b->where('school_year', $year);
}
if ($onlyActive === true) {
$b = $b->where('active', 1);
@@ -98,16 +115,23 @@ class WhatsappGroupLinkModel extends Model
$payload = [
'class_section_id' => $sectionId,
'class_section_name' => $sectionName,
'school_year' => trim($year),
'invite_link' => trim($inviteLink),
'active' => $active ? 1 : 0,
];
if ($this->hasSchoolYearColumn()) {
$payload['school_year'] = trim($year);
}
// Try to find existing row (exact term)
$existing = $this->asArray()
->where('class_section_id', $sectionId)
->where('school_year', $payload['school_year'])
->first();
->where('class_section_id', $sectionId);
if ($this->hasSchoolYearColumn()) {
$existing = $existing->where('school_year', $payload['school_year']);
}
$existing = $existing->first();
if ($existing) {
$this->update((int)$existing['id'], $payload);