feat: enhance doctor import process with source profile ID for improved idempotency and deduplication

This commit is contained in:
hamed
2026-07-19 20:19:35 +03:30
parent 74577c2ff6
commit e670b38821
11 changed files with 593 additions and 13 deletions
+63
View File
@@ -190,6 +190,69 @@ class DoctorImportTest extends ApiTestCase
$this->assertSame('manual', $doctor->getSource());
}
/** UUID تازه برای هر اجرا — یونیک‌ایندکس (source, source_profile_id) تکرار را رد می‌کند. */
private function freshProfileId(): string
{
return bin2hex(random_bytes(16)); // ۳۲ نویسهٔ hex، منطبق با استخراج‌کنندهٔ profile id
}
private function payloadWithProfile(string $code, string $profileId): array
{
$p = $this->importPayload($code);
$p['source_ref'] = "https://membersearch.irimc.org/member/profile?id=$profileId";
return $p;
}
public function testSameProfileIdWithDifferentCodeUpdatesInsteadOfDuplicating(): void
{
$admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']);
$profileId = $this->freshProfileId();
$code1 = $this->freshCode();
$code2 = $this->freshCode();
$first = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $this->payloadWithProfile($code1, $profileId));
$this->assertSame(201, $this->responseCode());
// همان پروفایل irimc، ولی کد نظام پزشکی متفاوت (نمایش دیگرِ همان پزشک)
$second = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $this->payloadWithProfile($code2, $profileId));
$this->assertSame(200, $this->responseCode());
$this->assertFalse($second['data']['created']);
$this->assertSame($first['data']['uuid'], $second['data']['uuid']);
$this->em->clear();
$count = $this->em->getRepository(Doctor::class)->count(['source' => 'irimc', 'sourceProfileId' => $profileId]);
$this->assertSame(1, $count, 'یک پروفایل نباید دو رکورد بسازد حتی با کد متفاوت');
$doctor = $this->em->getRepository(Doctor::class)->findOneBy(['sourceProfileId' => $profileId]);
$this->assertSame($code2, $doctor->getMedicalSystemCode(), 'کد باید به آخرین مقدار به‌روزرسانی شود');
}
public function testDifferentProfileIdsAreKeptSeparate(): void
{
$admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']);
// همان نام، ولی دو پروفایل متمایز irimc → دو رکورد، بدون ادغام خودکار
$a = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $this->payloadWithProfile($this->freshCode(), $this->freshProfileId()));
$this->assertSame(201, $this->responseCode());
$b = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $this->payloadWithProfile($this->freshCode(), $this->freshProfileId()));
$this->assertSame(201, $this->responseCode());
$this->assertTrue($b['data']['created']);
$this->assertNotSame($a['data']['uuid'], $b['data']['uuid']);
}
public function testProfileIdIsBackfilledFromSourceRefOnImport(): void
{
$admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']);
$profileId = $this->freshProfileId();
$data = $this->authJson('POST', '/api/v1/admin/doctors/import', $admin, $this->payloadWithProfile($this->freshCode(), $profileId));
$this->assertSame(201, $this->responseCode());
$this->em->clear();
$doctor = $this->em->getRepository(Doctor::class)->findOneBy(['uuid' => $data['data']['uuid']]);
$this->assertSame($profileId, $doctor->getSourceProfileId());
}
public function testValidationErrors(): void
{
$admin = $this->createUser(['ROLE_USER', 'ROLE_ADMIN']);