From 3e8126c5201cb79b0933b541899e4375743e510d Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Thu, 16 Jul 2026 09:57:03 +0330 Subject: [PATCH] fix: return patient national code from profile in patients list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit National code is stored on the profiles table, not users, so the patients search returned null user_national_code for patients that actually have one — which blocked selecting an existing patient on the appointment create form. Backfill user_national_code from the profile (batch query) in the list endpoint. On the create page, show a picked patient's stored national code read-only and only prompt for input when the record genuinely lacks one. Add backend tests and update docs/api/patient.md. Co-Authored-By: Claude Opus 4.8 (1M context) --- assets/admin/pages/AppointmentCreatePage.tsx | 19 ++++-- docs/api/patient.md | 10 +++- src/Patient/Controller/PatientController.php | 18 ++++-- .../Repository/UserProfileRepository.php | 25 ++++++++ tests/Patient/PatientListNationalCodeTest.php | 59 +++++++++++++++++++ 5 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 tests/Patient/PatientListNationalCodeTest.php diff --git a/assets/admin/pages/AppointmentCreatePage.tsx b/assets/admin/pages/AppointmentCreatePage.tsx index 97178a50..b61546b2 100644 --- a/assets/admin/pages/AppointmentCreatePage.tsx +++ b/assets/admin/pages/AppointmentCreatePage.tsx @@ -217,11 +217,20 @@ export default function AppointmentCreatePage() { - -
- -
+ {/^\d{10}$/.test((picked.user_national_code ?? '').replace(/\D/g, '')) ? ( +
+ کد ملی + {nationalCode} +
+ ) : ( + <> + +
+ +
+ + )} )} diff --git a/docs/api/patient.md b/docs/api/patient.md index 366a216f..1f950f70 100644 --- a/docs/api/patient.md +++ b/docs/api/patient.md @@ -45,9 +45,13 @@ Returns a paginated list of patient records belonging to the authenticated entit "uuid": "...", "entity_type": "doctor", "entity_id": 5, - "user": { "uuid": "...", "fullName": "علی رضایی", "phone": "09123456789" }, + "user_uuid": "...", + "user_name": "علی رضایی", + "user_mobile": "09123456789", + "user_national_code": "0012345675", + "record_number": "1024", + "tags": [], "created_by_type": "doctor", - "created_by_id": 5, "created_at": 1718375000 } ], @@ -59,6 +63,8 @@ Returns a paginated list of patient records belonging to the authenticated entit } ``` +> `user_national_code` منبعِ حقیقتش جدول `profiles` است (نه `users`). اگر روی خودِ کاربر خالی باشد، از پروفایل پر می‌شود؛ اگر هیچ‌کدام نداشته باشند `null` است. + **Errors:** | Code | HTTP | Description | diff --git a/src/Patient/Controller/PatientController.php b/src/Patient/Controller/PatientController.php index e02edc44..591efae4 100644 --- a/src/Patient/Controller/PatientController.php +++ b/src/Patient/Controller/PatientController.php @@ -542,12 +542,18 @@ class PatientController extends BaseController $records = $this->recordRepo->findByEntity($entityType, $entityId, $page, $limit, $search, $filters); $total = $this->recordRepo->countByEntity($entityType, $entityId, $search, $filters); - return $this->paginated( - array_map(fn(PatientRecord $r) => $r->toArray(), $records), - $total, - $page, - $limit - ); + // کد ملی روی profiles ذخیره می‌شود نه users؛ اگر روی user خالی بود از پروفایل پر کن. + $userIds = array_map(fn(PatientRecord $r) => $r->getUser()->getId(), $records); + $profileCodes = $this->profileRepo->nationalCodesByUserIds($userIds); + $rows = array_map(function (PatientRecord $r) use ($profileCodes) { + $row = $r->toArray(); + if (empty($row['user_national_code'])) { + $row['user_national_code'] = $profileCodes[$r->getUser()->getId()] ?? null; + } + return $row; + }, $records); + + return $this->paginated($rows, $total, $page, $limit); } #[Route('/api/v1/patient', methods: ['POST'])] diff --git a/src/UserProfile/Repository/UserProfileRepository.php b/src/UserProfile/Repository/UserProfileRepository.php index 86a4b3ae..06cc6c35 100644 --- a/src/UserProfile/Repository/UserProfileRepository.php +++ b/src/UserProfile/Repository/UserProfileRepository.php @@ -29,6 +29,31 @@ class UserProfileRepository extends ServiceEntityRepository return $this->findOneBy(['nationalCode' => $nationalCode]); } + /** + * نگاشتِ userId → کد ملیِ ذخیره‌شده روی پروفایل، فقط برای پروفایل‌هایی که کد ملی دارند. + * برای پر کردنِ گروهیِ کد ملی در لیست بیماران (کد ملی روی profiles است نه users). + * + * @param int[] $userIds + * @return array + */ + public function nationalCodesByUserIds(array $userIds): array + { + if ($userIds === []) { + return []; + } + $rows = $this->createQueryBuilder('p') + ->select('IDENTITY(p.user) AS uid', 'p.nationalCode AS nc') + ->where('p.user IN (:ids)')->setParameter('ids', $userIds) + ->andWhere('p.nationalCode IS NOT NULL') + ->getQuery()->getArrayResult(); + + $map = []; + foreach ($rows as $r) { + $map[(int) $r['uid']] = (string) $r['nc']; + } + return $map; + } + public function save(UserProfile $profile, bool $flush = true): void { $this->getEntityManager()->persist($profile); diff --git a/tests/Patient/PatientListNationalCodeTest.php b/tests/Patient/PatientListNationalCodeTest.php new file mode 100644 index 00000000..5175ddc6 --- /dev/null +++ b/tests/Patient/PatientListNationalCodeTest.php @@ -0,0 +1,59 @@ +createUser(['ROLE_DOCTOR']); + $doctor = new Doctor($owner, 'دکتر تست'); + $this->em->persist($doctor); + $this->em->flush(); + + return [$owner, $doctor]; + } + + public function testNationalCodeFromProfileIsReturned(): void + { + [$owner, $doctor] = $this->doctor(); + + $patient = $this->createUser(['ROLE_USER']); + // کد ملی فقط روی پروفایل، نه روی خود کاربر + $profile = new UserProfile($patient); + $profile->setNationalCode('0012345675'); + $this->em->persist($profile); + + $record = new PatientRecord('doctor', $doctor->getId(), $patient, 'doctor', $doctor->getId()); + $this->em->persist($record); + $this->em->flush(); + + $res = $this->authJson('GET', '/api/v1/patients', $owner); + self::assertSame(200, $this->responseCode()); + self::assertSame($record->getUuid(), $res['data'][0]['uuid']); + self::assertSame('0012345675', $res['data'][0]['user_national_code']); + } + + public function testNullWhenNoNationalCodeAnywhere(): void + { + [$owner, $doctor] = $this->doctor(); + + $patient = $this->createUser(['ROLE_USER']); + $record = new PatientRecord('doctor', $doctor->getId(), $patient, 'doctor', $doctor->getId()); + $this->em->persist($record); + $this->em->flush(); + + $res = $this->authJson('GET', '/api/v1/patients', $owner); + self::assertSame(200, $this->responseCode()); + self::assertNull($res['data'][0]['user_national_code']); + } +}