Files
FOSSBilling/tests-legacy/modules/Client/ServiceTest.php
T
Yağızhan Burak YakarandAdam Daley f2ccbf491a Permission system improvements and new permission keys (#3396)
* Decouple hide_permissions and can_always_access

* Introduce 13 new permission keys for Client and Hook

* Create a new `has_permission` function in Twig and start using it

* Created 5 new permission keys for Currency

* Remove unused logMock

* Implemented per-request caching for staff permissions

* Decouple hide_permissions and can_always_access

* Introduce 13 new permission keys for Client and Hook

* Create a new `has_permission` function in Twig and start using it

* Created 5 new permission keys for Currency

* Remove unused logMock

* Implemented per-request caching for staff permissions

* Created 3 new permission keys for System

* Return a more helpful exception message

* Make permission errors return HTTP 403 instead of 401

* Created 2 new permission keys for Redirect

* Renamed the keys to keep in line

* Fixed tests

* Add manage_settings permission key to Redirect

* Refactor API authentication flow and improve token handling

* Enforce `client.view` and refactor staff cache

---------

Co-authored-by: Adam Daley <admdly@users.noreply.github.com>
2026-04-15 18:36:58 +01:00

1180 lines
38 KiB
PHP

<?php
declare(strict_types=1);
namespace Box\Tests\Mod\Client;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
#[Group('Core')]
final class ServiceTest extends \BBTestCase
{
public function testGetDi(): void
{
$di = $this->getDi();
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$getDi = $service->getDi();
$this->assertEquals($di, $getDi);
}
public function testGetModulePermissions(): void
{
$service = new \Box\Mod\Client\Service();
$permissions = $service->getModulePermissions();
$this->assertArrayHasKey('create', $permissions);
$this->assertArrayHasKey('edit_profile', $permissions);
$this->assertArrayHasKey('impersonate_login', $permissions);
$this->assertArrayHasKey('manage_api_keys', $permissions);
$this->assertArrayHasKey('change_password', $permissions);
$this->assertArrayHasKey('manage_balance', $permissions);
$this->assertArrayHasKey('view_login_history', $permissions);
$this->assertArrayHasKey('manage_groups', $permissions);
$this->assertArrayHasKey('delete', $permissions);
$this->assertArrayHasKey('bulk_delete', $permissions);
$this->assertArrayHasKey('export', $permissions);
$this->assertArrayHasKey('manage_settings', $permissions);
}
public function testApproveClientEmailByHash(): void
{
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())
->method('getRow')->willReturn(['client_id' => 2, 'id' => 1]);
$database->expects($this->atLeastOnce())->method('exec');
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->approveClientEmailByHash('');
$this->assertTrue($result);
}
public function testApproveClientEmailByHashException(): void
{
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())
->method('getRow')->willReturn([]);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('Invalid email confirmation link');
$clientService->approveClientEmailByHash('');
}
public function testGenerateEmailConfirmationLink(): void
{
$model = new \Model_ExtensionMeta();
$model->loadBean(new \DummyBean());
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())
->method('dispense')->willReturn($model);
$database->expects($this->atLeastOnce())->method('store')
->willReturn(1);
$toolsMock = $this->createMock(\FOSSBilling\Tools::class);
$toolsMock->expects($this->atLeastOnce())->method('url')
->willReturn('fossbilling.org/index.php/client/confirm-email/');
$di = $this->getDi();
$di['db'] = $database;
$di['tools'] = $toolsMock;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$client_id = 1;
$result = $clientService->generateEmailConfirmationLink($client_id);
$this->assertIsString($result);
$this->assertTrue(str_contains($result, '/client/confirm-email/'));
}
public function testOnAfterClientSignUp(): void
{
$eventParams = [
'password' => 'testPassword',
'id' => 1,
];
$eventMock = $this->getMockBuilder('\Box_Event')->disableOriginalConstructor()->getMock();
$eventMock->expects($this->atLeastOnce())->
method('getParameters')->willReturn($eventParams);
$service = $this->createMock(\Box\Mod\Email\Service::class);
$service->expects($this->atLeastOnce())
->method('sendTemplate')
->willReturn(true);
$di = $this->getDi();
$di['mod_service'] = $di->protect(fn (): \PHPUnit\Framework\MockObject\MockObject => $service);
$di['mod_config'] = $di->protect(fn ($name): array => ['require_email_confirmation' => false]);
$eventMock->expects($this->atLeastOnce())
->method('getDi')
->willReturn($di);
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->onAfterClientSignUp($eventMock);
$this->assertTrue($result);
}
public function testRequireEmailConfirmonAfterClientSignUp(): void
{
$eventMock = $this->getMockBuilder('\Box_Event')->disableOriginalConstructor()->getMock();
$eventParams = [
'password' => 'testPassword',
'id' => 1,
'require_email_confirmation' => true,
];
$eventMock->expects($this->atLeastOnce())->
method('getParameters')->willReturn($eventParams);
$service = $this->createMock(\Box\Mod\Email\Service::class);
$service->expects($this->atLeastOnce())
->method('sendTemplate')
->willReturn(true);
$clientServiceMock = $this->getMockBuilder(\Box\Mod\Client\Service::class)->onlyMethods(['generateEmailConfirmationLink'])->getMock();
$clientServiceMock->expects($this->atLeastOnce())->
method('generateEmailConfirmationLink')->willReturn('Link_string');
$di = $this->getDi();
$di['mod_service'] = $di->protect(function ($serviceName) use ($service, $clientServiceMock) {
if ($serviceName == 'email') {
return $service;
}
if ($serviceName == 'client') {
return $clientServiceMock;
}
});
$di['mod_config'] = $di->protect(fn ($name): array => ['require_email_confirmation' => true]);
$eventMock->expects($this->atLeastOnce())
->method('getDi')
->willReturn($di);
$clientService = new \Box\Mod\Client\Service();
$result = $clientService->onAfterClientSignUp($eventMock);
$this->assertTrue($result);
}
public function testExceptiononAfterClientSignUp(): void
{
$eventParams = [
'password' => 'testPassword',
'id' => 1,
];
$eventMock = $this->getMockBuilder('\Box_Event')->disableOriginalConstructor()->getMock();
$eventMock->expects($this->atLeastOnce())->
method('getParameters')->willReturn($eventParams);
$service = $this->createMock(\Box\Mod\Email\Service::class);
$service->expects($this->atLeastOnce())->
method('sendTemplate')->will($this->throwException(new \Exception('exception created in unit test')));
$di = $this->getDi();
$di['mod_service'] = $di->protect(fn (): \PHPUnit\Framework\MockObject\MockObject => $service);
$di['mod_config'] = $di->protect(function ($name): void {
['require_email_confirmation' => false];
});
$eventMock->expects($this->atLeastOnce())
->method('getDi')
->willReturn($di);
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->onAfterClientSignUp($eventMock);
$this->assertTrue($result);
}
public static function searchQueryData(): array
{
return [
[[], 'SELECT c.*', []],
[
['id' => 1],
'(c.id = :client_id OR c.aid = :alt_client_id)',
[':client_id' => '', ':alt_client_id' => ''],
],
[
['name' => 'test'],
'(c.first_name LIKE :first_name or c.last_name LIKE :last_name )',
[':first_name' => '', ':last_name' => ''],
],
[
['email' => 'test@example.com'],
'c.email LIKE :email',
[':email' => 'test@example.com'],
],
[
['company' => 'LTD company'],
'c.company LIKE :company',
[':company' => 'LTD company'],
],
[
['status' => 'TEST status'],
'c.status = :status',
[':status' => 'TEST status'],
],
[
['group_id' => '1'],
'c.client_group_id = :group_id',
[':group_id' => '1'],
],
[
['created_at' => '2012-12-12'],
"DATE_FORMAT(c.created_at, '%Y-%m-%d') = :created_at",
[':created_at' => '2012-12-12'],
],
[
['date_from' => '2012-12-10'],
'UNIX_TIMESTAMP(c.created_at) >= :date_from',
[':date_from' => '2012-12-10'],
],
[
['date_to' => '2012-12-11'],
'UNIX_TIMESTAMP(c.created_at) <= :date_from',
[':date_to' => '2012-12-11'],
],
[
['search' => '2'],
'(c.id = :cid OR c.aid = :caid)',
[':cid' => '2', ':caid' => '2'],
],
[
['search' => 'Keyword'],
"c.company LIKE :s_company OR c.first_name LIKE :s_first_time OR c.last_name LIKE :s_last_name OR c.email LIKE :s_email OR CONCAT(c.first_name, ' ', c.last_name ) LIKE :full_name",
[':s_company' => 'Keyword',
':s_first_time' => 'Keyword',
':s_last_name' => 'Keyword',
':s_email' => 'Keyword',
':full_name' => 'Keyword',
],
],
];
}
#[DataProvider('searchQueryData')]
public function testGetSearchQuery(array $data, string $expectedStr, array $expectedParams): void
{
$clientService = new \Box\Mod\Client\Service();
$result = $clientService->getSearchQuery($data);
$this->assertIsString($result[0]);
$this->assertIsArray($result[1]);
$this->assertTrue(str_contains($result[0], $expectedStr), $result[0]);
$this->assertEquals([], array_diff_key($result[1], $expectedParams));
}
public function testGetSearchQueryChangeSelect(): void
{
$data = [];
$selectStmt = 'c.id, CONCAT(c.first_name, c.last_name) as full_name';
$clientService = new \Box\Mod\Client\Service();
$result = $clientService->getSearchQuery($data, $selectStmt);
$this->assertIsString($result[0]);
$this->assertIsArray($result[1]);
$this->assertTrue(str_contains($result[0], $selectStmt), $result[0]);
}
public function testGetPairs(): void
{
$data = [];
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())->method('getAssoc')
->willReturn([]);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->getPairs($data);
$this->assertIsArray($result);
}
public function testToSessionArray(): void
{
$expectedArrayKeys = [
'id' => 1,
'email' => 'email@example.com',
'name' => 'John Smith',
'role' => 'admin',
];
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$clientService = new \Box\Mod\Client\Service();
$result = $clientService->toSessionArray($model);
$this->assertIsArray($result);
$this->assertEquals([], array_diff_key($result, $expectedArrayKeys));
}
public function testEmailAlreadyRegistered(): void
{
$email = 'test@example.com';
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())->method('findOne')
->willReturn($model);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->emailAlreadyRegistered($email);
$this->assertIsBool($result);
}
public function testEmailAlreadyRegWithModel(): void
{
$email = 'test@example.com';
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$model->email = $email;
$clientService = new \Box\Mod\Client\Service();
$result = $clientService->emailAlreadyRegistered($email, $model);
$this->assertIsBool($result);
$this->assertFalse($result);
}
public function testCanChangeCurrency(): void
{
$currency = 'EUR';
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$model->currency = 'USD';
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())->method('findOne')
->willReturn(null);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->canChangeCurrency($model, $currency);
$this->assertIsBool($result);
$this->assertTrue($result);
}
public function testCanChangeCurrencyModelCurrencyNotSet(): void
{
$currency = 'EUR';
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$database = $this->createMock('\Box_Database');
$database->expects($this->never())->method('findOne');
$clientService = new \Box\Mod\Client\Service();
$result = $clientService->canChangeCurrency($model, $currency);
$this->assertIsBool($result);
$this->assertTrue($result);
}
public function testCanChangeCurrencyIdenticalCurrencies(): void
{
$currency = 'EUR';
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$model->currency = $currency;
$database = $this->createMock('\Box_Database');
$database->expects($this->never())->method('findOne');
$clientService = new \Box\Mod\Client\Service();
$result = $clientService->canChangeCurrency($model, $currency);
$this->assertIsBool($result);
$this->assertFalse($result);
}
public function testCanChangeCurrencyHasInvoice(): void
{
$currency = 'EUR';
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$model->id = 1;
$model->currency = 'USD';
$invoiceModel = new \Model_Invoice();
$invoiceModel->loadBean(new \DummyBean());
$database = $this->createMock('\Box_Database');
$database->expects($this->once())
->method('findOne')
->willReturn($invoiceModel);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('Currency cannot be changed. Client already has invoices issued.');
$clientService->canChangeCurrency($model, $currency);
}
/* Disabled due to the random PHPUnit failures
public function testCanChangeCurrencyHasOrder(): void
{
$currency = 'EUR';
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$model->id = 1;
$model->currency = 'USD';
$clientOrderModel = new \Model_ClientOrder();
$clientOrderModel->loadBean(new \DummyBean());
$database = $this->createMock('\Box_Database');
$database->expects($this->exactly(2))->method('findOne')
->willReturnOnConsecutiveCalls(null, null);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$clientService->canChangeCurrency($model, $currency);
}
*/
public static function searchBalanceQueryData(): array
{
return [
[[], 'FROM client_balance as m', []],
[
['id' => 1],
'm.id = :id',
[':id' => '1'],
],
[
['client_id' => 1],
'm.client_id = :client_id',
[':client_id' => '1'],
],
[
['date_from' => '2012-12-10'],
'm.created_at >= :date_from',
[':date_from' => '2012-12-10'],
],
[
['date_to' => '2012-12-11'],
'm.created_at <= :date_to',
[':date_to' => '2012-12-11'],
],
];
}
#[DataProvider('searchBalanceQueryData')]
public function testGetBalanceSearchQuery(array $data, string $expectedStr, array $expectedParams): void
{
$di = $this->getDi();
$clientBalanceService = new \Box\Mod\Client\ServiceBalance();
$clientBalanceService->setDi($di);
[$sql, $params] = $clientBalanceService->getSearchQuery($data);
$this->assertNotEmpty($sql);
$this->assertIsString($sql);
$this->assertIsArray($params);
$this->assertTrue(str_contains($sql, $expectedStr), $sql);
$this->assertEquals([], array_diff_key($params, $expectedParams));
}
public function testAddFunds(): void
{
$modelClient = new \Model_Client();
$modelClient->loadBean(new \DummyBean());
$modelClient->currency = 'USD';
$model = new \Model_ClientBalance();
$model->loadBean(new \DummyBean());
$amount = '2.22';
$description = 'test description';
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())->method('dispense')
->willReturn($model);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->addFunds($modelClient, $amount, $description);
$this->assertTrue($result);
}
public function testAddFundsCurrencyNotDefined(): void
{
$modelClient = new \Model_Client();
$modelClient->loadBean(new \DummyBean());
$amount = '2.22';
$description = 'test description';
$clientService = new \Box\Mod\Client\Service();
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('You must define the client\'s currency before adding funds.');
$clientService->addFunds($modelClient, $amount, $description);
}
public function testAddFundsAmountMissing(): void
{
$modelClient = new \Model_Client();
$modelClient->loadBean(new \DummyBean());
$modelClient->currency = 'USD';
$amount = null;
$description = '';
$clientService = new \Box\Mod\Client\Service();
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('Funds amount is invalid');
$clientService->addFunds($modelClient, $amount, $description);
}
public function testAddFundsInvalidDescription(): void
{
$modelClient = new \Model_Client();
$modelClient->loadBean(new \DummyBean());
$modelClient->currency = 'USD';
$amount = '2.22';
$description = null;
$clientService = new \Box\Mod\Client\Service();
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('Funds description is invalid');
$result = $clientService->addFunds($modelClient, $amount, $description);
$this->assertTrue($result);
}
public function testGetExpiredPasswordReminders(): void
{
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())->method('find')
->willReturn([]);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->getExpiredPasswordReminders();
$this->assertIsArray($result);
}
public static function searchHistoryQueryData(): array
{
return [
[[], 'SELECT ach.*, c.first_name, c.last_name, c.email', []],
[
['search' => 'sameValue'],
'c.first_name LIKE :first_name OR c.last_name LIKE :last_name OR c.id LIKE :id',
[
':first_name' => '%sameValue%',
':last_name' => '%sameValue%',
':id' => 'sameValue'],
],
[
['client_id' => '1'],
'ach.client_id = :client_id',
[':client_id' => '1'],
],
];
}
#[DataProvider('searchHistoryQueryData')]
public function testGetHistorySearchQuery(array $data, string $expectedStr, array $expectedParams): void
{
$clientService = new \Box\Mod\Client\Service();
$di = $this->getDi();
$clientService->setDi($di);
[$sql, $params] = $clientService->getHistorySearchQuery($data);
$this->assertNotEmpty($sql);
$this->assertIsString($sql);
$this->assertIsArray($params);
$this->assertTrue(str_contains($sql, $expectedStr), $sql);
$this->assertEquals([], array_diff_key($params, $expectedParams));
}
public function testCounter(): void
{
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())->method('getAssoc')
->willReturn([]);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->counter();
$this->assertIsArray($result);
$expected = [
'total' => 0,
\Model_Client::ACTIVE => 0,
\Model_Client::SUSPENDED => 0,
\Model_Client::CANCELED => 0,
];
}
public function testGetGroupPairs(): void
{
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())->method('getAssoc')
->willReturn([]);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->getGroupPairs();
$this->assertIsArray($result);
}
public function testClientAlreadyExists(): void
{
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())->method('findOne')
->willReturn($model);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->clientAlreadyExists('email@example.com');
$this->assertTrue($result);
}
public function testGetByLoginDetails(): void
{
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$database = $this->createMock('\Box_Database');
$database->expects($this->atLeastOnce())->method('findOne')
->willReturn($model);
$di = $this->getDi();
$di['db'] = $database;
$clientService = new \Box\Mod\Client\Service();
$clientService->setDi($di);
$result = $clientService->getByLoginDetails('email@example.com', 'password');
$this->assertInstanceOf('\Model_Client', $result);
}
public static function getProvider(): array
{
return [
['id', 1],
['email', 'test@email.com'],
];
}
#[DataProvider('getProvider')]
public function testGet(string $fieldName, int|string $fieldValue): void
{
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('findOne')->willReturn($model);
$di = $this->getDi();
$di['db'] = $dbMock;
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$data = [$fieldName => $fieldValue];
$result = $service->get($data);
$this->assertInstanceOf('\Model_Client', $result);
}
public function testGetClientNotFound(): void
{
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('findOne')->willReturn([]);
$di = $this->getDi();
$di['db'] = $dbMock;
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$data = ['id' => 0];
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('Client not found');
$service->get($data);
}
public function testGetClientBalance(): void
{
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('getCell')->willReturn(1.0);
$di = $this->getDi();
$di['db'] = $dbMock;
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$result = $service->getClientBalance($model);
$this->assertIsNumeric($result);
}
public function testToApiArray(): void
{
$model = new \Model_Client();
$model->loadBean(new \DummyBean());
$model->api_token = 'client-token';
$model->custom_1 = 'custom field';
$clientGroup = new \Model_ClientGroup();
$clientGroup->loadBean(new \DummyBean());
$clientGroup->title = 'Group Title';
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('toArray')->willReturn([]);
$dbMock->expects($this->atLeastOnce())
->method('load')->willReturn($clientGroup);
$di = $this->getDi();
$di['db'] = $dbMock;
$serviceMock = $this->getMockBuilder(\Box\Mod\Client\Service::class)
->onlyMethods(['getClientBalance'])
->getMock();
$serviceMock->expects($this->atLeastOnce())
->method('getClientBalance');
$serviceMock->setDi($di);
$result = $serviceMock->toApiArray($model, true, new \Model_Admin());
$this->assertIsArray($result);
$this->assertArrayNotHasKey('api_token', $result);
$result = $serviceMock->toApiArray($model, true, new \Model_Admin(), true);
$this->assertArrayHasKey('api_token', $result);
$this->assertSame('client-token', $result['api_token']);
}
public static function isClientTaxableProvider(): array
{
return [
[
false,
false,
false,
],
[
true,
true,
false,
],
[
true,
false,
true,
],
];
}
#[DataProvider('isClientTaxableProvider')]
public function testIsClientTaxable(bool $getParamValueReturn, bool $tax_exempt, bool $expected): void
{
$service = $this->createMock(\Box\Mod\System\Service::class);
$service->expects($this->atLeastOnce())
->method('getParamValue')
->willReturn($getParamValueReturn);
$di = $this->getDi();
$di['mod_service'] = $di->protect(fn (): \PHPUnit\Framework\MockObject\MockObject => $service);
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$client = new \Model_Client();
$client->loadBean(new \DummyBean());
$client->tax_exempt = $tax_exempt;
$result = $service->isClientTaxable($client);
$this->assertEquals($expected, $result);
}
public function testAdminCreateClient(): void
{
$clientModel = new \Model_Client();
$clientModel->loadBean(new \DummyBean());
$clientModel->id = 1;
$data = [
'password' => uniqid(),
'email' => 'test@unit.vm',
'first_name' => 'test',
];
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('dispense')
->willReturn($clientModel);
$dbMock->expects($this->atLeastOnce())
->method('store');
$eventManagerMock = $this->createMock('\Box_EventManager');
$eventManagerMock->expects($this->exactly(2))
->method('fire');
$passwordMock = $this->createMock(\FOSSBilling\PasswordManager::class);
$passwordMock->expects($this->atLeastOnce())
->method('hashIt')
->with($data['password']);
$modMock = $this->getMockBuilder(\FOSSBilling\Module::class)->disableOriginalConstructor()->getMock();
$modMock->expects($this->atLeastOnce())
->method('getConfig')
->willReturn([]);
$di = $this->getDi();
$di['db'] = $dbMock;
$di['events_manager'] = $eventManagerMock;
$di['logger'] = new \Box_Log();
$di['mod'] = $di->protect(fn (): \PHPUnit\Framework\MockObject\MockObject => $modMock);
$di['password'] = $passwordMock;
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$result = $service->adminCreateClient($data);
$this->assertIsInt($result);
}
public function testDeleteGroup(): void
{
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('findOne');
$dbMock->expects($this->once())
->method('trash');
$di = $this->getDi();
$di['db'] = $dbMock;
$di['logger'] = new \Box_Log();
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$model = new \Model_ClientGroup();
$model->loadBean(new \DummyBean());
$result = $service->deleteGroup($model);
$this->assertTrue($result);
}
public function testDeleteGroupGroupHasClients(): void
{
$clientModel = new \Model_Client();
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('findOne')
->willReturn($clientModel);
$di = $this->getDi();
$di['db'] = $dbMock;
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$model = new \Model_ClientGroup();
$model->loadBean(new \DummyBean());
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('Cannot remove groups with clients');
$service->deleteGroup($model);
}
public function testAuthorizeClientDidntFoundEmail(): void
{
$email = 'example@fossbilling.vm';
$password = '123456';
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('findOne')
->with('Client')
->willReturn(null);
$authMock = $this->getMockBuilder('\Box_Authorization')->disableOriginalConstructor()->getMock();
$authMock->expects($this->atLeastOnce())
->method('authorizeUser')
->with(null, $password)
->willReturn(null);
$di = $this->getDi();
$di['db'] = $dbMock;
$di['auth'] = $authMock;
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$result = $service->authorizeClient($email, $password);
$this->assertNull($result);
}
public function testAuthorizeClient(): void
{
$email = 'example@fossbilling.vm';
$password = '123456';
$clientModel = new \Model_Client();
$clientModel->loadBean(new \DummyBean());
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('findOne')
->with('Client')
->willReturn($clientModel);
$authMock = $this->getMockBuilder('\Box_Authorization')->disableOriginalConstructor()->getMock();
$authMock->expects($this->atLeastOnce())
->method('authorizeUser')
->with($clientModel, $password)
->willReturn($clientModel);
$di = $this->getDi();
$di['db'] = $dbMock;
$di['auth'] = $authMock;
$di['mod_config'] = $di->protect(fn ($name): array => ['require_email_confirmation' => false]);
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$result = $service->authorizeClient($email, $password);
$this->assertInstanceOf('\Model_Client', $result);
}
public function testAuthorizeClientEmailRequiredConfirmed(): void
{
$email = 'example@fossbilling.vm';
$password = '123456';
$clientModel = new \Model_Client();
$clientModel->loadBean(new \DummyBean());
$clientModel->email_approved = 1;
$dbMock = $this->createMock('\Box_Database');
$dbMock->expects($this->atLeastOnce())
->method('findOne')
->with('Client')
->willReturn($clientModel);
$authMock = $this->getMockBuilder('\Box_Authorization')->disableOriginalConstructor()->getMock();
$authMock->expects($this->any())
->method('authorizeUser')
->with($clientModel, $password)
->willReturn($clientModel);
$di = $this->getDi();
$di['db'] = $dbMock;
$di['auth'] = $authMock;
$di['mod_config'] = $di->protect(fn ($name): array => ['require_email_confirmation' => true]);
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$result = $service->authorizeClient($email, $password);
$this->assertInstanceOf('\Model_Client', $result);
}
public function testCanChangeEmail(): void
{
$clientModel = new \Model_Client();
$clientModel->loadBean(new \DummyBean());
$email = 'client@fossbilling.org';
$config = [
'disable_change_email' => false,
];
$di = $this->getDi();
$di['mod_config'] = $di->protect(fn ($modName): array => $config);
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$result = $service->canChangeEmail($clientModel, $email);
$this->assertTrue($result);
}
public function testCanChangeEmailEmailAreTheSame(): void
{
$clientModel = new \Model_Client();
$clientModel->loadBean(new \DummyBean());
$email = 'client@fossbilling.org';
$clientModel->email = $email;
$config = [
'disable_change_email' => false,
];
$di = $this->getDi();
$di['mod_config'] = $di->protect(fn ($modName): array => $config);
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$result = $service->canChangeEmail($clientModel, $email);
$this->assertTrue($result);
}
public function testCanChangeEmailEmptyConfig(): void
{
$clientModel = new \Model_Client();
$clientModel->loadBean(new \DummyBean());
$email = 'client@fossbilling.org';
$config = [];
$di = $this->getDi();
$di['mod_config'] = $di->protect(fn ($modName): array => $config);
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$result = $service->canChangeEmail($clientModel, $email);
$this->assertTrue($result);
}
public function testCanChangeEmailCanntChangeEmail(): void
{
$clientModel = new \Model_Client();
$clientModel->loadBean(new \DummyBean());
$email = 'client@fossbilling.org';
$config = [
'disable_change_email' => true,
];
$di = $this->getDi();
$di['mod_config'] = $di->protect(fn ($modName): array => $config);
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('Email address cannot be changed');
$service->canChangeEmail($clientModel, $email);
}
public function testCheckExtraRequiredFields(): void
{
$required = ['id'];
$data = [];
$config['required'] = $required;
$di = $this->getDi();
$di['mod_config'] = $di->protect(fn ($modName): array => $config);
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('Field Id cannot be empty');
$service->checkExtraRequiredFields($data);
}
public function testCheckCustomFields(): void
{
$custom_field = [
'custom_field_name' => [
'active' => true,
'required' => true,
'title' => 'custom_field_title',
],
];
$config['custom_fields'] = $custom_field;
$di = $this->getDi();
$di['mod_config'] = $di->protect(fn ($modName): array => $config);
$data = [];
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$this->expectException(\FOSSBilling\Exception::class);
$this->expectExceptionMessage('Field custom_field_title cannot be empty');
$service->checkCustomFields($data);
}
public function testCheckCustomFieldsNotRequired(): void
{
$custom_field = [
'custom_field_name' => [
'active' => true,
'required' => false,
'title' => 'custom_field_title',
],
];
$config['custom_fields'] = $custom_field;
$di = $this->getDi();
$di['mod_config'] = $di->protect(fn ($modName): array => $config);
$data = [];
$service = new \Box\Mod\Client\Service();
$service->setDi($di);
$result = $service->checkCustomFields($data);
$this->assertNull($result);
}
}