refactor(resource): drop the branch domain from resources

Resources never needed a branch: devices and rooms belong to the clinic
itself, and the picker always had exactly one option — a mandatory click
that decided nothing.

- `address_uuid` is now optional on resource and pool creation; when it is
  missing the environment's own address is used. Clients still sending it
  keep working.
- The panel no longer asks for or displays a branch anywhere: resource
  form, list column and filter, pool form and column, detail row, and the
  resource-first booking page.
- Availability no longer gates on `doctor_addresses.active`. That gate shut
  down every device of a clinic whose address row happened to be inactive,
  with a message no page in the panel could act on — no endpoint writes
  that column at all.

`address_id` stays on the resource: the timezone and the tenant pair are
derived from it. It is simply no longer the user's decision.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hamed
2026-08-03 14:57:47 +03:30
co-authored by Claude Opus 5
parent 05bb4a4ade
commit 581a553516
19 changed files with 246 additions and 117 deletions
+1 -1
View File
@@ -156,7 +156,7 @@
| `national_holiday` | تعطیل رسمی کشور |
| `tenant_holiday` | این محیط آن روز را تعطیل اعلام کرده |
| `exception` | مرخصی/غیبت/سرویس بخشی یا تمام روز را بریده |
| `resource_inactive` / `address_inactive` | منبع یا محل نوبت‌دهی غیرفعال است |
| `resource_inactive` | خودِ منبع غیرفعال است (آدرس دیگر گیت نیست — منابع دامنهٔ شعبه ندارند) |
**۴۲۲:** نبودِ `from`/`to` · `to < from` · بازهٔ بیش از ۹۲ روز (خروجی واقعی):
+26 -3
View File
@@ -176,7 +176,7 @@
| فیلد | نوع | الزامی | قاعده |
|---|---|---|---|
| `address_uuid` | string | | محل نوبت‌دهی؛ جفت محیطِ منبع **از همین** مشتق می‌شود، نه از بدنه |
| `address_uuid` | string | | **از ۲۰۲۶-۰۸ اختیاری.** نیامدنش یعنی آدرسِ خودِ محیط؛ جفت محیطِ منبع از همین مشتق می‌شود، نه از بدنه |
| `type_uuid` | string | ✅ | |
| `supervisor_doctor_uuid` | string | ✅ | پزشکِ ناظرِ منبع. باید پزشکِ همین محیط باشد وگرنه ۴۰۴ |
| `name` | string | ✅ | حداکثر ۱۵۰ نویسه |
@@ -186,6 +186,29 @@
| `attributes` | object | — | حداکثر ۲۰ کلید · کلید `[a-z_]{1,40}` · مقدار فقط اسکالر |
| `active` | bool | — | پیش‌فرض `true` |
### شعبه از منابع حذف شد (2026-08)
منابع دامنهٔ «شعبه» ندارند: دستگاه و اتاق مالِ خودِ کلینیک‌اند، و آن انتخابگر همیشه یک
گزینه داشت — یک کلیک اجباری که هیچ تصمیمی نبود.
| قبل | حالا |
|---|---|
| `address_uuid` در ساخت منبع و استخر الزامی | اختیاری؛ نیامدنش = آدرسِ خودِ محیط (اولین آدرس) |
| پنل «شعبه» می‌پرسید و ستون/فیلترش را داشت | هیچ‌جای پنل شعبه پرسیده یا نشان داده نمی‌شود |
| `doctor_addresses.active = 0` روزِ منبع را خالی می‌کرد (`address_inactive`) | فعال‌بودنِ آدرس دیگر گیت نیست |
ستون `address_id` سرِ جایش می‌ماند: منطقهٔ زمانی و جفتِ محیطِ منبع از آن می‌آیند. فقط
دیگر تصمیمِ کاربر نیست.
حذف گیتِ `address_inactive` یک باگ واقعی را می‌بندد: یک ردیف آدرسِ قدیمی با `active = 0`
همهٔ دستگاه‌های آن کلینیک را با پیامی خاموش می‌کرد که **هیچ صفحه‌ای در پنل راهی برای
روشن‌کردنش نداشت** — هیچ اندپوینتی هم `active` آدرس را نمی‌نویسد.
محیطی که هیچ آدرسی ندارد، `422` می‌گیرد با پیام «برای این محیط آدرسی ثبت نشده است —
ابتدا آدرس کلینیک را کامل کنید»، نه یک خطای مبهم.
تست: `tests/Resource/ResourceWithoutBranchTest.php`.
### `service_section` روی فهرست سرویس‌های منبع (2026-08)
`GET /api/v1/resource/{uuid}/services` برای هر سرویس `service_section` را هم می‌دهد
@@ -471,7 +494,7 @@
```
`empty_reason` وقتی `windows` خالی است می‌گوید چرا: `no_shift`، `national_holiday`،
`tenant_holiday`، `exception`، `resource_inactive`، `address_inactive`. خالی‌بودن خطا
`tenant_holiday`، `exception`، `resource_inactive`. خالی‌بودن خطا
نیست و کلاینت نباید همه را «تعطیل» بنامد.
### `GET /api/v1/resource/{uuid}/service-slots` (2026-08)
@@ -633,7 +656,7 @@ 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 \