createUser(['ROLE_USER', 'ROLE_DOCTOR']); $doctor = new Doctor($doctorUser, 'دکتر قرارداد شخصی'); $doctor->setMobileNumber($doctorUser->getMobileNumber()); $this->em->persist($doctor); $owner = $this->createUser(['ROLE_USER', 'ROLE_CLINIC']); $clinic = new Clinic($owner); $clinic->setName('کلینیک مطالبه'); $clinic->getDoctors()->add($doctor); $this->em->persist($clinic); $insurance = new Insurance('بیمه مطالبه ' . random_int(1000, 9999), InsuranceType::Basic); $this->em->persist($insurance); $this->em->flush(); // قرارداد روی خودِ پزشک — همان کاری که پنل کلینیک می‌کند. $this->authJson('POST', '/api/v1/billing/tenant-insurances', $owner, [ 'doctor_uuid' => $doctor->getUuid(), 'insurance_id' => $insurance->getId(), 'coverage_percent' => $coveragePercent, ]); self::assertSame(201, $this->responseCode()); return [$owner, $doctor, $clinic, $insurance]; } private function appointment(Doctor $doctor, Clinic $clinic, Insurance $insurance): Appointment { $appointment = $this->newAppointment( $doctor, $this->createUser(['ROLE_USER']), time() + 3600, time() + 5400, $clinic, ); $appointment->setVisitPriceRials(self::VISIT_PRICE); $appointment->setInsuranceBaseId($insurance->getId()); $appointment->transitionTo(Appointment::STATUS_CONFIRMED); $this->em->persist($appointment); $this->em->flush(); return $appointment; } public function testTheInsuranceShareIsDeductedFromWhatThePatientOwes(): void { [, $doctor, $clinic, $insurance] = $this->scenario(30); $appointment = $this->appointment($doctor, $clinic, $insurance); $session = static::getContainer()->get(PatientService::class) ->autoCreateOnAppointmentConfirm($appointment); self::assertNotNull($session); self::assertSame(990_000, $session->getBaseInsuranceRials(), 'سهم بیمه ۳۰٪ ویزیت است'); self::assertSame(2_310_000, $session->getPatientShareRials()); self::assertSame(2_310_000, $session->getRemainingRials(), 'مانده نباید شامل سهم بیمه باشد'); } public function testTheInvoiceCarriesTheInsuranceShareSoAClaimCanBeBuilt(): void { [, $doctor, $clinic, $insurance] = $this->scenario(30); $appointment = $this->appointment($doctor, $clinic, $insurance); $session = static::getContainer()->get(PatientService::class) ->autoCreateOnAppointmentConfirm($appointment); $invoice = static::getContainer()->get(\App\Billing\Service\InvoiceService::class) ->createFromSession($session, 'clinic', (int) $clinic->getId()); $shares = array_map( static fn ($item): int => $item->getBaseInsuranceRials(), $invoice->getItems()->toArray(), ); self::assertContains(990_000, $shares, 'خط ویزیت باید سهم بیمه داشته باشد'); // صورتحساب همان‌جا نهایی می‌شود و مطالبهٔ بیمه از روی همین سهم ساخته می‌شود؛ // با سهمِ صفر هیچ مطالبه‌ای ساخته نمی‌شد و صفحهٔ مطالبات خالی می‌ماند. $claims = $this->em->getRepository(\App\Billing\Entity\Claim::class) ->findBy(['entityType' => 'clinic', 'entityId' => (int) $clinic->getId()]); self::assertNotSame([], $claims, 'باید برای سهم بیمه مطالبه ساخته شود'); self::assertSame(990_000, $claims[0]->getTotalClaimedRials()); } /** * ویرایش دستیِ همان مراجعه هم نباید سهم بیمه را دور بیندازد: فرم ویرایش سرویس‌ها * کل مبلغ را دوباره حساب می‌کند و اگر درصد را از محیط اشتباه بگیرد، مراجعه‌ای که * درست ساخته شده بود با یک ذخیرهٔ ساده خراب می‌شود. */ public function testEditingTheSessionKeepsTheInsuranceShare(): void { [$owner, $doctor, $clinic, $insurance] = $this->scenario(30); $appointment = $this->appointment($doctor, $clinic, $insurance); $session = static::getContainer()->get(PatientService::class) ->autoCreateOnAppointmentConfirm($appointment); $this->authJson('PATCH', '/api/v1/session/' . $session->getUuid(), $owner, [ 'visit_price_rials' => self::VISIT_PRICE, ]); self::assertSame(200, $this->responseCode()); // درخواستِ کرنل روی EntityManager دیگری نوشت، پس ردیف دوباره خوانده می‌شود. $row = $this->em->getConnection()->fetchAssociative( 'SELECT base_insurance_rials, patient_share_rials FROM patient_sessions WHERE uuid = ?', [$session->getUuid()], ); self::assertSame(990_000, (int) $row['base_insurance_rials']); self::assertSame(2_310_000, (int) $row['patient_share_rials']); } /** نوبتِ بدون قرارداد، مثل قبل کاملاً سهم بیمار می‌ماند. */ public function testAnAppointmentWithoutAnyContractStillBillsThePatientInFull(): void { [, $doctor, $clinic, ] = $this->scenario(30); $other = new Insurance('بیمه بی‌قرارداد ' . random_int(1000, 9999), InsuranceType::Basic); $this->em->persist($other); $this->em->flush(); $appointment = $this->newAppointment( $doctor, $this->createUser(['ROLE_USER']), time() + 7200, time() + 9000, $clinic, ); $appointment->setVisitPriceRials(self::VISIT_PRICE); $appointment->transitionTo(Appointment::STATUS_CONFIRMED); $this->em->persist($appointment); $this->em->flush(); $session = static::getContainer()->get(PatientService::class) ->autoCreateOnAppointmentConfirm($appointment); self::assertSame(0, $session->getBaseInsuranceRials()); self::assertSame(self::VISIT_PRICE, $session->getPatientShareRials()); } }