This commit is contained in:
@@ -82,7 +82,7 @@ The following fields on `violations` are locked after submission. They are the b
|
||||
- `prior_active_points` (snapshot at insert time)
|
||||
- `prior_tier_label`
|
||||
|
||||
Amendable fields (non-scoring): `location`, `details`, `witness_name`, `acknowledged_by`, `acknowledged_date`
|
||||
Amendable fields (non-scoring): `incident_time`, `location`, `details`, `submitted_by`, `witness_name`, `acknowledged_by`, `acknowledged_date`, `amount`
|
||||
|
||||
### Soft-Delete Pattern
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ const FIELD_LABELS = {
|
||||
details: 'Incident Notes',
|
||||
submitted_by: 'Submitted By',
|
||||
witness_name: 'Witness / Documenting Officer',
|
||||
amount: 'Amount in Question',
|
||||
};
|
||||
|
||||
const s = {
|
||||
@@ -84,6 +85,7 @@ export default function AmendViolationModal({ violation, onClose, onSaved }) {
|
||||
details: violation.details || '',
|
||||
submitted_by: violation.submitted_by || '',
|
||||
witness_name: violation.witness_name || '',
|
||||
amount: violation.amount || '',
|
||||
});
|
||||
const [changedBy, setChangedBy] = useState('');
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
@@ -36,7 +36,6 @@ const s = {
|
||||
const EMPTY_FORM = {
|
||||
employeeId: '', employeeName: '', department: '', supervisor: '', witnessName: '',
|
||||
violationType: '', incidentDate: '', incidentTime: '',
|
||||
// TODO [MAJOR #6]: `amount` and `minutesLate` are rendered but never sent to the API
|
||||
amount: '', minutesLate: '', location: '', additionalDetails: '', points: 1,
|
||||
acknowledgedBy: '', acknowledgedDate: '',
|
||||
};
|
||||
@@ -159,6 +158,7 @@ export default function ViolationForm() {
|
||||
witness_name: form.witnessName || null,
|
||||
acknowledged_by: form.acknowledgedBy || null,
|
||||
acknowledged_date: form.acknowledgedDate || null,
|
||||
amount: form.amount || null,
|
||||
});
|
||||
|
||||
const newId = violRes.data.id;
|
||||
|
||||
@@ -21,6 +21,8 @@ if (!cols.includes('prior_active_points')) db.exec("ALTER TABLE violations ADD C
|
||||
if (!cols.includes('prior_tier_label')) db.exec("ALTER TABLE violations ADD COLUMN prior_tier_label TEXT");
|
||||
if (!cols.includes('acknowledged_by')) db.exec("ALTER TABLE violations ADD COLUMN acknowledged_by TEXT");
|
||||
if (!cols.includes('acknowledged_date')) db.exec("ALTER TABLE violations ADD COLUMN acknowledged_date TEXT");
|
||||
// Financial amount in question (record-keeping / repayment for chargeback, receipt negligence, etc.)
|
||||
if (!cols.includes('amount')) db.exec("ALTER TABLE violations ADD COLUMN amount TEXT");
|
||||
|
||||
// Employee notes column (free-text, does not affect scoring)
|
||||
const empCols = db.prepare('PRAGMA table_info(employees)').all().map(c => c.name);
|
||||
|
||||
@@ -25,6 +25,7 @@ CREATE TABLE IF NOT EXISTS violations (
|
||||
prior_tier_label TEXT, -- optional human-readable tier
|
||||
acknowledged_by TEXT, -- employee name who acknowledged receipt
|
||||
acknowledged_date TEXT, -- date of acknowledgment (YYYY-MM-DD)
|
||||
amount TEXT, -- dollar amount in question for financial violations (record-keeping / repayment)
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
|
||||
@@ -243,6 +243,11 @@ function buildHtml(v, score) {
|
||||
<div class="field-label">Submitted By</div>
|
||||
<div class="field-value">${v.submitted_by || 'System'}</div>
|
||||
</div>
|
||||
${v.amount ? `
|
||||
<div class="field" style="grid-column: 1 / -1;">
|
||||
<div class="field-label">Amount in Question</div>
|
||||
<div class="field-value prominent">${v.amount}</div>
|
||||
</div>` : ''}
|
||||
${v.location ? `
|
||||
<div class="field" style="grid-column: 1 / -1;">
|
||||
<div class="field-label">Location / Context</div>
|
||||
|
||||
@@ -266,7 +266,8 @@ app.post('/api/violations', (req, res) => {
|
||||
employee_id, violation_type, violation_name, category,
|
||||
points, incident_date, incident_time, location,
|
||||
details, submitted_by, witness_name,
|
||||
acknowledged_by, acknowledged_date
|
||||
acknowledged_by, acknowledged_date,
|
||||
amount
|
||||
} = req.body;
|
||||
|
||||
if (!employee_id || !violation_type || !points || !incident_date) {
|
||||
@@ -282,15 +283,17 @@ app.post('/api/violations', (req, res) => {
|
||||
points, incident_date, incident_time, location,
|
||||
details, submitted_by, witness_name,
|
||||
prior_active_points,
|
||||
acknowledged_by, acknowledged_date
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
acknowledged_by, acknowledged_date,
|
||||
amount
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
employee_id, violation_type, violation_name || violation_type,
|
||||
category || 'General', ptsInt, incident_date,
|
||||
incident_time || null, location || null,
|
||||
details || null, submitted_by || null, witness_name || null,
|
||||
priorPts,
|
||||
acknowledged_by || null, acknowledged_date || null
|
||||
acknowledged_by || null, acknowledged_date || null,
|
||||
amount || null
|
||||
);
|
||||
|
||||
audit('violation_created', 'violation', result.lastInsertRowid, submitted_by, {
|
||||
@@ -302,7 +305,7 @@ app.post('/api/violations', (req, res) => {
|
||||
|
||||
// ── Violation Amendment (edit) ───────────────────────────────────────────────
|
||||
// PATCH /api/violations/:id/amend — edit mutable fields; logs a diff per changed field
|
||||
const AMENDABLE_FIELDS = ['incident_time', 'location', 'details', 'submitted_by', 'witness_name', 'acknowledged_by', 'acknowledged_date'];
|
||||
const AMENDABLE_FIELDS = ['incident_time', 'location', 'details', 'submitted_by', 'witness_name', 'acknowledged_by', 'acknowledged_date', 'amount'];
|
||||
|
||||
// Pre-build one prepared UPDATE statement per amendable field combination is not
|
||||
// practical (2^n combos), so instead we validate columns against the static
|
||||
|
||||
Reference in New Issue
Block a user