Files
clinicpro/docs/api/patient.md
T
hamedandClaude Opus 4.8 51d7e24e04 feat: create patient record without prior signup
Extend POST /api/v1/patient to resolve user by uuid or mobile, and
create a new ROLE_USER (name + optional national code, no password)
when no user exists. Admin modal shows a new-patient form on lookup miss.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:20:56 +03:30

290 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Patient Records & Sessions API
## Overview
Patient records track patients per entity (doctor or clinic). Each record holds multiple sessions (visits). Access requires an active subscription with the `patient_records` feature.
**Base path:** `/api/v1`
**Auth:** Bearer JWT (doctor, clinic, or secretary with `appointments.view` permission required)
---
## Endpoints
### List Patients
```
GET /api/v1/patients
```
Returns a paginated list of patient records belonging to the authenticated entity.
**Query params:**
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `page` | int | 1 | Page number |
| `limit` | int | 20 | Items per page (1050) |
| `search` | string | — | Search by patient name or phone |
**Response 200:**
```json
{
"success": true,
"data": [
{
"uuid": "...",
"entity_type": "doctor",
"entity_id": 5,
"user": { "uuid": "...", "fullName": "علی رضایی", "phone": "09123456789" },
"created_by_type": "doctor",
"created_by_id": 5,
"created_at": 1718375000
}
],
"meta": {
"totalRecords": 42,
"totalPages": 3,
"currentPage": 1
}
}
```
**Errors:**
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No active plan with `patient_records` feature |
---
### Create Patient Record
```
POST /api/v1/patient
```
Creates a patient record for a user under the current entity. If the record already exists, returns the existing record (idempotent).
سه حالت پشتیبانی می‌شود:
1. **کاربر ثبت‌نام‌کرده با uuid:** `user_uuid` ارسال شود.
2. **کاربر ثبت‌نام‌کرده با موبایل:** `mobile` ارسال شود (کاربر موجود پیدا می‌شود).
3. **بیمار جدید بدون ثبت‌نام:** `mobile` + `name` ارسال شود؛ اگر کاربری با آن موبایل نباشد، `User` جدید (نقش `ROLE_USER`، بدون رمز عبور) ساخته می‌شود سپس پرونده.
**Request body:**
```json
{
"user_uuid": "string (اختیاری)",
"mobile": "09xxxxxxxxx (اختیاری — برای جستجو یا ساخت بیمار جدید)",
"name": "string (الزامی فقط هنگام ساخت بیمار جدید)",
"national_code": "string (اختیاری، ۱۰ رقم)"
}
```
- اگر `user_uuid` و `mobile` هر دو خالی باشند → خطا.
- `national_code` فقط وقتی روی کاربر ست می‌شود که کاربر کد ملی نداشته باشد.
- موبایل تکراری duplicate نمی‌سازد؛ همان کاربر استفاده می‌شود.
**Response 201:**
```json
{
"success": true,
"data": {
"uuid": "...",
"entity_type": "doctor",
"entity_id": 5,
"user": { "uuid": "...", "fullName": "...", "phone": "..." },
"created_by_type": "doctor",
"created_by_id": 5,
"created_at": 1718375000
}
}
```
**Errors:**
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_VALIDATION_001` | 422 | `user_uuid`/`mobile` خالی، یا موبایل/کد ملی نامعتبر، یا نام برای بیمار جدید خالی |
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature |
---
### Get Patient Record
```
GET /api/v1/patient/{uuid}
```
Returns a single patient record.
**Response 200:**
```json
{
"success": true,
"data": {
"uuid": "...",
"entity_type": "doctor",
"entity_id": 5,
"user": { "uuid": "...", "fullName": "...", "phone": "..." },
"created_by_type": "doctor",
"created_by_id": 5,
"created_at": 1718375000
}
}
```
**Errors:**
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_PATIENT_NOT_FOUND` | 404 | Record not found or not owned by caller |
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature |
---
### List Patient Sessions
```
GET /api/v1/patient/{uuid}/sessions
```
Returns paginated sessions for a patient record.
**Query params:** `page`, `limit` (same as list)
**Response 200:**
```json
{
"success": true,
"data": [
{
"uuid": "...",
"record_uuid": "...",
"appointment_uuid": null,
"insurance_base_id": null,
"insurance_supplementary_id": null,
"visit_price_rials": 200000,
"base_insurance_discount_percent": "10.00",
"supplementary_discount_percent": "5.00",
"services_total_rials": 50000,
"final_price_rials": 230000,
"payment_method": "cash",
"notes": "...",
"created_at": 1718375000,
"updated_at": 1718375000
}
],
"meta": { "totalRecords": 8, "totalPages": 1, "currentPage": 1 }
}
```
**Errors:**
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_PATIENT_NOT_FOUND` | 404 | Record not found or not owned by caller |
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature |
---
### Create Session
```
POST /api/v1/patient/{uuid}/session
```
Creates a new visit session for a patient record.
**Request body:**
```json
{
"visit_price_rials": 200000,
"base_insurance_discount_percent": 10,
"supplementary_discount_percent": 5,
"insurance_base_id": null,
"insurance_supplementary_id": null,
"payment_method": "cash",
"notes": "...",
"services": [
{
"service_item_uuid": "...",
"staff_uuid": null
}
]
}
```
**Field notes:**
- `payment_method`: `cash` | `card` | `insurance` | `online` | `pending`
- `services`: array of service items to attach; `price_rials` is snapshot-copied from ServiceItem
- `final_price_rials` is computed: `(visit_price × (1 - base%) × (1 - supp%)) + services_total`
**Response 201:**
```json
{
"success": true,
"data": { ...session object... }
}
```
**Errors:**
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_PATIENT_NOT_FOUND` | 404 | Record not found or not owned |
| `ERR_SUBSCRIPTION_REQUIRED` | 403 | No `patient_records` feature |
---
### Update Session
```
PATCH /api/v1/session/{uuid}
```
Updates mutable fields on a session.
**Request body (all optional):**
```json
{
"notes": "...",
"payment_method": "card"
}
```
**Response 200:**
```json
{
"success": true,
"data": { ...session object... }
}
```
**Errors:**
| Code | HTTP | Description |
|------|------|-------------|
| `ERR_SESSION_NOT_FOUND` | 404 | Session not found or not owned |
---
## Auto-Creation on Appointment Confirm
When an appointment's status changes to `confirmed` via `PATCH /api/v1/appointment/{uuid}/status`, the system automatically:
1. Creates a `PatientRecord` for the appointment's user (if not already existing) under the doctor entity
2. Creates a blank `PatientSession` linked to the appointment
This only runs if the doctor has the `patient_records` subscription feature active.