feat: insurance & medical billing system (6 phases)
Multi-tenant insurance contracts, service coverage, versioned tariffs, invoice calculation, and insurance claims with debt reporting. - TenantInsurance: per-tenant insurance contracts (coverage/franchise/ceiling, versioning, soft-deactivate) + active guard - ServiceItem.insuranceCovered + TenantServiceCoverage per-service overrides - Tariff: versioned yearly tariffs with fallback to ServiceItem price - Billing domain: Money/ShareBreakdown VOs, BillingCalculator (unit-tested), Invoice/InvoiceItem aggregate, InvoiceService.createFromSession - Claim/ClaimItem with state machine (pending->submitted->approved/rejected->paid), ClaimService, insurance-debt report - ClaimSubmitterInterface + ManualClaimSubmitter (future insurance API ready) - Admin UI: insurance-pricing page, claims page, service tariff modal, service insurance toggle; routes + sidebar entries - Architecture doc + billing/insurance/clinic-services API docs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Billing;
|
||||
|
||||
use App\Billing\Service\BillingCalculator;
|
||||
use App\Billing\ValueObject\Money;
|
||||
use App\Insurance\ValueObject\CoverageRule;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BillingCalculatorTest extends TestCase
|
||||
{
|
||||
private BillingCalculator $calc;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->calc = new BillingCalculator();
|
||||
}
|
||||
|
||||
public function testNoInsuranceAllPatient(): void
|
||||
{
|
||||
$b = $this->calc->calculateItem(new Money(600_000), null, null);
|
||||
$this->assertSame(600_000, $b->patientRials);
|
||||
$this->assertSame(0, $b->baseInsuranceRials);
|
||||
$this->assertSame(0, $b->supplementaryRials);
|
||||
}
|
||||
|
||||
public function testBaseAndSupplementary(): void
|
||||
{
|
||||
// کل 600,000؛ پایه 70% → 420,000؛ مکمل روی 180,000 با ~66.667% → 120,000؛ بیمار 60,000
|
||||
$base = new CoverageRule(coveragePercent: 70, franchiseRials: 0, ceilingRials: null);
|
||||
$supp = new CoverageRule(coveragePercent: 66.6667, franchiseRials: 0, ceilingRials: null);
|
||||
|
||||
$b = $this->calc->calculateItem(new Money(600_000), $base, $supp);
|
||||
|
||||
$this->assertSame(420_000, $b->baseInsuranceRials);
|
||||
$this->assertSame(120_000, $b->supplementaryRials);
|
||||
$this->assertSame(60_000, $b->patientRials);
|
||||
$this->assertSame(
|
||||
$b->totalRials,
|
||||
$b->baseInsuranceRials + $b->supplementaryRials + $b->patientRials
|
||||
);
|
||||
}
|
||||
|
||||
public function testBaseOnly(): void
|
||||
{
|
||||
$base = new CoverageRule(coveragePercent: 70, franchiseRials: 0, ceilingRials: null);
|
||||
$b = $this->calc->calculateItem(new Money(600_000), $base, null);
|
||||
$this->assertSame(420_000, $b->baseInsuranceRials);
|
||||
$this->assertSame(0, $b->supplementaryRials);
|
||||
$this->assertSame(180_000, $b->patientRials);
|
||||
}
|
||||
|
||||
public function testBaseCeilingCapsShare(): void
|
||||
{
|
||||
// پایه 70% = 420,000 ولی سقف 300,000 → بیمار باقی را میدهد
|
||||
$base = new CoverageRule(coveragePercent: 70, franchiseRials: 0, ceilingRials: 300_000);
|
||||
$b = $this->calc->calculateItem(new Money(600_000), $base, null);
|
||||
$this->assertSame(300_000, $b->baseInsuranceRials);
|
||||
$this->assertSame(300_000, $b->patientRials);
|
||||
}
|
||||
|
||||
public function testFranchiseAddedToPatient(): void
|
||||
{
|
||||
// پایه 100% ولی فرانشیز 50,000 سهم بیمار
|
||||
$base = new CoverageRule(coveragePercent: 100, franchiseRials: 50_000, ceilingRials: null);
|
||||
$b = $this->calc->calculateItem(new Money(600_000), $base, null);
|
||||
$this->assertSame(50_000, $b->patientRials);
|
||||
$this->assertSame(600_000, $b->baseInsuranceRials);
|
||||
}
|
||||
|
||||
public function testNotCoveredRule(): void
|
||||
{
|
||||
$b = $this->calc->calculateItem(new Money(600_000), CoverageRule::notCovered(), CoverageRule::notCovered());
|
||||
$this->assertSame(600_000, $b->patientRials);
|
||||
$this->assertSame(0, $b->baseInsuranceRials);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user