createUser(['ROLE_USER', 'ROLE_DOCTOR']); $doctor = new Doctor($user, $name); $doctor->setMobileNumber($user->getMobileNumber()); $this->em->persist($doctor); $this->em->flush(); $this->em->persist(new UserActiveContext($user, $doctor->getUuid(), EntityContext::TYPE_DOCTOR)); $this->em->flush(); return $doctor; } /** پرداختی که «پزشکِ پرداخت‌کننده» برای نوبتِ «پزشکِ مقصد» انجام داده است. */ private function makeCrossTenantPayment(Doctor $target, User $payer): Payment { $start = strtotime('+20 days') + random_int(0, 500_000) * 7; $appointment = $this->newAppointment($target, $payer, $start, $start + 900); $appointment->setVisitPriceRials(1_500_000); $this->em->persist($appointment); $this->em->flush(); $payment = new Payment($payer, 1_500_000, 'mellat', Payment::TYPE_APPOINTMENT, ''); $payment->setAppointment($appointment); $payment->assignTenant(EntityContext::forBooking($target, null)); $this->em->persist($payment); $this->em->flush(); return $payment; } public function testDoctorSeesThePaymentHeMadeAtAnotherPractice(): void { $target = $this->makeDoctor('پزشک مقصد'); $payer = $this->makeDoctor('پزشک پرداخت‌کننده'); $payment = $this->makeCrossTenantPayment($target, $payer->getUser()); $body = $this->authJson('GET', '/api/v1/payment/' . $payment->getUuid(), $payer->getUser()); self::assertSame(200, $this->responseCode()); self::assertSame($payment->getUuid(), $body['data']['uuid']); } public function testTheSamePaymentAppearsInHisPaymentsList(): void { $target = $this->makeDoctor('پزشک مقصد'); $payer = $this->makeDoctor('پزشک پرداخت‌کننده'); $payment = $this->makeCrossTenantPayment($target, $payer->getUser()); $body = $this->authJson('GET', '/api/v1/my/payments?limit=100', $payer->getUser()); self::assertSame(200, $this->responseCode()); self::assertContains( $payment->getUuid(), array_column($body['data'], 'uuid'), 'پرداختِ خودِ کاربر باید در فهرست پرداخت‌هایش باشد', ); } /** بیمار ساده — بدون محیط — از قبل هم کار می‌کرد و نباید بشکند. */ public function testPlainPatientStillSeesHisPayment(): void { $target = $this->makeDoctor('پزشک مقصد'); $patient = $this->createUser(); $payment = $this->makeCrossTenantPayment($target, $patient); $body = $this->authJson('GET', '/api/v1/payment/' . $payment->getUuid(), $patient); self::assertSame(200, $this->responseCode()); self::assertSame($payment->getUuid(), $body['data']['uuid']); } /** دورزدنِ فیلتر نباید به معنی بازشدن پرداختِ دیگران باشد. */ public function testAnotherUserIsStillForbidden(): void { $target = $this->makeDoctor('پزشک مقصد'); $payer = $this->createUser(); $stranger = $this->createUser(); $payment = $this->makeCrossTenantPayment($target, $payer); $this->authJson('GET', '/api/v1/payment/' . $payment->getUuid(), $stranger); self::assertSame(403, $this->responseCode()); } /** * همان الگو روی نوبت: نوبتی که کاربر به‌عنوان بیمار گرفته، در محیطِ پزشکِ مقصد * ثبت می‌شود و برای کاربرِ صاحبِ محیطِ دیگر نامرئی می‌شد. */ public function testDoctorSeesTheAppointmentHeBookedAtAnotherPractice(): void { $target = $this->makeDoctor('پزشک مقصد'); $payer = $this->makeDoctor('پزشک بیمار'); $payment = $this->makeCrossTenantPayment($target, $payer->getUser()); $body = $this->authJson('GET', '/api/v1/appointments/user', $payer->getUser()); self::assertSame(200, $this->responseCode()); self::assertContains( $payment->getAppointment()->getUuid(), array_column($body['data']['data'] ?? $body['data'], 'uuid'), 'نوبتِ خودِ کاربر باید در فهرست نوبت‌هایش باشد', ); } public function testUnknownPaymentIsStillNotFound(): void { $user = $this->createUser(); $this->authJson('GET', '/api/v1/payment/00000000-0000-4000-8000-000000000000', $user); self::assertSame(404, $this->responseCode()); } }