- 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.
6.3 KiB
6.3 KiB
تسک ۰۹ — موتور قوانین ششدستهای
فاز: ۲ (قوانین) · وابستگی: ۰۵، ۰۶، ۰۸ · زمان: ۲۰-۲۴ ساعت
هدف
مستند بند ۸: شش دستهٔ قانون، هر کدام با نقطهٔ اجرای مشخص، شرط از فهرست بسته، اولویتدار، نسخهبندیشده، و بدون کد دلخواه.
| دسته | کِی اجرا میشود | نقطهٔ اتصال در کد |
|---|---|---|
انتخاب (selection) |
موقع انتخاب آیتم | ServiceSelectionValidator (تسک ۰۴) |
صلاحیت بیمار (eligibility) |
قبل از جستجوی وقت | AvailabilityEngine::search ابتدا · BookingService::confirm مرحلهٔ ۳ |
منبع (resource) |
موقع ساخت برنامه | AppointmentPlanBuilder مرحلهٔ ۷ (تسک ۰۵) |
زمان (timing) |
موقع ساخت برنامه | همان |
فاصلهٔ زمانی (spacing) |
موقع جستجوی وقت | AvailabilityEngine مرحلهٔ ۶ |
قیمت (pricing) |
بعد از نهایی شدن برنامه | PricingEngine مرحلهٔ ۳ (تسک ۰۸) |
همهٔ این قلابها در تسکهای ۰۴ تا ۰۸ از قبل بهصورت no-op گذاشته شدهاند. این تسک پُرشان میکند.
وضعیت فعلی
DiscountRule + DiscountEngine تنها موتور قانون موجود است و الگوی درستی دارد:
// src/Discount/Entity/DiscountRule.php
public const TYPES = [TYPE_PATIENT_TAG, TYPE_INVOICE_AMOUNT, TYPE_SPECIFIC_PATIENT,
TYPE_OCCASION, TYPE_SERVICE, TYPE_VISIT_COUNT]; // enum بسته ✅
private int $priority; // ✅
private bool $combinable; // ✅
private ?int $validFrom; // ✅
private ?int $validTo; // ✅
فقط دستهٔ «قیمت» را پوشش میدهد، نسخهبندی ندارد، و محیط آزمایش ندارد.
دامنه
هست:
Policy— قانون با دسته، شرط، نتیجه، اولویت، بازهٔ اعتبار، نسخهPolicyVersionLog— تاریخچهٔ نسخهها (قانون ویرایش نمیشود، نسخه میگیرد)ConditionEvaluator— ارزیابی شرط از فهرست بسته- شش موتور دسته، هر کدام یک کلاس
- حل تناقض: اولویت → اختصاصیبودن → قدمت
- ترکیب اثرها طبق جدول مستند بند ۸
- ثبت قانونهای اعمالشده روی نوبت (
applied_policy_idsتسک ۰۸)
نیست: فرم ساخت قانون و محیط آزمایش (تسک ۱۰ — همان تسک UI است).
DiscountRule موجود مهاجرت نمیکند؛ کنار Policy دستهٔ pricing زندگی میکند
(دلیل در implementation_notes).
Endpoint ها
| متد | مسیر | توضیح |
|---|---|---|
| GET | /api/v1/policies |
لیست با فیلتر دسته/وضعیت |
| POST | /api/v1/policy |
ساخت (نسخهٔ ۱) |
| GET | /api/v1/policy/{uuid} |
جزئیات + تاریخچهٔ نسخه |
| POST | /api/v1/policy/{uuid}/version |
نسخهٔ جدید با تاریخ شروع |
| POST | /api/v1/policy/{uuid}/activate | /deactivate |
|
| GET | /api/v1/policy-schema |
فهرست بستهٔ فیلدها، عملگرها و اثرها per دسته |
GET /policy-schema برای تسک ۱۰ حیاتی است: فرم ساخت قانون از همین schema ساخته میشود،
نه از کد hard-coded در فرانت.
معیار پذیرش
- ✅ موفق: قانون «خدمات دسته جراحی به جراح نیاز دارند» (دسته
resource) →POST /appointment-plan/previewبرای سرویسی در آن دسته، یک نیازمندی اضافه دارد. - ✅ موفق: قانون «حداقل ۷ روز از جلسهٔ قبلی» (دسته
spacing) → جستجوی وقت برای بیماری که ۳ روز پیش جلسه داشته، روزهای زودتر از روز هفتم را برنمیگرداند. - ✅ موفق: قانون «بیمار زیر ۱۸ سال بدون رضایت والدین نمیشود» (دسته
eligibility) →confirmبا422و پیام قابل فهم رد میشود. - ✅ موفق: قانون «بیمار VIP ۱۰٪ تخفیف» (دسته
pricing) → درprice_snapshot_linesیک ردیفdiscountبا نام قانون ظاهر میشود و شناسه+نسخه درapplied_policy_idsثبت میشود. - ✅ موفق (قانون پنجم مستند): بعد از ثبت نوبت، قانون نسخهٔ ۲ میگیرد →
نوبت قبلی همان نسخهٔ ۱ را در
applied_policy_idsدارد و فاکتورش تغییر نمیکند. - ✅ موفق: دو قانون «حداقل مدت» با مقادیر ۴۵ و ۶۰ دقیقه → بیشترین برنده است (۶۰).
- ✅ موفق: دو قانون «اضافه کردن زمان» ۱۰ و ۵ دقیقه → جمع میشوند (۱۵).
- ✅ موفق: یک قانون «ممنوعیت» → کل عملیات رد میشود، حتی اگر ده قانون مجازکننده باشند.
- ❌ خطا: شرط با فیلد خارج از فهرست بسته →
422با نام فیلد مجاز. - ❌ خطا: نتیجه با نوع اثر ناسازگار با دسته →
422. - ⚠️ مرزی: دو قانون با اولویت مساوی → اختصاصیتر (شعبه بر محیط، سرویس بر دسته) برنده.
- ⚠️ مرزی: باز هم مساوی → قانون قدیمیتر برنده (مستند بند ۸).
- ⚠️ مرزی: قانون با
valid_fromآینده → در محاسبهٔ امروز اعمال نمیشود. - ⚠️ مرزی: هیچ قانونی وجود ندارد → همهچیز مثل قبل کار میکند (تست سازگاری).
- ⚠️ مرزی: قانون
spacingباید قابل تبدیل به کوئری باشد؛ ارزیابی per-slot در PHP برای ۹۰ روز غیرقابل قبول است (مستند بند ۸ صریح).
خروجی
src/Policy/docs/api/policy.md+ سند معماریdocs/architecture/policy-engine.md- پر کردن همهٔ قلابهای no-op تسکهای ۰۴ تا ۰۸