fix delibration and below 60
This commit is contained in:
@@ -1068,37 +1068,67 @@ class GradingController extends Controller
|
||||
return $scores;
|
||||
}
|
||||
|
||||
public function belowSixty()
|
||||
{
|
||||
$configuredYear = (string) $this->schoolYear;
|
||||
public function belowSixty()
|
||||
{
|
||||
$configuredYear = (string) $this->schoolYear;
|
||||
|
||||
$requestedSemester = strtolower(trim((string)($this->request->getGet('semester') ?? '')));
|
||||
$requestedYear = trim((string)($this->request->getGet('school_year') ?? ''));
|
||||
$schoolYear = trim((string)($this->request->getGet('school_year') ?? ''));
|
||||
|
||||
// This page intentionally supports only Fall and Whole Year.
|
||||
// Spring is still used internally for the Whole Year calculation, but it is not selectable here.
|
||||
$isYearMode = ($requestedSemester === 'year');
|
||||
$semester = $isYearMode ? 'year' : 'Fall';
|
||||
$schoolYear = $requestedYear !== '' ? $requestedYear : $configuredYear;
|
||||
|
||||
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
|
||||
$rows = $this->fetchBelowSixtyRows($schoolYear, $semester);
|
||||
|
||||
$canViewGrading = $this->userHasMenuUrl('grading');
|
||||
|
||||
return view('grading/below_sixty', [
|
||||
'rows' => $rows,
|
||||
'semester' => $semester,
|
||||
'schoolYear' => $schoolYear,
|
||||
'schoolYears' => $schoolYears,
|
||||
'canViewGrading' => $canViewGrading,
|
||||
'isYearMode' => $isYearMode,
|
||||
'semesterOptions' => ['Fall'],
|
||||
'showAllSemesterOption' => true,
|
||||
]);
|
||||
if ($schoolYear === '') {
|
||||
$schoolYear = $configuredYear;
|
||||
}
|
||||
|
||||
// This page is Fall only.
|
||||
$semester = 'fall';
|
||||
$isYearMode = false;
|
||||
|
||||
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
|
||||
|
||||
/*
|
||||
* Use your existing below-60 fetcher.
|
||||
* Do NOT query below_sixty_status. That table does not exist.
|
||||
*/
|
||||
$rows = $this->fetchBelowSixtyRows($schoolYear, $semester);
|
||||
|
||||
/*
|
||||
* Hard guard:
|
||||
* Keep only Fall semester rows with semester_score < 60.
|
||||
* This prevents whole-year rows or accidental other semester rows
|
||||
* from sneaking into this Fall-only page.
|
||||
*/
|
||||
$rows = array_values(array_filter($rows, static function ($row) {
|
||||
$semesterValue = strtolower(trim((string)($row['semester'] ?? 'fall')));
|
||||
$scoreRaw = $row['semester_score'] ?? null;
|
||||
|
||||
if ($semesterValue !== '' && $semesterValue !== 'fall') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_numeric($scoreRaw)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (float)$scoreRaw < 60;
|
||||
}));
|
||||
|
||||
foreach ($rows as &$row) {
|
||||
$row['status'] = $row['status'] ?? 'Open';
|
||||
$row['note'] = $row['note'] ?? '';
|
||||
}
|
||||
|
||||
unset($row);
|
||||
|
||||
$canViewGrading = $this->userHasMenuUrl('grading');
|
||||
|
||||
return view('grading/below_sixty', [
|
||||
'rows' => $rows,
|
||||
'semester' => $semester,
|
||||
'schoolYear' => $schoolYear,
|
||||
'schoolYears' => $schoolYears,
|
||||
'isYearMode' => $isYearMode,
|
||||
'canViewGrading' => $canViewGrading,
|
||||
]);
|
||||
}
|
||||
public function editBelowSixtyEmail()
|
||||
{
|
||||
$studentId = (int)$this->request->getGet('student_id');
|
||||
@@ -2298,87 +2328,185 @@ class GradingController extends Controller
|
||||
return 50000;
|
||||
}
|
||||
|
||||
public function belowSixtyDecisions()
|
||||
public function belowSixtyDecisions()
|
||||
{
|
||||
$configuredSemester = (string) $this->semester;
|
||||
$configuredYear = (string) $this->schoolYear;
|
||||
$configuredYear = (string) $this->schoolYear;
|
||||
|
||||
$semester = trim((string)($this->request->getGet('semester') ?? ''));
|
||||
$schoolYear = trim((string)($this->request->getGet('school_year') ?? ''));
|
||||
|
||||
if ($semester === '') {
|
||||
$semester = $configuredSemester !== '' ? $configuredSemester : 'Fall';
|
||||
}
|
||||
|
||||
if ($schoolYear === '') {
|
||||
$schoolYear = $configuredYear;
|
||||
}
|
||||
|
||||
// This page is whole-year only.
|
||||
$semester = 'year';
|
||||
|
||||
$schoolYears = $this->getSchoolYearsForScores($schoolYear);
|
||||
$rows = $this->fetchBelowSixtyRows($schoolYear, $semester);
|
||||
|
||||
$studentIds = array_values(array_unique(array_filter(
|
||||
array_map(static fn($r) => (int)($r['student_id'] ?? 0), $rows),
|
||||
static fn($id) => $id > 0
|
||||
)));
|
||||
$db = $this->db;
|
||||
|
||||
// ── Load manual below-60 semester decisions ─────────────────────────────
|
||||
//
|
||||
// This table still uses semester, because below-60 decisions are tied to
|
||||
// the selected below-60 screen/term.
|
||||
$decisionModel = new BelowSixtyDecisionModel();
|
||||
/*
|
||||
* Whole-year score source:
|
||||
* Fall semester_score + Spring semester_score / 2
|
||||
*
|
||||
* Only students with BOTH Fall and Spring scores are included.
|
||||
* Only students with year_score < 60 are listed.
|
||||
*/
|
||||
$scoreRows = $db->table('semester_scores ss')
|
||||
->select([
|
||||
's.id AS student_id',
|
||||
's.firstname',
|
||||
's.lastname',
|
||||
's.school_id',
|
||||
'cs.class_section_name',
|
||||
'LOWER(TRIM(ss.semester)) AS sem_key',
|
||||
'ss.semester_score',
|
||||
])
|
||||
->join('students s', 's.id = ss.student_id', 'inner')
|
||||
->join('classSection cs', 'cs.class_section_id = ss.class_section_id', 'left')
|
||||
->where('s.is_active', 1)
|
||||
->where('ss.school_year', $schoolYear)
|
||||
->whereIn('LOWER(TRIM(ss.semester))', ['fall', 'spring'])
|
||||
->where('ss.semester_score IS NOT NULL', null, false)
|
||||
->orderBy('cs.class_section_name', 'ASC')
|
||||
->orderBy('s.lastname', 'ASC')
|
||||
->orderBy('s.firstname', 'ASC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
$decisionMap = [];
|
||||
$studentMap = [];
|
||||
|
||||
if (!empty($studentIds)) {
|
||||
$dRows = $decisionModel
|
||||
->whereIn('student_id', $studentIds)
|
||||
->where('semester', $semester)
|
||||
->where('school_year', $schoolYear)
|
||||
->findAll();
|
||||
foreach ($scoreRows as $row) {
|
||||
$sid = (int)($row['student_id'] ?? 0);
|
||||
|
||||
foreach ($dRows as $d) {
|
||||
$decisionMap[(int)$d['student_id']] = $d;
|
||||
if ($sid <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($studentMap[$sid])) {
|
||||
$studentMap[$sid] = [
|
||||
'student_id' => $sid,
|
||||
'school_id' => $row['school_id'] ?? '',
|
||||
'firstname' => $row['firstname'] ?? '',
|
||||
'lastname' => $row['lastname'] ?? '',
|
||||
'class_section_name' => $row['class_section_name'] ?? '',
|
||||
'fall_score' => null,
|
||||
'spring_score' => null,
|
||||
'year_score' => null,
|
||||
];
|
||||
}
|
||||
|
||||
$semKey = strtolower(trim((string)($row['sem_key'] ?? '')));
|
||||
$score = is_numeric($row['semester_score']) ? (float)$row['semester_score'] : null;
|
||||
|
||||
if ($score === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($semKey === 'fall') {
|
||||
$studentMap[$sid]['fall_score'] = $score;
|
||||
} elseif ($semKey === 'spring') {
|
||||
$studentMap[$sid]['spring_score'] = $score;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rows as &$row) {
|
||||
$sid = (int)($row['student_id'] ?? 0);
|
||||
$rows = [];
|
||||
|
||||
foreach ($studentMap as $sid => $student) {
|
||||
$fall = $student['fall_score'];
|
||||
$spring = $student['spring_score'];
|
||||
|
||||
// Whole-year result requires both semesters.
|
||||
if ($fall === null || $spring === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$yearScore = round(($fall + $spring) / 2, 2);
|
||||
|
||||
if ($yearScore >= 60) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$student['year_score'] = $yearScore;
|
||||
$rows[$sid] = $student;
|
||||
}
|
||||
|
||||
$studentIds = array_keys($rows);
|
||||
|
||||
/*
|
||||
* Load saved below-60 manual decisions.
|
||||
* These are year-level decisions now.
|
||||
*/
|
||||
$decisionMap = [];
|
||||
|
||||
if (!empty($studentIds)) {
|
||||
$belowDecModel = new BelowSixtyDecisionModel();
|
||||
|
||||
$decisionRows = $belowDecModel
|
||||
->whereIn('student_id', $studentIds)
|
||||
->where('semester', 'year')
|
||||
->where('school_year', $schoolYear)
|
||||
->findAll();
|
||||
|
||||
foreach ($decisionRows as $d) {
|
||||
$sid = (int)($d['student_id'] ?? 0);
|
||||
|
||||
if ($sid > 0) {
|
||||
$decisionMap[$sid] = $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rows as $sid => &$row) {
|
||||
$row['decision'] = $decisionMap[$sid]['decision'] ?? '';
|
||||
$row['decision_notes'] = $decisionMap[$sid]['notes'] ?? '';
|
||||
}
|
||||
|
||||
unset($row);
|
||||
|
||||
// ── Load consolidated YEAR decisions from student_decisions ─────────────
|
||||
//
|
||||
// IMPORTANT:
|
||||
// student_decisions no longer has semester or semester_score.
|
||||
// It is now one row per student per school_year using year_score.
|
||||
$sdMap = [];
|
||||
/*
|
||||
* Load final generated whole-year decisions from student_decisions.
|
||||
* This table is now year-based, so do NOT filter by semester.
|
||||
*/
|
||||
$finalDecisionMap = [];
|
||||
|
||||
if (!empty($studentIds)) {
|
||||
$sdRows = $this->db->table('student_decisions')
|
||||
$finalRows = $db->table('student_decisions')
|
||||
->whereIn('student_id', $studentIds)
|
||||
->where('school_year', $schoolYear)
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($sdRows as $sd) {
|
||||
$sid = (int)($sd['student_id'] ?? 0);
|
||||
foreach ($finalRows as $fr) {
|
||||
$sid = (int)($fr['student_id'] ?? 0);
|
||||
|
||||
if ($sid > 0) {
|
||||
$sdMap[$sid] = $sd;
|
||||
$finalDecisionMap[$sid] = $fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Load the most recent certificate per student for this school year ───
|
||||
foreach ($rows as $sid => &$row) {
|
||||
$row['consolidated_decision'] = $finalDecisionMap[$sid]['decision'] ?? null;
|
||||
|
||||
if (
|
||||
isset($finalDecisionMap[$sid]['year_score'])
|
||||
&& $finalDecisionMap[$sid]['year_score'] !== ''
|
||||
&& is_numeric($finalDecisionMap[$sid]['year_score'])
|
||||
) {
|
||||
$row['year_score'] = round((float)$finalDecisionMap[$sid]['year_score'], 2);
|
||||
}
|
||||
}
|
||||
|
||||
unset($row);
|
||||
|
||||
/*
|
||||
* Load certificate numbers.
|
||||
*/
|
||||
$certMap = [];
|
||||
|
||||
if (!empty($studentIds)) {
|
||||
$certRows = $this->db->table('certificate_records')
|
||||
$certRows = $db->table('certificate_records')
|
||||
->select('student_id, certificate_number, issued_at')
|
||||
->where('school_year', $schoolYear)
|
||||
->whereIn('student_id', $studentIds)
|
||||
@@ -2395,16 +2523,15 @@ class GradingController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rows as &$row) {
|
||||
$sid = (int)($row['student_id'] ?? 0);
|
||||
|
||||
$row['consolidated_decision'] = $sdMap[$sid]['decision'] ?? null;
|
||||
$row['year_score'] = $sdMap[$sid]['year_score'] ?? null;
|
||||
$row['certificate_number'] = $certMap[$sid] ?? '';
|
||||
foreach ($rows as $sid => &$row) {
|
||||
$row['certificate_number'] = $certMap[$sid] ?? '';
|
||||
}
|
||||
|
||||
unset($row);
|
||||
|
||||
// Re-index for the view.
|
||||
$rows = array_values($rows);
|
||||
|
||||
$canViewGrading = $this->userHasMenuUrl('grading');
|
||||
|
||||
return view('grading/below_sixty_decisions', [
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
<!--
|
||||
Steps for enrollment process:
|
||||
Admission under review
|
||||
Payment pending //we should generate invoice
|
||||
Enrolled
|
||||
|
||||
|
||||
Steps for Withdrawn:
|
||||
Withdraw under review
|
||||
Refund pending
|
||||
After providing refund if any -> Withdrawn
|
||||
|
||||
|
||||
add Withdraw deadline at configuration table
|
||||
|
||||
|
||||
##########################################################################################################################
|
||||
cron job command for paypal to update payment table:
|
||||
*/15 * * * * /usr/bin/php /home/u280815660/domains/alrahmaisgl.org/alrahma/spark sync_paypal_payments >> /home/u280815660/domains/alrahmaisgl.org/alrahma/writable/logs/paypal_cron.log 2>&1
|
||||
|
||||
###########################################################################################################################
|
||||
|
||||
|
||||
dX7!aPz9#LmqR2@t
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
curl -i -X POST https://test.alrahmaisgl.org/api/paypal-webhook \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @payload.json
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
curl -i -X POST http://localhost:8080/api/paypal-webhook \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @payload.json
|
||||
|
||||
|
||||
|
||||
get:
|
||||
'balance', and 'paid_amount', from invoice table
|
||||
invoice table has parent_id = user_id
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
webhook_id, client_id, and secret should ideally be stored in .env or config files.
|
||||
|
||||
|
||||
|
||||
################################################
|
||||
<table id="myTable" class="display">
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#myTable').DataTable();
|
||||
});
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
#####################################################
|
||||
|
||||
|
||||
when the payment status=paid update the enrollment status = enrolled
|
||||
refund amount at http://localhost:8080/invoice_payment/invoice_management need to be updated
|
||||
need to track the refund status either refunded or not
|
||||
|
||||
################################################################################
|
||||
#very important to add to deployment script
|
||||
If the file is currently in writable/uploads/checks/, then you need to:
|
||||
# From project root
|
||||
ln -s writable/uploads public/uploads
|
||||
|
||||
Then it can be accessed via:
|
||||
<?= base_url('uploads/checks/' . $refund['check_file']) ?>
|
||||
##########################################################################
|
||||
|
||||
|
||||
I want to design pages to show everything about the school:
|
||||
financial report
|
||||
number of students
|
||||
number of teachers
|
||||
number of admins
|
||||
number of parents
|
||||
expenses
|
||||
number of tables chairs
|
||||
@@ -1,28 +1,71 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?php
|
||||
// This page is Fall semester only.
|
||||
// Do not expose Whole Year mode here.
|
||||
$semester = 'fall';
|
||||
$actionSemester = 'fall';
|
||||
|
||||
$schoolYear = $schoolYear ?? '';
|
||||
$schoolYears = $schoolYears ?? [];
|
||||
|
||||
if (empty($schoolYears) && $schoolYear !== '') {
|
||||
$schoolYears = [$schoolYear];
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="wrapper below-sixty-wrapper">
|
||||
<h2 class="text-center mt-4 mb-4 below-sixty-title">Below 60 Summary</h2>
|
||||
|
||||
<?= $this->include('partials/academic_filter') ?>
|
||||
<!-- School year filter only -->
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-body py-3">
|
||||
<form method="get"
|
||||
action="<?= site_url('grading/below-60') ?>"
|
||||
class="row g-2 align-items-end justify-content-center">
|
||||
|
||||
<input type="hidden" name="semester" value="fall">
|
||||
|
||||
<div class="col-12 col-sm-auto">
|
||||
<label class="form-label mb-1 small fw-semibold">School Year</label>
|
||||
|
||||
<?php if (!empty($schoolYears)): ?>
|
||||
<select name="school_year"
|
||||
class="form-select form-select-sm"
|
||||
style="min-width:160px;">
|
||||
<?php foreach ($schoolYears as $yr): ?>
|
||||
<option value="<?= esc($yr) ?>" <?= (string)$yr === (string)$schoolYear ? 'selected' : '' ?>>
|
||||
<?= esc($yr) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php else: ?>
|
||||
<input type="text"
|
||||
name="school_year"
|
||||
class="form-control form-control-sm"
|
||||
style="min-width:160px;"
|
||||
value="<?= esc($schoolYear) ?>"
|
||||
placeholder="2025-2026">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-auto">
|
||||
<button type="submit" class="btn btn-sm btn-primary">
|
||||
<i class="bi bi-funnel me-1"></i>Apply
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
|
||||
<div class="text-muted">
|
||||
<?= !empty($isYearMode) ? 'Whole Year' : 'Fall' ?> • <?= esc($schoolYear ?? '') ?>
|
||||
Fall • <?= esc($schoolYear) ?>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<?php if (!empty($isYearMode)): ?>
|
||||
<a class="btn btn-outline-primary btn-sm"
|
||||
href="<?= site_url('grading/below-60/decisions?' . http_build_query([
|
||||
'semester' => 'year',
|
||||
'school_year' => $schoolYear ?? '',
|
||||
])) ?>">
|
||||
Decisions
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($canViewGrading)): ?>
|
||||
<a class="btn btn-outline-secondary btn-sm" href="<?= base_url('grading') ?>">
|
||||
Back to Grading
|
||||
@@ -43,15 +86,11 @@
|
||||
|
||||
return esc($value);
|
||||
};
|
||||
|
||||
// Fall mode uses Fall.
|
||||
// Whole Year mode uses year.
|
||||
$actionSemester = !empty($isYearMode) ? 'year' : 'fall';
|
||||
?>
|
||||
|
||||
<?php if (empty($rows)): ?>
|
||||
<div class="alert alert-success text-center d-inline-block">
|
||||
No students below 60 for this selection.
|
||||
No students below 60 for Fall in <?= esc($schoolYear) ?>.
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive below-sixty-table">
|
||||
@@ -62,7 +101,7 @@
|
||||
<tr>
|
||||
<th>Student Name</th>
|
||||
<th>Section</th>
|
||||
<th class="text-center">Score</th>
|
||||
<th class="text-center">Fall Score</th>
|
||||
<th>Status</th>
|
||||
<th>Email Parent</th>
|
||||
<th>Schedule Meeting</th>
|
||||
@@ -72,6 +111,7 @@
|
||||
<tbody>
|
||||
<?php foreach ($rows as $row): ?>
|
||||
<?php
|
||||
// Fall-only page: use semester_score.
|
||||
$scoreRaw = $row['semester_score'] ?? null;
|
||||
$scoreVal = is_numeric($scoreRaw) ? (float)$scoreRaw : null;
|
||||
|
||||
@@ -102,7 +142,7 @@
|
||||
style="font-size:0.72rem;padding:1px 7px;"
|
||||
data-student-id="<?= (int)($row['student_id'] ?? 0) ?>"
|
||||
data-student-name="<?= esc($studentLabel) ?>"
|
||||
data-school-year="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
data-school-year="<?= esc((string)$schoolYear) ?>">
|
||||
Details
|
||||
</button>
|
||||
</td>
|
||||
@@ -119,15 +159,15 @@
|
||||
|
||||
<input type="hidden"
|
||||
name="semester"
|
||||
value="<?= esc($actionSemester) ?>">
|
||||
value="fall">
|
||||
|
||||
<input type="hidden"
|
||||
name="school_year"
|
||||
value="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
value="<?= esc((string)$schoolYear) ?>">
|
||||
|
||||
<select name="status"
|
||||
class="form-select form-select-sm"
|
||||
style="width: 110px;">
|
||||
style="width:110px;">
|
||||
<option value="Open" <?= ($row['status'] ?? 'Open') === 'Open' ? 'selected' : '' ?>>
|
||||
Open
|
||||
</option>
|
||||
@@ -139,7 +179,7 @@
|
||||
<input type="text"
|
||||
name="note"
|
||||
class="form-control form-control-sm"
|
||||
style="width: 140px;"
|
||||
style="width:140px;"
|
||||
placeholder="Note (optional)"
|
||||
value="<?= esc((string)($row['note'] ?? '')) ?>">
|
||||
|
||||
@@ -156,7 +196,11 @@
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<a class="btn btn-sm btn-outline-primary"
|
||||
href="<?= site_url('grading/below-60/email/edit?student_id=' . (int)($row['student_id'] ?? 0) . '&semester=' . rawurlencode($actionSemester) . '&school_year=' . rawurlencode((string)($schoolYear ?? ''))) ?>">
|
||||
href="<?= site_url('grading/below-60/email/edit?' . http_build_query([
|
||||
'student_id' => (int)($row['student_id'] ?? 0),
|
||||
'semester' => 'fall',
|
||||
'school_year' => (string)$schoolYear,
|
||||
])) ?>">
|
||||
Send Email
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
@@ -169,7 +213,11 @@
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<a class="btn btn-sm btn-outline-secondary"
|
||||
href="<?= site_url('grading/below-60/schedule?student_id=' . (int)($row['student_id'] ?? 0) . '&semester=' . rawurlencode($actionSemester) . '&school_year=' . rawurlencode((string)($schoolYear ?? ''))) ?>">
|
||||
href="<?= site_url('grading/below-60/schedule?' . http_build_query([
|
||||
'student_id' => (int)($row['student_id'] ?? 0),
|
||||
'semester' => 'fall',
|
||||
'school_year' => (string)$schoolYear,
|
||||
])) ?>">
|
||||
Schedule
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
@@ -246,21 +294,6 @@
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
function normalizeSemesterFilter() {
|
||||
const semesterSelect = document.querySelector('select[name="semester"]');
|
||||
|
||||
if (!semesterSelect) return;
|
||||
|
||||
const wholeYearSelected = <?= !empty($isYearMode) ? 'true' : 'false' ?>;
|
||||
|
||||
semesterSelect.innerHTML = '';
|
||||
semesterSelect.add(new Option('Fall', 'fall', !wholeYearSelected, !wholeYearSelected));
|
||||
semesterSelect.add(new Option('Whole Year', 'year', wholeYearSelected, wholeYearSelected));
|
||||
semesterSelect.value = wholeYearSelected ? 'year' : 'fall';
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', normalizeSemesterFilter);
|
||||
|
||||
if (window.$ && $.fn && $.fn.DataTable) {
|
||||
$(function () {
|
||||
const table = $('.below-sixty-dt');
|
||||
|
||||
@@ -5,29 +5,77 @@
|
||||
// This page is Whole Year only.
|
||||
// Do not expose semester filter here.
|
||||
$semester = 'year';
|
||||
|
||||
$schoolYear = $schoolYear ?? '';
|
||||
$schoolYears = $schoolYears ?? [];
|
||||
|
||||
if (empty($schoolYears) && $schoolYear !== '') {
|
||||
$schoolYears = [$schoolYear];
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="wrapper below-sixty-decisions-wrapper">
|
||||
<h2 class="text-center mt-4 mb-4">Below 60 — Whole Year Decisions</h2>
|
||||
<h2 class="text-center mt-4 mb-4">School Year Decisions</h2>
|
||||
|
||||
<!-- School year filter -->
|
||||
<div class="card shadow-sm mb-3">
|
||||
<div class="card-body py-3">
|
||||
<form method="get"
|
||||
action="<?= site_url('grading/below-60/decisions') ?>"
|
||||
class="row g-2 align-items-end justify-content-center">
|
||||
|
||||
<input type="hidden" name="semester" value="year">
|
||||
|
||||
<div class="col-12 col-sm-auto">
|
||||
<label class="form-label mb-1 small fw-semibold">School Year</label>
|
||||
|
||||
<?php if (!empty($schoolYears)): ?>
|
||||
<select name="school_year"
|
||||
class="form-select form-select-sm"
|
||||
style="min-width: 160px;">
|
||||
<?php foreach ($schoolYears as $yr): ?>
|
||||
<option value="<?= esc($yr) ?>" <?= (string)$yr === (string)$schoolYear ? 'selected' : '' ?>>
|
||||
<?= esc($yr) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php else: ?>
|
||||
<input type="text"
|
||||
name="school_year"
|
||||
class="form-control form-control-sm"
|
||||
style="min-width: 160px;"
|
||||
value="<?= esc($schoolYear) ?>"
|
||||
placeholder="2025-2026">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-auto">
|
||||
<button type="submit" class="btn btn-sm btn-primary">
|
||||
<i class="bi bi-funnel me-1"></i>Apply
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
|
||||
<div class="text-muted">
|
||||
Whole Year • <?= esc($schoolYear ?? '') ?>
|
||||
Whole Year • <?= esc($schoolYear) ?>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<a class="btn btn-outline-secondary btn-sm"
|
||||
href="<?= site_url('grading/below-60?' . http_build_query([
|
||||
'semester' => 'year',
|
||||
'school_year' => $schoolYear ?? '',
|
||||
'school_year' => $schoolYear,
|
||||
])) ?>">
|
||||
← Back to Below 60
|
||||
</a>
|
||||
|
||||
<a class="btn btn-outline-primary btn-sm"
|
||||
href="<?= site_url('grading/decisions?' . http_build_query([
|
||||
'school_year' => $schoolYear ?? '',
|
||||
'school_year' => $schoolYear,
|
||||
])) ?>">
|
||||
All Decisions
|
||||
</a>
|
||||
@@ -89,7 +137,7 @@ $semester = 'year';
|
||||
|
||||
<?php if (empty($rows)): ?>
|
||||
<div class="alert alert-success text-center d-inline-block">
|
||||
No students below 60 for the whole year.
|
||||
No students below 60 for the whole year in <?= esc($schoolYear) ?>.
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
@@ -99,21 +147,19 @@ $semester = 'year';
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="min-width:160px">Student Name</th>
|
||||
<th>Section</th>
|
||||
<th>Class-Section</th>
|
||||
<th class="text-center">Year Score</th>
|
||||
<th style="min-width:300px">Comments / Rationale & Decision</th>
|
||||
<th style="min-width:150px" class="text-center">Below-60 Decision</th>
|
||||
<th style="min-width:130px" class="text-center">Final Decision</th>
|
||||
<th style="min-width:130px" class="text-center">Certificate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<?php foreach ($rows as $row): ?>
|
||||
<?php
|
||||
// Whole-year score. Prefer year_score if the controller provides it.
|
||||
// Fall/Spring details remain available through the Details modal.
|
||||
$scoreRaw = $row['year_score'] ?? $row['semester_score'] ?? null;
|
||||
// Whole-year page: use year_score only.
|
||||
// Do not fall back to semester_score, because this page should not display semester results.
|
||||
$scoreRaw = $row['year_score'] ?? null;
|
||||
$scoreVal = is_numeric($scoreRaw) ? (float)$scoreRaw : null;
|
||||
|
||||
$rowClass = '';
|
||||
@@ -126,11 +172,6 @@ $semester = 'year';
|
||||
$currentDecision = (string)($row['decision'] ?? '');
|
||||
$currentNotes = (string)($row['decision_notes'] ?? '');
|
||||
$badge = $decisionBadge[$currentDecision] ?? null;
|
||||
|
||||
$finalDecision = $row['consolidated_decision'] ?? null;
|
||||
$finalBadge = $finalDecision !== null ? ($decisionBadge[$finalDecision] ?? 'secondary') : null;
|
||||
|
||||
$certNumber = (string)($row['certificate_number'] ?? '');
|
||||
?>
|
||||
|
||||
<tr class="<?= esc($rowClass) ?>">
|
||||
@@ -146,7 +187,7 @@ $semester = 'year';
|
||||
style="font-size:0.72rem;padding:1px 7px;"
|
||||
data-student-id="<?= (int)($row['student_id'] ?? 0) ?>"
|
||||
data-student-name="<?= esc($studentLabel) ?>"
|
||||
data-school-year="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
data-school-year="<?= esc((string)$schoolYear) ?>">
|
||||
Details
|
||||
</button>
|
||||
</td>
|
||||
@@ -165,7 +206,7 @@ $semester = 'year';
|
||||
|
||||
<input type="hidden"
|
||||
name="school_year"
|
||||
value="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
value="<?= esc((string)$schoolYear) ?>">
|
||||
|
||||
<textarea name="notes"
|
||||
class="form-control form-control-sm decision-notes"
|
||||
@@ -199,41 +240,13 @@ $semester = 'year';
|
||||
class="btn btn-sm btn-outline-primary btn-send-email"
|
||||
data-student-id="<?= (int)($row['student_id'] ?? 0) ?>"
|
||||
data-semester="year"
|
||||
data-school-year="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
data-school-year="<?= esc((string)$schoolYear) ?>">
|
||||
Send Email
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<span class="text-muted small">Pending</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<td class="text-center align-middle">
|
||||
<?php if ($finalDecision !== null && $finalDecision !== ''): ?>
|
||||
<span class="badge bg-<?= esc($finalBadge) ?> px-2 py-1">
|
||||
<?= esc($finalDecision) ?>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<a href="<?= site_url('grading/decisions?' . http_build_query([
|
||||
'school_year' => $schoolYear ?? '',
|
||||
])) ?>"
|
||||
class="text-muted small">
|
||||
Generate
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<td class="text-center align-middle">
|
||||
<?php if ($certNumber !== ''): ?>
|
||||
<a href="<?= site_url('administrator/certificates/reprint/' . rawurlencode($certNumber)) ?>"
|
||||
target="_blank"
|
||||
class="font-monospace text-decoration-none fw-semibold"
|
||||
title="Click to reprint certificate">
|
||||
<?= esc($certNumber) ?>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<span class="text-muted small">—</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
0 2 * * * php /path/to/your/project/public/index.php notifications:cleanup >> /path/to/your/project/writable/logs/cron_cleanup.log 2>&1
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<IfModule authz_core_module>
|
||||
Require all denied
|
||||
</IfModule>
|
||||
<IfModule !authz_core_module>
|
||||
Deny from all
|
||||
</IfModule>
|
||||
@@ -1,75 +0,0 @@
|
||||
//create the docker image:
|
||||
docker build -t lamp-codeigniter4 .
|
||||
docker build --no-cache -t lamp-codeigniter4 .
|
||||
|
||||
//run the container only port 80 exposed.
|
||||
docker run -d -p 8080:80 --name lamp-codeigniter4-container lamp-codeigniter4
|
||||
|
||||
//run the container with port 80, 3306 exposed.
|
||||
docker run -d -p 8080:80 -p 3306:3306 --name lamp-codeigniter4-container lamp-codeigniter4
|
||||
|
||||
|
||||
|
||||
//run the shell on container:
|
||||
docker exec -it lamp-codeigniter4-container bash
|
||||
|
||||
//install nano
|
||||
apt install nano
|
||||
|
||||
|
||||
//open mysql and execute the following
|
||||
mysql -u root -ppassword
|
||||
|
||||
//create user and grant access to localhost
|
||||
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'password';
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'alrahma'@'localhost' WITH GRANT OPTION;
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
|
||||
//create user and grant access to "192.168.3.%"
|
||||
CREATE USER 'alrahma'@'192.168.3.%' IDENTIFIED BY '@alrahma2024';
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'alrahma'@'192.168.3.%' WITH GRANT OPTION;
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
//exit mysql.
|
||||
|
||||
//update the config to enable accepting requests from all IP's
|
||||
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf //and add thefollowing line
|
||||
bind-address = 0.0.0.0
|
||||
|
||||
sudo service mysql restart
|
||||
|
||||
|
||||
//update these files database config, open each file
|
||||
nano /var/www/html/codeigniter4/app/Views/frontend/partials/navbar.php
|
||||
nano /var/www/html/codeigniter4/app/db_connection.php
|
||||
nano /var/www/codeigniter/app/Config/Database.php
|
||||
nano /var/www/codeigniter/app/Controllers/ParentController.php
|
||||
|
||||
and look for those lines
|
||||
$host = 'localhost';
|
||||
$dbname = 'school';
|
||||
$username = 'root';
|
||||
$password = '';
|
||||
|
||||
|
||||
|
||||
and update them as follow:
|
||||
|
||||
// new Database configuration
|
||||
$host = '127.0.0.1';
|
||||
$dbname = 'school';
|
||||
$username = 'admin';
|
||||
$password = 'password';
|
||||
|
||||
// Database configuration
|
||||
$host = '192.168.3.110';
|
||||
$dbname = 'school';
|
||||
$username = 'alrahma';
|
||||
$password = '@alrahma2024';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
apt update
|
||||
apt upgrade
|
||||
|
||||
nano /var/ww/codeigniter/app/Config/App.php
|
||||
|
||||
#copy the content of the project folder into "/var/www/codeigniter/"
|
||||
|
||||
#make sure the permissions is granted
|
||||
chown -R www-data:www-data /var/www/codeigniter/writable/cache/
|
||||
chmod -R 775 /var/www/codeigniter/writable/cache/
|
||||
chown -R www-data:www-data /var/www/codeigniter/writable/session/
|
||||
chmod -R 775 /var/www/codeigniter/writable/session/
|
||||
|
||||
rm -rf /var/www/codeigniter/writable/cache/*
|
||||
systemctl restart apache2
|
||||
|
||||
nano /etc/mysql/mariadb.conf.d/50-server.cnf or nano /etc/mysql/my.cnf
|
||||
bind-address = 0.0.0.0
|
||||
|
||||
|
||||
#run myphpadmin in docker container poiting to remote database
|
||||
docker run --name myphpmyadmin -d \
|
||||
-e PMA_HOST=192.168.3.126 \
|
||||
-e PMA_PORT=3306 \
|
||||
-e PMA_USER=alrahma \
|
||||
-e PMA_PASSWORD=@alrahma2024 \
|
||||
-p 8080:80 \
|
||||
phpmyadmin
|
||||
Reference in New Issue
Block a user