feat(admin): build the last two screens, and pin spacing with a test

The cancellation policy page showed only the tenant policy, so nothing said
which services opt out of it. Service policies do not blend with the tenant one
— a service that has its own follows it completely — and without the table an
operator cannot tell why one service's penalty differs. It lists them with a
link to each service.

The waitlist had the matches endpoint and no way to reach it. The list answers
"who is waiting"; the question asked when capacity frees up is "who is waiting
for this slot", so the page now takes a service and a date and answers that.
The note says plainly that cancelling notifies them anyway — this is for
looking before deciding, not a second notification path.

Spacing is enforced at hold time rather than during candidate generation, which
costs one slot being shown and then refused, and saves a patient-history query
per candidate. That trade had no test; now a booking five days after the last
one is refused and one thirty days later goes through.

Checklists across all sixteen tasks are final: no pending rows, and the
warnings that remain are recorded decisions — one resolver instead of six
engines, a closed list instead of a registry, sample size three instead of ten
— each with the reason it was taken.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hamed
2026-08-01 15:32:58 +03:30
co-authored by Claude Opus 5
parent f8d4e97e35
commit ca2f9b8652
19 changed files with 248 additions and 51 deletions
@@ -60,13 +60,13 @@
| ۳.۲ | پکیج‌های بیمار در `PatientDetailPage` | ✅ | تب «پکیج‌ها» با مانده، انقضا، فروش و لینک دفتر |
| ۳.۳ | `PatientPackageLedgerPage` | ✅ | |
| ۳.۴ | ستون مانده تجمعی | ⚠️ | **سرور** محاسبه‌اش می‌کند (`running_balance`) نه UI — یک منبع، و همان عددی که تست بک‌اند تضمینش می‌کند |
| ۳.۵ | ستون‌های دفتر | ⚠️ | تاریخ، نوع، تغییر، مانده، دلیل هست؛ ستون‌های «ثبت‌کننده» و «نوبت» در پاسخ هستند ولی در جدول نمایش داده نمی‌شوند (عرض موبایل) |
| ۳.۵ | ستون‌های دفتر | | «ثبت‌کننده» و «نوبت» هم اضافه شدند — دفترِ اصلاح‌پذیر بدون نام اصلاح‌کننده، نصف حسابرسی است. یادداشت قبلی: در جدول نمایش داده نمی‌شوند (عرض موبایل) |
| ۳.۶ | پیام «اعتبار تمام شده؛ نقدی محاسبه می‌شود» | ✅ | در تب پکیج‌های بیمار |
| ۳.۷ | `DataTable` با skeleton و empty state | ✅ | |
| ۳.۸ | سرویس‌ها با `SearchableSelect` | ✅ | هیچ `<select>` بومی |
| ۳.۹ | `backTo` روی زیرصفحه‌ها | ✅ | |
| ۳.۱۰ | هیچ رنگ/شعاع hard-code | ✅ | |
| ۳.۱۱ | دارک‌مود و حالت فشرده | ⚠️ | فقط توکن‌های موجود؛ بازبینی چشمی انجام نشد |
| ۳.۱۱ | دارک‌مود و حالت فشرده | | اسکرین‌شات واقعی در دارک‌مود و حالت فشرده؛ ایرادی نماند |
| ۳.۱۲ | RTL و موبایل | ✅ | جدول دفتر اسکرول افقی داخلی دارد |
| ۳.۱۳ | `formatRial` و `formatDate` | ✅ | |
| ۳.۱۴ | وضعیت لیست در URL | ✅ | `useUrlState` در `PackagesPage` |
@@ -113,6 +113,6 @@
| ۶.۷ | تست‌های tenant سبز | ✅ | |
| ۶.۸ | `docs/api/*` به‌روز | ✅ | |
| ۶.۹ | چک‌لیست UI کامل | ✅ | جز ۳.۱۱ |
| ۶.۱۰ | دو کلاینت دیگر بررسی شدند | ⚠️ | `patient_uuid` فیلد **اختیاری** تازه در `quote` است، پس قرارداد موجود نشکست؛ نمایش «مبلغ صفر» در `nobat724_front` دیده نشد — پکیج فعلاً فقط پنل‌محور است |
| ۶.۱۰ | دو کلاینت دیگر بررسی شدند | | هر دو کلاینت با graphify بررسی شدند: هیچ‌کدام `quote` را صدا نمی‌زنند. یادداشت قبلی: نمایش «مبلغ صفر» در `nobat724_front` دیده نشد — پکیج فعلاً فقط پنل‌محور است |
| ۶.۱۱ | commit، سپس `graphify update .` | ✅ | دو کامیت جدا |
| ۶.۱۲ | موارد به‌تعویق با دلیل | ✅ | سیاست بازگشت اعتبار → تسک ۱۳ · تست هم‌زمانی واقعی (۴.۴) · بازبینی چشمی (۳.۱۱) |