Files
clinicpro/tests/Billing/InvoiceSyncOnSessionEditTest.php
T

152 lines
6.6 KiB
PHP

<?php
namespace App\Tests\Billing;
use App\Auth\Entity\User;
use App\Auth\Entity\UserActiveContext;
use App\Billing\Entity\Invoice;
use App\Clinic\Entity\Clinic;
use App\ClinicService\Entity\ServiceItem;
use App\ClinicService\Entity\ServiceSection;
use App\Doctor\Entity\Doctor;
use App\Patient\Entity\PatientRecord;
use App\Patient\Entity\PatientSession;
use App\Tests\ApiTestCase;
/**
* صورتحساب باید با محتوای فعلیِ مراجعه هم‌تراز بماند.
*
* پیش از این عکسِ لحظهٔ ساخت بود: مراجعه‌ای که بعداً سرویس می‌گرفت، صورتحسابش روی
* مبلغ قدیمی می‌ماند، «پرداخت‌شده» دیده می‌شد و آمار فهرست پرداخت‌ها (مجموع/
* تسویه‌نشده) که از همان ستون‌ها ساخته می‌شود غلط بود.
*/
class InvoiceSyncOnSessionEditTest extends ApiTestCase
{
/** @return array{0: User, 1: Clinic, 2: PatientRecord, 3: ServiceSection} */
private function scenario(): array
{
$owner = $this->createUser(['ROLE_CLINIC']);
$clinic = new Clinic($owner);
$this->em->persist($clinic);
$doctor = new Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر تست');
$this->em->persist($doctor);
$clinic->getDoctors()->add($doctor);
$this->em->persist(new UserActiveContext($owner, $clinic->getUuid(), 'clinic'));
$patient = $this->createUser(['ROLE_USER']);
$patient->setRealName('بیمار تست');
$record = new PatientRecord('clinic', $clinic->getId(), $patient, 'clinic', $clinic->getId());
$this->em->persist($record);
$section = new ServiceSection('clinic', $clinic->getId(), 'لیزر');
$this->em->persist($section);
$this->em->flush();
return [$owner, $clinic, $record, $section];
}
private function service(ServiceSection $section, string $name, int $priceRials): ServiceItem
{
$item = new ServiceItem($section, $name);
$item->setPriceRials($priceRials);
$this->em->persist($item);
$this->em->flush();
return $item;
}
private function invoiceOf(PatientSession $session): ?Invoice
{
$this->em->clear();
return $this->em->getRepository(Invoice::class)->findOneBy(['patientSessionId' => $session->getId()]);
}
/** ✅ موفق: افزودن سرویس به مراجعه، مبلغ صورتحساب را هم بالا می‌برد. */
public function testEditingSessionServicesUpdatesTheInvoiceTotal(): void
{
[$owner, , $record, $section] = $this->scenario();
$first = $this->service($section, 'لیزر ناحیه‌ای', 10_000_000);
$second = $this->service($section, 'لیزر توتال', 13_000_000);
$created = $this->authJson('POST', '/api/v1/patient/' . $record->getUuid() . '/session', $owner, [
'services' => [['service_item_uuid' => $first->getUuid(), 'quantity' => 1]],
]);
self::assertSame(201, $this->responseCode());
$sessionUuid = $created['data']['uuid'];
// صورتحساب از مسیر پرداخت ساخته می‌شود (مراجعهٔ بدون بیمه).
$this->authJson('POST', '/api/v1/billing/invoices', $owner, ['session_uuid' => $sessionUuid]);
self::assertSame(201, $this->responseCode());
$session = $this->em->getRepository(PatientSession::class)->findOneBy(['uuid' => $sessionUuid]);
self::assertSame(10_000_000, $this->invoiceOf($session)->getTotalRials());
// ویرایش: سرویس دوم اضافه می‌شود.
$this->authJson('PATCH', '/api/v1/session/' . $sessionUuid, $owner, [
'services' => [
['service_item_uuid' => $first->getUuid(), 'quantity' => 1],
['service_item_uuid' => $second->getUuid(), 'quantity' => 1],
],
]);
self::assertSame(200, $this->responseCode());
$session = $this->em->getRepository(PatientSession::class)->findOneBy(['uuid' => $sessionUuid]);
$invoice = $this->invoiceOf($session);
self::assertSame(23_000_000, $invoice->getTotalRials());
self::assertSame(23_000_000, $invoice->getPatientRials());
self::assertCount(2, $invoice->getItems());
}
/** ⚠️ مرزی: حذف سرویس هم باید مبلغ را پایین بیاورد، نه اینکه خط یتیم بماند. */
public function testRemovingAServiceShrinksTheInvoice(): void
{
[$owner, , $record, $section] = $this->scenario();
$first = $this->service($section, 'سرویس اول', 5_000_000);
$second = $this->service($section, 'سرویس دوم', 7_000_000);
$created = $this->authJson('POST', '/api/v1/patient/' . $record->getUuid() . '/session', $owner, [
'services' => [
['service_item_uuid' => $first->getUuid(), 'quantity' => 1],
['service_item_uuid' => $second->getUuid(), 'quantity' => 1],
],
]);
$sessionUuid = $created['data']['uuid'];
$this->authJson('POST', '/api/v1/billing/invoices', $owner, ['session_uuid' => $sessionUuid]);
$this->authJson('PATCH', '/api/v1/session/' . $sessionUuid, $owner, [
'services' => [['service_item_uuid' => $first->getUuid(), 'quantity' => 1]],
]);
self::assertSame(200, $this->responseCode());
$session = $this->em->getRepository(PatientSession::class)->findOneBy(['uuid' => $sessionUuid]);
$invoice = $this->invoiceOf($session);
self::assertSame(5_000_000, $invoice->getTotalRials());
self::assertCount(1, $invoice->getItems());
}
/** ⚠️ مرزی: مراجعهٔ بدونِ صورتحساب نباید با ویرایش، صورتحساب بگیرد. */
public function testSessionWithoutInvoiceStaysWithoutOne(): void
{
[$owner, , $record, $section] = $this->scenario();
$item = $this->service($section, 'سرویس', 4_000_000);
$created = $this->authJson('POST', '/api/v1/patient/' . $record->getUuid() . '/session', $owner, [
'services' => [['service_item_uuid' => $item->getUuid(), 'quantity' => 1]],
]);
$sessionUuid = $created['data']['uuid'];
$this->authJson('PATCH', '/api/v1/session/' . $sessionUuid, $owner, [
'services' => [['service_item_uuid' => $item->getUuid(), 'quantity' => 2]],
]);
self::assertSame(200, $this->responseCode());
$session = $this->em->getRepository(PatientSession::class)->findOneBy(['uuid' => $sessionUuid]);
self::assertNull($this->invoiceOf($session));
}
}