Files
clinicpro/tests/Patient/RecordNumberOnCreateTest.php
T
hamed 85a27812c7 feat(patient): implement record number pattern management
- Add RecordNumberSettingsController for managing patient record number patterns.
- Create RecordNumberPattern entity to represent the pattern configuration.
- Implement RecordNumberPatternRepository for database interactions.
- Develop RecordNumberGenerator service for generating and validating record numbers.
- Add tests for record number generation, backfilling, and API interactions.
- Ensure proper access control for viewing and updating patterns based on user roles.
2026-08-04 12:30:17 +03:30

140 lines
5.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Tests\Patient;
use App\Auth\Entity\User;
use App\Auth\Entity\UserActiveContext;
use App\Clinic\Entity\Clinic;
use App\Doctor\Entity\Doctor;
use App\Patient\Entity\RecordNumberPattern;
use App\Secretary\Entity\DoctorSecretary;
use App\Tests\ApiTestCase;
/**
* شمارهٔ پرونده هنگام ساختِ پرونده از الگو ساخته می‌شود — و ورودِ دستی فقط از
* صاحب مجموعه پذیرفته می‌شود.
*/
class RecordNumberOnCreateTest extends ApiTestCase
{
/** @return array{0: User, 1: Clinic, 2: Doctor} */
private function clinicWithPattern(?string $pattern = 'MD-{SEQ:4}', bool $enabled = true): array
{
$owner = $this->createUser(['ROLE_CLINIC']);
$clinic = new Clinic($owner);
$this->em->persist($clinic);
$doctor = new Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر عضو');
$this->em->persist($doctor);
$clinic->getDoctors()->add($doctor);
$this->em->persist(new UserActiveContext($owner, $clinic->getUuid(), 'clinic'));
$this->em->flush();
if ($pattern !== null) {
$row = new RecordNumberPattern('clinic', $clinic->getId());
$row->setPattern($pattern)->setResetPolicy(RecordNumberPattern::RESET_NONE)->setEnabled($enabled);
$this->em->persist($row);
$this->em->flush();
}
// فیچرِ `patient_records` از پلنِ «free» می‌آید که ApiTestCase تضمینش می‌کند.
return [$owner, $clinic, $doctor];
}
private function createPatientPayload(string $suffix): array
{
return [
'mobile' => '0912' . str_pad((string) random_int(0, 9_999_999), 7, '0', STR_PAD_LEFT),
'name' => 'بیمار ' . $suffix,
'national_code' => (string) random_int(1_000_000_000, 9_999_999_999),
];
}
/** ✅ موفق: بدون فرستادن شماره، سرور از الگو می‌سازد و دنباله جلو می‌رود. */
public function testCreateGeneratesSequentialNumbers(): void
{
[$owner] = $this->clinicWithPattern();
$first = $this->authJson('POST', '/api/v1/patient', $owner, $this->createPatientPayload('الف'));
self::assertSame(201, $this->responseCode());
self::assertSame('MD-0001', $first['data']['record_number']);
$second = $this->authJson('POST', '/api/v1/patient', $owner, $this->createPatientPayload('ب'));
self::assertSame('MD-0002', $second['data']['record_number']);
}
/** ⚠️ مرزی: بدون الگوی فعال، رفتار امروز حفظ می‌شود (شمارهٔ دستی، برای همه). */
public function testWithoutPatternTheManualNumberStillWins(): void
{
[$owner] = $this->clinicWithPattern(null);
$res = $this->authJson('POST', '/api/v1/patient', $owner, [
...$this->createPatientPayload('ج'),
'record_number' => 'کاغذی-77',
]);
self::assertSame(201, $this->responseCode());
self::assertSame('کاغذی-77', $res['data']['record_number']);
}
/** ✅ موفق: صاحب مجموعه می‌تواند خارج از دنباله شماره بگذارد. */
public function testOwnerMayOverrideTheGeneratedNumber(): void
{
[$owner] = $this->clinicWithPattern();
$res = $this->authJson('POST', '/api/v1/patient', $owner, [
...$this->createPatientPayload('د'),
'record_number' => 'ARCHIVE-1',
]);
self::assertSame(201, $this->responseCode());
self::assertSame('ARCHIVE-1', $res['data']['record_number']);
}
/** ❌ خطا: منشی حق ورود دستی ندارد — نه در ساخت، نه در ویرایش. */
public function testSecretaryCannotSetTheNumberManually(): void
{
[, $clinic, $doctor] = $this->clinicWithPattern();
$secretary = $this->createUser(['ROLE_SECRETARY']);
$rel = new DoctorSecretary($doctor, $secretary, $clinic);
$rel->mergePermissions(['resources' => ['patients' => ['view' => true, 'create' => true, 'update' => true]]]);
$this->em->persist($rel);
$this->em->persist(new UserActiveContext($secretary, $clinic->getUuid(), 'clinic'));
$this->em->flush();
$this->authJson('POST', '/api/v1/patient', $secretary, [
...$this->createPatientPayload('ه'),
'record_number' => 'HAND-9',
]);
self::assertSame(403, $this->responseCode());
// بدون شمارهٔ دستی همان منشی می‌تواند پرونده بسازد و شماره از الگو می‌آید.
$ok = $this->authJson('POST', '/api/v1/patient', $secretary, $this->createPatientPayload('و'));
self::assertSame(201, $this->responseCode());
self::assertSame('MD-0001', $ok['data']['record_number']);
}
/** ⚠️ مرزی: پروندهٔ خودکارِ نوبت هم در همان دنباله می‌نشیند. */
public function testAutoCreatedRecordFromAppointmentGetsANumber(): void
{
[, $clinic, $doctor] = $this->clinicWithPattern();
$patient = $this->createUser(['ROLE_USER']);
$patient->setRealName('بیمار نوبت');
$this->em->flush();
$appointment = new \App\Appointment\Entity\Appointment($doctor, $patient, time() + 3_600, time() + 5_400);
$appointment->setClinic($clinic);
$appointment->assignTenant(\App\Shared\Context\EntityContext::forBooking($doctor, $clinic));
$this->em->persist($appointment);
$this->em->flush();
$service = static::getContainer()->get(\App\Patient\Service\PatientService::class);
$session = $service->autoCreateOnAppointmentConfirm($appointment);
self::assertNotNull($session);
self::assertSame('MD-0001', $session->getRecord()->getRecordNumber());
}
}