createUser(['ROLE_DOCTOR']); $doctor = new Doctor($owner, 'دکتر تست'); $this->em->persist($doctor); $this->em->flush(); return [$owner, $doctor]; } private function patientRecord(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 setField(object $obj, string $prop, mixed $value): void { $ref = new \ReflectionProperty($obj, $prop); $ref->setAccessible(true); $ref->setValue($obj, $value); } public function testShowIncludesSessionPaymentsConsumablesAndDiscount(): void { [$owner, $doctor] = $this->doctor(); $record = $this->patientRecord($doctor); $session = new PatientSession($record); $session->setServicesTotalRials(2_400_000) ->setFinalPriceRials(2_200_000) ->setDiscount('amount', 200_000, 200_000) ->setSessionAt(1_700_000_000) ->setPaidAt(1_700_100_000); $this->em->persist($session); $this->em->flush(); $payment = new SessionPayment($session, 'wallet', 1_500_000, 1_700_100_000); $payment->setCreatedByName('منشی تست'); $this->em->persist($payment); $session->addPayment($payment); $item = new InventoryItem('doctor', $doctor->getId(), 'عینک'); $item->setPrice(20_000); $this->em->persist($item); $this->em->flush(); $consumable = new SessionConsumable($session, $item, 2); $this->em->persist($consumable); $session->addConsumable($consumable); $this->em->flush(); $invoice = new Invoice('doctor', $doctor->getId()); $invoice->setPatientSessionId($session->getId()) ->setPatientRecordId($record->getId()); $this->em->persist($invoice); $this->em->flush(); $res = $this->authJson('GET', '/api/v1/billing/invoices/' . $invoice->getUuid(), $owner); self::assertSame(200, $this->responseCode()); $data = $res['data']['data']; self::assertSame($invoice->getUuid(), $data['uuid']); self::assertIsArray($data['session']); $s = $data['session']; self::assertSame($session->getUuid(), $s['uuid']); self::assertSame(1_700_000_000, $s['session_at']); self::assertSame(1_700_100_000, $s['paid_at']); self::assertSame(2_400_000, $s['services_total_rials']); self::assertSame(2_200_000, $s['final_price_rials']); self::assertSame(200_000, $s['discount_rials']); // payments — real rows, not heuristics self::assertCount(1, $s['payments']); self::assertSame('wallet', $s['payments'][0]['method']); self::assertSame(1_500_000, $s['payments'][0]['amount_rials']); self::assertSame('منشی تست', $s['payments'][0]['created_by_name']); self::assertSame(1_500_000, $s['paid_total_rials']); // consumables — snapshot price × quantity self::assertCount(1, $s['consumables']); self::assertSame('عینک', $s['consumables'][0]['item_name']); self::assertSame(2, $s['consumables'][0]['quantity']); self::assertSame(40_000, $s['consumables'][0]['line_total_rials']); self::assertSame(40_000, $s['consumables_total_rials']); } public function testShowSessionNullWhenInvoiceHasNoSession(): void { [$owner, $doctor] = $this->doctor(); $record = $this->patientRecord($doctor); $invoice = new Invoice('doctor', $doctor->getId()); $invoice->setPatientRecordId($record->getId()); $this->em->persist($invoice); $this->em->flush(); $res = $this->authJson('GET', '/api/v1/billing/invoices/' . $invoice->getUuid(), $owner); self::assertSame(200, $this->responseCode()); self::assertNull($res['data']['data']['session']); } public function testShowNotFoundForUnknownUuid(): void { [$owner] = $this->doctor(); $this->authJson('GET', '/api/v1/billing/invoices/00000000-0000-0000-0000-000000000000', $owner); self::assertSame(404, $this->responseCode()); } public function testShowNotFoundForOtherTenant(): void { [, $doctor] = $this->doctor(); $invoice = new Invoice('doctor', $doctor->getId()); $this->em->persist($invoice); $this->em->flush(); [$other] = $this->doctor(); $this->authJson('GET', '/api/v1/billing/invoices/' . $invoice->getUuid(), $other); self::assertSame(404, $this->responseCode()); } public function testShowSessionEmptyPaymentsAndConsumables(): void { [$owner, $doctor] = $this->doctor(); $record = $this->patientRecord($doctor); $session = new PatientSession($record); $this->em->persist($session); $this->em->flush(); $invoice = new Invoice('doctor', $doctor->getId()); $invoice->setPatientSessionId($session->getId()); $this->em->persist($invoice); $this->em->flush(); $res = $this->authJson('GET', '/api/v1/billing/invoices/' . $invoice->getUuid(), $owner); self::assertSame(200, $this->responseCode()); $s = $res['data']['data']['session']; self::assertSame([], $s['payments']); self::assertSame([], $s['consumables']); self::assertSame(0, $s['paid_total_rials']); self::assertSame(0, $s['discount_rials']); } }