feat: implement cancellation policy, no-show tracking, and waitlist management
- 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.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# تسک ۱۱ — پکیج و دفتر اعتبار جلسات
|
||||
|
||||
**فاز:** ۳ (کسبوکار) · **وابستگی:** ۰۸ · **زمان:** ۱۰-۱۲ ساعت
|
||||
|
||||
---
|
||||
|
||||
## هدف
|
||||
|
||||
مستند بند ۱۲: «پکیج شش جلسه لیزر» حالت رایج کلینیک زیبایی است. بیمار یکجا پول میدهد و
|
||||
بعداً جلساتش را رزرو میکند.
|
||||
|
||||
نکتهٔ فنی مستند: **اعتبار را به صورت دفتر حساب نگه میداریم، نه یک عدد شمارنده.**
|
||||
|
||||
## وضعیت فعلی
|
||||
|
||||
هیچ مفهومی از پکیج وجود ندارد. ولی الگوی «دفتر حساب» از قبل در پروژه هست و **درست
|
||||
پیاده شده**: `WalletTransaction` + `getWalletBalance(user)` — موجودی از جمع تراکنشها
|
||||
محاسبه میشود، نه از یک ستون شمارنده. همان الگو اینجا تکرار میشود.
|
||||
|
||||
⚠️ نکتهٔ tenancy: `wallet_transactions` عمداً `ENTITIES` است (پول مال شخص است) ولی هر
|
||||
ردیف `recorded_entity_*` دارد. دفتر اعتبار جلسه **متفاوت** است: اعتبار جلسهٔ لیزر در
|
||||
کلینیک الف در کلینیک ب معنا ندارد. پس جفت tenant واقعی میگیرد، نه انتساب.
|
||||
|
||||
## دامنه
|
||||
|
||||
**هست:**
|
||||
- `Package` — تعریف پکیج (سرویس، تعداد جلسه، قیمت، اعتبار زمانی)
|
||||
- `PatientPackage` — پکیج خریداریشدهٔ یک بیمار
|
||||
- `SessionCreditLedger` — دفتر اعتبار: هر تراکنش یک ردیف
|
||||
- مصرف اعتبار در `confirm` نوبت، بازگشت در لغو
|
||||
- اتصال به `PricingEngine` مرحلهٔ ۴ (قلاب تسک ۰۸)
|
||||
|
||||
**نیست:** پروتکل دوره و فاصلهٔ جلسات (تسک ۱۲)، سیاست لغو (تسک ۱۳).
|
||||
|
||||
## Endpoint ها
|
||||
|
||||
| متد | مسیر | توضیح |
|
||||
|---|---|---|
|
||||
| GET/POST | `/api/v1/packages` | تعریف پکیج |
|
||||
| GET/PATCH/DELETE | `/api/v1/package/{uuid}` | |
|
||||
| POST | `/api/v1/patient/{uuid}/package` | فروش پکیج به بیمار |
|
||||
| GET | `/api/v1/patient/{uuid}/packages` | پکیجهای بیمار + مانده |
|
||||
| GET | `/api/v1/patient-package/{uuid}/ledger` | دفتر تراکنشهای اعتبار |
|
||||
| POST | `/api/v1/patient-package/{uuid}/adjust` | اصلاح دستی با دلیل (فقط مدیر) |
|
||||
| POST | `/api/v1/patient-package/{uuid}/expire` | ابطال دستی |
|
||||
|
||||
## معیار پذیرش
|
||||
|
||||
- ✅ موفق: پکیج «۶ جلسه لیزر فولبادی» با قیمت تعریف میشود، به بیمار فروخته میشود →
|
||||
`GET /patient/{uuid}/packages` مانده `6` میدهد و دفتر یک ردیف `purchase +6` دارد.
|
||||
- ✅ موفق: ثبت نوبت لیزر برای همان بیمار → `PricingEngine` مرحلهٔ ۴ یک واحد کسر میکند،
|
||||
مبلغ نهایی صفر میشود، دفتر ردیف `consume -1` میگیرد، مانده `5`.
|
||||
- ✅ موفق: لغو همان نوبت → ردیف `refund +1`، مانده `6`. **ردیف `consume` حذف نمیشود.**
|
||||
- ✅ موفق (**دفتر، نه شمارنده**): مانده همیشه `SUM(delta)` است. یک تست باید ثابت کند
|
||||
هیچ ستون `remaining` یا `used_count` در schema وجود ندارد.
|
||||
- ✅ موفق: `POST /adjust` با دلیل → ردیف `adjustment` با `reason` و `created_by`.
|
||||
- ❌ خطا: ثبت نوبت با پکیجی که ماندهاش صفر است → پکیج اعمال نمیشود، مبلغ کامل
|
||||
محاسبه میشود (نه خطا — بیمار میتواند نقدی بپردازد).
|
||||
- ❌ خطا: پکیج محیط الف روی نوبت محیط ب → `404`.
|
||||
- ❌ خطا: `adjust` با نقش منشی → `403`.
|
||||
- ⚠️ مرزی: پکیج منقضیشده (`valid_to` گذشته) → مانده در نمایش صفر میشود ولی دفتر
|
||||
دستنخورده میماند؛ ردیف `expiry` با delta منفی برابر مانده ثبت میشود.
|
||||
- ⚠️ مرزی: دو نوبت همزمان که هر دو آخرین اعتبار را میخواهند → یکی میگیرد، دیگری
|
||||
مبلغ کامل. **بدون منفی شدن مانده.**
|
||||
- ⚠️ مرزی: بیمار دو پکیج معتبر برای یک سرویس دارد → قدیمیترِ منقضینشده اول مصرف شود (FIFO).
|
||||
- ⚠️ مرزی: پکیجی که هیچ سرویسی به آن وصل نیست → `422` هنگام ساخت.
|
||||
|
||||
## خروجی
|
||||
|
||||
- `src/Package/`
|
||||
- `assets/admin/pages/PackagesPage.tsx` + کارت پکیج در `PatientDetailPage.tsx`
|
||||
- `docs/api/package.md`
|
||||
Reference in New Issue
Block a user