From ff90ffb9ca07f6fbc34c66654190bffc6019956a Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Mon, 15 Jun 2026 18:01:36 +0330 Subject: [PATCH] docs(api): document booking lock, patient fields, and payment confirm appointment.md: for_self + patient_* request fields, expires_at and patient_* response fields, the 15-minute lock/expiry behavior, and the atomic-conflict 409. payment.md: successful appointment payment confirms the booking and SMSes the patient. Co-Authored-By: Claude Opus 4.8 --- docs/api/appointment.md | 32 ++++++++++++++++++++++++++------ docs/api/payment.md | 2 ++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/api/appointment.md b/docs/api/appointment.md index 21282f2c..1eed79bc 100644 --- a/docs/api/appointment.md +++ b/docs/api/appointment.md @@ -78,6 +78,12 @@ Book an appointment slot. "doctor_uuid": "550e8400-e29b-41d4-a716-446655440000", "slot_start": 1718438400, "slot_end": 1718439600, + "for_self": false, + "patient_name": "علی احمدی", + "patient_mobile": "09120000000", + "patient_national_code": "0012345678", + "patient_gender": "male", + "patient_reason": "چکاپ", "note": "لطفاً سریع ویزیت شوم" } ``` @@ -87,21 +93,35 @@ Book an appointment slot. | `doctor_uuid` | string (UUID) | ✅ | Doctor UUID | | `slot_start` | integer | ✅ | Slot start (Unix timestamp) | | `slot_end` | integer | ✅ | Slot end (Unix timestamp) | +| `for_self` | boolean | ❌ | `true` (default) = patient is the logged-in payer; `false` = booking for someone else | +| `patient_name` | string | ⚠️ | Required when `for_self=false`; otherwise filled from the payer's profile | +| `patient_mobile` | string | ⚠️ | Required when `for_self=false`; otherwise the payer's mobile | +| `patient_national_code` | string | ❌ | Patient national code (only when for another person) | +| `patient_gender` | string | ❌ | `male` / `female` | +| `patient_reason` | string | ❌ | Reason for visit | | `note` | string | ❌ | Patient note | +> **Payer vs patient:** the authenticated user (`user`) is always the payer; the `patient_*` fields describe who the visit is for and are stored separately. **Temporary lock:** the slot is held by the new `pending` booking for **15 minutes** (`expires_at = created_at + 900`). If payment is not completed in time, the booking is moved to `expired` and the slot is freed (see `app:cancel-expired-appointments`). An expired pending booking no longer blocks the slot even before the cron runs. + ### Response `201` ```json { "success": true, "data": { "uuid": "appt-uuid-...", - "doctor": { "uuid": "...", "title": "دکتر علی احمدی" }, - "user": { "uuid": "...", "real_name": "..." }, + "doctor": { "uuid": "...", "name": "دکتر علی احمدی" }, + "user": { "uuid": "...", "mobile": "..." }, "slot_start": 1718438400, "slot_end": 1718439600, "status": "pending", "note": "...", - "price": 500000, + "expires_at": 1718438100, + "patient_name": "علی احمدی", + "patient_mobile": "09120000000", + "patient_national_code": "0012345678", + "patient_gender": "male", + "patient_reason": "چکاپ", + "version": 1, "created_at": 1717000000 } } @@ -120,9 +140,9 @@ Book an appointment slot. | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | -| `ERR_NOT_FOUND_001` | 404 | Doctor not found | -| `ERR_CONFLICT_001` | 409 | Slot already booked | -| `ERR_VALIDATION_001` | 422 | Invalid slot times | +| `ERR_VALIDATION_002` | 404 | Doctor not found | +| `ERR_CONFLICT_001` | 409 | Slot already booked (incl. concurrent booking — the booking is atomic) | +| `ERR_VALIDATION_001` | 422 | Invalid slot times, past slot, or missing patient name/mobile when `for_self=false` | --- diff --git a/docs/api/payment.md b/docs/api/payment.md index a27b4fa5..760247b7 100644 --- a/docs/api/payment.md +++ b/docs/api/payment.md @@ -62,6 +62,8 @@ Initiate payment for an appointment. Returns a redirect URL to the payment gatew } ``` +> **On successful callback** for an appointment payment, the booking is transitioned `pending → confirmed` (its 15-minute `expires_at` is cleared) and a confirmation SMS is dispatched to the patient's mobile. If the booking already lapsed to `expired` before payment confirmed, it is **not** re-confirmed (the transition is rejected) — handle refund out of band. + ### Errors | Code | HTTP | Description | |------|------|-------------|