feat: Enhance insurance billing system to support supplementary insurance
- Updated CoverageRule and related entities to include franchise_percent instead of franchise_rials. - Modified Appointment entity to carry supplementary insurance ID alongside base insurance. - Implemented SessionBillingService to ensure finalized invoices for insured patient sessions. - Created InvoiceFinalized event to trigger claims creation upon invoice finalization. - Added BackfillMissingClaimsCommand to generate claims for finalized invoices without existing claims. - Developed tests to validate the new functionality for supplementary insurance handling in appointments and claims.
This commit is contained in:
@@ -27,19 +27,25 @@ export interface TenantContract {
|
||||
/** ویزیت آیتم سرویس نیست؛ نوعِ پیشفرضش سرپایی است. */
|
||||
export const DEFAULT_SERVICE_CATEGORY = 'outpatient';
|
||||
|
||||
/** سهم بیمهٔ پایه از کل مبلغ یک ردیف (با سقف تعهد). */
|
||||
export function baseShareOf(total: number, base: CoverageRule | null): number {
|
||||
if (!base || !base.covered) return 0;
|
||||
|
||||
const share = Math.round(total * (base.percent / 100));
|
||||
|
||||
return base.ceiling !== null ? Math.min(share, base.ceiling) : share;
|
||||
}
|
||||
|
||||
/**
|
||||
* سهم بیمار یک ردیف: کل − سهم پایه (با سقف) − سهم تکمیلی.
|
||||
* فرانشیزِ تکمیلی درصدی از همان مبلغِ تحت پوشش است و از سهم تکمیلی کسر میشود،
|
||||
* نه اینکه روی سهم بیمار سوار شود؛ فرانشیزِ بیمهٔ پایه در محاسبه دخالت نمیکند.
|
||||
* سهم بیمار یک ردیف: کل − سهم پایه (با سقف) − سهم تکمیلی. محاسبه زنجیرهای است؛
|
||||
* تکمیلی روی باقیماندهٔ بعد از پایه کار میکند، نه روی کل مبلغ. فرانشیزِ تکمیلی
|
||||
* درصدی از همان باقیمانده است و از سهم تکمیلی کسر میشود، نه اینکه روی سهم بیمار
|
||||
* سوار شود؛ فرانشیزِ بیمهٔ پایه در محاسبه دخالت نمیکند.
|
||||
*/
|
||||
export function patientShareOf(total: number, base: CoverageRule | null, supp: CoverageRule | null): number {
|
||||
let baseShare = 0;
|
||||
let remaining = total;
|
||||
if (base && base.covered) {
|
||||
baseShare = Math.round(total * (base.percent / 100));
|
||||
if (base.ceiling !== null) baseShare = Math.min(baseShare, base.ceiling);
|
||||
remaining = total - baseShare;
|
||||
}
|
||||
const baseShare = baseShareOf(total, base);
|
||||
const remaining = total - baseShare;
|
||||
|
||||
let suppShare = 0;
|
||||
if (supp && supp.covered) {
|
||||
suppShare = Math.max(
|
||||
@@ -80,21 +86,35 @@ export interface BillableLine {
|
||||
|
||||
export interface ShareBreakdown {
|
||||
total: number;
|
||||
/** مجموع سهم هر دو بیمه — برای نمایشِ یکخطی. */
|
||||
insurance: number;
|
||||
base: number;
|
||||
supplementary: number;
|
||||
patient: number;
|
||||
}
|
||||
|
||||
/** تفکیک سهم بیمه/بیمار برای مجموعهای از ردیفها تحت یک قرارداد پایه. */
|
||||
export function breakdownOf(lines: BillableLine[], base: TenantContract | null): ShareBreakdown {
|
||||
/**
|
||||
* تفکیک سهم برای مجموعهای از ردیفها تحت قرارداد پایه و (اختیاری) تکمیلی.
|
||||
* محاسبه زنجیرهای است: پایه روی کل، تکمیلی روی باقیماندهٔ بعد از پایه.
|
||||
*/
|
||||
export function breakdownOf(
|
||||
lines: BillableLine[],
|
||||
base: TenantContract | null,
|
||||
supplementary: TenantContract | null = null,
|
||||
): ShareBreakdown {
|
||||
return lines.reduce<ShareBreakdown>((acc, line) => {
|
||||
const patient = line.insured
|
||||
? patientShareOf(line.total, ruleOf(base, line.category), null)
|
||||
: line.total;
|
||||
const baseRule = line.insured ? ruleOf(base, line.category) : null;
|
||||
const suppRule = line.insured ? ruleOf(supplementary, line.category) : null;
|
||||
|
||||
const patient = line.insured ? patientShareOf(line.total, baseRule, suppRule) : line.total;
|
||||
const baseShare = baseShareOf(line.total, baseRule);
|
||||
|
||||
return {
|
||||
total: acc.total + line.total,
|
||||
insurance: acc.insurance + (line.total - patient),
|
||||
patient: acc.patient + patient,
|
||||
total: acc.total + line.total,
|
||||
base: acc.base + baseShare,
|
||||
supplementary: acc.supplementary + (line.total - patient - baseShare),
|
||||
insurance: acc.insurance + (line.total - patient),
|
||||
patient: acc.patient + patient,
|
||||
};
|
||||
}, { total: 0, insurance: 0, patient: 0 });
|
||||
}, { total: 0, base: 0, supplementary: 0, insurance: 0, patient: 0 });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user