feat: add hierarchical subitems to checklist templates and executions
This commit is contained in:
11
backend/src/database/migrations/073_checklist_subitems.sql
Normal file
11
backend/src/database/migrations/073_checklist_subitems.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- Add parent_item_id to vorlage items (self-referential)
|
||||
ALTER TABLE checklist_vorlage_items
|
||||
ADD COLUMN parent_item_id INT REFERENCES checklist_vorlage_items(id) ON DELETE CASCADE;
|
||||
|
||||
CREATE INDEX idx_vorlage_items_parent ON checklist_vorlage_items(parent_item_id);
|
||||
|
||||
-- Add parent_ausfuehrung_item_id to execution items (self-referential)
|
||||
ALTER TABLE checklist_ausfuehrung_items
|
||||
ADD COLUMN parent_ausfuehrung_item_id INT REFERENCES checklist_ausfuehrung_items(id) ON DELETE CASCADE;
|
||||
|
||||
CREATE INDEX idx_ausfuehrung_items_parent ON checklist_ausfuehrung_items(parent_ausfuehrung_item_id);
|
||||
@@ -212,13 +212,14 @@ async function addVorlageItem(vorlageId: number, data: {
|
||||
beschreibung?: string | null;
|
||||
pflicht?: boolean;
|
||||
sort_order?: number;
|
||||
parent_item_id?: number | null;
|
||||
}) {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`INSERT INTO checklist_vorlage_items (vorlage_id, bezeichnung, beschreibung, pflicht, sort_order)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
`INSERT INTO checklist_vorlage_items (vorlage_id, bezeichnung, beschreibung, pflicht, sort_order, parent_item_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING *`,
|
||||
[vorlageId, data.bezeichnung, data.beschreibung ?? null, data.pflicht ?? true, data.sort_order ?? 0]
|
||||
[vorlageId, data.bezeichnung, data.beschreibung ?? null, data.pflicht ?? true, data.sort_order ?? 0, data.parent_item_id ?? null]
|
||||
);
|
||||
return result.rows[0];
|
||||
} catch (error) {
|
||||
@@ -609,17 +610,34 @@ async function startExecution(fahrzeugId: string | null, vorlageId: number, user
|
||||
);
|
||||
const execution = execResult.rows[0];
|
||||
|
||||
// Copy template items into execution items
|
||||
// Copy template items into execution items (two-pass to preserve parent-child hierarchy)
|
||||
const vorlageItems = await client.query(
|
||||
`SELECT * FROM checklist_vorlage_items WHERE vorlage_id = $1 ORDER BY sort_order ASC, id ASC`,
|
||||
[vorlageId]
|
||||
);
|
||||
// First pass: insert all items, record the vorlage_item_id → ausfuehrung_item_id mapping
|
||||
const vorlageToAusfuehrungId = new Map<number, number>();
|
||||
for (const item of vorlageItems.rows) {
|
||||
await client.query(
|
||||
const inserted = await client.query(
|
||||
`INSERT INTO checklist_ausfuehrung_items (ausfuehrung_id, vorlage_item_id, bezeichnung)
|
||||
VALUES ($1, $2, $3)`,
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING id`,
|
||||
[execution.id, item.id, item.bezeichnung]
|
||||
);
|
||||
vorlageToAusfuehrungId.set(item.id, inserted.rows[0].id);
|
||||
}
|
||||
// Second pass: set parent_ausfuehrung_item_id for items that have a parent
|
||||
for (const item of vorlageItems.rows) {
|
||||
if (item.parent_item_id != null) {
|
||||
const parentAusfuehrungId = vorlageToAusfuehrungId.get(item.parent_item_id);
|
||||
const childAusfuehrungId = vorlageToAusfuehrungId.get(item.id);
|
||||
if (parentAusfuehrungId && childAusfuehrungId) {
|
||||
await client.query(
|
||||
`UPDATE checklist_ausfuehrung_items SET parent_ausfuehrung_item_id = $1 WHERE id = $2`,
|
||||
[parentAusfuehrungId, childAusfuehrungId]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy entity-specific items (vehicle or equipment)
|
||||
@@ -714,6 +732,7 @@ async function submitExecution(
|
||||
}
|
||||
|
||||
// Check if all pflicht items have ergebnis = 'ok'
|
||||
// Exclude parent items (those that have subitems) — their children carry the pflicht flag
|
||||
const pflichtCheck = await client.query(
|
||||
`SELECT ai.id, ai.ergebnis, ai.vorlage_item_id, ai.fahrzeug_item_id, ai.ausruestung_item_id
|
||||
FROM checklist_ausfuehrung_items ai
|
||||
@@ -721,7 +740,11 @@ async function submitExecution(
|
||||
LEFT JOIN fahrzeug_checklist_items fi ON fi.id = ai.fahrzeug_item_id
|
||||
LEFT JOIN ausruestung_checklist_items aci ON aci.id = ai.ausruestung_item_id
|
||||
WHERE ai.ausfuehrung_id = $1
|
||||
AND (COALESCE(vi.pflicht, fi.pflicht, aci.pflicht, true) = true)`,
|
||||
AND (COALESCE(vi.pflicht, fi.pflicht, aci.pflicht, true) = true)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM checklist_ausfuehrung_items child
|
||||
WHERE child.parent_ausfuehrung_item_id = ai.id
|
||||
)`,
|
||||
[id]
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user