Files
clinicpro/docs/new_feture/taskes/task-11-package-credit-ledger/task.md
T
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

4.7 KiB

تسک ۱۱ — پکیج و دفتر اعتبار جلسات

فاز: ۳ (کسب‌وکار) · وابستگی: ۰۸ · زمان: ۱۰-۱۲ ساعت


هدف

مستند بند ۱۲: «پکیج شش جلسه لیزر» حالت رایج کلینیک زیبایی است. بیمار یکجا پول می‌دهد و بعداً جلساتش را رزرو می‌کند.

نکتهٔ فنی مستند: اعتبار را به صورت دفتر حساب نگه می‌داریم، نه یک عدد شمارنده.

وضعیت فعلی

هیچ مفهومی از پکیج وجود ندارد. ولی الگوی «دفتر حساب» از قبل در پروژه هست و درست پیاده شده: 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