createUser(['ROLE_USER', 'ROLE_DOCTOR']); $doctor = new Doctor($doctorUser, 'دکتر دو-محیطی'); $doctor->setMobileNumber($doctorUser->getMobileNumber()); $this->em->persist($doctor); $ownerUser = $this->createUser(['ROLE_USER', 'ROLE_CLINIC']); $clinic = new Clinic($ownerUser); $clinic->setName('کلینیک تست'); $clinic->getDoctors()->add($doctor); $this->em->persist($clinic); $this->em->flush(); $personal = DoctorAddress::forDoctor($doctor); $inClinic = DoctorAddress::forClinic($clinic->getId()); $this->em->persist($personal); $this->em->persist($inClinic); $this->em->flush(); return [$doctor, $clinic, $ownerUser, $personal, $inClinic]; } /** @param array $days */ private function settingOf(array $days): array { $setting = []; foreach ($days as $dayKey => $spec) { $setting[(string) $dayKey] = ['sessions' => [[ 'active' => true, 'location_id' => $spec['location'], 'start_time' => $spec['start'], 'end_time' => $spec['end'], 'duration_per_patient' => 30, 'has_rest' => false, 'patient_limit' => null, ]]]; } return $setting; } public function testDoctorSeesEveryPlaceOfTheirsAsSelectable(): void { [$doctor, , , $personal, $inClinic] = $this->makeDoctorWithBothPlaces(); $body = $this->authJson('GET', "/api/v1/appointment-settings/available-locations/{$doctor->getUuid()}", $doctor->getUser()); self::assertSame(200, $this->responseCode()); $ids = array_map(static fn(array $a): int => (int) $a['id'], $body['data']['data'] ?? []); self::assertContains($personal->getId(), $ids); self::assertContains($inClinic->getId(), $ids, 'آدرس کلینیک هم باید برای خود پزشک انتخاب‌شدنی باشد'); } public function testClinicOwnerOnlySeesClinicAddressesAsSelectable(): void { [$doctor, $clinic, $owner, $personal, $inClinic] = $this->makeDoctorWithBothPlaces(); $body = $this->authJson('GET', "/api/v1/appointment-settings/available-locations/{$doctor->getUuid()}?clinic_uuid={$clinic->getUuid()}", $owner); self::assertSame(200, $this->responseCode()); $ids = array_map(static fn(array $a): int => (int) $a['id'], $body['data']['data'] ?? []); self::assertSame([$inClinic->getId()], $ids); self::assertNotContains($personal->getId(), $ids); } public function testBothContextsReadTheSameRecord(): void { [$doctor, $clinic, , $personal] = $this->makeDoctorWithBothPlaces(); $this->em->persist($this->newWeeklySchedule($doctor, $this->settingOf([ 0 => ['location' => $personal->getId(), 'start' => '09:00', 'end' => '12:00'], ]))); $this->em->flush(); $personalView = $this->authJson('GET', "/api/v1/appointment-settings/weekly-schedule/{$doctor->getUuid()}", $doctor->getUser())['data']['data']; self::assertSame(200, $this->responseCode()); $clinicView = $this->authJson('GET', "/api/v1/appointment-settings/weekly-schedule/{$doctor->getUuid()}?clinic_uuid={$clinic->getUuid()}", $doctor->getUser())['data']['data']; self::assertSame(200, $this->responseCode()); self::assertSame($personalView['uuid'], $clinicView['uuid'], 'برنامه یکی است، از هر دو پنل همان دیده می‌شود'); self::assertNotEmpty($personalView['locations'], 'پاسخ باید همهٔ مکان‌های پزشک را برای برچسب‌زدن بدهد'); } public function testClinicOwnerCannotWipeThePersonalShift(): void { [$doctor, $clinic, $owner, $personal, $inClinic] = $this->makeDoctorWithBothPlaces(); $this->em->persist($this->newWeeklySchedule($doctor, $this->settingOf([ 0 => ['location' => $personal->getId(), 'start' => '09:00', 'end' => '12:00'], ]))); $this->em->flush(); // مدیر کلینیک شنبه را با شیفت کلینیک می‌فرستد و شیفت مطب را از ورودی حذف کرده. $this->authJson('PATCH', "/api/v1/appointment-settings/weekly-schedule/{$doctor->getUuid()}", $owner, [ 'clinic_uuid' => $clinic->getUuid(), 'schedule' => $this->settingOf([ 0 => ['location' => $inClinic->getId(), 'start' => '16:00', 'end' => '20:00'], ]), ]); self::assertSame(200, $this->responseCode()); $this->em->clear(); $reloaded = $this->em->getRepository(Doctor::class)->find($doctor->getId()); $schedule = $this->em->getRepository(WeeklySchedule::class)->findUnified($reloaded); $ids = array_map( static fn(array $s): int => (int) $s['location_id'], $schedule->getSetting()['0']['sessions'] ); self::assertContains($personal->getId(), $ids, 'شیفت مطب شخصی باید دست‌نخورده بماند'); self::assertContains($inClinic->getId(), $ids); } public function testEachContextOnlySeesItsOwnDays(): void { [$doctor, $clinic, , $personal, $inClinic] = $this->makeDoctorWithBothPlaces(); // همهٔ روزها را می‌سازیم تا نتیجه به روزِ هفتهٔ اجرای تست وابسته نباشد: // روزهای زوج مطب، روزهای فرد کلینیک. $days = []; foreach (range(0, 6) as $dayKey) { $days[$dayKey] = $dayKey % 2 === 0 ? ['location' => $personal->getId(), 'start' => '09:00', 'end' => '12:00'] : ['location' => $inClinic->getId(), 'start' => '16:00', 'end' => '20:00']; } $this->em->persist($this->newWeeklySchedule($doctor, $this->settingOf($days))); $this->em->flush(); $date = date('Y-m-d', strtotime('+3 days')); // شاخص روز در برنامه: ۰ شنبه است و date('w') یکشنبه را صفر می‌گیرد. $dayKey = ((int) date('w', strtotime($date)) + 1) % 7; $isOwn = $dayKey % 2 === 0; $personalSessions = $this->authJson('GET', "/api/v1/appointment-slots?doctor_uuid={$doctor->getUuid()}&date={$date}", $doctor->getUser())['data']['sessions']; $clinicSessions = $this->authJson('GET', "/api/v1/appointment-slots?doctor_uuid={$doctor->getUuid()}&date={$date}&clinic_uuid={$clinic->getUuid()}", $doctor->getUser())['data']['sessions']; if ($isOwn) { self::assertNotEmpty($personalSessions, 'روز مطب باید در محیط شخصی نوبت بدهد'); self::assertSame([], $clinicSessions, 'روز مطب نباید در کلینیک نوبت بدهد'); } else { self::assertSame([], $personalSessions, 'روز کلینیک نباید در مطب شخصی نوبت بدهد'); self::assertNotEmpty($clinicSessions, 'روز کلینیک باید در محیط کلینیک نوبت بدهد'); } } }