Add tests and implementation for ServiceDetailPage and PriceInput components
- Implement PriceInput component tests to validate Persian and Arabic numeral handling, input formatting, and controlled behavior. - Create ServiceDetailPage component with detailed service information, including pricing, insurance coverage, and editing capabilities. - Add API tests for service item detail retrieval and coverage synchronization with insurance contracts. - Ensure proper error handling and user feedback for service item retrieval and coverage management.
This commit is contained in:
@@ -115,6 +115,46 @@
|
||||
|
||||
---
|
||||
|
||||
## GET /api/v1/service-item/{uuid}
|
||||
|
||||
یک سرویس مشخص — پشتیبان صفحهی اختصاصی «جزئیات سرویس» (`/admin/clinic-services/{uuid}`) که باید با
|
||||
refresh مستقیم هم کار کند، بنابراین فیلترکردن سمت کلاینت از فهرست کامل کافی نبود.
|
||||
|
||||
**Permission:** `IS_AUTHENTICATED_FULLY` + پنل Basic+ · فقط سرویسهای همان مطب/کلینیک
|
||||
(`ServiceItem→section→entity_type/entity_id`).
|
||||
|
||||
**Response 200:** یک ServiceItem object (ساختار یکسان با آیتمهای فهرست، شامل `section_uuid`،
|
||||
`section_name`، `staff_members`، `created_at` و `updated_at`):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"uuid": "...",
|
||||
"section_uuid": "...",
|
||||
"section_name": "تزریقات",
|
||||
"name": "سرم ۵۰۰cc",
|
||||
"price_rials": 850000,
|
||||
"active": true,
|
||||
"insurance_covered": true,
|
||||
"insurance_price_rials": null,
|
||||
"duration_minutes": 30,
|
||||
"bookable": true,
|
||||
"staff": { "uuid": "...", "full_name": "مریم امینی" },
|
||||
"staff_members": [{ "uuid": "...", "full_name": "مریم امینی" }],
|
||||
"created_at": 1718000000,
|
||||
"updated_at": 1718000000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**خطاها:** `404 ERR_SERVICE_NOT_FOUND` — هم برای uuid ناموجود و هم برای سرویس متعلق به tenant دیگر
|
||||
(وجود سرویس نباید لو برود) · `401` بدون احراز هویت.
|
||||
|
||||
> `section_name` تازه به `ServiceItem::toArray()` اضافه شده و در **همهی** پاسخهای این فایل هست، نه فقط این endpoint.
|
||||
|
||||
---
|
||||
|
||||
## POST /api/v1/service-item
|
||||
|
||||
ایجاد سرویس جدید.
|
||||
@@ -142,8 +182,8 @@
|
||||
| price_rials | integer | ❌ (پیشفرض 0) — «قیمت پایه» |
|
||||
| staff_uuids | UUID[] | ❌ — پرسنل مسئول (چند نفر). ترجیح داده میشود |
|
||||
| staff_uuid | UUID | ❌ — legacy تکپرسنل (اگر `staff_uuids` نباشد استفاده میشود) |
|
||||
| insurance_covered | boolean | ❌ (پیشفرض false) — آیا خدمت شامل بیمه میشود |
|
||||
| insurance_price_rials | integer\|null | ❌ — سهم/قیمت بیمار با بیمه |
|
||||
| insurance_covered | boolean | ❌ (پیشفرض false) — **deprecated برای نوشتن.** پنل ادمین دیگر این فیلد را نمیفرستد؛ مقدارش بهصورت خودکار از ردیفهای پوشش بیمه همگام میشود (به [insurance.md](insurance.md#put-apiv1billingtenant-insurancesuuidservice-coverage) نگاه کن). endpoint هنوز آن را میپذیرد تا کلاینتهای قدیمی نشکنند، ولی ذخیرهی پوشش بعداً آن را بازنویسی میکند |
|
||||
| insurance_price_rials | integer\|null | ❌ — **deprecated.** سهم تقریبی بیمار؛ از فرم سرویس حذف شد. محاسبهی دقیق سهم بیمار از `TenantServiceCoverage` انجام میشود |
|
||||
| duration_minutes | integer\|null | ❌ — «زمان متوسط» انجام خدمت به دقیقه (`""`/`null` = بدون مقدار) |
|
||||
| bookable | boolean | ❌ (پیشفرض false) — «نمایش در نوبتدهی». فقط سرویسهای `bookable=true` در حالت نوبتدهی سرویسی قابلانتخاباند |
|
||||
|
||||
|
||||
@@ -477,6 +477,12 @@ override پوشش یک خدمت خاص تحت قرارداد یک بیمه. فی
|
||||
|
||||
سرویس باید متعلق به همان مطب/کلینیکِ قرارداد باشد (`ServiceItem→section→entity_type/entity_id`).
|
||||
|
||||
**اثر جانبی — همگامسازی `ServiceItem.insurance_covered`:** پس از ذخیرهی ردیف پوشش، پرچم
|
||||
`insurance_covered` همان خدمت بازمحاسبه میشود: اگر زیر **هر** قرارداد بیمهای دستکم یک ردیف با
|
||||
`covered=true` بماند ⇒ `true`، وگرنه `false`. پنل ادمین دیگر این پرچم را دستی نمیفرستد (سوییچ «این خدمت
|
||||
شامل بیمه میشود» از فرم سرویس حذف شد)، پس این endpoint تنها منبع حقیقت آن است. پیادهسازی:
|
||||
`TenantInsuranceService::syncServiceItemInsuranceFlag()` + `TenantServiceCoverageRepository::hasActiveCoverage()`.
|
||||
|
||||
پاسخ `200`: `{ success, data: { message } }`.
|
||||
خطاها: `404 ERR_NOT_FOUND_001` قرارداد یافت نشد · `422 ERR_VALIDATION_001` سرویس یافت نشد · `403 ERR_FORBIDDEN_001` سرویس متعلق به شما نیست.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user