feat(appointments): backend for clinic workflow (Figma نوبتها) — phase A
Extend Appointment for the clinic-facing appointments area:
- New nullable relations service_section/service_item/staff (بخش/سرویس/پرسنل)
plus deposit_required/deposit_amount_rials (بیعانه) and is_reserve.
- New statuses following_up (در حال پیگیری) and salon (سالن) with day-of
transition rules; reserve entries never occupy a slot (several reserves may
share one day), enforced in refreshActiveSlotKey.
- rescheduleTo(slotStart, slotEnd, isReserve) keeps active_slot_key consistent
for جا به جایی and reserve transfers.
- New PATCH /api/v1/appointment/{uuid}: partial update covering edit, slot
move (409 on taken slot, race backstop on the unique key), reserve toggle,
patient swap (جایگزینی) and optional status transition; optimistic lock via
version like the status endpoint.
- POST /my/appointment now accepts the workflow fields and is_reserve
(day-level entry: no past-slot rule, no atomic slot booking); GET
/my/appointments gains reserve=1 and returns the new fields per row.
Migration Version20260713195434 (+ mirrored on db_test). Docs updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -475,3 +475,47 @@ Role-aware paginated list of appointments. Returns only what the authenticated u
|
||||
"currentPage": 1
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
## Clinic workflow extensions (نوبتها — Figma)
|
||||
|
||||
New optional fields on `Appointment` (all backward-compatible): `service_section` (بخش), `service_item` (سرویس), `staff` (پرسنل), `deposit_required` / `deposit_amount_rials` (بیعانه), `is_reserve` (نوبت رزرو — day-level, never occupies a slot).
|
||||
|
||||
New statuses: `following_up` (در حال پیگیری), `salon` (سالن). Transitions:
|
||||
`pending → confirmed|following_up|cancelled_*|expired` · `confirmed → completed|following_up|salon|cancelled_*|no_show` · `following_up → confirmed|salon|completed|cancelled_*|no_show` · `salon → completed|following_up|cancelled_*|no_show`
|
||||
|
||||
### PATCH `/api/v1/appointment/{uuid}`
|
||||
General update (ویرایش / جا به جایی / انتقال به رزرو / جایگزینی). All body fields optional; only present keys change. **Permission:** appointment's patient, owning doctor, or admin.
|
||||
|
||||
```json
|
||||
{
|
||||
"slot_start": 1731000000, "slot_end": 1731001800,
|
||||
"is_reserve": false,
|
||||
"service_section_uuid": "…", "service_item_uuid": "…", "staff_uuid": "…",
|
||||
"deposit_required": true, "deposit_amount_rials": 5000000,
|
||||
"note": "…", "patient_name": "…", "patient_mobile": "…",
|
||||
"status": "confirmed", "version": 3
|
||||
}
|
||||
```
|
||||
|
||||
- `slot_start`/`slot_end` must be sent together; moving to an occupied slot → `409`.
|
||||
- Relation uuids: empty string clears; unknown uuid → `422`.
|
||||
- `status` follows the same transition rules as `PATCH /appointment/{uuid}/status`.
|
||||
- Optimistic lock via `version` → `409` on concurrent edit.
|
||||
|
||||
Response `200`: `{ success, data: { data: <appointment.toArray()> } }`
|
||||
|
||||
| HTTP | Description |
|
||||
|------|-------------|
|
||||
| 404 | نوبت یافت نشد |
|
||||
| 403 | not patient/doctor/admin |
|
||||
| 422 | half slot pair, end < start, unknown relation uuid, invalid transition |
|
||||
| 409 | slot taken or version conflict |
|
||||
|
||||
### POST `/api/v1/my/appointment` (extended)
|
||||
Extra optional body fields: `service_section_uuid`, `service_item_uuid`, `staff_uuid`, `deposit_required`, `deposit_amount_rials`, `is_reserve`.
|
||||
`is_reserve: true` → day-level reserve entry: `slot_end` may equal `slot_start`, the past-slot rule is skipped, and the entry never occupies a slot (several reserves may share a day). Response `201` now also returns `is_reserve`.
|
||||
|
||||
### GET `/api/v1/my/appointments` (extended)
|
||||
New query param `reserve=1` → returns only reserve-list entries; without it only regular slot bookings are returned. Each row now also includes: `patient_uuid`, `is_reserve`, `deposit_required`, `deposit_amount_rials`, `note`, `service_section`, `service_item`, `staff` (each `{uuid, name|full_name}` or null).
|
||||
|
||||
Reference in New Issue
Block a user