getContent(), true) ?? []; $type = trim($data['type'] ?? ''); $name = trim($data['name'] ?? ''); $mobile = trim($data['mobile'] ?? ''); $info = trim($data['info'] ?? '') ?: null; $validTypes = [ PreRegistration::TYPE_INDEPENDENT_DOCTOR, PreRegistration::TYPE_DOCTOR_WITH_CLINIC, PreRegistration::TYPE_CLINIC_MANAGER, ]; if (!in_array($type, $validTypes, true)) { return $this->error(ErrorCodes::ERR_VALIDATION_001, 'نوع حساب معتبر نیست', 422); } if (mb_strlen($mobile) < 10 || mb_strlen($mobile) > 15) { return $this->error(ErrorCodes::ERR_VALIDATION_001, 'شماره موبایل معتبر نیست', 422); } if (mb_strlen($name) < 2) { return $this->error(ErrorCodes::ERR_VALIDATION_001, 'نام الزامی است', 422); } if ($this->preRegRepo->hasPendingForMobile($mobile)) { return $this->error(ErrorCodes::DUPLICATE_REQUEST, 'درخواست ثبت‌نام شما در حال بررسی است', 409); } $preReg = new PreRegistration($type, $name, $mobile, $info); $this->em->persist($preReg); $this->em->flush(); return $this->success(['uuid' => $preReg->getUuid(), 'status' => $preReg->getStatus()], 201); } #[Route('/api/v1/admin/pre-registrations', methods: ['GET'])] #[IsGranted('ROLE_ADMIN')] public function list(Request $request): JsonResponse { $page = max(1, (int) $request->query->get('page', 1)); $limit = min(50, max(1, (int) $request->query->get('limit', 20))); $status = $request->query->get('status', 'pending'); $qb = $this->em->createQueryBuilder() ->select('p.uuid, p.type, p.name, p.mobile, p.info, p.status, p.adminNote AS admin_note, p.createdAt AS created_at') ->from(PreRegistration::class, 'p'); if ($status !== 'all') { $qb->where('p.status = :status')->setParameter('status', $status); } $total = (clone $qb)->select('COUNT(p.id)')->getQuery()->getSingleScalarResult(); $items = $qb ->orderBy('p.createdAt', 'DESC') ->setFirstResult(($page - 1) * $limit) ->setMaxResults($limit) ->getQuery() ->getArrayResult(); return $this->paginated($items, (int) $total, $page, $limit); } #[Route('/api/v1/admin/pre-registrations/{uuid}/approve', methods: ['POST'])] #[IsGranted('ROLE_ADMIN')] public function approve(string $uuid): JsonResponse { $preReg = $this->preRegRepo->findOneBy(['uuid' => $uuid]); if (!$preReg) { return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'درخواست یافت نشد', 404); } if (!$preReg->isPending()) { return $this->error(ErrorCodes::ERR_CONFLICT_001, 'این درخواست قبلاً پردازش شده است', 409); } $password = bin2hex(random_bytes(4)); $user = $this->userRepo->findOneBy(['mobileNumber' => $preReg->getMobile()]); if (!$user) { $user = new User($preReg->getMobile()); } $user->setPasswordHash($this->hasher->hashPassword($user, $password)); $user->setRealName($preReg->getName()); $this->em->persist($user); $type = $preReg->getType(); $doctor = null; if ($type === PreRegistration::TYPE_INDEPENDENT_DOCTOR || $type === PreRegistration::TYPE_DOCTOR_WITH_CLINIC) { $user->addRole('ROLE_DOCTOR'); $doctor = $this->doctorRepo->findOneBy(['user' => $user]); if (!$doctor) { $doctor = new Doctor($user, $preReg->getName()); $doctor->setMobileNumber($preReg->getMobile()); $this->em->persist($doctor); } } if ($type === PreRegistration::TYPE_DOCTOR_WITH_CLINIC || $type === PreRegistration::TYPE_CLINIC_MANAGER) { $user->addRole('ROLE_CLINIC'); if (!$this->clinicRepo->findOneBy(['user' => $user])) { $clinic = new Clinic($user); $clinic->setName($preReg->getName()); $clinic->setTelephone($preReg->getMobile()); $clinic->setNotificationMobile($preReg->getMobile()); if ($doctor !== null) { $clinic->getDoctors()->add($doctor); } $this->em->persist($clinic); } } $preReg->approve(); $this->em->flush(); try { $this->sms->dispatchTemplate( \App\Sms\Entity\SmsLog::TAG_PRE_REGISTRATION, $preReg->getMobile(), [ 'username' => $preReg->getMobile(), 'password' => $password, 'link' => rtrim($this->appUrl, '/') . '/admin', ], ); } catch (\Throwable $e) { $this->logger->warning('PreRegistration SMS failed', ['uuid' => $uuid, 'error' => $e->getMessage()]); } return $this->success(['message' => 'تأیید شد و اطلاعات ورود ارسال گردید']); } #[Route('/api/v1/admin/pre-registrations/{uuid}/reject', methods: ['POST'])] #[IsGranted('ROLE_ADMIN')] public function reject(string $uuid, Request $request): JsonResponse { $preReg = $this->preRegRepo->findOneBy(['uuid' => $uuid]); if (!$preReg) { return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'درخواست یافت نشد', 404); } if (!$preReg->isPending()) { return $this->error(ErrorCodes::ERR_CONFLICT_001, 'این درخواست قبلاً پردازش شده است', 409); } $data = json_decode($request->getContent(), true) ?? []; $preReg->reject($data['note'] ?? null); $this->em->flush(); return $this->success(['message' => 'درخواست رد شد']); } }