Files
clinicpro/docs/api/patient.md
T
hamedandClaude Opus 4.8 2206f02396 feat: enrich patient record with full profile
GET /api/v1/patient/{uuid} now returns a `profile` object from UserProfile
(demographics, contact, insurance names resolved). Admin record detail shows
a "patient info" section. Empty fields render as "ثبت نشده".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 17:21:33 +03:30

8.8 KiB
Raw Blame History

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:

{
  "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:

{
  "user_uuid": "string (اختیاری)",
  "mobile": "09xxxxxxxxx (اختیاری — برای جستجو یا ساخت بیمار جدید)",
  "name": "string (الزامی فقط هنگام ساخت بیمار جدید)",
  "national_code": "string (اختیاری، ۱۰ رقم)"
}
  • اگر user_uuid و mobile هر دو خالی باشند → خطا.
  • national_code فقط وقتی روی کاربر ست می‌شود که کاربر کد ملی نداشته باشد.
  • موبایل تکراری duplicate نمی‌سازد؛ همان کاربر استفاده می‌شود.

Response 201:

{
  "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, enriched with the patient's full profile (profile) درون‌خطی از UserProfile. اگر پروفایل وجود نداشت، فیلدها null برمی‌گردند (نه خطا). نام بیمه‌ها از روی id resolve می‌شوند.

Response 200:

{
  "success": true,
  "data": {
    "uuid": "...",
    "entity_type": "doctor",
    "entity_id": 5,
    "user_uuid": "...",
    "user_name": "...",
    "user_mobile": "0912...",
    "user_national_code": "...",
    "created_at": 1718375000,
    "profile": {
      "full_name": "محمد محمدی",
      "national_code": "0012345678",
      "gender": "male",
      "date_of_birth": 700000000,
      "blood_type": "O+",
      "marital_status": "single",
      "job": "...",
      "address": "...",
      "home_phone": "...",
      "work_phone": "...",
      "mobile": "0912...",
      "basic_insurance_id": 3,
      "basic_insurance_name": "تأمین اجتماعی",
      "supplementary_insurance_id": 9,
      "supplementary_insurance_name": "دانا"
    }
  }
}

date_of_birth یک Unix timestamp است؛ سمت کلاینت با formatDate() شمسی نمایش داده می‌شود. profile برای هر دو entity_type (doctor/clinic) یکسان است.

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:

{
  "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:

{
  "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:

{
  "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):

{
  "notes": "...",
  "payment_method": "card"
}

Response 200:

{
  "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
  3. اگر نوبت با آدرس کلینیک ثبت شده باشد (appointment.address_idDoctorAddress.clinic_id)، همان دو مرحله برای آن کلینیک (entity_type='clinic') هم تکرار می‌شود. اگر آدرس نوبت کلینیک نداشت ولی دکتر فقط عضو یک کلینیک بود، به همان کلینیک اضافه می‌شود.

هر شاخه (doctor / clinic) مستقل و فقط در صورت فعال‌بودن ویژگی patient_records برای همان entity اجرا می‌شود. duplicate با findByEntityAndUser جلوگیری می‌شود.

انتساب پزشک: هر PatientSession در پاسخ، doctor_uuid و doctor_name را از روی نوبتِ متناظر برمی‌گرداند؛ پس در پرونده‌ی کلینیک مشخص است هر مراجعه برای کدام پزشک بوده است.

آدرس نوبت: هنگام رزرو، address_id خودکار از location_id همان session برنامه‌ی هفتگی ست می‌شود (در همه‌ی مسیرهای رزرو). ثبت location_id برای هر شیفت فعال در برنامه‌ی هفتگی الزامی است (POST/PATCH /api/v1/appointment-settings/weekly-schedule)؛ در غیر این صورت 422.