'دکتر تست ایمپورت', 'medical_system_code' => $code, 'source_ref' => 'https://membersearch.irimc.org/member/profile?id=test', 'gender' => 'man', 'degree' => 'general', 'info' => 'دکترای حرفه‌ای پزشکی', ]; } /** db_test is never reset — randomise the natural key per run. */ private function freshCode(): string { return 'T' . random_int(100_000, 999_999) . random_int(100, 999); } public function testImportCreatesUnclaimedDoctorWithSurrogateUser(): void { $admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']); $code = $this->freshCode(); $data = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $this->importPayload($code)); $this->assertSame(201, $this->responseCode()); $this->assertTrue($data['success']); $this->assertTrue($data['data']['created']); $this->assertNotEmpty($data['data']['uuid']); $doctor = $this->em->getRepository(Doctor::class)->findOneBy(['uuid' => $data['data']['uuid']]); $this->assertSame('unclaimed', $doctor->getOwnerStatus()); $this->assertSame('irimc', $doctor->getSource()); $this->assertFalse($doctor->isActiveDoctorAppointment()); $surrogate = $doctor->getUser(); $this->assertStringStartsWith('imp_', $surrogate->getMobileNumber()); $this->assertSame(0, $surrogate->getStatus()); $this->assertTrue($surrogate->hasRole('ROLE_UNCLAIMED_DOCTOR')); } public function testReimportUpdatesInsteadOfDuplicating(): void { $admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']); $code = $this->freshCode(); $first = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $this->importPayload($code)); $this->assertSame(201, $this->responseCode()); $payload = $this->importPayload($code); $payload['name'] = 'دکتر تست ویرایش‌شده'; $second = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $payload); $this->assertSame(200, $this->responseCode()); $this->assertFalse($second['data']['created']); $this->assertSame($first['data']['uuid'], $second['data']['uuid']); $count = $this->em->getRepository(Doctor::class)->count(['source' => 'irimc', 'medicalSystemCode' => $code]); $this->assertSame(1, $count); $this->em->clear(); $doctor = $this->em->getRepository(Doctor::class)->findOneBy(['uuid' => $first['data']['uuid']]); $this->assertSame('دکتر تست ویرایش‌شده', $doctor->getName()); } public function testClaimedDoctorIsNeverOverwritten(): void { $admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']); $code = $this->freshCode(); $created = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $this->importPayload($code)); $uuid = $created['data']['uuid']; $doctor = $this->em->getRepository(Doctor::class)->findOneBy(['uuid' => $uuid]); $owner = $this->createUser(['ROLE_USER', 'ROLE_DOCTOR']); $doctor->transferOwnershipTo($owner); $this->em->flush(); $originalName = $doctor->getName(); $payload = $this->importPayload($code); $payload['name'] = 'دکتر بازنویسی ممنوع'; $reimport = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $payload); $this->assertSame(200, $this->responseCode()); $this->assertSame('claimed', $reimport['data']['skipped']); $this->em->clear(); $doctor = $this->em->getRepository(Doctor::class)->findOneBy(['uuid' => $uuid]); $this->assertSame($originalName, $doctor->getName()); $this->assertSame('claimed', $doctor->getOwnerStatus()); } public function testValidationErrors(): void { $admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']); $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, ['medical_system_code' => $this->freshCode()]); $this->assertSame(422, $this->responseCode()); $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, ['name' => 'دکتر بی‌کد']); $this->assertSame(422, $this->responseCode()); } public function testNonAdminIsRejected(): void { $user = $this->createUser(['ROLE_USER']); $this->authJson('POST', '/api/v1/admin/doctors/import', $user, $this->importPayload($this->freshCode())); $this->assertSame(403, $this->responseCode()); } public function testImporterRoleCanImportButNothingElse(): void { $importer = $this->createUser(['ROLE_USER', 'ROLE_IMPORTER']); $this->authJson('POST', '/api/v1/admin/doctors/import', $importer, $this->importPayload($this->freshCode())); $this->assertSame(201, $this->responseCode(), 'ROLE_IMPORTER must be able to import'); $this->authJson('GET', '/api/v1/admin/users', $importer); $this->assertSame(403, $this->responseCode(), 'ROLE_IMPORTER must NOT reach other admin endpoints'); $this->authJson('GET', '/api/v1/admin/doctor-claims', $importer); $this->assertSame(403, $this->responseCode()); } }