feat(doctor): prevent duplicate doctor imports based on medical system code
This commit is contained in:
@@ -39,6 +39,10 @@
|
|||||||
- اگر وجود داشته باشد و `owner_status != claimed` → **بهروزرسانی** میشود (`200`).
|
- اگر وجود داشته باشد و `owner_status != claimed` → **بهروزرسانی** میشود (`200`).
|
||||||
- اگر وجود داشته باشد و `owner_status == claimed` → **رد** میشود (`200`, `skipped: "claimed"`)
|
- اگر وجود داشته باشد و `owner_status == claimed` → **رد** میشود (`200`, `skipped: "claimed"`)
|
||||||
تا دادهٔ مالک واقعی بازنویسی نشود.
|
تا دادهٔ مالک واقعی بازنویسی نشود.
|
||||||
|
- **تکرار بین منابع:** اگر پزشکی با همان `medical_system_code` ولی `source` متفاوت
|
||||||
|
(مثلاً ثبت دستی در پنل) وجود داشته باشد → **رد** میشود (`200`, `skipped: "duplicate"`)؛
|
||||||
|
نه رکورد جدیدی ساخته میشود و نه رکورد موجود بازنویسی میشود. `uuid` همان رکورد موجود
|
||||||
|
برگردانده میشود (تست: `DoctorImportTest::testManualDoctorWithSameCodeIsNeverDuplicated`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -108,6 +112,11 @@
|
|||||||
{ "success": true, "data": { "uuid": "…", "created": false, "skipped": "claimed" } }
|
{ "success": true, "data": { "uuid": "…", "created": false, "skipped": "claimed" } }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `200 OK` (رد بهدلیل کد نظام پزشکی تکراری با منبع دیگر)
|
||||||
|
```json
|
||||||
|
{ "success": true, "data": { "uuid": "…", "created": false, "skipped": "duplicate" } }
|
||||||
|
```
|
||||||
|
|
||||||
### `422` (اعتبارسنجی)
|
### `422` (اعتبارسنجی)
|
||||||
```json
|
```json
|
||||||
{ "success": false, "data": null, "errors": [ { "code": "…", "message": "کد نظام پزشکی الزامی است", "field": "medical_system_code" } ] }
|
{ "success": false, "data": null, "errors": [ { "code": "…", "message": "کد نظام پزشکی الزامی است", "field": "medical_system_code" } ] }
|
||||||
|
|||||||
@@ -65,6 +65,15 @@ class DoctorImportService
|
|||||||
return new DoctorImportResult($doctor, false, 'claimed');
|
return new DoctorImportResult($doctor, false, 'claimed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($doctor === null) {
|
||||||
|
// جلوگیری از تکرار بین منابع: اگر همین کد نظام پزشکی با هر source دیگری
|
||||||
|
// (مثلاً ثبت دستی) وجود دارد، ایمپورت نه میسازد و نه بازنویسی میکند.
|
||||||
|
$existing = $doctorRepo->findOneBy(['medicalSystemCode' => $code]);
|
||||||
|
if ($existing !== null) {
|
||||||
|
return new DoctorImportResult($existing, false, 'duplicate');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($doctor === null) {
|
if ($doctor === null) {
|
||||||
// کاربر جانشینِ یکتا و غیرفعال؛ شناسهٔ مصنوعی قطعی از روی کد نظام پزشکی
|
// کاربر جانشینِ یکتا و غیرفعال؛ شناسهٔ مصنوعی قطعی از روی کد نظام پزشکی
|
||||||
$synthetic = 'imp_' . substr(md5($source . ':' . $code), 0, 14); // ≤ ۱۸ کاراکتر، ASCII، یکتا
|
$synthetic = 'imp_' . substr(md5($source . ':' . $code), 0, 14); // ≤ ۱۸ کاراکتر، ASCII، یکتا
|
||||||
|
|||||||
@@ -164,6 +164,32 @@ class DoctorImportTest extends ApiTestCase
|
|||||||
$this->assertSame('مطب دکتر صفورا حجازی نیا', $doctor->getAddresses()->first()->getName());
|
$this->assertSame('مطب دکتر صفورا حجازی نیا', $doctor->getAddresses()->first()->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testManualDoctorWithSameCodeIsNeverDuplicated(): void
|
||||||
|
{
|
||||||
|
$admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']);
|
||||||
|
$code = $this->freshCode();
|
||||||
|
|
||||||
|
$owner = $this->createUser(['ROLE_USER', 'ROLE_DOCTOR']);
|
||||||
|
$manual = new Doctor($owner, 'پزشک دستی');
|
||||||
|
$manual->setMedicalSystemCode($code);
|
||||||
|
$this->em->persist($manual);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$data = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $this->importPayload($code));
|
||||||
|
|
||||||
|
$this->assertSame(200, $this->responseCode());
|
||||||
|
$this->assertFalse($data['data']['created']);
|
||||||
|
$this->assertSame('duplicate', $data['data']['skipped']);
|
||||||
|
$this->assertSame($manual->getUuid(), $data['data']['uuid']);
|
||||||
|
|
||||||
|
$this->em->clear();
|
||||||
|
$count = $this->em->getRepository(Doctor::class)->count(['medicalSystemCode' => $code]);
|
||||||
|
$this->assertSame(1, $count);
|
||||||
|
$doctor = $this->em->getRepository(Doctor::class)->findOneBy(['medicalSystemCode' => $code]);
|
||||||
|
$this->assertSame('پزشک دستی', $doctor->getName());
|
||||||
|
$this->assertSame('manual', $doctor->getSource());
|
||||||
|
}
|
||||||
|
|
||||||
public function testValidationErrors(): void
|
public function testValidationErrors(): void
|
||||||
{
|
{
|
||||||
$admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']);
|
$admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']);
|
||||||
|
|||||||
Reference in New Issue
Block a user