- Added SecretaryAccessChecker to manage resource access for secretaries. - Integrated permission checks for payments, inventory, and tags in relevant controllers. - Updated PaymentController and PaymentMethodController to enforce secretary permissions. - Enhanced TenantTagController to check permissions for tag management actions. - Introduced tests for secretary resource enforcement, ensuring proper access control. - Updated DoctorSecretary entity to include inventory and tags permissions. - Created a comprehensive audit document for secretary permissions coverage and enforcement. - Fixed potential crashes in SecretaryDashboard when rendering without doctor data.
228 lines
8.4 KiB
PHP
228 lines
8.4 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\PaymentMethod;
|
|
|
|
use App\Tests\ApiTestCase;
|
|
|
|
/**
|
|
* Functional coverage for the per-clinic payment methods API
|
|
* (bank accounts + POS devices). Success, error and boundary cases.
|
|
*/
|
|
class PaymentMethodTest extends ApiTestCase
|
|
{
|
|
// ---- Bank accounts -----------------------------------------------------
|
|
|
|
public function testEmptyBankAccountListForNewClinic(): void
|
|
{
|
|
$user = $this->createUser(['ROLE_CLINIC']);
|
|
|
|
$res = $this->authJson('GET', '/api/v1/my/payment-methods/bank-accounts', $user);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$this->assertTrue($res['success']);
|
|
$this->assertSame([], $res['data']);
|
|
}
|
|
|
|
public function testCreateAndListBankAccount(): void
|
|
{
|
|
$user = $this->createUser(['ROLE_CLINIC']);
|
|
|
|
$created = $this->authJson('POST', '/api/v1/my/payment-methods/bank-accounts', $user, [
|
|
'bank_name' => 'ملی',
|
|
'card_number' => '6037991234567890',
|
|
'account_number' => '0101234567890',
|
|
'shaba_number' => 'IR820540102680020817909002',
|
|
]);
|
|
|
|
$this->assertSame(201, $this->responseCode());
|
|
$this->assertSame('ملی', $created['data']['bank_name']);
|
|
$this->assertTrue($created['data']['is_active']);
|
|
$this->assertNotEmpty($created['data']['uuid']);
|
|
|
|
$list = $this->authJson('GET', '/api/v1/my/payment-methods/bank-accounts', $user);
|
|
$this->assertCount(1, $list['data']);
|
|
$this->assertSame('0101234567890', $list['data'][0]['account_number']);
|
|
}
|
|
|
|
public function testCreateBankAccountValidationErrorWhenBankNameMissing(): void
|
|
{
|
|
$user = $this->createUser(['ROLE_CLINIC']);
|
|
|
|
$res = $this->authJson('POST', '/api/v1/my/payment-methods/bank-accounts', $user, [
|
|
'account_number' => '0101234567890',
|
|
]);
|
|
|
|
$this->assertSame(422, $this->responseCode());
|
|
$this->assertFalse($res['success']);
|
|
$this->assertSame('bank_name', $res['errors'][0]['field']);
|
|
}
|
|
|
|
public function testUpdateBankAccount(): void
|
|
{
|
|
$user = $this->createUser(['ROLE_CLINIC']);
|
|
$created = $this->authJson('POST', '/api/v1/my/payment-methods/bank-accounts', $user, [
|
|
'bank_name' => 'ملی',
|
|
'account_number' => '0101234567890',
|
|
]);
|
|
$uuid = $created['data']['uuid'];
|
|
|
|
$updated = $this->authJson('PUT', "/api/v1/my/payment-methods/bank-accounts/$uuid", $user, [
|
|
'bank_name' => 'ملت',
|
|
'account_number' => '0209876543210',
|
|
]);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$this->assertSame('ملت', $updated['data']['bank_name']);
|
|
$this->assertSame('0209876543210', $updated['data']['account_number']);
|
|
}
|
|
|
|
public function testToggleBankAccountStatus(): void
|
|
{
|
|
$user = $this->createUser(['ROLE_CLINIC']);
|
|
$created = $this->authJson('POST', '/api/v1/my/payment-methods/bank-accounts', $user, [
|
|
'bank_name' => 'ملی',
|
|
'account_number' => '0101234567890',
|
|
]);
|
|
$uuid = $created['data']['uuid'];
|
|
$this->assertTrue($created['data']['is_active']);
|
|
|
|
$toggled = $this->authJson('PATCH', "/api/v1/my/payment-methods/bank-accounts/$uuid/status", $user);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$this->assertFalse($toggled['data']['is_active']);
|
|
}
|
|
|
|
public function testToggleUnknownBankAccountReturns404(): void
|
|
{
|
|
$user = $this->createUser(['ROLE_CLINIC']);
|
|
|
|
$res = $this->authJson('PATCH', '/api/v1/my/payment-methods/bank-accounts/does-not-exist/status', $user);
|
|
|
|
$this->assertSame(404, $this->responseCode());
|
|
$this->assertFalse($res['success']);
|
|
}
|
|
|
|
public function testCannotTouchAnotherClinicsBankAccount(): void
|
|
{
|
|
$owner = $this->createUser(['ROLE_CLINIC']);
|
|
$other = $this->createUser(['ROLE_CLINIC']);
|
|
$created = $this->authJson('POST', '/api/v1/my/payment-methods/bank-accounts', $owner, [
|
|
'bank_name' => 'ملی',
|
|
'account_number' => '0101234567890',
|
|
]);
|
|
$uuid = $created['data']['uuid'];
|
|
|
|
$res = $this->authJson('PATCH', "/api/v1/my/payment-methods/bank-accounts/$uuid/status", $other);
|
|
|
|
$this->assertSame(404, $this->responseCode());
|
|
$this->assertFalse($res['success']);
|
|
}
|
|
|
|
public function testBankAccountForbiddenForPlainUser(): void
|
|
{
|
|
$user = $this->createUser(['ROLE_USER']);
|
|
|
|
$this->authJson('GET', '/api/v1/my/payment-methods/bank-accounts', $user);
|
|
|
|
$this->assertSame(403, $this->responseCode());
|
|
}
|
|
|
|
// ---- POS devices -------------------------------------------------------
|
|
|
|
public function testCreateAndListPos(): void
|
|
{
|
|
$user = $this->createUser(['ROLE_DOCTOR']);
|
|
|
|
$created = $this->authJson('POST', '/api/v1/my/payment-methods/pos', $user, [
|
|
'bank_name' => 'ملت',
|
|
'serial_number' => 'SN-98765',
|
|
'terminal_number' => '123456',
|
|
]);
|
|
|
|
$this->assertSame(201, $this->responseCode());
|
|
$this->assertSame('ملت', $created['data']['bank_name']);
|
|
$this->assertSame('123456', $created['data']['terminal_number']);
|
|
$this->assertTrue($created['data']['is_active']);
|
|
|
|
$list = $this->authJson('GET', '/api/v1/my/payment-methods/pos', $user);
|
|
$this->assertCount(1, $list['data']);
|
|
}
|
|
|
|
public function testCreatePosValidationErrorWhenTerminalMissing(): void
|
|
{
|
|
$user = $this->createUser(['ROLE_DOCTOR']);
|
|
|
|
$res = $this->authJson('POST', '/api/v1/my/payment-methods/pos', $user, [
|
|
'bank_name' => 'ملت',
|
|
]);
|
|
|
|
$this->assertSame(422, $this->responseCode());
|
|
$this->assertSame('terminal_number', $res['errors'][0]['field']);
|
|
}
|
|
|
|
public function testTogglePosStatus(): void
|
|
{
|
|
// منشی به روشهای پرداخت فقط با مجوز payments از طریق رابطهٔ فعال دسترسی دارد.
|
|
$user = $this->createSecretaryWithPayments(['view' => true, 'create' => true, 'update' => true]);
|
|
$created = $this->authJson('POST', '/api/v1/my/payment-methods/pos', $user, [
|
|
'bank_name' => 'تجارت',
|
|
'terminal_number' => '345678',
|
|
]);
|
|
$uuid = $created['data']['uuid'];
|
|
|
|
$toggled = $this->authJson('PATCH', "/api/v1/my/payment-methods/pos/$uuid/status", $user);
|
|
|
|
$this->assertSame(200, $this->responseCode());
|
|
$this->assertFalse($toggled['data']['is_active']);
|
|
}
|
|
|
|
public function testSecretaryWithoutPaymentsPermissionCannotManagePos(): void
|
|
{
|
|
$user = $this->createSecretaryWithPayments(['view' => false, 'create' => false, 'update' => false]);
|
|
|
|
$this->authJson('POST', '/api/v1/my/payment-methods/pos', $user, [
|
|
'bank_name' => 'تجارت',
|
|
'terminal_number' => '345678',
|
|
]);
|
|
|
|
$this->assertSame(403, $this->responseCode());
|
|
}
|
|
|
|
/** منشی با رابطهٔ فعالِ کلینیک + context + مجوز payments مشخص. */
|
|
private function createSecretaryWithPayments(array $payments): \App\Auth\Entity\User
|
|
{
|
|
$owner = $this->createUser(['ROLE_CLINIC']);
|
|
$clinic = new \App\Clinic\Entity\Clinic($owner);
|
|
$this->em->persist($clinic);
|
|
|
|
$doctor = new \App\Doctor\Entity\Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر تست');
|
|
$this->em->persist($doctor);
|
|
$clinic->getDoctors()->add($doctor);
|
|
|
|
$secretary = $this->createUser(['ROLE_SECRETARY']);
|
|
$rel = new \App\Secretary\Entity\DoctorSecretary(
|
|
$doctor, $secretary, \App\Secretary\Entity\DoctorSecretary::OWNER_CLINIC, $clinic
|
|
);
|
|
$rel->mergePermissions(['resources' => ['payments' => $payments]]);
|
|
$this->em->persist($rel);
|
|
$this->em->persist(new \App\Auth\Entity\UserActiveContext($secretary, $clinic->getUuid()));
|
|
$this->em->flush();
|
|
|
|
return $secretary;
|
|
}
|
|
|
|
public function testPosListIsolatedPerUser(): void
|
|
{
|
|
$a = $this->createUser(['ROLE_CLINIC']);
|
|
$b = $this->createUser(['ROLE_CLINIC']);
|
|
$this->authJson('POST', '/api/v1/my/payment-methods/pos', $a, [
|
|
'bank_name' => 'صادرات',
|
|
'terminal_number' => '901234',
|
|
]);
|
|
|
|
$listB = $this->authJson('GET', '/api/v1/my/payment-methods/pos', $b);
|
|
|
|
$this->assertSame([], $listB['data']);
|
|
}
|
|
}
|