feat: convert deposit amounts from toman to rials in appointment handling
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Insurance;
|
||||
|
||||
use App\Appointment\Entity\Appointment;
|
||||
use App\Auth\Entity\User;
|
||||
use App\Clinic\Entity\Clinic;
|
||||
use App\Doctor\Entity\Doctor;
|
||||
use App\Insurance\Entity\EntityInsurancePricing;
|
||||
use App\Patient\Entity\PatientRecord;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Tests\ApiTestCase;
|
||||
|
||||
/**
|
||||
* فلگ «الزامی کردن هزینه ویزیت» (require_visit_price روی ردیف free-visit):
|
||||
* - PUT /insurance-pricing: فلگ فعال بدون قیمت > 0 → 422؛ فلگ-فقط بدون ردیف → ردیف ساخته نشود.
|
||||
* - POST /patient/{uuid}/session: با فلگ فعال، visit_price_rials <= 0 → 422.
|
||||
* - POST /my/appointment و /admin/appointment: فلگ برای پزشکِ نوبت resolve میشود
|
||||
* (ردیف پزشک، وگرنه کلینیکِ واحد او)؛ بدون هزینه ویزیت → 422.
|
||||
*/
|
||||
class RequireVisitPriceTest extends ApiTestCase
|
||||
{
|
||||
/** @return array{0: User, 1: Doctor} */
|
||||
private function doctor(): array
|
||||
{
|
||||
$owner = $this->createUser(['ROLE_DOCTOR']);
|
||||
$doctor = new Doctor($owner, 'دکتر');
|
||||
$this->em->persist($doctor);
|
||||
$this->em->flush();
|
||||
|
||||
return [$owner, $doctor];
|
||||
}
|
||||
|
||||
private function pricingRow(string $type, int $entityId, int $priceRials, bool $require): EntityInsurancePricing
|
||||
{
|
||||
$row = new EntityInsurancePricing($type, $entityId, null, $priceRials);
|
||||
$row->setRequireVisitPrice($require);
|
||||
$this->em->persist($row);
|
||||
$this->em->flush();
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
private function recordFor(Doctor $doctor): PatientRecord
|
||||
{
|
||||
$patient = $this->createUser(['ROLE_USER']);
|
||||
$record = new PatientRecord('doctor', $doctor->getId(), $patient, 'doctor', $doctor->getId());
|
||||
$this->em->persist($record);
|
||||
$this->em->flush();
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
private function appointmentBody(string $doctorUuid): array
|
||||
{
|
||||
$start = time() + 86_400 + random_int(0, 3_600) * 100;
|
||||
|
||||
return [
|
||||
'doctor_uuid' => $doctorUuid,
|
||||
'slot_start' => $start,
|
||||
'slot_end' => $start + 1_800,
|
||||
'patient_mobile' => '09' . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT),
|
||||
'patient_name' => 'بیمار تست',
|
||||
'patient_national_code' => '00' . str_pad((string) random_int(0, 99_999_999), 8, '0', STR_PAD_LEFT),
|
||||
];
|
||||
}
|
||||
|
||||
// ── PUT /api/v1/insurance-pricing ────────────────────────────────────────
|
||||
|
||||
public function testSaveFlagOnWithZeroPriceIs422(): void
|
||||
{
|
||||
[$owner] = $this->doctor();
|
||||
|
||||
$res = $this->authJson('PUT', '/api/v1/insurance-pricing', $owner, [
|
||||
'free_visit_price_rials' => 0,
|
||||
'require_visit_price' => true,
|
||||
]);
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame(ErrorCodes::ERR_VALIDATION_001, $res['errors'][0]['code']);
|
||||
}
|
||||
|
||||
public function testSaveFlagOnWithValidPricePersistsBoth(): void
|
||||
{
|
||||
[$owner] = $this->doctor();
|
||||
|
||||
$this->authJson('PUT', '/api/v1/insurance-pricing', $owner, [
|
||||
'free_visit_price_rials' => 500_000,
|
||||
'require_visit_price' => true,
|
||||
]);
|
||||
self::assertSame(200, $this->responseCode());
|
||||
|
||||
$res = $this->authJson('GET', '/api/v1/insurance-pricing', $owner);
|
||||
self::assertSame(500_000, $res['data']['free_visit_price_rials']);
|
||||
self::assertTrue($res['data']['require_visit_price']);
|
||||
}
|
||||
|
||||
public function testSaveFlagAloneKeepsStoredPrice(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_DOCTOR, $doctor->getId(), 300_000, false);
|
||||
|
||||
$this->authJson('PUT', '/api/v1/insurance-pricing', $owner, ['require_visit_price' => true]);
|
||||
self::assertSame(200, $this->responseCode());
|
||||
|
||||
$res = $this->authJson('GET', '/api/v1/insurance-pricing', $owner);
|
||||
self::assertSame(300_000, $res['data']['free_visit_price_rials']);
|
||||
self::assertTrue($res['data']['require_visit_price']);
|
||||
}
|
||||
|
||||
public function testSaveFlagAloneOnEnabledRowWithZeroStoredPriceIs422(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_DOCTOR, $doctor->getId(), 0, false);
|
||||
|
||||
$this->authJson('PUT', '/api/v1/insurance-pricing', $owner, ['require_visit_price' => true]);
|
||||
self::assertSame(422, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testSaveFlagFalseWithoutRowDoesNotCreateRow(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
|
||||
$this->authJson('PUT', '/api/v1/insurance-pricing', $owner, ['require_visit_price' => false]);
|
||||
self::assertSame(200, $this->responseCode());
|
||||
|
||||
$row = $this->em->getRepository(EntityInsurancePricing::class)->findOneBy([
|
||||
'entityType' => EntityInsurancePricing::TYPE_DOCTOR,
|
||||
'entityId' => $doctor->getId(),
|
||||
'insuranceId' => null,
|
||||
]);
|
||||
self::assertNull($row);
|
||||
}
|
||||
|
||||
// ── POST /api/v1/patient/{uuid}/session ─────────────────────────────────
|
||||
|
||||
public function testSessionWithoutVisitPriceIs422WhenFlagOn(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_DOCTOR, $doctor->getId(), 500_000, true);
|
||||
$record = $this->recordFor($doctor);
|
||||
|
||||
$res = $this->authJson('POST', '/api/v1/patient/' . $record->getUuid() . '/session', $owner, [
|
||||
'visit_price_rials' => 0,
|
||||
]);
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame(ErrorCodes::ERR_VALIDATION_001, $res['errors'][0]['code']);
|
||||
}
|
||||
|
||||
public function testSessionWithVisitPriceIs201WhenFlagOn(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_DOCTOR, $doctor->getId(), 500_000, true);
|
||||
$record = $this->recordFor($doctor);
|
||||
|
||||
$res = $this->authJson('POST', '/api/v1/patient/' . $record->getUuid() . '/session', $owner, [
|
||||
'visit_price_rials' => 400_000,
|
||||
]);
|
||||
|
||||
self::assertSame(201, $this->responseCode());
|
||||
self::assertSame(400_000, $res['data']['visit_price_rials']);
|
||||
}
|
||||
|
||||
public function testSessionWithZeroVisitPriceStaysAllowedWhenFlagOff(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_DOCTOR, $doctor->getId(), 500_000, false);
|
||||
$record = $this->recordFor($doctor);
|
||||
|
||||
$this->authJson('POST', '/api/v1/patient/' . $record->getUuid() . '/session', $owner, [
|
||||
'visit_price_rials' => 0,
|
||||
]);
|
||||
|
||||
self::assertSame(201, $this->responseCode());
|
||||
}
|
||||
|
||||
// ── POST /api/v1/my/appointment ─────────────────────────────────────────
|
||||
|
||||
public function testMyAppointmentWithoutVisitPriceIs422WhenFlagOn(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_DOCTOR, $doctor->getId(), 500_000, true);
|
||||
|
||||
$res = $this->authJson('POST', '/api/v1/my/appointment', $owner, $this->appointmentBody($doctor->getUuid()));
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame('visit_price_rials', $res['errors'][0]['field']);
|
||||
}
|
||||
|
||||
public function testMyAppointmentWithVisitPriceIs201AndStored(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_DOCTOR, $doctor->getId(), 500_000, true);
|
||||
|
||||
$body = $this->appointmentBody($doctor->getUuid());
|
||||
$body['visit_price_rials'] = 500_000;
|
||||
$res = $this->authJson('POST', '/api/v1/my/appointment', $owner, $body);
|
||||
|
||||
self::assertSame(201, $this->responseCode());
|
||||
$appointment = $this->em->getRepository(Appointment::class)->findOneBy(['uuid' => $res['data']['uuid']]);
|
||||
self::assertSame(500_000, $appointment->getVisitPriceRials());
|
||||
}
|
||||
|
||||
public function testMyAppointmentWithoutVisitPriceIs201WhenFlagOff(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
|
||||
$this->authJson('POST', '/api/v1/my/appointment', $owner, $this->appointmentBody($doctor->getUuid()));
|
||||
|
||||
self::assertSame(201, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testFlagFallsBackToSingleClinicOfDoctor(): void
|
||||
{
|
||||
[$owner, $doctor] = $this->doctor();
|
||||
|
||||
$clinicOwner = $this->createUser(['ROLE_CLINIC']);
|
||||
$clinic = new Clinic($clinicOwner);
|
||||
$clinic->getDoctors()->add($doctor);
|
||||
$this->em->persist($clinic);
|
||||
$this->em->flush();
|
||||
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_CLINIC, $clinic->getId(), 500_000, true);
|
||||
|
||||
$this->authJson('POST', '/api/v1/my/appointment', $owner, $this->appointmentBody($doctor->getUuid()));
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
}
|
||||
|
||||
// ── POST /api/v1/admin/appointment ──────────────────────────────────────
|
||||
|
||||
public function testAdminAppointmentWithoutVisitPriceIs422WhenFlagOn(): void
|
||||
{
|
||||
[, $doctor] = $this->doctor();
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_DOCTOR, $doctor->getId(), 500_000, true);
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
|
||||
$res = $this->authJson('POST', '/api/v1/admin/appointment', $admin, $this->appointmentBody($doctor->getUuid()));
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame('visit_price_rials', $res['errors'][0]['field']);
|
||||
}
|
||||
|
||||
public function testAdminAppointmentWithVisitPriceIs201(): void
|
||||
{
|
||||
[, $doctor] = $this->doctor();
|
||||
$this->pricingRow(EntityInsurancePricing::TYPE_DOCTOR, $doctor->getId(), 500_000, true);
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
|
||||
$body = $this->appointmentBody($doctor->getUuid());
|
||||
$body['visit_price_rials'] = 500_000;
|
||||
$res = $this->authJson('POST', '/api/v1/admin/appointment', $admin, $body);
|
||||
|
||||
self::assertSame(201, $this->responseCode());
|
||||
$appointment = $this->em->getRepository(Appointment::class)->findOneBy(['uuid' => $res['data']['uuid']]);
|
||||
self::assertSame(500_000, $appointment->getVisitPriceRials());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user