- Add implementation notes for cancellation and waitlist features. - Create task documentation outlining goals, current status, and acceptance criteria for cancellation policy and resource utilization reporting. - Establish architecture for domain events and outbox pattern to ensure reliable event publishing. - Define database schema for domain events and necessary queries for resource utilization and plan accuracy reports. - Implement detailed implementation notes covering edge cases, testing strategies, and documentation requirements.
103 lines
5.6 KiB
Markdown
103 lines
5.6 KiB
Markdown
# تسک ۰۵ — بخشهای نوبت و سازندهٔ برنامه
|
||
|
||
**فاز:** ۱ (هسته) · **وابستگی:** ۰۲، ۰۴ · **زمان:** ۱۶-۲۰ ساعت
|
||
|
||
---
|
||
|
||
## هدف
|
||
|
||
مهمترین بخش مستند (بند ۷). یک نوبت یک تکه زمان پیوسته نیست:
|
||
|
||
| بخش | مدت | اتاق | اپراتور | دستگاه |
|
||
|---|---|---|---|---|
|
||
| مالیدن کرم بیحسی | ۵ | اشغال | اشغال | آزاد |
|
||
| انتظار اثر کرم | ۳۰ | اشغال | **آزاد** | آزاد |
|
||
| خود لیزر | ۲۰ | اشغال | اشغال | اشغال |
|
||
| مراقبت بعد | ۵ | اشغال | اشغال | آزاد |
|
||
|
||
با مدل امروز اپراتور ۶۰ دقیقه قفل میشود در حالی که ۳۰ دقیقه کار میکند. نصف ظرفیت
|
||
هدر میرود.
|
||
|
||
## وضعیت فعلی
|
||
|
||
```php
|
||
// src/Appointment/Entity/Appointment.php
|
||
private int $slotStart; // یک بازهٔ پیوسته
|
||
private int $slotEnd;
|
||
```
|
||
|
||
هیچ مفهومی از بخش، و هیچ نیازمندی منبعی وجود ندارد. تنها منبعی که تداخلش بررسی میشود
|
||
پزشک است (`AppointmentRepository::isSlotTaken`).
|
||
|
||
## دامنه
|
||
|
||
**هست:**
|
||
- `SegmentTemplate` — الگوی بخشهای یک سرویس (و بخشهای اضافهٔ هر `ServiceOption`)
|
||
- `SegmentRequirement` — نیازمندی منبع هر بخش: نقش، تعداد، شرط مهارت، قید، نوع اشغال
|
||
- `AppointmentPlanBuilder` — از (سرویس، آیتمها، بیمار، شعبه) یک **برنامهٔ نوبت** میسازد
|
||
- ادغام بخشهای همنوع، محاسبهٔ مدت هر بخش، چیدمان ترتیبی
|
||
- `GET /api/v1/appointment-plan/preview` برای دیدن برنامه پیش از جستجوی وقت
|
||
|
||
**نیست:** پیدا کردن منابع آزاد و زمان (تسک ۰۶)، ثبت اشغال (تسک ۰۷)،
|
||
اعمال قوانین روی برنامه (تسک ۰۹ — نقطهٔ اتصالش اینجا آماده میشود).
|
||
|
||
## Endpoint ها
|
||
|
||
| متد | مسیر | توضیح |
|
||
|---|---|---|
|
||
| GET/PUT | `/api/v1/service-item/{uuid}/segments` | الگوی بخشهای سرویس |
|
||
| PUT | `/api/v1/segment-template/{uuid}/requirements` | نیازمندیهای منبع یک بخش |
|
||
| POST | `/api/v1/appointment-plan/preview` | ساخت و برگرداندن برنامهٔ نوبت (بدون ثبت) |
|
||
|
||
## خروجی `POST /appointment-plan/preview`
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"total_minutes": 60,
|
||
"segments": [
|
||
{ "sequence": 1, "name": "بیحسی موضعی", "offset_minutes": 0, "duration_minutes": 5,
|
||
"patient_present": true,
|
||
"requirements": [
|
||
{ "role": "room", "count": 1, "occupancy": "exclusive", "candidates": 3 },
|
||
{ "role": "operator", "count": 1, "occupancy": "exclusive", "candidates": 2 }
|
||
] },
|
||
{ "sequence": 2, "name": "انتظار", "offset_minutes": 5, "duration_minutes": 30,
|
||
"patient_present": true, "mergeable": true,
|
||
"requirements": [ { "role": "room", "count": 1, "occupancy": "exclusive", "candidates": 3 } ] }
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
`candidates` تعداد منابع واجد شرایط است — اگر صفر باشد، برنامه ساخته نمیشود و خطای
|
||
انسانی برمیگردد: «هیچ اپراتور خانمی با مهارت لیزر در این شعبه نیست» (مستند بند ۱۰).
|
||
|
||
## معیار پذیرش
|
||
|
||
- ✅ موفق: سرویس «لیزر» با چهار بخش بالا تعریف میشود؛ `preview` برنامهای با
|
||
`total_minutes = 60` و چهار بخش با `offset_minutes` صحیح (۰، ۵، ۳۵، ۵۵) برمیگرداند.
|
||
- ✅ موفق: انتخاب دو ناحیه (صورت + بیکینی) → بخش «آمادهسازی» **یک بار** میآید
|
||
(`mergeable=true` همنوعها ادغام میشوند) ولی بخش «لیزر» مدتش با `DurationCalculator`
|
||
تسک ۰۴ محاسبه شده است.
|
||
- ✅ موفق: سرویسی که هیچ `SegmentTemplate` ندارد → برنامهای با **یک بخش** برابر کل مدت
|
||
و نیازمندی پیشفرض (منبع `type=doctor`). این همان رفتار امروز است.
|
||
- ❌ خطا: نیازمندی با مهارتی که هیچ منبعی در آن شعبه ندارد →
|
||
`422` با `ERR_NO_ELIGIBLE_RESOURCE` و پیام فارسی شامل نقش و مهارت.
|
||
- ❌ خطا: بخش با `duration_minutes <= 0` و بدون منبع مدت پویا → `422`.
|
||
- ⚠️ مرزی: بخش با `requirements = []` (مثلاً «انتظار در خانه») → معتبر؛ زمان میگیرد،
|
||
هیچ منبعی نمیگیرد.
|
||
- ⚠️ مرزی: قید `same_gender_as_patient` وقتی جنسیت بیمار نامشخص است → نیازمندی نادیده
|
||
گرفته **نمیشود**؛ `422` با پیام «برای این سرویس ثبت جنسیت بیمار الزامی است».
|
||
- ⚠️ مرزی: `setup/cleanup` منبع در `preview` **نمایش داده نمیشود** ولی در
|
||
`occupancy_offset` هر نیازمندی میآید تا تسک ۰۶ همان را استفاده کند.
|
||
- ⚠️ مرزی: مجموع مدت بخشها بیشتر از ۸ ساعت → `422` (حفاظت از جستجوی وقت).
|
||
|
||
## خروجی
|
||
|
||
- `src/Appointment/Plan/` — entity ها، `AppointmentPlanBuilder`، DTO ها
|
||
- `assets/admin/pages/ServiceSegmentsPage.tsx` + پیشنمایش برنامه
|
||
- `docs/api/appointment-plan.md`
|
||
- الگوهای آماده: `app:segment:seed-templates --preset=beauty|dental|physio` (مستند بند ۱۷)
|