feat(profile): enforce uniqueness of national_code across user profiles and update related error handling
This commit is contained in:
@@ -145,6 +145,19 @@ class PatientController extends BaseController
|
||||
$patient = $this->userRepo->findByMobile($mobile);
|
||||
}
|
||||
|
||||
// کد ملی باید در سطح بیمار یکتا باشد: اگر به پروفایلِ کاربر دیگری تعلق دارد، رد کن
|
||||
if ($nationalCode !== '') {
|
||||
$owner = $this->profileRepo->findOneByNationalCode($nationalCode);
|
||||
if ($owner !== null && ($patient === null || $owner->getUser()->getId() !== $patient->getId())) {
|
||||
return $this->error(
|
||||
ErrorCodes::ERR_PROFILE_NATIONAL_CODE_TAKEN,
|
||||
'این کد ملی قبلاً برای کاربر دیگری ثبت شده است',
|
||||
409,
|
||||
'national_code'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// بیمار جدید بدون ثبتنام قبلی: موبایل + نام آمده ولی کاربری وجود ندارد
|
||||
if ($patient === null) {
|
||||
if ($mobile === '' || $name === '') {
|
||||
|
||||
@@ -63,6 +63,9 @@ class ErrorCodes
|
||||
public const ERR_PATIENT_NOT_FOUND = 'ERR_PATIENT_NOT_FOUND';
|
||||
public const ERR_SESSION_NOT_FOUND = 'ERR_SESSION_NOT_FOUND';
|
||||
|
||||
// Profile
|
||||
public const ERR_PROFILE_NATIONAL_CODE_TAKEN = 'ERR_PROFILE_001';
|
||||
|
||||
// SMS Wallet
|
||||
public const ERR_SMS_WALLET_INSUFFICIENT = 'ERR_SMS_WALLET_INSUFFICIENT';
|
||||
|
||||
@@ -106,6 +109,7 @@ class ErrorCodes
|
||||
self::ERR_SERVICE_ITEM_IN_USE => 'این سرویس در پرونده بیمار ثبت شده است',
|
||||
self::ERR_SERVICE_NOT_FOUND => 'سرویس یافت نشد',
|
||||
self::ERR_PATIENT_NOT_FOUND => 'پرونده بیمار یافت نشد',
|
||||
self::ERR_PROFILE_NATIONAL_CODE_TAKEN => 'این کد ملی قبلاً برای کاربر دیگری ثبت شده است',
|
||||
self::ERR_SESSION_NOT_FOUND => 'مراجعه یافت نشد',
|
||||
self::ERR_SMS_WALLET_INSUFFICIENT => 'موجودی کیف پیامک کافی نیست',
|
||||
self::ERR_RATING_NOT_ELIGIBLE => 'برای ثبت نظر یا امتیاز باید در یک ماه گذشته نوبت تاییدشده نزد این پزشک داشته باشید',
|
||||
|
||||
@@ -91,6 +91,11 @@ class UserProfileController extends BaseController
|
||||
}
|
||||
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
|
||||
if ($error = $this->guardNationalCode($data, null)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$profile = new UserProfile($user);
|
||||
$this->hydrate($profile, $data);
|
||||
$this->repository->save($profile);
|
||||
@@ -131,12 +136,8 @@ class UserProfileController extends BaseController
|
||||
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
|
||||
if (array_key_exists('national_code', $data) && $data['national_code'] !== null && $data['national_code'] !== '') {
|
||||
$code = InputValidator::toEnglishDigits((string) $data['national_code']);
|
||||
if (!InputValidator::isValidIranNationalCode($code)) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'کد ملی نامعتبر است', 422, 'national_code');
|
||||
}
|
||||
$data['national_code'] = $code;
|
||||
if ($error = $this->guardNationalCode($data, $profile)) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$this->hydrate($profile, $data);
|
||||
@@ -202,6 +203,36 @@ class UserProfileController extends BaseController
|
||||
|| $currentUser->hasRole('ROLE_ADMIN');
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize, format-validate and uniqueness-check national_code in $data.
|
||||
* Mutates $data['national_code'] to the latin-digit form. Returns an error
|
||||
* response if invalid or already taken by another profile, otherwise null.
|
||||
*/
|
||||
private function guardNationalCode(array &$data, ?UserProfile $current): ?JsonResponse
|
||||
{
|
||||
if (!array_key_exists('national_code', $data) || $data['national_code'] === null || $data['national_code'] === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$code = InputValidator::toEnglishDigits((string) $data['national_code']);
|
||||
if (!InputValidator::isValidIranNationalCode($code)) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'کد ملی نامعتبر است', 422, 'national_code');
|
||||
}
|
||||
$data['national_code'] = $code;
|
||||
|
||||
$existing = $this->repository->findOneByNationalCode($code);
|
||||
if ($existing !== null && ($current === null || $existing->getUuid() !== $current->getUuid())) {
|
||||
return $this->error(
|
||||
ErrorCodes::ERR_PROFILE_NATIONAL_CODE_TAKEN,
|
||||
'این کد ملی قبلاً برای کاربر دیگری ثبت شده است',
|
||||
409,
|
||||
'national_code'
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function hydrate(UserProfile $profile, array $data): void
|
||||
{
|
||||
if (array_key_exists('name', $data)) $profile->setLabel($data['name']);
|
||||
|
||||
@@ -9,7 +9,7 @@ use Symfony\Component\Uid\Uuid;
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'profiles')]
|
||||
#[ORM\UniqueConstraint(name: 'idx_profiles_user', columns: ['user_id'])]
|
||||
#[ORM\Index(columns: ['national_code'], name: 'idx_profiles_national_code')]
|
||||
#[ORM\UniqueConstraint(name: 'uniq_profiles_national_code', columns: ['national_code'])]
|
||||
class UserProfile
|
||||
{
|
||||
#[ORM\Id]
|
||||
|
||||
@@ -24,6 +24,11 @@ class UserProfileRepository extends ServiceEntityRepository
|
||||
return $this->findOneBy(['uuid' => $uuid]);
|
||||
}
|
||||
|
||||
public function findOneByNationalCode(string $nationalCode): ?UserProfile
|
||||
{
|
||||
return $this->findOneBy(['nationalCode' => $nationalCode]);
|
||||
}
|
||||
|
||||
public function save(UserProfile $profile, bool $flush = true): void
|
||||
{
|
||||
$this->getEntityManager()->persist($profile);
|
||||
|
||||
Reference in New Issue
Block a user