Add API documentation for Representation, Secretary, Settlement, SMS, Specialty, Tag, and User Profile endpoints
This commit is contained in:
@@ -0,0 +1,540 @@
|
||||
# Appointment Settings API
|
||||
|
||||
> **Prefix:** `/api/v1/appointment-settings`
|
||||
> **Permission:** All write endpoints require `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
Doctors configure their availability via three resources: **weekly schedule**, **date overrides**, and **holidays**.
|
||||
|
||||
---
|
||||
|
||||
## Weekly Schedule
|
||||
|
||||
Each doctor has **one** weekly schedule (upsert). The schedule is keyed by **day index** (0=Saturday ... 6=Friday), each day containing a `sessions` array.
|
||||
|
||||
### Day Index Convention
|
||||
|
||||
| Index | Day (EN) | Day (FA) |
|
||||
|-------|----------|----------|
|
||||
| `"0"` | Saturday | شنبه |
|
||||
| `"1"` | Sunday | یکشنبه |
|
||||
| `"2"` | Monday | دوشنبه |
|
||||
| `"3"` | Tuesday | سهشنبه |
|
||||
| `"4"` | Wednesday | چهارشنبه |
|
||||
| `"5"` | Thursday | پنجشنبه |
|
||||
| `"6"` | Friday | جمعه |
|
||||
|
||||
---
|
||||
|
||||
### POST `/api/v1/appointment-settings/weekly-schedule`
|
||||
|
||||
Create or update the weekly schedule for a doctor (upsert).
|
||||
|
||||
**Permission:** `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
### Request Body (`application/json`)
|
||||
```json
|
||||
{
|
||||
"doctor_uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"schedule": {
|
||||
"0": {
|
||||
"sessions": [
|
||||
{
|
||||
"active": true,
|
||||
"location_id": 1973,
|
||||
"start_time": "09:00",
|
||||
"end_time": "13:00",
|
||||
"duration_per_patient": 20,
|
||||
"has_rest": true,
|
||||
"rest_interval": 60,
|
||||
"time_to_rest": 10,
|
||||
"patient_limit": null
|
||||
},
|
||||
{
|
||||
"active": true,
|
||||
"location_id": 1973,
|
||||
"start_time": "15:00",
|
||||
"end_time": "18:00",
|
||||
"duration_per_patient": 20,
|
||||
"has_rest": false,
|
||||
"rest_interval": 0,
|
||||
"time_to_rest": 0,
|
||||
"patient_limit": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"1": { "sessions": [] },
|
||||
"2": { "sessions": [] },
|
||||
"3": { "sessions": [] },
|
||||
"4": { "sessions": [] },
|
||||
"5": { "sessions": [] },
|
||||
"6": { "sessions": [] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `doctor_uuid` | string (UUID) | ✅ | Doctor UUID |
|
||||
| `schedule` | object | ✅ | Keys `"0"` through `"6"` (day indices) |
|
||||
| `schedule.{n}.sessions` | array | ✅ | Array of session config objects |
|
||||
|
||||
**Session Config Object:**
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `active` | boolean | ✅ | Whether this session is active |
|
||||
| `location_id` | integer\|null | ❌ | Doctor address/location ID |
|
||||
| `start_time` | string | ✅ | Session start `"HH:MM"` |
|
||||
| `end_time` | string | ✅ | Session end `"HH:MM"` |
|
||||
| `duration_per_patient` | integer | ✅ | Minutes per appointment slot |
|
||||
| `has_rest` | boolean | ❌ | Whether to insert rest breaks |
|
||||
| `rest_interval` | integer | ❌ | Work minutes before taking a rest break |
|
||||
| `time_to_rest` | integer | ❌ | Duration of each rest break (minutes) |
|
||||
| `patient_limit` | integer\|null | ❌ | Max patients per session (`null` = unlimited) |
|
||||
|
||||
> Multiple sessions per day are supported (e.g., morning + afternoon). Sessions are sorted by `start_time` and overlapping ones are skipped.
|
||||
|
||||
### Response `201`
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"data": {
|
||||
"uuid": "sched-uuid-...",
|
||||
"doctor_uuid": "550e8400-...",
|
||||
"schedule": {
|
||||
"0": { "sessions": [ { "active": true, "start_time": "09:00", ... } ] },
|
||||
"1": { "sessions": [] },
|
||||
"2": { "sessions": [] },
|
||||
"3": { "sessions": [] },
|
||||
"4": { "sessions": [] },
|
||||
"5": { "sessions": [] },
|
||||
"6": { "sessions": [] }
|
||||
},
|
||||
"created_at": 1717000000,
|
||||
"updated_at": 1717000000
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> ⚠️ **Double-nested:** Frontend extracts with `data?.data?.data`
|
||||
> This is an **upsert** — if a schedule already exists for the doctor, it is overwritten.
|
||||
|
||||
### Errors
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_AUTH_001` | 401 | Missing token |
|
||||
| `ERR_VALIDATION_002` | 404 | Doctor not found |
|
||||
| `ERR_AUTH_006` | 403 | Not the doctor owner |
|
||||
|
||||
---
|
||||
|
||||
### GET `/api/v1/appointment-settings/weekly-schedule/{uuid}`
|
||||
|
||||
Get weekly schedule. `{uuid}` can be either the **schedule UUID** or the **doctor UUID** — the controller tries both.
|
||||
|
||||
**Permission:** `AUTH` (class-level `IS_AUTHENTICATED_FULLY`)
|
||||
|
||||
### Response `200`
|
||||
Same structure as POST response.
|
||||
|
||||
### Errors
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_AUTH_001` | 401 | Missing token |
|
||||
| `ERR_VALIDATION_002` | 404 | Schedule not found |
|
||||
|
||||
---
|
||||
|
||||
### PATCH `/api/v1/appointment-settings/weekly-schedule/{uuid}`
|
||||
|
||||
Update weekly schedule. `{uuid}` can be schedule UUID or doctor UUID.
|
||||
|
||||
**Permission:** `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
### Request Body
|
||||
```json
|
||||
{
|
||||
"schedule": {
|
||||
"0": {
|
||||
"sessions": [
|
||||
{
|
||||
"active": true,
|
||||
"location_id": 1973,
|
||||
"start_time": "10:00",
|
||||
"end_time": "14:00",
|
||||
"duration_per_patient": 30,
|
||||
"has_rest": false,
|
||||
"rest_interval": 0,
|
||||
"time_to_rest": 0,
|
||||
"patient_limit": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> Replaces the entire `schedule` object if provided.
|
||||
|
||||
### Response `200`
|
||||
Updated schedule object (same structure as POST).
|
||||
|
||||
### Errors
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_AUTH_001` | 401 | Missing token |
|
||||
| `ERR_AUTH_006` | 403 | Not the doctor owner |
|
||||
| `ERR_VALIDATION_002` | 404 | Schedule not found |
|
||||
|
||||
---
|
||||
|
||||
### DELETE `/api/v1/booking-setting/{uuid}`
|
||||
|
||||
Delete a weekly schedule.
|
||||
|
||||
**Permission:** `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
> Note: route is `/booking-setting/`, not `/appointment-settings/`
|
||||
|
||||
### Response `200`
|
||||
```json
|
||||
{ "success": true, "data": { "message": "برنامه هفتگی با موفقیت حذف شد" } }
|
||||
```
|
||||
|
||||
### Errors
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_AUTH_001` | 401 | Missing token |
|
||||
| `ERR_AUTH_006` | 403 | Not the doctor owner |
|
||||
| `ERR_VALIDATION_002` | 404 | Schedule not found |
|
||||
|
||||
---
|
||||
|
||||
## Date Overrides
|
||||
|
||||
Override a specific date — mark it inactive (day off) or give it custom sessions.
|
||||
|
||||
### GET `/api/v1/appointment-settings/date-override/list/{doctorUuid}`
|
||||
|
||||
Get all date overrides for a doctor.
|
||||
|
||||
**Permission:** `AUTH` (class-level)
|
||||
|
||||
### Response `200`
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"data": [
|
||||
{
|
||||
"uuid": "...",
|
||||
"doctor_uuid": "...",
|
||||
"date": 1718476800,
|
||||
"active": false,
|
||||
"reason": "تعطیل خاص",
|
||||
"custom_slots": [],
|
||||
"created_at": 1717000000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `date` is a Unix timestamp. `active: false` = entire day blocked. `active: true` with `custom_slots` = custom session schedule.
|
||||
|
||||
---
|
||||
|
||||
### POST `/api/v1/appointment-settings/date-override`
|
||||
|
||||
Create a date override.
|
||||
|
||||
**Permission:** `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
### Request Body
|
||||
```json
|
||||
{
|
||||
"doctor_uuid": "550e8400-...",
|
||||
"date": "2024-06-20",
|
||||
"active": false,
|
||||
"reason": "تعطیل رسمی",
|
||||
"custom_slots": null
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `doctor_uuid` | string (UUID) | ✅ | Doctor UUID |
|
||||
| `date` | string | ✅ | Date in `Y-m-d` format (e.g. `"2024-06-20"`) |
|
||||
| `active` | boolean | ❌ | `false` = full day off (default); `true` = use custom_slots |
|
||||
| `reason` | string | ❌ | Reason for override |
|
||||
| `custom_slots` | array\|null | ❌ | Custom sessions (same SessionConfig format as weekly schedule, see below) |
|
||||
|
||||
**`custom_slots` format when `active: true`:**
|
||||
```json
|
||||
{
|
||||
"custom_slots": [
|
||||
{
|
||||
"start_time": "14:00",
|
||||
"end_time": "18:00",
|
||||
"duration_per_patient": 20,
|
||||
"location_id": 1973,
|
||||
"has_rest": false,
|
||||
"rest_interval": 0,
|
||||
"time_to_rest": 0,
|
||||
"patient_limit": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Legacy format (backward compatible):**
|
||||
```json
|
||||
{
|
||||
"custom_slots": [
|
||||
{ "start": "14:00", "end": "18:00", "duration": 20 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Response `201`
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"data": {
|
||||
"uuid": "override-uuid-...",
|
||||
"doctor_uuid": "...",
|
||||
"date": 1718476800,
|
||||
"active": false,
|
||||
"reason": "تعطیل رسمی",
|
||||
"custom_slots": [],
|
||||
"created_at": 1717000000
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Errors
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_AUTH_001` | 401 | Missing token |
|
||||
| `ERR_AUTH_006` | 403 | Not the doctor owner |
|
||||
| `ERR_VALIDATION_002` | 404 | Doctor not found |
|
||||
| `ERR_VALIDATION_001` | 422 | Invalid date format |
|
||||
|
||||
---
|
||||
|
||||
### GET `/api/v1/appointment-settings/date-override/{uuid}`
|
||||
|
||||
Get a single date override.
|
||||
|
||||
**Permission:** `AUTH` (class-level)
|
||||
|
||||
### Response `200`
|
||||
Override object (same structure as above).
|
||||
|
||||
---
|
||||
|
||||
### PATCH `/api/v1/appointment-settings/date-override/{uuid}`
|
||||
|
||||
Update a date override.
|
||||
|
||||
**Permission:** `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
### Request Body (all optional)
|
||||
```json
|
||||
{
|
||||
"active": true,
|
||||
"reason": "جبران مرخصی",
|
||||
"custom_slots": [
|
||||
{
|
||||
"start_time": "14:00",
|
||||
"end_time": "18:00",
|
||||
"duration_per_patient": 20,
|
||||
"location_id": 1973,
|
||||
"has_rest": false,
|
||||
"rest_interval": 0,
|
||||
"time_to_rest": 0,
|
||||
"patient_limit": null
|
||||
}
|
||||
],
|
||||
"date": "2024-06-21"
|
||||
}
|
||||
```
|
||||
|
||||
### Response `200`
|
||||
Updated override object.
|
||||
|
||||
### Errors
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_AUTH_001` | 401 | Missing token |
|
||||
| `ERR_AUTH_006` | 403 | Not the doctor owner |
|
||||
| `ERR_VALIDATION_002` | 404 | Override not found |
|
||||
|
||||
---
|
||||
|
||||
### DELETE `/api/v1/appointment-settings/date-override/{uuid}`
|
||||
|
||||
Delete a date override.
|
||||
|
||||
**Permission:** `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
### Response `200`
|
||||
```json
|
||||
{ "success": true, "data": { "message": "Override با موفقیت حذف شد" } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Holidays
|
||||
|
||||
Mark a date range as holiday — all slots blocked, no overrides apply.
|
||||
|
||||
### GET `/api/v1/appointment-settings/holidays/list/{doctorUuid}`
|
||||
|
||||
Get all holidays for a doctor.
|
||||
|
||||
**Permission:** `AUTH` (class-level)
|
||||
|
||||
### Response `200`
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"data": [
|
||||
{
|
||||
"uuid": "...",
|
||||
"doctor_uuid": "...",
|
||||
"start_date": 1719792000,
|
||||
"end_date": 1720656000,
|
||||
"reason": "تعطیلات تابستانی",
|
||||
"active": true,
|
||||
"created_at": 1717000000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `start_date` and `end_date` are Unix timestamps. Holidays take **highest priority** — they block the day even if a date override exists.
|
||||
|
||||
---
|
||||
|
||||
### POST `/api/v1/appointment-settings/holidays`
|
||||
|
||||
Create a holiday range.
|
||||
|
||||
**Permission:** `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
### Request Body
|
||||
```json
|
||||
{
|
||||
"doctor_uuid": "550e8400-...",
|
||||
"start_date": "2024-07-01",
|
||||
"end_date": "2024-07-10",
|
||||
"reason": "تعطیلات تابستانی"
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `doctor_uuid` | string (UUID) | ✅ | Doctor UUID |
|
||||
| `start_date` | string | ✅ | Start date `Y-m-d` |
|
||||
| `end_date` | string | ✅ | End date `Y-m-d` (must be ≥ start_date) |
|
||||
| `reason` | string | ❌ | Holiday reason |
|
||||
|
||||
### Response `201`
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"data": {
|
||||
"uuid": "holiday-uuid-...",
|
||||
"doctor_uuid": "...",
|
||||
"start_date": 1719792000,
|
||||
"end_date": 1720656000,
|
||||
"reason": "تعطیلات تابستانی",
|
||||
"active": true,
|
||||
"created_at": 1717000000
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Errors
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_AUTH_001` | 401 | Missing token |
|
||||
| `ERR_AUTH_006` | 403 | Not the doctor owner |
|
||||
| `ERR_VALIDATION_002` | 404 | Doctor not found |
|
||||
| `ERR_VALIDATION_001` | 422 | end_date before start_date or invalid format |
|
||||
|
||||
---
|
||||
|
||||
### GET `/api/v1/appointment-settings/holidays/{uuid}`
|
||||
|
||||
Get a single holiday.
|
||||
|
||||
**Permission:** `AUTH` (class-level)
|
||||
|
||||
---
|
||||
|
||||
### PATCH `/api/v1/appointment-settings/holidays/{uuid}`
|
||||
|
||||
Update a holiday.
|
||||
|
||||
**Permission:** `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
### Request Body (all optional)
|
||||
```json
|
||||
{
|
||||
"start_date": "2024-07-02",
|
||||
"end_date": "2024-07-12",
|
||||
"reason": "تمدید تعطیلات",
|
||||
"active": false
|
||||
}
|
||||
```
|
||||
|
||||
### Response `200`
|
||||
Updated holiday object.
|
||||
|
||||
---
|
||||
|
||||
### DELETE `/api/v1/appointment-settings/holidays/{uuid}`
|
||||
|
||||
Delete a holiday.
|
||||
|
||||
**Permission:** `AUTH` — must be the doctor owner or `ROLE_ADMIN`
|
||||
|
||||
### Response `200`
|
||||
```json
|
||||
{ "success": true, "data": { "message": "تعطیلات حذف شد" } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Slot Calculation Logic (Reference)
|
||||
|
||||
The `SlotCalculatorService` calculates available slots in this priority order:
|
||||
|
||||
1. **Holiday** — if date falls in a holiday range → return empty (no slots)
|
||||
2. **Date Override** — if a date override exists for this date:
|
||||
- `active: false` → return empty
|
||||
- `active: true` → use `custom_slots` sessions
|
||||
3. **Weekly Schedule** — use the day's `sessions` array (only `active: true` sessions, sorted by `start_time`, overlapping sessions skipped)
|
||||
|
||||
**Slot output format:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"start": 1718438400,
|
||||
"end": 1718439600,
|
||||
"start_time": "09:00",
|
||||
"end_time": "09:20",
|
||||
"location_id": 1973
|
||||
}
|
||||
]
|
||||
```
|
||||
Reference in New Issue
Block a user