Files
clinicpro/tests/Billing/ClaimAutoCreationTest.php
T
hamed e6267080b2 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.
2026-07-29 19:57:02 +03:30

126 lines
4.3 KiB
PHP

<?php
namespace App\Tests\Billing;
use App\Auth\Entity\User;
use App\Billing\Entity\Invoice;
use App\Billing\Entity\InvoiceItem;
use App\Billing\Repository\ClaimRepository;
use App\Billing\Service\InvoiceService;
use App\Billing\ValueObject\ShareBreakdown;
use App\Doctor\Entity\Doctor;
use App\Patient\Entity\PatientRecord;
use App\Tests\ApiTestCase;
/**
* مطالبهٔ بیمه اثر جانبیِ نهایی‌شدن صورتحساب است، نه کارِ یک endpoint خاص.
* پیش از این فقط `POST /api/v1/patient/{uuid}/session` مطالبه می‌ساخت، و هر
* صورتحسابی که از مسیر دیگری نهایی می‌شد بی‌صدا بدون مطالبه می‌ماند.
*/
class ClaimAutoCreationTest extends ApiTestCase
{
private Doctor $doctor;
private PatientRecord $record;
protected function setUp(): void
{
parent::setUp();
$owner = $this->createUser(['ROLE_DOCTOR']);
$this->doctor = new Doctor($owner, 'دکتر مطالبه');
$this->em->persist($this->doctor);
$this->em->flush();
$patient = $this->createUser(['ROLE_USER']);
$this->record = new PatientRecord('doctor', $this->doctor->getId(), $patient, 'doctor', $this->doctor->getId());
$this->em->persist($this->record);
$this->em->flush();
}
/** صورتحساب draft با سهم بیمهٔ پایه/تکمیلی روی تنها آیتمش. */
private function draftInvoice(?int $baseId, ?int $suppId, int $baseShare, int $suppShare): Invoice
{
$total = 10_000_000;
$invoice = new Invoice('doctor', $this->doctor->getId());
$invoice->setPatientRecordId((int) $this->record->getId())
->setBaseInsuranceId($baseId)
->setSupplementaryInsuranceId($suppId);
$item = new InvoiceItem(
$invoice,
'ویزیت',
$total,
1,
new ShareBreakdown($total, $baseShare, $suppShare, $total - $baseShare - $suppShare),
);
$invoice->addItem($item);
$invoice->recalculateTotals();
$this->em->persist($invoice);
$this->em->persist($item);
$this->em->flush();
return $invoice;
}
private function claimRepo(): ClaimRepository
{
return static::getContainer()->get(ClaimRepository::class);
}
private function invoiceService(): InvoiceService
{
return static::getContainer()->get(InvoiceService::class);
}
public function testFinalizingAnInsuredInvoiceCreatesItsClaims(): void
{
$invoice = $this->draftInvoice(1, 2, 6_000_000, 2_000_000);
$this->invoiceService()->finalize($invoice);
$kinds = $this->claimRepo()->kindsForInvoice((int) $invoice->getId());
sort($kinds);
self::assertSame(['base', 'supplementary'], $kinds);
}
public function testASupplementaryOnlyInvoiceStillGetsItsClaim(): void
{
// همان حالتی که در پنل دیده شد: بیمار بیمهٔ پایه ندارد، فقط تکمیلی.
$invoice = $this->draftInvoice(null, 2, 0, 4_760_000);
$this->invoiceService()->finalize($invoice);
self::assertSame(['supplementary'], $this->claimRepo()->kindsForInvoice((int) $invoice->getId()));
}
public function testFinalizingTwiceDoesNotDuplicateClaims(): void
{
$invoice = $this->draftInvoice(1, null, 3_000_000, 0);
$this->invoiceService()->finalize($invoice);
$this->invoiceService()->finalize($invoice);
self::assertCount(1, $this->claimRepo()->kindsForInvoice((int) $invoice->getId()));
}
public function testAnInvoiceWithoutAnyInsuranceShareGetsNoClaim(): void
{
$invoice = $this->draftInvoice(null, null, 0, 0);
$this->invoiceService()->finalize($invoice);
self::assertSame([], $this->claimRepo()->kindsForInvoice((int) $invoice->getId()));
}
/** بیمه‌ای که فقط روی صورتحساب ثبت شده ولی سهمی نبرده، مطالبه نمی‌سازد. */
public function testAZeroShareInsuranceIsNotClaimed(): void
{
$invoice = $this->draftInvoice(1, 2, 6_000_000, 0);
$this->invoiceService()->finalize($invoice);
self::assertSame(['base'], $this->claimRepo()->kindsForInvoice((int) $invoice->getId()));
}
}