Files
hamed 021d0eb6b2 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.
2026-07-30 11:43:58 +03:30

5.1 KiB
Raw Permalink Blame History

دیتابیس — تسک ۰۹

policies

ستون نوع توضیح
id INT PK AI
uuid VARCHAR(36) UNIQUE
entity_type / entity_id VARCHAR(10) / INT NOT NULL
branch_id INT NULL NULL = همهٔ شعب — FK ON DELETE CASCADE
name VARCHAR(200) NOT NULL «خدمات جراحی به جراح نیاز دارند»
category VARCHAR(20) NOT NULL یکی از شش دسته
priority SMALLINT NOT NULL DEFAULT 0
specificity SMALLINT NOT NULL DEFAULT 0 محاسبه‌شده هنگام ذخیره
version SMALLINT NOT NULL DEFAULT 1
valid_from INT NULL
valid_to INT NULL
active TINYINT(1) NOT NULL DEFAULT 0 پیش‌فرض غیرفعال
conditions JSON NOT NULL
effects JSON NOT NULL
created_at/updated_at INT NOT NULL
KEY idx_policies_lookup (entity_type, entity_id, category, active, valid_from)
KEY idx_policies_branch (branch_id, category, active)

idx_policies_lookup کوئری داغ است: «قوانین فعال دستهٔ X این محیط که امروز معتبرند». با ۶ دسته و معمولاً < ۵۰ قانون per محیط، این کوئری همیشه ارزان است — و باید بماند. اگر روزی قوانین به هزاران رسیدند، کش per (محیط، دسته) اضافه شود، نه ایندکس پیچیده‌تر.

policy_version_log

CREATE TABLE policy_version_log (
  id INT PRIMARY KEY AUTO_INCREMENT,
  policy_id INT NOT NULL,
  version SMALLINT NOT NULL,
  snapshot JSON NOT NULL,             -- کل قانون در آن نسخه، نه diff
  valid_from INT NULL,
  valid_to INT NULL,
  changed_by INT NULL,                -- FK users ON DELETE SET NULL
  changed_at INT NOT NULL,
  UNIQUE KEY uniq_policy_version (policy_id, version),
  KEY idx_pvl_policy (policy_id, version),
  CONSTRAINT fk_pvl_policy FOREIGN KEY (policy_id) REFERENCES policies(id) ON DELETE CASCADE
);

snapshot کامل است، نه diff: بازسازی نسخهٔ ۳ از یک قانون که الان نسخهٔ ۹ است، باید یک SELECT باشد. حجم ناچیز (JSON چند کیلوبایتی × چند ده نسخه).

هیچ تغییری در discount_rules

جدول و entity موجود دست‌نخورده می‌مانند. PricingPolicyEngine هر دو را می‌خواند:

$effects = array_merge(
    $this->discountEngine->evaluate($ctx),        // DiscountRule موجود
    $this->pricingPolicies->evaluate($ctx),       // Policy دستهٔ pricing
);
$combined = $this->combiner->combine($effects);   // ترکیب واحد

دلیل عدم مهاجرت در implementation_notes بند ۱.

applied_policy_ids — تسک ۰۸

ستون از قبل در price_snapshots هست. قرارداد مقدارش اینجا تعیین می‌شود:

[
  { "source": "policy",        "id": 12, "version": 3, "name": "تخفیف VIP" },
  { "source": "discount_rule", "id": 5,  "version": 1, "name": "تخفیف تولد" }
]

name کپی متنی — همان دلیل price_snapshot_lines.label: قانون ممکن است حذف شود.

ذخیرهٔ قوانین اعمال‌شده روی خودِ نوبت

قوانین غیرقیمتی هم باید ثبت شوند (مستند: «هر نوبت فهرست قانون‌هایی که رویش اعمال شده را ذخیره می‌کند»)، ولی price_snapshots جای قوانین منبع و زمان نیست.

ALTER TABLE appointments
  ADD COLUMN applied_policies JSON NULL;

همان قرارداد بالا. یک ستون JSON کافی است — هیچ کوئری‌ای روی آن زده نمی‌شود، فقط برای آدیت و پاسخ به «چرا این نوبت ۷۵ دقیقه شد؟» خوانده می‌شود.

Migration

ddev exec php bin/console doctrine:migrations:diff --no-interaction
ddev exec php bin/console doctrine:migrations:migrate --no-interaction

بدون backfill. هیچ قانونی از قبل وجود ندارد و DiscountRule ها سر جایشان می‌مانند.

نمونهٔ داده برای تست

ddev exec php bin/console app:policy:seed-examples --tenant=clinic:12 --force

پنج قانون نمونه (یکی از هر دسته جز selection)، همه با active=false تا کلینیک اول آزمایششان کند:

resource    | خدمات جراحی به جراح نیاز دارند
timing      | حداقل مدت درمان پیچیده یک ساعت است
spacing     | حداقل ۲۱ روز از جلسهٔ قبلی لیزر
eligibility | بیمار زیر ۱۸ سال بدون رضایت والدین نمی‌شود
pricing     | بیمار VIP ده درصد تخفیف

این نمونه‌ها هم مستندات زنده‌اند و هم داده تست تسک ۱۰.

طبقه‌بندی tenant

جدول وضعیت
policies جفت tenant
policy_version_log AGGREGATE_CHILDREN → ریشه Policy