feat(availability): resource ordering strategies, and a real fix for the flaky suite
Strategies (task 06 debt, task 12 dependency) - ResourcePicker orders candidates; it deliberately does not choose. Only the engine knows which resource actually fits this slot and which was already taken by another role, and a strategy that picked would have to duplicate both checks - Four implementations behind a tagged iterator: first_available (name order, the previous behaviour and still the default because it is predictable), least_gap, least_loaded, same_as_previous - least_gap and least_loaded are deliberate opposites and both are correct; choosing between them is a business decision, so it lives in settings - same_as_previous lifts a course's preferred resource to the front and keeps everyone else behind it. A preference, not a filter: forcing the same operator would make the patient wait two weeks, which is worse than a different operator - Availability accepts course_uuid to supply that preference, closing the dependency task 12 recorded against task 06 - An unknown strategy falls back at search time but is rejected at save time. Stale settings must not stop bookings; a user typing a wrong value must not believe it took effect Test suite flake createUser() retries on a mobile-number collision — db_test is never reset and holds tens of thousands of users, so the random draw does collide. The failed INSERT closes the EntityManager, and the retry asked the container for it again, which hands back the *same closed instance*. So the retry threw, and every later test in that process inherited a dead manager. That is the intermittent "EntityManager is closed" on an unrelated, always-different test that made roughly half of full runs red and never reproduced in a subset. Resetting the registry gives a live manager back. UserCollisionRetryTest pins it by closing the manager on purpose. Two consecutive full runs are green: 1334 tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -139,3 +139,53 @@
|
||||
ddev exec php bin/phpunit tests/Appointment/AvailabilityEngineTest.php # ۹ تست
|
||||
ddev exec php bin/phpunit tests/Appointment/AvailabilityPerformanceTest.php
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## استراتژی ترتیب منابع
|
||||
|
||||
وقتی چند منبع برای یک نقش واجد شرایطاند، **ترتیب امتحانکردنشان** از تنظیمات محیط
|
||||
میآید (`meta.resource_strategy`). استراتژی فقط مرتب میکند؛ تصمیم نهایی همچنان با
|
||||
موتور است، چون فقط موتور میداند کدام منبع در این زمان جا دارد و کدام برای نقش دیگری
|
||||
برداشته شده.
|
||||
|
||||
| کلید | رفتار | کِی مناسب است |
|
||||
|---|---|---|
|
||||
| `first_available` | ترتیب نام (پیشفرض) | خروجی کاملاً قابل پیشبینی |
|
||||
| `least_gap` | کمترین وقت مردهٔ باقیمانده | تقویم کمتر تکهتکه شود |
|
||||
| `least_loaded` | منبعِ آزادتر زودتر | بار بین چند اپراتور پخش شود |
|
||||
| `same_as_previous` | منبع ترجیحی جلو، بقیه پشت آن | دورهٔ درمان با همان اپراتور |
|
||||
|
||||
`least_gap` و `least_loaded` عکس هم عمل میکنند و **هر دو درستاند**؛ انتخاب بینشان
|
||||
تصمیم کسبوکاری است نه فنی.
|
||||
|
||||
### ترجیح منبع دوره
|
||||
|
||||
`POST /api/v1/appointment-availability` یک فیلد اختیاری `course_uuid` میگیرد. با آن،
|
||||
`preferred_resource` همان دوره به بالای فهرست میرود.
|
||||
|
||||
**ترجیح است نه فیلتر:** اگر آن منبع آزاد نباشد، رزرو رد نمیشود و به ترتیب پایه
|
||||
برمیگردد — اجبار یعنی بیمار دو هفته منتظر بماند، و آن بدتر از عوض شدن اپراتور است.
|
||||
|
||||
### فهرست استراتژیها
|
||||
|
||||
`GET /api/v1/appointment-settings/resource-strategies`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{ "code": "first_available", "label": "به ترتیب نام — ساده و قابل پیشبینی" },
|
||||
{ "code": "least_gap", "label": "کمترین وقت مرده — تقویم کمتر تکهتکه میشود" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
انتخابگر پنل از همین ساخته میشود؛ افزودن استراتژی تازه یعنی افزودن **یک کلاس** با تگ
|
||||
`app.resource_picker` — نه تغییر موتور، نه تغییر فرانت.
|
||||
|
||||
### رفتار با کلید ناشناخته
|
||||
|
||||
هنگام **جستجو** به پیشفرض برمیگردد (تنظیماتِ قدیمی نباید نوبتدهی را بخواباند)، ولی
|
||||
هنگام **ذخیرهٔ تنظیمات** `422` میگیرد — وگرنه کاربر فکر میکند استراتژیاش اعمال
|
||||
میشود در حالی که نمیشود.
|
||||
|
||||
Reference in New Issue
Block a user