createUser(['ROLE_DOCTOR']); $doctor = new Doctor($owner, 'دکتر مراجعه'); $this->em->persist($doctor); $this->em->flush(); $patient = $this->createUser(['ROLE_USER']); $record = new PatientRecord('doctor', $doctor->getId(), $patient, 'doctor', $doctor->getId()); $this->em->persist($record); $this->em->flush(); return [$owner, $doctor, $record]; } private function serviceFor(Doctor $doctor, string $name, int $price): ServiceItem { $section = new ServiceSection('doctor', $doctor->getId(), 'بخش ' . $name); $this->em->persist($section); $item = new ServiceItem($section, $name, $price); $this->em->persist($item); $this->em->flush(); return $item; } private function createSession(\App\Auth\Entity\User $owner, PatientRecord $record, array $body = []): array { $res = $this->authJson( 'POST', '/api/v1/patient/' . $record->getUuid() . '/session', $owner, $body + ['visit_price_rials' => 500_000], ); self::assertSame(201, $this->responseCode(), 'ساخت مراجعه باید موفق باشد'); return $res['data']; } /** ✅ سرویس خودی وارد فاکتور می‌شود. */ public function testOwnServiceIsPriced(): void { [$owner, $doctor, $record] = $this->recordFor(); $mine = $this->serviceFor($doctor, 'سرویس خودی', 900_000); $session = $this->createSession($owner, $record, [ 'services' => [['service_item_uuid' => $mine->getUuid(), 'quantity' => 1]], ]); self::assertSame(900_000, $session['services_total_rials'], 'سرویس خودی باید قیمت بخورد'); } /** ❌ سرویسِ محیط دیگر نه در قیمت می‌آید نه ذخیره می‌شود. */ public function testAnotherEnvironmentsServiceIsIgnoredOnCreate(): void { [$owner, , $record] = $this->recordFor(); [, $stranger] = $this->recordFor(); $foreign = $this->serviceFor($stranger, 'سرویس بیگانه', 900_000); $session = $this->createSession($owner, $record, [ 'services' => [['service_item_uuid' => $foreign->getUuid(), 'quantity' => 1]], ]); self::assertSame(0, $session['services_total_rials'], 'قیمت سرویس بیگانه نباید اضافه شود'); // قیمت‌گذاری و ذخیره‌سازی دو حلقهٔ جدا در PatientService هستند؛ این یکی // ذخیره را می‌سنجد و مستقیم از دیتابیس می‌خواند تا به شکل پاسخ وابسته نباشد. self::assertSame(0, $this->storedServiceCount($session['uuid']), 'نباید روی مراجعه ذخیره شود'); } private function storedServiceCount(string $sessionUuid): int { $this->em->clear(); $session = $this->em->getRepository(PatientSession::class)->findOneBy(['uuid' => $sessionUuid]); return $session === null ? -1 : $session->getServices()->count(); } /** ❌ همان قاعده در ویرایش مراجعه. */ public function testAnotherEnvironmentsServiceIsIgnoredOnUpdate(): void { [$owner, , $record] = $this->recordFor(); [, $stranger] = $this->recordFor(); $foreign = $this->serviceFor($stranger, 'سرویس بیگانه', 900_000); $session = $this->createSession($owner, $record); $res = $this->authJson('PATCH', '/api/v1/session/' . $session['uuid'], $owner, [ 'services' => [['service_item_uuid' => $foreign->getUuid(), 'quantity' => 1]], ]); self::assertSame(200, $this->responseCode()); self::assertSame(0, $res['data']['services_total_rials'], 'سرویس بیگانه نباید در فاکتور بنشیند'); self::assertSame([], $res['data']['services'] ?? [], 'و نباید روی مراجعه ذخیره شود'); } /** ⚠️ مرزی: سرویس خودی می‌ماند حتی وقتی یک بیگانه هم در فهرست است. */ public function testOwnServiceSurvivesAlongsideAForeignOne(): void { [$owner, $doctor, $record] = $this->recordFor(); [, $stranger] = $this->recordFor(); $mine = $this->serviceFor($doctor, 'سرویس خودی', 300_000); $foreign = $this->serviceFor($stranger, 'سرویس بیگانه', 900_000); $session = $this->createSession($owner, $record); $res = $this->authJson('PATCH', '/api/v1/session/' . $session['uuid'], $owner, [ 'services' => [ ['service_item_uuid' => $mine->getUuid(), 'quantity' => 1], ['service_item_uuid' => $foreign->getUuid(), 'quantity' => 1], ], ]); self::assertSame(200, $this->responseCode()); self::assertSame(300_000, $res['data']['services_total_rials'], 'فقط سرویس خودی باید بماند'); self::assertCount(1, $res['data']['services'] ?? []); } /** ❌ پرسنلِ محیط دیگر هم روی سرویس نمی‌نشیند. */ public function testAnotherEnvironmentsStaffIsNotAttached(): void { [$owner, $doctor, $record] = $this->recordFor(); [, $stranger] = $this->recordFor(); $mine = $this->serviceFor($doctor, 'سرویس خودی', 300_000); $foreignStaff = new ClinicStaff('doctor', $stranger->getId(), 'پرسنل بیگانه'); $this->em->persist($foreignStaff); $this->em->flush(); $session = $this->createSession($owner, $record); $res = $this->authJson('PATCH', '/api/v1/session/' . $session['uuid'], $owner, [ 'services' => [[ 'service_item_uuid' => $mine->getUuid(), 'staff_uuid' => $foreignStaff->getUuid(), 'quantity' => 1, ]], ]); self::assertSame(200, $this->responseCode()); $service = ($res['data']['services'] ?? [])[0] ?? null; self::assertNotNull($service, 'سرویس خودی باید ثبت شود'); self::assertNull($service['staff_uuid'] ?? null, 'پرسنل بیگانه نباید چسبیده باشد'); } }