# Fill Permit Form

| | |
|---|---|
| **Nav ID** | `fill-form` |
| **Component** | `AdminFormFillPage.jsx` |
| **Services** | `formsApi.js`, `permitsApi.js` |

Uses `useMasterData()` for job types and question types.

---

## Endpoints

See existing endpoint table in prior sections. Key write endpoint: **POST `/submissions`**.

---

## SQL queries

### Pre-submit reads

```sql
SELECT * FROM `ptw_form_details`;

SELECT * FROM ptw_permits WHERE permit_id = ? LIMIT 1;

SELECT * FROM `ptw_submissions` WHERE `permit_id` = ?;

SELECT * FROM `ptw_opening_closing_map` WHERE `permit_id` = ?;
```

Form tree queries — same as [permit-preview.md](permit-preview.md) (`ptw_form_section_map`, `ptw_section_question_map`).

### POST `/submissions` — validation reads

```sql
SELECT permit_id, permit_status_id, valid_from, valid_until
FROM ptw_permits WHERE permit_id = ? LIMIT 1;

SELECT 1 FROM ptw_form_details WHERE form_id = ? LIMIT 1;

SELECT question_id FROM ptw_questions WHERE question_id IN (?);

-- handback duplicate guard:
SELECT submission_id FROM ptw_submissions
WHERE permit_id = ? AND submission_role = 'handback' LIMIT 1;
```

### POST `/submissions` — write transaction (core)

```sql
INSERT INTO ptw_submissions (permit_id, submitter_id, form_id, submission_role)
VALUES (?, ?, ?, ?);

-- per answer:
INSERT INTO ptw_answers (submission_id, question_id, is_media, answer_value)
VALUES (?, ?, ?, ?);

-- per uploaded file / inline media:
INSERT INTO ptw_answers_media (answers_id, occurrence, media)
VALUES (?, ?, ?);   -- media is LONGBLOB
```

### Lifecycle side-effects by `submission_role`

**Opening** — start validity window and link map:

```sql
INSERT INTO ptw_opening_closing_map (permit_id, opening_sub_id, closing_sub_id)
VALUES (?, ?, NULL);

UPDATE ptw_permits
SET valid_from = NOW(),
    valid_until = DATE_ADD(NOW(), INTERVAL ? HOUR),
    permit_status_id = ?
WHERE permit_id = ? AND valid_from IS NULL;
```

**Handover** — extend validity:

```sql
UPDATE ptw_permits
SET valid_until = DATE_ADD(NOW(), INTERVAL ? HOUR),
    permit_status_id = ?
WHERE permit_id = ?;
```

**Handback** — close permit:

```sql
UPDATE ptw_opening_closing_map SET closing_sub_id = ?
WHERE permit_id = ? AND opening_sub_id = ?;

UPDATE ptw_permits
SET permit_status_id = ?, valid_until = NOW()
WHERE permit_id = ?;
```

**Audit** — record shift audit while permit is active (repeatable; no validity or status change):

```sql
-- validation only: valid_from IS NOT NULL, permit not closed
INSERT INTO ptw_submissions (permit_id, submitter_id, form_id, submission_role)
VALUES (?, ?, ?, 'audit');
-- answers persisted via ptw_answers / ptw_answers_media; no UPDATE on ptw_permits
```

**Closing** — link to opening submission:

```sql
SELECT opening_sub_id FROM ptw_opening_closing_map
WHERE permit_id = ? AND closing_sub_id IS NULL
ORDER BY opening_sub_id DESC LIMIT 1;

UPDATE ptw_opening_closing_map SET closing_sub_id = ?
WHERE permit_id = ? AND opening_sub_id = ?;
```

### Return saved answers

```sql
SELECT answers_id, submission_id, question_id, is_media, answer_value
FROM ptw_answers WHERE submission_id = ? ORDER BY answers_id;
```

### POST `/submissions/section`

Same INSERT pattern as above but scoped to one section step (`submitFormSection` in `ptwSubmissionController.js`).

**Controller:** `ptwSubmissionController.js` → `createSubmission`
