createUser(['ROLE_DOCTOR']); $doctor = new Doctor($owner, 'دکتر'); $this->em->persist($doctor); $this->em->flush(); $appointment = new Appointment($doctor, $this->createUser(), time() + 86_400, time() + 86_400 + 1_800); $this->em->persist($appointment); $this->em->flush(); return [$owner, $doctor, $appointment]; } public function testUpdatesWorkflowFields(): void { [$owner, $doctor, $appointment] = $this->booking(); $section = new ServiceSection('doctor', $doctor->getId(), 'زیبایی'); $item = new ServiceItem($section, 'لیزر توتال'); $staff = new ClinicStaff('doctor', $doctor->getId(), 'سحر ایمانی'); $this->em->persist($section); $this->em->persist($item); $this->em->persist($staff); $this->em->flush(); $res = $this->authJson('PATCH', '/api/v1/appointment/' . $appointment->getUuid(), $owner, [ 'service_section_uuid' => $section->getUuid(), 'service_item_uuid' => $item->getUuid(), 'staff_uuid' => $staff->getUuid(), 'deposit_required' => true, 'deposit_amount_rials' => 5_000_000, 'note' => 'یادداشت', 'patient_name' => 'مریم خلیلی', ]); self::assertSame(200, $this->responseCode()); $d = $res['data']['data']; self::assertSame('زیبایی', $d['service_section']['name']); self::assertSame('لیزر توتال', $d['service_item']['name']); self::assertSame('سحر ایمانی', $d['staff']['full_name']); self::assertTrue($d['deposit_required']); self::assertSame('مریم خلیلی', $d['patient_name']); } public function testRescheduleMovesSlot(): void { [$owner, , $appointment] = $this->booking(); $newStart = time() + 2 * 86_400; $res = $this->authJson('PATCH', '/api/v1/appointment/' . $appointment->getUuid(), $owner, [ 'slot_start' => $newStart, 'slot_end' => $newStart + 1_800, ]); self::assertSame(200, $this->responseCode()); self::assertSame($newStart, $res['data']['data']['slot_start']); } public function testRescheduleRejectsTakenSlot(): void { [$owner, $doctor, $appointment] = $this->booking(); $otherStart = time() + 3 * 86_400; $this->em->persist(new Appointment($doctor, $this->createUser(), $otherStart, $otherStart + 1_800)); $this->em->flush(); $this->authJson('PATCH', '/api/v1/appointment/' . $appointment->getUuid(), $owner, [ 'slot_start' => $otherStart, 'slot_end' => $otherStart + 1_800, ]); self::assertSame(409, $this->responseCode()); } public function testTransferToReserveAndBack(): void { [$owner, , $appointment] = $this->booking(); $day = strtotime('tomorrow midnight'); $res = $this->authJson('PATCH', '/api/v1/appointment/' . $appointment->getUuid(), $owner, [ 'is_reserve' => true, 'slot_start' => $day, 'slot_end' => $day, ]); self::assertSame(200, $this->responseCode()); self::assertTrue($res['data']['data']['is_reserve']); $back = time() + 4 * 86_400; $version = $res['data']['data']['version']; $res2 = $this->authJson('PATCH', '/api/v1/appointment/' . $appointment->getUuid(), $owner, [ 'is_reserve' => false, 'slot_start' => $back, 'slot_end' => $back + 1_800, 'version' => $version, ]); self::assertSame(200, $this->responseCode()); self::assertFalse($res2['data']['data']['is_reserve']); } public function testRejectsHalfSlotPair(): void { [$owner, , $appointment] = $this->booking(); $this->authJson('PATCH', '/api/v1/appointment/' . $appointment->getUuid(), $owner, [ 'slot_start' => time() + 86_400, ]); self::assertSame(422, $this->responseCode()); } public function testForbiddenForStranger(): void { [, , $appointment] = $this->booking(); $stranger = $this->createUser(['ROLE_DOCTOR']); $this->authJson('PATCH', '/api/v1/appointment/' . $appointment->getUuid(), $stranger, ['note' => 'x']); self::assertSame(403, $this->responseCode()); } public function testUnknownStaffUuidIs422(): void { [$owner, , $appointment] = $this->booking(); $this->authJson('PATCH', '/api/v1/appointment/' . $appointment->getUuid(), $owner, [ 'staff_uuid' => 'no-such-uuid', ]); self::assertSame(422, $this->responseCode()); } }