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:
@@ -9,6 +9,8 @@ use App\Billing\Entity\Invoice;
|
||||
use App\Billing\Entity\InvoiceItem;
|
||||
use App\Billing\ValueObject\ShareBreakdown;
|
||||
use App\Doctor\Entity\Doctor;
|
||||
use App\Insurance\Entity\Insurance;
|
||||
use App\Insurance\Enum\InsuranceType;
|
||||
use App\Patient\Entity\PatientRecord;
|
||||
use App\Tests\ApiTestCase;
|
||||
|
||||
@@ -40,8 +42,13 @@ class ClaimsByPatientTest extends ApiTestCase
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
/** Invoice of $total split into insurance/patient shares, with its claim(s). */
|
||||
private function invoiceWithClaims(int $total, int $baseShare, int $suppShare, array $statuses = ['pending']): Invoice
|
||||
/**
|
||||
* Invoice of $total split into insurance/patient shares, with its claim(s).
|
||||
*
|
||||
* @param list<int> $insuranceIds one per claim; defaults to synthetic ids when the
|
||||
* test does not care which insurance it is
|
||||
*/
|
||||
private function invoiceWithClaims(int $total, int $baseShare, int $suppShare, array $statuses = ['pending'], array $insuranceIds = []): Invoice
|
||||
{
|
||||
$patient = $total - $baseShare - $suppShare;
|
||||
|
||||
@@ -58,7 +65,7 @@ class ClaimsByPatientTest extends ApiTestCase
|
||||
$kind = $i === 0 ? Claim::KIND_BASE : Claim::KIND_SUPPLEMENTARY;
|
||||
$share = $i === 0 ? $baseShare : $suppShare;
|
||||
|
||||
$claim = new Claim('doctor', $this->doctor->getId(), 1 + $i, $kind);
|
||||
$claim = new Claim('doctor', $this->doctor->getId(), $insuranceIds[$i] ?? (1 + $i), $kind);
|
||||
$claimItem = new ClaimItem($claim, (int) $item->getId(), $share);
|
||||
$claim->addItem($claimItem);
|
||||
if ($status !== Claim::STATUS_PENDING) {
|
||||
@@ -118,6 +125,67 @@ class ClaimsByPatientTest extends ApiTestCase
|
||||
self::assertSame('mixed', $res['data'][0]['overall_status']);
|
||||
}
|
||||
|
||||
public function testEachRowCarriesTheInsurancesItsClaimsBelongTo(): void
|
||||
{
|
||||
$iran = new Insurance('بیمه ایران تست', InsuranceType::Basic);
|
||||
$asia = new Insurance('بیمه آسیا تست', InsuranceType::Supplementary);
|
||||
$this->em->persist($iran);
|
||||
$this->em->persist($asia);
|
||||
$this->em->flush();
|
||||
|
||||
$this->invoiceWithClaims(10_000_000, 6_000_000, 2_000_000, ['pending', 'pending'], [
|
||||
(int) $iran->getId(), (int) $asia->getId(),
|
||||
]);
|
||||
|
||||
$res = $this->authJson('GET', '/api/v1/billing/claims/by-patient', $this->owner);
|
||||
$row = $res['data'][0];
|
||||
|
||||
self::assertCount(2, $row['insurances']);
|
||||
$names = array_column($row['insurances'], 'insurance_name');
|
||||
self::assertContains('بیمه ایران تست', $names);
|
||||
self::assertContains('بیمه آسیا تست', $names);
|
||||
self::assertSame(
|
||||
['base', 'supplementary'],
|
||||
array_values(array_unique(array_column($row['insurances'], 'kind'))),
|
||||
);
|
||||
}
|
||||
|
||||
public function testKindFilterKeepsOnlyThatKindOfClaim(): void
|
||||
{
|
||||
$this->invoiceWithClaims(10_000_000, 6_000_000, 2_000_000, ['pending', 'pending']);
|
||||
|
||||
$supp = $this->authJson('GET', '/api/v1/billing/claims/by-patient?kind=supplementary', $this->owner);
|
||||
self::assertSame(1, $supp['data'][0]['claims_count']);
|
||||
self::assertSame(2_000_000, $supp['data'][0]['total_insurance_rials']);
|
||||
|
||||
$base = $this->authJson('GET', '/api/v1/billing/claims/by-patient?kind=base', $this->owner);
|
||||
self::assertSame(6_000_000, $base['data'][0]['total_insurance_rials']);
|
||||
}
|
||||
|
||||
public function testAnUnknownKindIsRejected(): void
|
||||
{
|
||||
$body = $this->authJson('GET', '/api/v1/billing/claims/by-patient?kind=bogus', $this->owner);
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame('kind', $body['errors'][0]['field']);
|
||||
}
|
||||
|
||||
public function testSearchAlsoMatchesTheInsuranceName(): void
|
||||
{
|
||||
$asia = new Insurance('بیمه آسیا جستجو', InsuranceType::Supplementary);
|
||||
$this->em->persist($asia);
|
||||
$this->em->flush();
|
||||
|
||||
$this->invoiceWithClaims(10_000_000, 0, 4_000_000, ['pending'], [(int) $asia->getId()]);
|
||||
|
||||
$hit = $this->authJson('GET', '/api/v1/billing/claims/by-patient?search=' . urlencode('آسیا'), $this->owner);
|
||||
self::assertSame(1, $hit['meta']['totalRecords']);
|
||||
|
||||
$miss = $this->authJson('GET', '/api/v1/billing/claims/by-patient?search=' . urlencode('بیمه ناموجود'), $this->owner);
|
||||
self::assertSame(0, $miss['meta']['totalRecords']);
|
||||
self::assertSame([], $miss['data']);
|
||||
}
|
||||
|
||||
public function testStatusFilterNarrowsTheAggregation(): void
|
||||
{
|
||||
$this->invoiceWithClaims(10_000_000, 7_000_000, 0);
|
||||
|
||||
Reference in New Issue
Block a user