feat(migrations): update franchise to percentage in tenant_insurances and tenant_service_coverage

- Changed franchise_rials to franchise_percent in tenant_insurances and tenant_service_coverage tables.
- Reset old rial values to 0/NULL as they are not convertible to percentage.

feat(command): add SeedInsuranceScenarioCommand for seeding insurance data

- Implemented a command to seed supplementary insurance contracts, patients, and claims for a specified doctor.
- Includes functionality for purging existing scenario data and generating new entries with predefined contracts and patient scenarios.
This commit is contained in:
hamed
2026-07-29 13:28:59 +03:30
parent 11b4dcdd34
commit 4f4bce9fe2
31 changed files with 1497 additions and 137 deletions
@@ -46,8 +46,8 @@ export function contractSummary(c: Contract, categories: ServiceCategoryOption[]
.map((cat) => `${cat.label} ${formatNumber(percents[cat.key])}٪`);
const parts = labelled.length > 0 ? labelled : [`پوشش ${formatNumber(c.coverage_percent)}٪`];
if (c.insurance_kind === 'supplementary' && c.franchise_rials > 0) {
parts.push(`فرانشیز ${formatRial(c.franchise_rials)}`);
if (c.insurance_kind === 'supplementary' && c.franchise_percent > 0) {
parts.push(`فرانشیز ${formatNumber(c.franchise_percent)}٪`);
}
parts.push(c.annual_ceiling_rials != null ? `سقف پوشش ${formatRial(c.annual_ceiling_rials)}` : 'سقف پوشش نامحدود');
@@ -112,6 +112,15 @@ export default function TenantInsuranceContracts() {
const contracts: Contract[] = (contractsQuery.data as any)?.data?.data ?? [];
const allInsurances: InsuranceOption[] = (pricingQuery.data as any)?.data?.insurances ?? [];
// فرم قرارداد فقط نوع خدمت‌هایی را می‌گیرد که همین tenant بیمه‌ای‌شان می‌کند؛
// لیست سراسری service-categories اینجا اشتباه است چون نوع خاموش را هم می‌آورد.
const enabledCategories: ServiceCategoryOption[] = useMemo(
() => ((pricingQuery.data as any)?.data?.service_categories ?? [])
.filter((c: { enabled: boolean }) => c.enabled)
.map((c: { key: string; label: string }) => ({ key: c.key, label: c.label })),
[pricingQuery.data],
);
const activeIds = new Set(contracts.map((c) => c.insurance_id));
// Add-mode options: only the active tab's kind, excluding already-contracted insurances.
const available = allInsurances.filter((i) => i.type === tab).filter((i) => !activeIds.has(i.insurance_id));
@@ -259,7 +268,7 @@ export default function TenantInsuranceContracts() {
open={modalOpen}
editContract={editContract}
options={editContract ? allInsurances : available}
categories={categories}
categories={enabledCategories}
kind={editContract ? kindOf(editContract) : tab}
doctorUuid={doctorUuid}
canUpdate={canUpdate}
@@ -338,7 +347,7 @@ function ContractDetails({ contract: c, categories }: { contract: Contract; cate
/>
))}
{isSupplementary && (
<DetailCell label="فرانشیز" value={c.franchise_rials > 0 ? formatRial(c.franchise_rials) : '—'} />
<DetailCell label="فرانشیز" value={c.franchise_percent > 0 ? `${formatNumber(c.franchise_percent)}٪` : '—'} />
)}
<DetailCell label="سقف تعهد سالانه" value={c.annual_ceiling_rials != null ? formatRial(c.annual_ceiling_rials) : 'نامحدود'} />
<DetailCell label="تاریخ شروع قرارداد" value={formatDate(c.effective_from)} />