Both permission forms in the admin panel can now render from the backend registry instead of their own hardcoded lists. Resources come back as an array so display order is part of the contract, each carrying its Persian label, its actions, and the clinic_only flag that used to live in the frontend. contextPermissions() normalizes the no-row branch through the registry too, so a doctor whose permission row was never provisioned sees the same shape as one who has it. Two existing assertions compared the API response against DEFAULT_PERMISSIONS by identity. The values are unchanged; only key order moved to the registry's, so both now compare through PermissionCatalog::merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
164 lines
6.6 KiB
PHP
164 lines
6.6 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Secretary;
|
|
|
|
use App\Doctor\Entity\Doctor;
|
|
use App\Tests\ApiTestCase;
|
|
|
|
/**
|
|
* Covers the national_code / address fields and the extended permission
|
|
* taxonomy (patients, payments) on the secretary create/update endpoints.
|
|
*/
|
|
class SecretaryFieldsTest extends ApiTestCase
|
|
{
|
|
/** @return array{0: \App\Auth\Entity\User, 1: Doctor} */
|
|
private function makeDoctor(): array
|
|
{
|
|
$owner = $this->createUser(['ROLE_DOCTOR']);
|
|
$doctor = new Doctor($owner, 'دکتر تست');
|
|
$this->em->persist($doctor);
|
|
$this->em->flush();
|
|
|
|
return [$owner, $doctor];
|
|
}
|
|
|
|
public function testCreatePersistsNationalCodeAddressAndExtendedPermissions(): void
|
|
{
|
|
[$owner, $doctor] = $this->makeDoctor();
|
|
$mobile = '09' . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT);
|
|
|
|
$res = $this->authJson('POST', '/api/v1/secretary', $owner, [
|
|
'doctor_uuid' => $doctor->getUuid(),
|
|
'mobile_number' => $mobile,
|
|
'name' => 'سارا احمدی',
|
|
'national_code' => '1234567890',
|
|
'address' => 'یزد، خیابان تست',
|
|
'permissions' => [
|
|
'version' => 1,
|
|
'resources' => [
|
|
'patients' => ['view' => true, 'create' => true],
|
|
'payments' => ['view' => true],
|
|
],
|
|
],
|
|
]);
|
|
|
|
$this->assertSame(201, $this->responseCode());
|
|
$data = $res['data']['data'] ?? $res['data'];
|
|
$this->assertSame('1234567890', $data['national_code']);
|
|
$this->assertSame('یزد، خیابان تست', $data['address']);
|
|
$this->assertTrue($data['permissions']['patients']['view']);
|
|
$this->assertTrue($data['permissions']['patients']['create']);
|
|
$this->assertTrue($data['permissions']['payments']['view']);
|
|
}
|
|
|
|
public function testCreateWithoutOptionalFieldsPersistsNulls(): void
|
|
{
|
|
[$owner, $doctor] = $this->makeDoctor();
|
|
$mobile = '09' . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT);
|
|
|
|
$res = $this->authJson('POST', '/api/v1/secretary', $owner, [
|
|
'doctor_uuid' => $doctor->getUuid(),
|
|
'mobile_number' => $mobile,
|
|
'name' => 'بدون کدملی',
|
|
]);
|
|
|
|
$this->assertSame(201, $this->responseCode());
|
|
$data = $res['data']['data'] ?? $res['data'];
|
|
$this->assertNull($data['national_code']);
|
|
$this->assertNull($data['address']);
|
|
}
|
|
|
|
public function testUpdateChangesNameNationalCodeAddressAndPermissions(): void
|
|
{
|
|
[$owner, $doctor] = $this->makeDoctor();
|
|
$mobile = '09' . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT);
|
|
|
|
$created = $this->authJson('POST', '/api/v1/secretary', $owner, [
|
|
'doctor_uuid' => $doctor->getUuid(),
|
|
'mobile_number' => $mobile,
|
|
'name' => 'نام اولیه',
|
|
]);
|
|
$uuid = ($created['data']['data'] ?? $created['data'])['uuid'];
|
|
|
|
$res = $this->authJson('PATCH', '/api/v1/secretary/' . $uuid, $owner, [
|
|
'name' => 'نام جدید',
|
|
'national_code' => '9999999999',
|
|
'address' => 'آدرس جدید',
|
|
'permissions' => [
|
|
'version' => 1,
|
|
'resources' => ['appointments' => ['create' => false]],
|
|
],
|
|
]);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$data = $res['data']['data'] ?? $res['data'];
|
|
$this->assertSame('نام جدید', $data['user_name']);
|
|
$this->assertSame('9999999999', $data['national_code']);
|
|
$this->assertSame('آدرس جدید', $data['address']);
|
|
$this->assertFalse($data['permissions']['appointments']['create']);
|
|
}
|
|
|
|
public function testCreateRequiresDoctorUuidAndMobile(): void
|
|
{
|
|
[$owner] = $this->makeDoctor();
|
|
|
|
$this->authJson('POST', '/api/v1/secretary', $owner, ['name' => 'ناقص']);
|
|
|
|
$this->assertSame(422, $this->responseCode());
|
|
}
|
|
/**
|
|
* صفحهٔ ادمین نقشهٔ تخت میفرستد — بدون envelope. تا پیش از رجیستری، کنترلر
|
|
* آن را میپذیرفت ولی Entity فقط $patch['resources'] را میخواند، پس ویرایش
|
|
* دسترسی بیصدا هیچ اثری نداشت.
|
|
*/
|
|
public function testUpdateAcceptsFlatPermissionMapFromAdminPage(): void
|
|
{
|
|
[$owner, $doctor] = $this->makeDoctor();
|
|
$mobile = '09' . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT);
|
|
|
|
$created = $this->authJson('POST', '/api/v1/secretary', $owner, [
|
|
'doctor_uuid' => $doctor->getUuid(),
|
|
'mobile_number' => $mobile,
|
|
'name' => 'منشی تخت',
|
|
]);
|
|
$uuid = ($created['data']['data'] ?? $created['data'])['uuid'];
|
|
|
|
$res = $this->authJson('PATCH', "/api/v1/secretary/{$uuid}", $owner, [
|
|
'permissions' => ['staff' => ['view' => true, 'create' => true]],
|
|
]);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$perms = ($res['data']['data'] ?? $res['data'])['permissions'];
|
|
$this->assertTrue($perms['staff']['view']);
|
|
$this->assertTrue($perms['staff']['create']);
|
|
$this->assertTrue($perms['appointments']['view'], 'بقیهٔ منابع نباید دست بخورند');
|
|
}
|
|
|
|
/** منشی تا پیش از این هیچ اعتبارسنجی نداشت و هر کلیدی را ذخیره میکرد. */
|
|
public function testUpdateDropsResourcesOutsideTheRegistry(): void
|
|
{
|
|
[$owner, $doctor] = $this->makeDoctor();
|
|
$mobile = '09' . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT);
|
|
|
|
$created = $this->authJson('POST', '/api/v1/secretary', $owner, [
|
|
'doctor_uuid' => $doctor->getUuid(),
|
|
'mobile_number' => $mobile,
|
|
'name' => 'منشی ناشناخته',
|
|
]);
|
|
$uuid = ($created['data']['data'] ?? $created['data'])['uuid'];
|
|
|
|
$res = $this->authJson('PATCH', "/api/v1/secretary/{$uuid}", $owner, [
|
|
'permissions' => ['resources' => [
|
|
'ghost_resource' => ['view' => true],
|
|
'tags' => ['view' => true],
|
|
]],
|
|
]);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$perms = ($res['data']['data'] ?? $res['data'])['permissions'];
|
|
$this->assertArrayNotHasKey('ghost_resource', $perms);
|
|
$this->assertTrue($perms['tags']['view']);
|
|
}
|
|
|
|
}
|