# Forms — Staff Forms, Alerts, Fitter's Reports & Signing

**Folder:** `CRUD/forms/` (everything except pod/pdi/timesheets) · **Reached from:** navbar → Forms

The rest of the Forms module. The three big field-capture flows (PODs, PDIs, Timesheets) are covered separately in [capture-flows.md](capture-flows.md); this document covers the six smaller areas that share the folder.

| Area | Purpose | Files |
|---|---|---|
| **Staff Forms** | Assign forms to staff and track completion | `forms_staff/` (10) |
| **Alerts** | Notices shown against hires and on the hire list | `alerts/` (8) |
| **Fitter's Reports** | Fitter job reports — can charge on and record a service | `fitters_report/` (7) |
| **PDF Signing** | Upload a PDF, assign it for signature, capture the signature | `pdf_sign/` (4) |
| **Medical Self-Cert** | Driver medical self-certification | `medical_sc/` (3) |
| **Credit Application** | Printable customer credit application | `credit_application/` (1) |
| *(root)* | Dashboards and the shared email-template modal | 5 |

> Documented to the format set by [sites.md](sites.md).

---

## Forms Dashboard — `forms_dashboard.php`

![Forms Dashboard](../screenshots/forms__dashboard.png)

The entry point for everything above plus the three capture flows. Also one of the few pages **field staff (drivers/fitters) are allowed to reach** — it is on the field-role allowlist in `CRUD/auth.php`, along with the POD/PDI/timesheet/fitter's-report capture pages.

`form_maintenance.php` handles form housekeeping.

---

## Staff Forms — `forms_staff/`

![Staff Forms Dashboard](../screenshots/forms__staff_dashboard.png)

Assign a form type to a member of staff and track whether they've completed it.

| Page | Purpose |
|---|---|
| `staff_forms_dashboard.php` | Overview of assigned forms and completion |
| `forms_staff_create.php` | Assign a form to staff |
| `forms_staff_edit.php` | Edit an assignment (`?id=`) |
| `forms_staff_complete.php` | Mark complete (handler) |
| `form_staff_delete.php` | Remove an assignment |
| `form_staff_assign.php` | Bulk assignment |
| `form_staff_types.php` | Manage the form-type catalogue |
| `form_staff_type_edit.php` / `_delete.php` / `_deactivate.php` | Maintain a form type |

![Staff Form Types](../screenshots/forms__staff_types.png)

---

## Alerts — `alerts/`

![Alerts Maintenance](../screenshots/forms__alerts_maintenance.png)

Notices raised against a hire, surfaced on the hire list.

| File | Purpose |
|---|---|
| `alerts_maintenance.php` | Manage all alerts |
| `alerts_create.php` / `alerts_edit.php` / `alerts_delete.php` | Maintain one alert |
| `alerts_complete.php` | Mark an alert actioned (handler) |
| `alerts_popup.php` | The popup shown to the user |
| `adhoc_alerts_widget.php` | **Included by `hire_list.php`** — shows active, unactioned notices whose reminder date falls in the next 14 days (or that have no reminder date, which always show) |
| `adhoc_alert_action.php` | Action an ad-hoc notice (handler) |

---

## Fitter's Reports — `fitters_report/`

![Fitter's Report](../screenshots/forms__fr_create.png)

A fitter's job report. Two things make this more than a form:

- **`fr_charge_lib.php`** — a fitter's report can be **charged on to a hire**, creating a chargeable event. (See also the chargeable works flow in [hire-list.md](hire-list.md).)
- **`fr_service_lib.php`** — a report marked as a service **updates the machine's fleet record** (last serviced date/hours), feeding the [Plant List](plant-list.md).

| File | Purpose |
|---|---|
| `fr_create.php` | Raise a fitter's report (1,965 lines — the biggest page here) |
| `fr_create_printable.php` | Printable version |
| `fr_index.php` | Report list |
| `fr_checknumber.php` | Validate a report number (JSON) |
| `fr_offline_sync.php` | Sync reports captured offline |
| `fr_charge_lib.php` / `fr_service_lib.php` | Libraries (see above) |

---

## PDF Signing — `pdf_sign/`

![Assign PDF](../screenshots/forms__pdf_assign.png)

Upload a PDF, assign it to someone for signature, capture the signature and merge it back in.

| Page | Purpose |
|---|---|
| `upload_pdf.php` | Upload a document to be signed |
| `assign_pdf.php` | Assign it to a signer |
| `sign_pdf.php` | The signing screen (`?id=` required — returns 400 without) |
| `merge_pdf_signature.php` | Merges the captured signature into the PDF (API) |

---

## Medical Self-Certification — `medical_sc/`

![Medical Self-Cert](../screenshots/forms__medical_sc.png)

Driver medical self-certification.

| Page | Purpose |
|---|---|
| `mdsc_create.php` | Complete a self-cert (`?id=`) |
| `mdsc_index.php` | List of self-certs |
| `mdsc_offline_sync.php` | Offline sync endpoint |

## Credit Application — `credit_application/`

![Credit Application](../screenshots/forms__credit_app.png)

`credit_application_printable.php` — a printable customer credit application, using the shared email modal below.

---

## Shared: printable templates + email

| File | Purpose |
|---|---|
| `templates_dashboard.php` | Index of printable templates |
| `templates_email_modal.php` | **Reusable "Send via Email" modal**, included by the printable pages (credit application, fitter's report, PDI create). Static markup only — no database access |
| `templates_send_eml.php` | Builds the Outlook `.eml` (POST only — a GET correctly returns 405) |

![Templates Dashboard](../screenshots/forms__templates.png)

---

## Known issues

Reviewed 2026-07-21.

**No bugs found in this pass.** Every page returned HTTP 200 with no PHP errors, warnings or deprecations. The non-200 responses were all correct validation: `?id=`-requiring edit pages redirect when it's missing, `sign_pdf.php` returns 400 ("Missing id"), and `templates_send_eml.php` returns 405 to a GET because it is POST-only.

| # | Observation | Status |
|---|---|---|
| 1 | Four files include no auth guard, flagged by the inventory. All four are **libraries included by authenticated pages**, not endpoints — `fr_charge_lib.php`, `fr_service_lib.php` and `adhoc_alerts_widget.php` return **0 bytes** when requested directly (they only define functions), and `templates_email_modal.php` renders static markup with no database access. | **Not an issue** — verified by direct request |
| 2 | Orphan candidates: `fr_index.php`, `mdsc_index.php`, `mdsc_offline_sync.php`, `form_staff_type_deactivate.php`. The first two are `*_index.php` landing pages that look **live but unlinked** — reachable only by typing the URL. | **Open** — likely need a link rather than deletion |
| 3 | Three `*_offline_sync.php` endpoints exist across the module (`fr_`, `ts_`, `mdsc_`), two of them unreferenced. This suggests an **offline/tablet capture feature that may be incomplete**. | **Open** — worth confirming whether offline sync was ever finished |
