- Extract import logic from AdminApiController into DoctorImportService (thin DoctorImportController keeps the same route/contract) - Surrogate users get marker role ROLE_UNCLAIMED_DOCTOR (+ backfill command app:doctors:backfill-surrogate-role) enabling safe deletion after claim - DB-level UNIQUE (source, medical_system_code) + concurrent-import retry - Doctor profile claim flow (climed.md): shahkar + PersonInfo identity checks via existing ApiIrService, Persian name normalization (PersianText), pessimistic-lock race protection, DoctorClaimRequest audit table (national code hashed, mobile masked), doctor_claim rate limiter, public claim-info endpoint, welcome SMS - Admin support tools: manual transfer endpoint + paginated doctor-claims audit list + owner_status filter/fields in admin doctors list - Least privilege: system owner now gets ROLE_IMPORTER (ROLE_ADMIN stripped), import endpoint accepts ADMIN|IMPORTER, isStaff includes IMPORTER - Headless crawler login: X-Service-Token header bypasses captcha only (rate limit + password checks intact; empty env = no bypass) - docs: doctor-claim.md (new), doctor-import.md, admin.md, doctor.md - tests: DoctorImportTest (6), DoctorClaimTest (11), PersianTextTest (5) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 lines
1.3 KiB
PHP
38 lines
1.3 KiB
PHP
<?php
|
||
|
||
namespace App\Tests\Shared;
|
||
|
||
use App\Shared\Util\PersianText;
|
||
use PHPUnit\Framework\TestCase;
|
||
|
||
class PersianTextTest extends TestCase
|
||
{
|
||
public function testArabicYehAndKafAreUnified(): void
|
||
{
|
||
$this->assertTrue(PersianText::sameName("علي اكبري", 'علی اکبری'));
|
||
}
|
||
|
||
public function testHalfSpaceAndExtraWhitespace(): void
|
||
{
|
||
$this->assertTrue(PersianText::sameName("محمد\u{200C}رضا کریمی ", 'محمد رضا کریمی'));
|
||
}
|
||
|
||
public function testPersianAndArabicDigits(): void
|
||
{
|
||
$this->assertSame('1371/1/1', PersianText::normalize('۱۳۷۱/۱/۱'));
|
||
$this->assertSame('0912', PersianText::normalize('٠٩١٢'));
|
||
}
|
||
|
||
public function testStripDoctorTitle(): void
|
||
{
|
||
$this->assertSame('فرخنده حسینی', PersianText::stripDoctorTitle('دکتر فرخنده حسینی'));
|
||
$this->assertSame('فرخنده حسینی', PersianText::stripDoctorTitle(' دکتر فرخنده حسینی '));
|
||
$this->assertSame('فرخنده حسینی', PersianText::stripDoctorTitle('فرخنده حسینی'));
|
||
}
|
||
|
||
public function testDifferentNamesStayDifferent(): void
|
||
{
|
||
$this->assertFalse(PersianText::sameName('علی اکبری', 'ولی اکبری'));
|
||
}
|
||
}
|