From 6c67d522baa71da87d5c1987e9954c7242d9b9cb Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Sat, 11 Jul 2026 19:21:24 +0330 Subject: [PATCH] feat(doctor): ensure default office address creation during doctor import --- docs/api/doctor-import.md | 16 ++++++ src/Doctor/Service/DoctorImportService.php | 35 +++++++++++++ tests/Doctor/DoctorImportTest.php | 57 ++++++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/docs/api/doctor-import.md b/docs/api/doctor-import.md index e6bc1da6..7403bdbc 100644 --- a/docs/api/doctor-import.md +++ b/docs/api/doctor-import.md @@ -75,6 +75,22 @@ --- +## آدرس پیش‌فرض (مطب) + +هر پزشک ایمپورت‌شده **همیشه دست‌کم یک آدرس** (`doctor_addresses`، type=`personal`) دارد: + +- اگر پزشک هیچ آدرسی نداشته باشد، یک آدرس با نام **«مطب دکتر {نام}»** ساخته می‌شود و + شهر/استان آن از **اولین** عنصر آرایه‌های `cities`/`states` همان درخواست پر می‌شود. +- در ایمپورت مجدد آدرس تکراری ساخته نمی‌شود؛ فقط فیلدهای **خالیِ** آدرس موجود + (نام/شهر/استان) backfill می‌شوند — مقادیر ویرایش‌شده توسط کاربر بازنویسی نمی‌شوند. +- اگر `cities`/`states` در درخواست نباشند، آدرس فقط با نام ساخته می‌شود (کرالر در حالت + auto همیشه هر دو را می‌فرستد). + +(تست‌ها: `DoctorImportTest::testImportCreatesDefaultOfficeAddressWithCityAndProvince`، +`testImportWithoutLocationStillCreatesOfficeAddress`) + +--- + ## Response ### `201 Created` (ساخته شد) diff --git a/src/Doctor/Service/DoctorImportService.php b/src/Doctor/Service/DoctorImportService.php index 7d184308..13c7800a 100644 --- a/src/Doctor/Service/DoctorImportService.php +++ b/src/Doctor/Service/DoctorImportService.php @@ -4,6 +4,7 @@ namespace App\Doctor\Service; use App\Auth\Entity\User; use App\Doctor\Entity\Doctor; +use App\Doctor\Entity\DoctorAddress; use App\Location\Entity\City; use App\Location\Entity\Province; use App\Specialty\Entity\Specialty; @@ -106,6 +107,8 @@ class DoctorImportService $this->syncRefCollection($doctor->getProvinces(), $data['states'] ?? null, Province::class); $this->syncRefCollection($doctor->getCities(), $data['cities'] ?? null, City::class); + $this->ensureDefaultAddress($doctor, $name, $data); + $this->em->persist($doctor); $this->em->flush(); @@ -113,6 +116,38 @@ class DoctorImportService }); } + /** + * هر پزشک ایمپورت‌شده باید دست‌کم یک آدرس «مطب دکتر …» با شهر و استان داشته باشد. + * اگر آدرسی ندارد می‌سازد؛ فیلدهای خالیِ آدرس موجود را backfill می‌کند و + * مقادیر واردشده توسط کاربر را بازنویسی نمی‌کند. + */ + private function ensureDefaultAddress(Doctor $doctor, string $name, array $data): void + { + $city = !empty($data['cities']) + ? $this->em->getRepository(City::class)->find((int) $data['cities'][0]) + : null; + $province = !empty($data['states']) + ? $this->em->getRepository(Province::class)->find((int) $data['states'][0]) + : null; + + $address = $doctor->getAddresses()->first() ?: null; + if ($address === null) { + $address = DoctorAddress::forDoctor($doctor); + $doctor->getAddresses()->add($address); + $this->em->persist($address); + } + + if ($address->getName() === null || $address->getName() === '') { + $address->setName('مطب دکتر ' . $name); + } + if ($address->getCity() === null && $city !== null) { + $address->setCity($city); + } + if ($address->getProvince() === null && $province !== null) { + $address->setProvince($province); + } + } + /** * یک مجموعهٔ ManyToMany پزشک را با آرایه‌ای از شناسه‌های مرجع همگام می‌کند. * اگر $ids null باشد دست نمی‌خورد؛ اگر آرایه باشد، پاک و از نو پر می‌شود. diff --git a/tests/Doctor/DoctorImportTest.php b/tests/Doctor/DoctorImportTest.php index eb602f0e..cd9dde43 100644 --- a/tests/Doctor/DoctorImportTest.php +++ b/tests/Doctor/DoctorImportTest.php @@ -3,6 +3,8 @@ namespace App\Tests\Doctor; use App\Doctor\Entity\Doctor; +use App\Location\Entity\City; +use App\Location\Entity\Province; use App\Tests\ApiTestCase; /** @@ -107,6 +109,61 @@ class DoctorImportTest extends ApiTestCase $this->assertSame('claimed', $doctor->getOwnerStatus()); } + public function testImportCreatesDefaultOfficeAddressWithCityAndProvince(): void + { + $admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']); + $code = $this->freshCode(); + + $province = new Province('استان تست ' . $code); + $city = new City('شهر تست ' . $code, $province); + $this->em->persist($province); + $this->em->persist($city); + $this->em->flush(); + + $payload = $this->importPayload($code); + $payload['states'] = [$province->getId()]; + $payload['cities'] = [$city->getId()]; + + $data = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $payload); + $this->assertSame(201, $this->responseCode()); + + $cityId = $city->getId(); + $provinceId = $province->getId(); + $this->em->clear(); + $doctor = $this->em->getRepository(Doctor::class)->findOneBy(['uuid' => $data['data']['uuid']]); + $this->assertCount(1, $doctor->getAddresses()); + $address = $doctor->getAddresses()->first(); + $this->assertSame('مطب دکتر صفورا حجازی نیا', $address->getName()); + $this->assertSame($cityId, $address->getCity()?->getId()); + $this->assertSame($provinceId, $address->getProvince()?->getId()); + + // ایمپورت مجدد نباید آدرس تکراری بسازد یا نام آدرس را بازنویسی کند + $address->setName('مطب ویرایش‌شده توسط کاربر'); + $this->em->flush(); + + $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $payload); + $this->assertSame(200, $this->responseCode()); + + $this->em->clear(); + $doctor = $this->em->getRepository(Doctor::class)->findOneBy(['uuid' => $data['data']['uuid']]); + $this->assertCount(1, $doctor->getAddresses()); + $this->assertSame('مطب ویرایش‌شده توسط کاربر', $doctor->getAddresses()->first()->getName()); + } + + public function testImportWithoutLocationStillCreatesOfficeAddress(): 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->em->clear(); + $doctor = $this->em->getRepository(Doctor::class)->findOneBy(['uuid' => $data['data']['uuid']]); + $this->assertCount(1, $doctor->getAddresses()); + $this->assertSame('مطب دکتر صفورا حجازی نیا', $doctor->getAddresses()->first()->getName()); + } + public function testValidationErrors(): void { $admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']);