7.9 KiB
Clinic Services API
مدیریت بخشها و سرویسهای کلینیک/مطب.
نیاز به پنل: Basic یا بالاتر (ERR_SUBSCRIPTION_REQUIRED اگر نداشت)
GET /api/v1/service-sections
لیست بخشهای سرویس entity جاری.
Permission: IS_AUTHENTICATED_FULLY + پنل Basic+
Response 200:
{
"success": true,
"data": [
{
"uuid": "...",
"entity_type": "clinic",
"entity_id": 5,
"name": "آزمایشگاه",
"active": true,
"items_count": 10,
"created_at": 1718000000,
"updated_at": 1718000000
}
]
}
items_countتعداد سرویسهای همان بخش است (فقط در این endpoint لیستی برگردانده میشود).
POST /api/v1/service-section
ایجاد بخش جدید.
Permission: IS_AUTHENTICATED_FULLY + پنل Basic+
Request Body:
{ "name": "رادیولوژی" }
Response 201: ServiceSection object
Errors:
| Code | HTTP | توضیح |
|---|---|---|
| ERR_SUBSCRIPTION_REQUIRED | 403 | نیاز به پنل Basic+ |
| ERR_VALIDATION_001 | 422 | name خالی است |
PATCH /api/v1/service-section/{uuid}
ویرایش بخش.
Permission: owner یا ROLE_ADMIN
{ "name": "رادیولوژی دیجیتال", "active": true }
DELETE /api/v1/service-section/{uuid}
حذف بخش (cascade — همه ServiceItem های آن حذف میشوند).
Permission: owner
GET /api/v1/service-items/{sectionUuid}
لیست سرویسهای یک بخش.
Response 200:
{
"success": true,
"data": [
{
"uuid": "...",
"section_uuid": "...",
"staff_uuid": "...",
"staff_name": "علی محمدی",
"staff": { "uuid": "...", "full_name": "علی محمدی" },
"staff_members": [
{ "uuid": "...", "full_name": "علی محمدی" },
{ "uuid": "...", "full_name": "سحر رحمانی" }
],
"name": "رادیوگرافی مستقیم",
"price_rials": 500000,
"active": true,
"insurance_covered": false,
"insurance_price_rials": null,
"duration_minutes": 50,
"bookable": true,
"created_at": 1718000000,
"updated_at": 1718000000
}
]
}
POST /api/v1/service-item
ایجاد سرویس جدید.
Permission: IS_AUTHENTICATED_FULLY + پنل Basic+
Request Body:
{
"section_uuid": "...",
"name": "رادیوگرافی مستقیم",
"price_rials": 500000,
"staff_uuid": "...",
"insurance_covered": true,
"insurance_price_rials": 200000,
"duration_minutes": 50,
"bookable": true
}
| فیلد | نوع | الزامی |
|---|---|---|
| section_uuid | UUID | ✅ |
| name | string | ✅ |
| price_rials | integer | ❌ (پیشفرض 0) — «قیمت پایه» |
| staff_uuids | UUID[] | ❌ — پرسنل مسئول (چند نفر). ترجیح داده میشود |
| staff_uuid | UUID | ❌ — legacy تکپرسنل (اگر staff_uuids نباشد استفاده میشود) |
| insurance_covered | boolean | ❌ (پیشفرض false) — آیا خدمت شامل بیمه میشود |
| insurance_price_rials | integer|null | ❌ — سهم/قیمت بیمار با بیمه |
| duration_minutes | integer|null | ❌ — «زمان متوسط» انجام خدمت به دقیقه (""/null = بدون مقدار) |
| bookable | boolean | ❌ (پیشفرض false) — «نمایش در نوبتدهی». فقط سرویسهای bookable=true در حالت نوبتدهی سرویسی قابلانتخاباند |
bookableدرPATCH /api/v1/service-item/{uuid}هم به همین شکل پذیرفته میشود.
Response 201: ServiceItem object (شامل insurance_covered و insurance_price_rials)
قیمت واحد: هنگام ساخت سرویس، یک تعرفه برای سال جاری با همان
price_rialsبهصورت خودکار ثبت میشود. قیمت سرویس = تعرفهی سال جاری است و همهجا (صورتحساب، مراجعه، مطالبات) از همین قیمت استفاده میشود.
PATCH /api/v1/service-item/{uuid}
ویرایش سرویس.
{
"name": "رادیوگرافی دیجیتال",
"price_rials": 600000,
"staff_uuid": null,
"active": false,
"insurance_covered": true,
"insurance_price_rials": 250000,
"duration_minutes": 30
}
فیلد
duration_minutes(زمان متوسط، دقیقه) در پاسخِtoArrayو در ساخت/ویرایش پشتیبانی میشود؛""/nullآن را پاک میکند.
پرسنل چندنفره: یک سرویس میتواند چند پرسنل داشته باشد.
staff_uuids(آرایه) ترجیح داده میشود؛ در نبود آن،staff_uuidتکنفره بهصورت backward-compatible پذیرفته میشود. پاسخ همیشهstaff_members[](کامل) وstaff/staff_uuid/staff_name(نفر اول، برای سازگاری) را برمیگرداند. هر پرسنل باید متعلق به همان tenant (entity_type/entity_id) باشد؛ در غیر این صورت →422 ERR_VALIDATION_001(field: staff_uuids). همین قید رویPOST /service-itemنیز اعمال میشود.
DELETE /api/v1/service-item/{uuid}
حذف سرویس.
اگر سرویس در پرونده بیماری استفاده شده باشد، خطا برمیگرداند:
{
"success": false,
"errors": [{ "code": "ERR_SERVICE_ITEM_IN_USE", "message": "این سرویس در پرونده بیمار ثبت شده است" }]
}
Errors:
| Code | HTTP | توضیح |
|---|---|---|
| ERR_SUBSCRIPTION_REQUIRED | 403 | نیاز به پنل Basic+ |
| ERR_SERVICE_NOT_FOUND | 404 | سرویس یافت نشد |
| ERR_SERVICE_ITEM_IN_USE | 409 | سرویس در پرونده بیمار استفاده شده |
تعرفهی نسخهدار سالانه (Tariff) — فاز ۳ سیستم صورتحساب
هر خدمت میتواند برای هر سال شمسی یک تعرفه داشته باشد. اگر تعرفهی سالی ثبت نشود، به price_rials خود خدمت fallback میشود (TariffService::resolvePrice). سال جاری شمسی سمت سرور با IntlDateFormatter (تقویم persian) محاسبه میشود.
GET /api/v1/service-items/{uuid}/tariffs
لیست تعرفههای یک خدمت + قیمت پیشفرض + سال جاری.
Permission: IS_AUTHENTICATED_FULLY (مالک خدمت)
{
"success": true,
"data": {
"current_year": 1405,
"default_price_rials": 500000,
"data": [
{ "uuid": "…", "service_item_id": 12, "year": 1405, "price_rials": 600000, "is_active": true },
{ "uuid": "…", "service_item_id": 12, "year": 1404, "price_rials": 500000, "is_active": true }
]
}
}
PUT /api/v1/service-items/{uuid}/tariffs/{year}
ثبت/بهروزرسانی تعرفهی یک سال (upsert). year بین ۱۳۹۰ تا ۱۵۰۰.
Body:
{ "price_rials": 600000 }
Response 200: { success, data: { …tariff } }
اگر
yearبرابر سال جاری باشد،ServiceItem.price_rialsهم با همین مقدار همگام میشود (قیمت واحد). تعرفهی سالهای دیگر فقط برای محاسبهی صورتحساب همان سال (TariffService::resolvePrice) بهکار میرود و قیمت پایهی سرویس را تغییر نمیدهد. همچنینPATCH /service-item/{uuid}با تغییرprice_rials، تعرفهی سال جاری را upsert میکند.
Errors:
| Code | HTTP | توضیح |
|---|---|---|
| ERR_SERVICE_NOT_FOUND | 404 | سرویس یافت نشد |
| ERR_VALIDATION_001 | 422 | سال نامعتبر |