feat(doctor): ensure default office address creation during doctor import

This commit is contained in:
hamed
2026-07-11 19:21:24 +03:30
parent 1508d38daa
commit 6c67d522ba
3 changed files with 108 additions and 0 deletions
+16
View File
@@ -75,6 +75,22 @@
---
## آدرس پیش‌فرض (مطب)
هر پزشک ایمپورت‌شده **همیشه دست‌کم یک آدرس** (`doctor_addresses`، type=`personal`) دارد:
- اگر پزشک هیچ آدرسی نداشته باشد، یک آدرس با نام **«مطب دکتر {نام}»** ساخته می‌شود و
شهر/استان آن از **اولین** عنصر آرایه‌های `cities`/`states` همان درخواست پر می‌شود.
- در ایمپورت مجدد آدرس تکراری ساخته نمی‌شود؛ فقط فیلدهای **خالیِ** آدرس موجود
(نام/شهر/استان) backfill می‌شوند — مقادیر ویرایش‌شده توسط کاربر بازنویسی نمی‌شوند.
- اگر `cities`/`states` در درخواست نباشند، آدرس فقط با نام ساخته می‌شود (کرالر در حالت
auto همیشه هر دو را می‌فرستد).
(تست‌ها: `DoctorImportTest::testImportCreatesDefaultOfficeAddressWithCityAndProvince`،
`testImportWithoutLocationStillCreatesOfficeAddress`)
---
## Response
### `201 Created` (ساخته شد)
@@ -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 باشد دست نمی‌خورد؛ اگر آرایه باشد، پاک و از نو پر می‌شود.
+57
View File
@@ -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']);