Files
clinicpro/tests/Billing/BillingCalculatorTest.php
T
hamedandClaude Opus 4.8 89191eee57 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>
2026-06-23 15:05:24 +03:30

78 lines
2.9 KiB
PHP

<?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);
}
}