- 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.
177 lines
7.4 KiB
PHP
177 lines
7.4 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Insurance;
|
|
|
|
use App\Doctor\Entity\Doctor;
|
|
use App\Insurance\Entity\Insurance;
|
|
use App\Insurance\Enum\InsuranceType;
|
|
use App\Insurance\Service\InsuranceCoverageDefaultService;
|
|
use App\Tests\ApiTestCase;
|
|
|
|
/**
|
|
* Contract-level per-category coverage overrides over the tenant insurance API:
|
|
* sending them stores an override, omitting them keeps the contract on the central
|
|
* admin default (live fallback).
|
|
*/
|
|
class TenantInsuranceCategoryCoverageApiTest extends ApiTestCase
|
|
{
|
|
/** @return array{0: \App\Auth\Entity\User, 1: Insurance} */
|
|
private function makeDoctorAndInsurance(): array
|
|
{
|
|
$owner = $this->createUser(['ROLE_DOCTOR']);
|
|
$doctor = new Doctor($owner, 'دکتر تست پوشش نوع خدمت');
|
|
$this->em->persist($doctor);
|
|
|
|
$insurance = new Insurance('بیمه پایه ' . random_int(1000, 9999), InsuranceType::Basic);
|
|
$this->em->persist($insurance);
|
|
$this->em->flush();
|
|
|
|
return [$owner, $insurance];
|
|
}
|
|
|
|
public function testContractWithoutOverridesFollowsTheAdminDefault(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
static::getContainer()->get(InsuranceCoverageDefaultService::class)->save($insurance->getId(), [
|
|
['key' => 'outpatient', 'coverage_percent' => 70],
|
|
['key' => 'inpatient', 'coverage_percent' => 30],
|
|
]);
|
|
|
|
$body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
]);
|
|
|
|
$this->assertSame(201, $this->responseCode());
|
|
$row = $body['data']['data'];
|
|
$this->assertEquals(70.0, $row['category_coverages']['outpatient']);
|
|
$this->assertEquals(30.0, $row['category_coverages']['inpatient']);
|
|
$this->assertSame('admin_default', $row['category_coverage_source']['outpatient']);
|
|
}
|
|
|
|
public function testSendingCategoryCoveragesStoresAnOverride(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
static::getContainer()->get(InsuranceCoverageDefaultService::class)->save($insurance->getId(), [
|
|
['key' => 'outpatient', 'coverage_percent' => 70],
|
|
['key' => 'inpatient', 'coverage_percent' => 30],
|
|
]);
|
|
|
|
$body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'category_coverages' => [
|
|
['key' => 'inpatient', 'coverage_percent' => 90],
|
|
],
|
|
]);
|
|
|
|
$this->assertSame(201, $this->responseCode());
|
|
$row = $body['data']['data'];
|
|
$this->assertEquals(90.0, $row['category_coverages']['inpatient']);
|
|
$this->assertSame('override', $row['category_coverage_source']['inpatient']);
|
|
$this->assertSame('admin_default', $row['category_coverage_source']['outpatient']);
|
|
}
|
|
|
|
public function testAnEnabledServiceKindCannotBeLeftWithoutAPercent(): void
|
|
{
|
|
// بدون پیشفرض مرکزی: ارسال درصد فقط برای سرپایی، بستری را صفر رها میکند.
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
|
|
$body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'category_coverages' => [
|
|
['key' => 'outpatient', 'coverage_percent' => 70],
|
|
['key' => 'inpatient', 'coverage_percent' => null],
|
|
],
|
|
]);
|
|
|
|
$this->assertSame(422, $this->responseCode());
|
|
$this->assertSame('category_coverages', $body['errors'][0]['field']);
|
|
$this->assertStringContainsString('خدمات بستری', $body['errors'][0]['message']);
|
|
}
|
|
|
|
public function testADisabledServiceKindNeedsNoPercent(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
$this->authJson('PUT', '/api/v1/insurance-pricing', $owner, [
|
|
'service_categories' => [
|
|
['key' => 'outpatient', 'enabled' => true],
|
|
['key' => 'inpatient', 'enabled' => false],
|
|
],
|
|
]);
|
|
|
|
$body = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'category_coverages' => [
|
|
['key' => 'outpatient', 'coverage_percent' => 70],
|
|
],
|
|
]);
|
|
|
|
$this->assertSame(201, $this->responseCode());
|
|
$this->assertEquals(70.0, $body['data']['data']['category_coverages']['outpatient']);
|
|
}
|
|
|
|
public function testListReturnsEffectivePercentsAndSources(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
static::getContainer()->get(InsuranceCoverageDefaultService::class)->save($insurance->getId(), [
|
|
['key' => 'outpatient', 'coverage_percent' => 55],
|
|
]);
|
|
$this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, ['insurance_id' => $insurance->getId()]);
|
|
|
|
$body = $this->authJson('GET', '/api/v1/billing/tenant-insurances', $owner);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$row = $body['data']['data'][0];
|
|
$this->assertEquals(55.0, $row['category_coverages']['outpatient']);
|
|
$this->assertArrayHasKey('inpatient', $row['category_coverage_source']);
|
|
}
|
|
|
|
public function testUnknownCategoryIsRejected(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
|
|
$this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'category_coverages' => [['key' => 'dental', 'coverage_percent' => 50]],
|
|
]);
|
|
|
|
$this->assertSame(422, $this->responseCode());
|
|
}
|
|
|
|
public function testPercentAbove100IsRejected(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
|
|
$this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'category_coverages' => [['key' => 'outpatient', 'coverage_percent' => 101]],
|
|
]);
|
|
|
|
$this->assertSame(422, $this->responseCode());
|
|
}
|
|
|
|
public function testPatchCanDropAnOverrideBackToTheAdminDefault(): void
|
|
{
|
|
[$owner, $insurance] = $this->makeDoctorAndInsurance();
|
|
// سرپایی هم پیشفرض دارد، وگرنه ساخت قرارداد بهخاطر «درصد پوشش الزامی است» رد میشود.
|
|
static::getContainer()->get(InsuranceCoverageDefaultService::class)->save($insurance->getId(), [
|
|
['key' => 'outpatient', 'coverage_percent' => 50],
|
|
['key' => 'inpatient', 'coverage_percent' => 30],
|
|
]);
|
|
|
|
$created = $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [
|
|
'insurance_id' => $insurance->getId(),
|
|
'category_coverages' => [['key' => 'inpatient', 'coverage_percent' => 90]],
|
|
]);
|
|
$uuid = $created['data']['data']['uuid'];
|
|
|
|
$body = $this->authJson('PATCH', '/api/v1/billing/tenant-insurances/' . $uuid, $owner, [
|
|
'category_coverages' => [['key' => 'inpatient', 'coverage_percent' => null]],
|
|
]);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$row = $body['data']['data'];
|
|
$this->assertEquals(30.0, $row['category_coverages']['inpatient']);
|
|
$this->assertSame('admin_default', $row['category_coverage_source']['inpatient']);
|
|
}
|
|
}
|