- 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.
163 lines
6.8 KiB
PHP
163 lines
6.8 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Insurance;
|
|
|
|
use App\Doctor\Entity\Doctor;
|
|
use App\Insurance\Entity\Insurance;
|
|
use App\Insurance\Enum\InsuranceType;
|
|
use App\Tests\ApiTestCase;
|
|
|
|
/**
|
|
* Covers the tenant insurance contract management flow used by the redesigned
|
|
* /admin/insurance-pricing page: create with contract dates + kind, edit those
|
|
* fields, toggle فعال/غیرفعال, and list returning inactive contracts too.
|
|
*/
|
|
class TenantInsuranceContractApiTest extends ApiTestCase
|
|
{
|
|
/** @return array{0: \App\Auth\Entity\User, 1: Insurance} */
|
|
private function makeDoctorAndInsurance(InsuranceType $type = InsuranceType::Basic): array
|
|
{
|
|
$owner = $this->createUser(['ROLE_DOCTOR']);
|
|
$doctor = new Doctor($owner, 'دکتر تست بیمه');
|
|
$this->em->persist($doctor);
|
|
|
|
$insurance = new Insurance('بیمه ایران ' . random_int(1000, 9999), $type);
|
|
$this->em->persist($insurance);
|
|
$this->em->flush();
|
|
|
|
return [$owner, $insurance];
|
|
}
|
|
|
|
public function testCreateContractPersistsDatesAndKind(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance(InsuranceType::Basic);
|
|
|
|
$body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'coverage_percent' => 70,
|
|
'franchise_percent' => 15,
|
|
'annual_ceiling_rials' => 20_000_000,
|
|
'effective_from' => 1_700_000_000,
|
|
'effective_to' => 1_800_000_000,
|
|
'kind' => 'supplementary',
|
|
]);
|
|
|
|
$this->assertSame(201, $this->responseCode());
|
|
$row = $body['data']['data'];
|
|
$this->assertEquals(70.0, $row['coverage_percent']);
|
|
$this->assertEquals(15.0, $row['franchise_percent']);
|
|
$this->assertSame(20_000_000, $row['annual_ceiling_rials']);
|
|
$this->assertSame(1_700_000_000, $row['effective_from']);
|
|
$this->assertSame(1_800_000_000, $row['effective_to']);
|
|
$this->assertSame('supplementary', $row['kind']);
|
|
$this->assertTrue($row['is_active']);
|
|
}
|
|
|
|
public function testFranchiseAboveHundredIsRejected(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance(InsuranceType::Supplementary);
|
|
|
|
$body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'coverage_percent' => 80,
|
|
'franchise_percent' => 150,
|
|
]);
|
|
|
|
$this->assertSame(422, $this->responseCode());
|
|
$this->assertSame('franchise_percent', $body['errors'][0]['field']);
|
|
}
|
|
|
|
public function testNegativeFranchiseOnEditIsRejected(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance(InsuranceType::Supplementary);
|
|
$created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'coverage_percent' => 80,
|
|
]);
|
|
$uuid = $created['data']['data']['uuid'];
|
|
|
|
$body = $this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, [
|
|
'franchise_percent' => -5,
|
|
]);
|
|
|
|
$this->assertSame(422, $this->responseCode());
|
|
$this->assertSame('franchise_percent', $body['errors'][0]['field']);
|
|
}
|
|
|
|
public function testKindDefaultsToCatalogTypeWhenOmitted(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance(InsuranceType::Basic);
|
|
|
|
$body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'coverage_percent' => 50,
|
|
]);
|
|
|
|
$this->assertSame(201, $this->responseCode());
|
|
$this->assertSame('basic', $body['data']['data']['kind']);
|
|
}
|
|
|
|
public function testEditUpdatesDatesKindAndAmounts(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
$created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'coverage_percent' => 40,
|
|
]);
|
|
$uuid = $created['data']['data']['uuid'];
|
|
|
|
$body = $this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, [
|
|
'coverage_percent' => 90,
|
|
'franchise_percent' => 20,
|
|
'annual_ceiling_rials' => null,
|
|
'effective_to' => 1_900_000_000,
|
|
'kind' => 'supplementary',
|
|
]);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$this->assertEquals(90.0, $body['data']['data']['coverage_percent']);
|
|
$this->assertEquals(20.0, $body['data']['data']['franchise_percent']);
|
|
$this->assertNull($body['data']['data']['annual_ceiling_rials']);
|
|
$this->assertSame(1_900_000_000, $body['data']['data']['effective_to']);
|
|
$this->assertSame('supplementary', $body['data']['data']['kind']);
|
|
}
|
|
|
|
public function testToggleIsActiveDoesNotClobberEffectiveTo(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
$created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'coverage_percent' => 60,
|
|
'effective_to' => 1_850_000_000,
|
|
]);
|
|
$uuid = $created['data']['data']['uuid'];
|
|
|
|
$off = $this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, ['is_active' => false]);
|
|
$this->assertFalse($off['data']['data']['is_active']);
|
|
// Deactivating via the toggle must keep the user-set effective_to intact.
|
|
$this->assertSame(1_850_000_000, $off['data']['data']['effective_to']);
|
|
|
|
$on = $this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, ['is_active' => true]);
|
|
$this->assertTrue($on['data']['data']['is_active']);
|
|
}
|
|
|
|
public function testListReturnsInactiveContracts(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
$created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'coverage_percent' => 30,
|
|
]);
|
|
$uuid = $created['data']['data']['uuid'];
|
|
$this->authJson('PATCH', "/api/v1/billing/tenant-insurances/$uuid", $owner, ['is_active' => false]);
|
|
|
|
$body = $this->authJson('GET', '/api/v1/billing/tenant-insurances', $owner);
|
|
$this->assertSame(200, $this->responseCode());
|
|
|
|
$rows = $body['data']['data'] ?? $body['data'];
|
|
$found = array_filter($rows, fn ($r) => $r['uuid'] === $uuid);
|
|
$this->assertCount(1, $found, 'inactive contract must still appear in the list');
|
|
$this->assertFalse(array_values($found)[0]['is_active']);
|
|
}
|
|
}
|