# Clinic Services API مدیریت بخش‌ها و سرویس‌های کلینیک/مطب. **نیاز به پنل:** Basic یا بالاتر (`ERR_SUBSCRIPTION_REQUIRED` اگر نداشت) --- ## GET /api/v1/service-sections لیست بخش‌های سرویس entity جاری. **Permission:** `IS_AUTHENTICATED_FULLY` + پنل Basic+ **Response 200:** ```json { "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:** ```json { "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 ```json { "name": "رادیولوژی دیجیتال", "active": true } ``` --- ## DELETE /api/v1/service-section/{uuid} حذف بخش (cascade — همه ServiceItem های آن حذف می‌شوند). **Permission:** owner --- ## GET /api/v1/service-items/{sectionUuid} لیست سرویس‌های یک بخش. **Response 200:** ```json { "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, "created_at": 1718000000, "updated_at": 1718000000 } ] } ``` --- ## POST /api/v1/service-item ایجاد سرویس جدید. **Permission:** `IS_AUTHENTICATED_FULLY` + پنل Basic+ **Request Body:** ```json { "section_uuid": "...", "name": "رادیوگرافی مستقیم", "price_rials": 500000, "staff_uuid": "...", "insurance_covered": true, "insurance_price_rials": 200000, "duration_minutes": 50 } ``` | فیلد | نوع | الزامی | |------|-----|--------| | 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` = بدون مقدار) | **Response 201:** ServiceItem object (شامل `insurance_covered` و `insurance_price_rials`) > **قیمت واحد:** هنگام ساخت سرویس، یک تعرفه برای **سال جاری** با همان `price_rials` به‌صورت خودکار ثبت می‌شود. قیمت سرویس = تعرفه‌ی سال جاری است و همه‌جا (صورتحساب، مراجعه، مطالبات) از همین قیمت استفاده می‌شود. --- ## PATCH /api/v1/service-item/{uuid} ویرایش سرویس. ```json { "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} حذف سرویس. اگر سرویس در پرونده بیماری استفاده شده باشد، خطا برمی‌گرداند: ```json { "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` (مالک خدمت) ```json { "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:** ```json { "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 | سال نامعتبر |