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']); } }