feat: Implement resource booking functionality
- Add service timeline builder for appointments to manage available slots. - Create a hook to fetch resource booking services with effective durations. - Develop ResourceBookingSlotController to handle API requests for resource booking slots. - Implement ResourceBookingSlotService to calculate available time slots based on resource occupancy and service durations. - Add tests for resource appointment creation and booking slot functionality to ensure correct behavior and edge cases.
This commit is contained in:
+56
-1
@@ -451,6 +451,58 @@
|
||||
> تعداد کوئری ثابت است: یک کوئری اشغال، یک کوئری شیفت، یک کوئری نوبت — نه یکی بهازای
|
||||
> هر منبع.
|
||||
|
||||
### `GET /api/v1/resource/{uuid}/day-slots` (2026-08)
|
||||
|
||||
مجوز: `appointment_settings.view`. پارامتر: `date=Y-m-d` (الزامی).
|
||||
|
||||
بازههای **کاری** منبع در یک روز — ورودیِ تایملاینِ سرویسیِ صفحهٔ نوبتها. معادلِ
|
||||
`appointment-slots` پزشک، ولی از تقویم خودِ منبع: ساعت شعبه ∩ شیفت منبع − تعطیلات −
|
||||
استثناها.
|
||||
|
||||
نوبتها اینجا **کسر نمیشوند**: تایملاین نوبتهای همان روز را جدا دارد و کارتها را
|
||||
داخل همین بازهها میچیند؛ کسرشان یعنی نوبتِ ثبتشده جایی برای نشستن ندارد.
|
||||
|
||||
```json
|
||||
{ "success": true, "data": {
|
||||
"resource_uuid": "ce07…", "date": "2026-08-04", "timezone": "Asia/Tehran",
|
||||
"windows": [{ "start": 1785220200, "end": 1785249000, "start_time": "09:00", "end_time": "17:00" }],
|
||||
"empty_reason": null
|
||||
} }
|
||||
```
|
||||
|
||||
`empty_reason` وقتی `windows` خالی است میگوید چرا: `no_shift`، `national_holiday`،
|
||||
`tenant_holiday`، `exception`، `resource_inactive`، `address_inactive`. خالیبودن خطا
|
||||
نیست و کلاینت نباید همه را «تعطیل» بنامد.
|
||||
|
||||
### `GET /api/v1/resource/{uuid}/service-slots` (2026-08)
|
||||
|
||||
مجوز: `appointment_settings.view`.
|
||||
|
||||
| پارامتر | توضیح |
|
||||
|---|---|
|
||||
| `date` | `Y-m-d`، الزامی |
|
||||
| `service_item_uuids[]` | یک یا چند سرویس؛ خالی ⇒ `422` |
|
||||
| `durations[<uuid>]` | override مدت، فقط برای همین محاسبه |
|
||||
|
||||
زمانهای خالیِ کافی برای مجموعِ مدتِ سرویسهای انتخابشده — معادلِ
|
||||
`appointment-service-slots` پزشک. مدت هر سرویس از زنجیرهٔ حلِ همان منبع میآید
|
||||
(`ResourceServiceResolver`)، اشغال از نوبتهای `resource_id` **و** ردیفهای
|
||||
`resource_occupancy` خوانده میشود، و ظرفیت منبع رعایت میشود. زمانها پشتسرهم
|
||||
چیده میشوند (بدون بافر) و زمانِ گذشته پیشنهاد نمیشود.
|
||||
|
||||
```json
|
||||
{ "success": true, "data": {
|
||||
"resource_uuid": "ce07…", "date": "2026-08-04", "total_duration_minutes": 60,
|
||||
"start_times": [{ "start": 1785220200, "end": 1785223800, "start_time": "09:00", "end_time": "10:00" }]
|
||||
} }
|
||||
```
|
||||
|
||||
**۴۲۲:** سرویسِ ناموجود · سرویسی که این منبع ارائه نمیدهد (یا offeringش غیرفعال است)
|
||||
· سرویسِ بیمدت · تاریخ بدفرم. **۴۰۴:** منبعِ محیط دیگر.
|
||||
|
||||
ثبتِ خودِ نوبت با همین زمانها از `POST /api/v1/my/appointment` با `resource_uuid`
|
||||
انجام میشود ([`appointment.md`](appointment.md)).
|
||||
|
||||
### `PUT /api/v1/resource/{uuid}/categories`
|
||||
|
||||
مجوز: `appointment_settings.update`.
|
||||
@@ -581,9 +633,12 @@ idempotent است: تکیهگاهش وجود یا نبودِ منبعِ مت
|
||||
## تستها
|
||||
|
||||
```bash
|
||||
ddev exec php bin/phpunit tests/Resource # ۵۲ تست / ۱۲۹ assertion
|
||||
ddev exec php bin/phpunit tests/Resource # ۱۳۱ تست / ۳۴۲ assertion
|
||||
ddev exec php vendor/bin/phpstan analyse src/Resource
|
||||
npx vitest run assets/admin/pages/ResourcesPage.test.tsx
|
||||
npx vitest run assets/admin/components/appointments/ResourceDayPanel.test.tsx \
|
||||
assets/admin/components/appointments/ResourceBookingModal.test.tsx \
|
||||
assets/admin/components/appointments/serviceTimeline.test.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user