173 lines
7.5 KiB
PHP
173 lines
7.5 KiB
PHP
<?= $this->extend('layout/main_layout') ?>
|
|
<?= $this->section('content') ?>
|
|
<?php
|
|
$isEditable = (bool) ($isEditable ?? true);
|
|
$disabledAttr = $isEditable ? '' : ' disabled';
|
|
?>
|
|
|
|
<div class="container my-4">
|
|
<h4 class="text-dark mb-3" style="font-family: Arial, sans-serif;">Distribute Books to Students</h4>
|
|
<?= view('partials/flash_messages') ?>
|
|
<?php if (!$isEditable): ?>
|
|
<div class="alert alert-info">
|
|
You are viewing <?= esc($schoolYear ?? 'a closed school year') ?>. Book distribution actions are read-only for closed years.
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Filter bar (GET) — no class section shown -->
|
|
<form id="filterForm" class="row g-3 mb-3" method="get" action="<?= site_url('inventory/books/distribute') ?>">
|
|
<!-- Keep class section hidden; controller sets $class_section_id -->
|
|
<input type="hidden" name="class_section_id" value="<?= esc($class_section_id) ?>">
|
|
|
|
<div class="col-md-5">
|
|
<label class="form-label">Book</label>
|
|
<select class="form-select" name="item_id" id="bookSelect" required>
|
|
<option value="">— Select a book —</option>
|
|
<?php foreach (($booksGrouped ?? []) as $group): ?>
|
|
<optgroup label="<?= esc($group['label']) ?>">
|
|
<?php foreach ($group['items'] as $b): ?>
|
|
<option value="<?= esc($b['id']) ?>" <?= ((int)$b['id'] === (int)$item_id) ? 'selected' : '' ?>>
|
|
<?= esc($b['display']) ?> (On Hand: <?= (int)$b['quantity'] ?>)
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</optgroup>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-md-2 d-flex align-items-end">
|
|
<button class="btn btn-secondary w-100">Load</button>
|
|
</div>
|
|
</form>
|
|
|
|
<?php if ($item_id && !empty($students)): ?>
|
|
<div class="alert alert-info py-2">
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<strong>School Year:</strong> <?= esc($schoolYear) ?>,
|
|
<strong>Semester:</strong> <?= esc($semester) ?>
|
|
</div>
|
|
<div>
|
|
<strong>On Hand:</strong> <?= (int)$onHand ?>
|
|
</div>
|
|
</div>
|
|
<?php if ((int)($priceConfirmed ?? 0) !== 1 || (int)($unitChargeCents ?? 0) <= 0): ?>
|
|
<div class="mt-2 text-danger">This book cannot be distributed until its active-year charge price is confirmed.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Submission form (POST) -->
|
|
<form method="post" action="<?= site_url('inventory/books/distribute') ?>" data-readonly="<?= $isEditable ? '0' : '1' ?>">
|
|
<?= csrf_field() ?>
|
|
<!-- Keep class section hidden -->
|
|
<input type="hidden" name="class_section_id" value="<?= esc($class_section_id) ?>">
|
|
<input type="hidden" name="item_id" value="<?= esc($item_id) ?>">
|
|
<input type="hidden" name="idempotency_key" value="<?= esc(hash('sha256', (string) microtime(true) . ':' . (string) random_int(1, PHP_INT_MAX))) ?>">
|
|
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<span>Students</span>
|
|
<div class="d-flex gap-2">
|
|
<button type="button" class="btn btn-sm btn-info" id="checkAllBtn"<?= $disabledAttr ?>>Check All</button>
|
|
<button type="button" class="btn btn-sm btn-secondary" id="uncheckAllBtn"<?= $disabledAttr ?>>Uncheck All</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-body table-responsive">
|
|
<table class="table table-bordered table-striped align-middle">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th style="width:48px; text-align:center;">#</th>
|
|
<th style="width:56px; text-align:center;">Give</th>
|
|
<th>School ID</th>
|
|
<th>First Name</th>
|
|
<th>Last Name</th>
|
|
<th style="text-align:center;">Age</th>
|
|
<th style="text-align:center;">Semester</th>
|
|
<th style="text-align:center;">School Year</th>
|
|
<th style="text-align:center;">History</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php $order = 1;
|
|
foreach ($students as $student):
|
|
$sid = $student['student_id'] ?? ($student['id'] ?? ($student['user_id'] ?? null));
|
|
if (!$sid) continue;
|
|
$given = (int)($already[$sid] ?? 0) > 0;
|
|
?>
|
|
<tr>
|
|
<td style="text-align:center;"><?= $order++ ?></td>
|
|
<td style="text-align:center;">
|
|
<input type="checkbox"
|
|
class="form-check-input student-box"
|
|
name="student_ids[]"
|
|
value="<?= esc($sid) ?>"
|
|
<?= $given ? 'checked disabled' : $disabledAttr ?>>
|
|
</td>
|
|
<td><?= esc($student['school_id'] ?? '-') ?></td>
|
|
<td><?= esc($student['firstname'] ?? '') ?></td>
|
|
<td><?= esc($student['lastname'] ?? '') ?></td>
|
|
<td style="text-align:center;"><?= esc($student['age'] ?? '-') ?></td>
|
|
<td style="text-align:center;"><?= esc($student['semester'] ?? $semester) ?></td>
|
|
<td style="text-align:center;"><?= esc($student['school_year'] ?? $schoolYear) ?></td>
|
|
<td style="text-align:center;">
|
|
<?php if ($given): ?>
|
|
<span class="badge bg-success">Given</span>
|
|
<?php else: ?>
|
|
<span class="text-muted">—</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="card-footer">
|
|
<div class="mb-2">
|
|
<label class="form-label">Note (optional)</label>
|
|
<textarea class="form-control" rows="2" name="note" placeholder="e.g., Distributed in class today"<?= $disabledAttr ?>></textarea>
|
|
</div>
|
|
<div class="d-flex gap-2">
|
|
<button type="submit" class="btn btn-success"<?= $disabledAttr ?><?= ((int)($priceConfirmed ?? 0) !== 1 || (int)($unitChargeCents ?? 0) <= 0) ? ' disabled' : '' ?>>Deduct & Save</button>
|
|
<button type="button" class="btn btn-secondary" id="clearSelectionBtn"<?= $disabledAttr ?>>Cancel</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<?php elseif ($item_id): ?>
|
|
<div class="alert alert-warning">No students found for this class.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<?= $this->endSection() ?>
|
|
|
|
<?= $this->section('scripts') ?>
|
|
<script>
|
|
const distributeForm = document.querySelector('form[data-readonly]');
|
|
const distributeReadonly = distributeForm?.getAttribute('data-readonly') === '1';
|
|
|
|
// Auto-submit filter when book changes
|
|
document.getElementById('bookSelect')?.addEventListener('change', () => {
|
|
document.getElementById('filterForm').submit();
|
|
});
|
|
|
|
document.getElementById('checkAllBtn')?.addEventListener('click', () => {
|
|
if (distributeReadonly) return;
|
|
document.querySelectorAll('.student-box:not(:disabled)').forEach(cb => cb.checked = true);
|
|
});
|
|
|
|
document.getElementById('uncheckAllBtn')?.addEventListener('click', () => {
|
|
if (distributeReadonly) return;
|
|
document.querySelectorAll('.student-box:not(:disabled)').forEach(cb => cb.checked = false);
|
|
});
|
|
|
|
// Cancel button clears all checkboxes
|
|
document.getElementById('clearSelectionBtn')?.addEventListener('click', () => {
|
|
if (distributeReadonly) return;
|
|
document.querySelectorAll('.student-box:not(:disabled)').forEach(cb => cb.checked = false);
|
|
});
|
|
</script>
|
|
|
|
<?= $this->endSection() ?>
|