Files
clinicpro/.claude/prompt/insurance-pricing-and-selects-cleanup.md

7.4 KiB
Raw Permalink Blame History

یکپارچه‌سازی قراردادهای بیمه، select یکدست، و تعداد خدمت در مراجعه

پروژه

clinicpro (admin frontend + کمی backend برای quantity)

زمینه

چهار مورد به‌هم‌مرتبط در پنل ادمین:

  1. صفحه‌ی /admin/insurance-pricing دو بخش دارد که هم‌پوشانی دارند → باید یکی شود.
  2. select listها در کل پنل یک‌شکل نیستند (بعضی <select className="input"> بومی، بعضی SearchableSelect).
  3. در «ثبت مراجعه جدید» هر خدمت فقط یک‌بار اضافه می‌شود؛ تعداد (مثلاً سرُم ۲ عدد) ممکن نیست.
  4. select بیمه‌ی پایه/تکمیلی در فرم مراجعه باید فقط بیمه‌هایی را نشان دهد که tenant در insurance-pricing قیمت‌گذاری/قرارداد کرده، و درصد تخفیف خودکار اعمال شود.

وضعیت فعلی

صفحه‌ی insurance-pricing (دو بخش هم‌پوشان)

assets/admin/pages/InsurancePricingPage.tsx:

<TenantInsuranceContracts />     {/* قراردادها: بیمه + درصد پوشش + فرانشیز + سقف */}
<InsurancePricingSection />      {/* قیمت‌گذاری: قیمت ویزیت آزاد + سهم هر بیمه‌ی پایه */}
  • TenantInsuranceContracts (assets/admin/components/TenantInsuranceContracts.tsx): per (tenant, insurance) قرارداد با coverage_percent, franchise_rials, annual_ceiling_rials؛ افزودن/ویرایش/حذف. هم basic هم supplementary. API: /api/v1/billing/tenant-insurances (GET/POST/PATCH/DELETE).
  • InsurancePricingSection (assets/admin/components/InsurancePricingSection.tsx): «قیمت ویزیت آزاد» + سهم بیمار به ازای هر بیمه‌ی پایه. API: GET/PUT /api/v1/insurance-pricing (جدول entity_insurance_pricing).

این دو منطق موازی‌اند و کاربر را گیج می‌کنند. قرارداد با coverage_percent کافی است؛ بخش «قیمت‌گذاری» زیرش بی‌معنی است.

select listها

نمونه‌ی بومی پراکنده (NewSessionPage.tsx, MyPatientsPage.tsx, SmsPage.tsx, ClaimsPage.tsx, SettingsPage.tsx, …):

<select className="input" value={...} onChange={...}>
  <option value="">...</option>
  {opts.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
</select>

و در کنارش کامپوننت SearchableSelect (assets/admin/components/ui/SearchableSelect.tsx) برای بخش خدمات استفاده می‌شود. ظاهر این دو فرق دارد.

تعداد خدمت

src/Patient/Entity/SessionService.php — فیلد quantity ندارد:

private ServiceItem $serviceItem;
private ?ClinicStaff $staff = null;
private int $priceRials;   // = serviceItem price، بدون ضرب در تعداد

PatientService::createSession services را تک‌واحدی جمع می‌زند:

$servicesTotal = array_sum(array_column($serviceItems, 'price_rials'));

فرانت (NewSessionPage.tsx) هم هر خدمت را یک‌بار اضافه می‌کند (chip بدون تعداد).

select بیمه در فرم مراجعه

NewSessionPage.tsx گزینه‌های بیمه را از GET /api/v1/insurance-pricing می‌گیرد (pricing.insurances)، ولی آن endpoint همه‌ی بیمه‌های فعال را برمی‌گرداند (نه فقط قراردادهای tenant). درصد هم از patient_share_rials همان endpoint محاسبه می‌شود — که بعد از حذف بخش قیمت‌گذاری دیگر منبع درستی نیست.

وظایف

۱. ادغام صفحه‌ی insurance-pricing

  • InsurancePricingSection و endpoint/جدول entity_insurance_pricing را کنار بگذار (از InsurancePricingPage حذف کن). قرارداد (TenantInsuranceContracts) تنها منبع باشد.
  • TenantInsuranceContracts باید واضح هم basic هم supplementary را پشتیبانی کند (الان هم می‌کند؛ متن/گروه‌بندی را شفاف کن: دو دسته «بیمه پایه» و «بیمه تکمیلی»).
  • اگر «قیمت ویزیت آزاد» جایی لازم است، آن را به‌صورت یک فیلد ساده در همان صفحه/پروفایل نگه‌دار یا حذف کن (تصمیم را در پیاده‌سازی مستند کن). مسیر /admin/insurance-pricing و آیتم سایدبار باقی بماند.
  • InsurancePricingSection.tsx حذف یا خالی شود؛ importها پاک‌سازی.

۲. یک کامپوننت select یکدست

  • یک کامپوننت Select در assets/admin/components/ui/ بساز (یا SearchableSelect را به‌عنوان استاندارد واحد بپذیر) با ظاهر یکسان: همان استایل، RTL، chevron، حالت focus/disabled، placeholder.
  • همه‌ی <select className="input">های پنل را با این کامپوننت جایگزین کن (صفحات بالا). رفتار/داده تغییر نکند، فقط ظاهر یکدست شود.
  • نمونه‌ی مرجع ظاهر: select خدمات (SearchableSelect) در فرم مراجعه.

۳. تعداد (quantity) برای خدمات

Backend:

  • به SessionService فیلد quantity (int, پیش‌فرض 1) اضافه کن + getter/setter + در toArray(). migration.
  • PatientService::createSession: body هر service می‌تواند quantity داشته باشد؛ line_total = price × quantity؛ services_total_rials و final_price_rials با احتساب تعداد محاسبه شوند.
  • docs/api/patient.md (یا فایل session مربوط) به‌روز شود.

Frontend (NewSessionPage.tsx):

  • chip خدمت دارای ورودی/استپر تعداد باشد (۱،۲،…)؛ نمایش price × qty.
  • body ارسالی: services: [{ service_item_uuid, quantity }].
  • خلاصه‌ی قیمت با تعداد محاسبه شود.

۴. select بیمه فقط از قراردادها + درصد خودکار

  • در NewSessionPage.tsx، گزینه‌های «بیمه پایه» و «بیمه تکمیلی» از قراردادهای tenant بیایند (GET /api/v1/billing/tenant-insurances)، نه از insurance-pricing.
  • هر گزینه coverage_percent خودش را دارد؛ با انتخاب بیمه، درصد تخفیف خودکار از coverage_percent قرارداد ست شود (نه از patient_share_rials).
  • فقط بیمه‌های فعال قرارداد نمایش داده شوند؛ تفکیک basic/supplementary بر اساس insurance_kind.

نکات مهم

  • backend فقط برای quantity تغییر می‌کند؛ بقیه frontend است.
  • بعد از تغییر Entity: doctrine:migrations:diff + migrate.
  • پاسخ‌ها/الگوها: BaseController، formatRial/formatNumber، RTL، Vazirmatn، CSS variables موجود.
  • چون insurance-pricing (entity_insurance_pricing) حذف می‌شود، هر مصرف‌کننده‌ی دیگرش را پیدا و پاک‌سازی کن (جستجوی insurance-pricing و EntityInsurancePricing در src/ و assets/). اگر BillingCalculator/InvoiceService به آن وابسته است، به coverage_percent قرارداد سوییچ کن.
  • tsc + yarn dev بدون خطا؛ هر بخش جدا commit.