Replace hardcoded PayPo condition (id=6, 40-1000 PLN) with generic min/max order amount columns on pp_shop_payment_methods. Admin form fields added, frontend basket checkout filters dynamically. Cache invalidation on save. 4 new tests (734 total, 2080 assertions). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
522 lines
18 KiB
PHP
522 lines
18 KiB
PHP
<?php
|
|
namespace Tests\Unit\Domain\PaymentMethod;
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
use Domain\PaymentMethod\PaymentMethodRepository;
|
|
|
|
class PaymentMethodRepositoryTest extends TestCase
|
|
{
|
|
public function testFindReturnsNullForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('get');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertNull($repository->find(0));
|
|
}
|
|
|
|
public function testFindReturnsNullWhenNotFound(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', '*', ['id' => 10])
|
|
->willReturn(null);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertNull($repository->find(10));
|
|
}
|
|
|
|
public function testFindNormalizesData(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', '*', ['id' => 11])
|
|
->willReturn([
|
|
'id' => '11',
|
|
'name' => ' Przelew ',
|
|
'description' => null,
|
|
'status' => '1',
|
|
'apilo_payment_type_id' => '7',
|
|
]);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$result = $repository->find(11);
|
|
|
|
$this->assertIsArray($result);
|
|
$this->assertSame(11, $result['id']);
|
|
$this->assertSame('Przelew', $result['name']);
|
|
$this->assertSame('', $result['description']);
|
|
$this->assertSame(1, $result['status']);
|
|
$this->assertSame(7, $result['apilo_payment_type_id']);
|
|
}
|
|
|
|
public function testSaveUpdatesRowAndReturnsId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$updateRow = null;
|
|
$updateWhere = null;
|
|
|
|
$mockDb->expects($this->once())
|
|
->method('update')
|
|
->willReturnCallback(function ($table, $row, $where) use (&$updateRow, &$updateWhere) {
|
|
$this->assertSame('pp_shop_payment_methods', $table);
|
|
$updateRow = $row;
|
|
$updateWhere = $where;
|
|
return true;
|
|
});
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$id = $repository->save(3, [
|
|
'description' => ' test ',
|
|
'status' => 'on',
|
|
'apilo_payment_type_id' => '22',
|
|
]);
|
|
|
|
$this->assertSame(3, $id);
|
|
$this->assertSame('test', $updateRow['description']);
|
|
$this->assertSame(1, $updateRow['status']);
|
|
$this->assertSame(22, $updateRow['apilo_payment_type_id']);
|
|
$this->assertNull($updateRow['min_order_amount']);
|
|
$this->assertNull($updateRow['max_order_amount']);
|
|
$this->assertSame(['id' => 3], $updateWhere);
|
|
}
|
|
|
|
public function testSavePreservesNonNumericApiloPaymentTypeId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$updateRow = null;
|
|
|
|
$mockDb->expects($this->once())
|
|
->method('update')
|
|
->willReturnCallback(function ($table, $row) use (&$updateRow) {
|
|
$this->assertSame('pp_shop_payment_methods', $table);
|
|
$updateRow = $row;
|
|
return true;
|
|
});
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$repository->save(4, [
|
|
'description' => 'X',
|
|
'status' => 1,
|
|
'apilo_payment_type_id' => 'CASH_ON_DELIVERY',
|
|
]);
|
|
|
|
$this->assertSame('CASH_ON_DELIVERY', $updateRow['apilo_payment_type_id']);
|
|
}
|
|
|
|
public function testSaveReturnsNullForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('update');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertNull($repository->save(0, ['status' => 1]));
|
|
}
|
|
|
|
public function testSavePersistsMinMaxOrderAmount(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$updateRow = null;
|
|
|
|
$mockDb->expects($this->once())
|
|
->method('update')
|
|
->willReturnCallback(function ($table, $row) use (&$updateRow) {
|
|
$updateRow = $row;
|
|
return true;
|
|
});
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$repository->save(5, [
|
|
'description' => 'test',
|
|
'status' => 1,
|
|
'apilo_payment_type_id' => '',
|
|
'min_order_amount' => '40.00',
|
|
'max_order_amount' => '1000.00',
|
|
]);
|
|
|
|
$this->assertSame(40.0, $updateRow['min_order_amount']);
|
|
$this->assertSame(1000.0, $updateRow['max_order_amount']);
|
|
}
|
|
|
|
public function testSaveConvertsEmptyMinMaxToNull(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$updateRow = null;
|
|
|
|
$mockDb->expects($this->once())
|
|
->method('update')
|
|
->willReturnCallback(function ($table, $row) use (&$updateRow) {
|
|
$updateRow = $row;
|
|
return true;
|
|
});
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$repository->save(6, [
|
|
'description' => 'test',
|
|
'status' => 1,
|
|
'apilo_payment_type_id' => '',
|
|
'min_order_amount' => '',
|
|
'max_order_amount' => '',
|
|
]);
|
|
|
|
$this->assertNull($updateRow['min_order_amount']);
|
|
$this->assertNull($updateRow['max_order_amount']);
|
|
}
|
|
|
|
public function testFindNormalizesMinMaxOrderAmount(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', '*', ['id' => 6])
|
|
->willReturn([
|
|
'id' => '6',
|
|
'name' => 'PayPo',
|
|
'description' => '',
|
|
'status' => '1',
|
|
'apilo_payment_type_id' => null,
|
|
'min_order_amount' => '40.00',
|
|
'max_order_amount' => '1000.00',
|
|
]);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$result = $repository->find(6);
|
|
|
|
$this->assertSame(40.0, $result['min_order_amount']);
|
|
$this->assertSame(1000.0, $result['max_order_amount']);
|
|
}
|
|
|
|
public function testFindNormalizesNullMinMaxOrderAmount(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', '*', ['id' => 7])
|
|
->willReturn([
|
|
'id' => '7',
|
|
'name' => 'Przelew',
|
|
'description' => '',
|
|
'status' => '1',
|
|
'apilo_payment_type_id' => null,
|
|
'min_order_amount' => null,
|
|
'max_order_amount' => null,
|
|
]);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$result = $repository->find(7);
|
|
|
|
$this->assertNull($result['min_order_amount']);
|
|
$this->assertNull($result['max_order_amount']);
|
|
}
|
|
|
|
public function testListForAdminWhitelistsSortAndDirection(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$queries = [];
|
|
|
|
$mockDb->method('query')
|
|
->willReturnCallback(function ($sql, $params = []) use (&$queries) {
|
|
$queries[] = ['sql' => $sql, 'params' => $params];
|
|
|
|
if (strpos($sql, 'COUNT(0)') !== false) {
|
|
return new class {
|
|
public function fetchAll()
|
|
{
|
|
return [[1]];
|
|
}
|
|
};
|
|
}
|
|
|
|
return new class {
|
|
public function fetchAll()
|
|
{
|
|
return [[
|
|
'id' => 1,
|
|
'name' => 'Przelew',
|
|
'description' => 'Opis',
|
|
'status' => 1,
|
|
'apilo_payment_type_id' => 5,
|
|
]];
|
|
}
|
|
};
|
|
});
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$result = $repository->listForAdmin(
|
|
[],
|
|
'name DESC; DROP TABLE pp_shop_payment_methods; --',
|
|
'DESC; DELETE FROM pp_users; --',
|
|
1,
|
|
999
|
|
);
|
|
|
|
$this->assertCount(2, $queries);
|
|
$dataSql = $queries[1]['sql'];
|
|
|
|
$this->assertMatchesRegularExpression('/ORDER BY\s+spm\.name\s+ASC,\s+spm\.id\s+ASC/i', $dataSql);
|
|
$this->assertStringNotContainsString('DROP TABLE', $dataSql);
|
|
$this->assertStringNotContainsString('DELETE FROM pp_users', $dataSql);
|
|
$this->assertMatchesRegularExpression('/LIMIT\s+100\s+OFFSET\s+0/i', $dataSql);
|
|
$this->assertSame(1, (int)$result['items'][0]['id']);
|
|
}
|
|
|
|
public function testAllActiveReturnsNormalizedRows(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('select')
|
|
->with('pp_shop_payment_methods', '*', [
|
|
'status' => 1,
|
|
'ORDER' => ['id' => 'ASC'],
|
|
])
|
|
->willReturn([
|
|
[
|
|
'id' => '2',
|
|
'name' => ' PayU ',
|
|
'description' => '',
|
|
'status' => '1',
|
|
'apilo_payment_type_id' => null,
|
|
],
|
|
]);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$rows = $repository->allActive();
|
|
|
|
$this->assertCount(1, $rows);
|
|
$this->assertSame(2, $rows[0]['id']);
|
|
$this->assertSame('PayU', $rows[0]['name']);
|
|
$this->assertSame(1, $rows[0]['status']);
|
|
$this->assertNull($rows[0]['apilo_payment_type_id']);
|
|
}
|
|
|
|
public function testAllForAdminReturnsRowsIncludingInactive(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('select')
|
|
->with('pp_shop_payment_methods', '*', [
|
|
'ORDER' => ['name' => 'ASC'],
|
|
])
|
|
->willReturn([
|
|
[
|
|
'id' => '1',
|
|
'name' => 'Przelew',
|
|
'description' => '',
|
|
'status' => '1',
|
|
'apilo_payment_type_id' => null,
|
|
],
|
|
[
|
|
'id' => '2',
|
|
'name' => 'PayPo',
|
|
'description' => '',
|
|
'status' => '0',
|
|
'apilo_payment_type_id' => null,
|
|
],
|
|
]);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$rows = $repository->allForAdmin();
|
|
|
|
$this->assertCount(2, $rows);
|
|
$this->assertSame(1, $rows[0]['id']);
|
|
$this->assertSame(2, $rows[1]['id']);
|
|
$this->assertSame(0, $rows[1]['status']);
|
|
}
|
|
|
|
public function testFindActiveByIdReturnsNullForNotFound(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', '*', [
|
|
'AND' => [
|
|
'id' => 4,
|
|
'status' => 1,
|
|
],
|
|
])
|
|
->willReturn(null);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertNull($repository->findActiveById(4));
|
|
}
|
|
|
|
public function testFindKeepsNonNumericApiloPaymentTypeId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', '*', ['id' => 12])
|
|
->willReturn([
|
|
'id' => '12',
|
|
'name' => 'PayPo',
|
|
'description' => '',
|
|
'status' => '1',
|
|
'apilo_payment_type_id' => 'PAYPO_DEFERRED',
|
|
]);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$result = $repository->find(12);
|
|
|
|
$this->assertIsArray($result);
|
|
$this->assertSame('PAYPO_DEFERRED', $result['apilo_payment_type_id']);
|
|
}
|
|
|
|
public function testIsActiveNormalizesStatusValue(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', 'status', ['id' => 5])
|
|
->willReturn('0');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertSame(0, $repository->isActive(5));
|
|
}
|
|
|
|
public function testGetApiloPaymentTypeIdHandlesNullAndInt(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->exactly(2))
|
|
->method('get')
|
|
->willReturnOnConsecutiveCalls(null, '8');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertNull($repository->getApiloPaymentTypeId(1));
|
|
$this->assertSame(8, $repository->getApiloPaymentTypeId(2));
|
|
}
|
|
|
|
public function testGetApiloPaymentTypeIdReturnsStringForNonNumericValue(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', 'apilo_payment_type_id', ['id' => 3])
|
|
->willReturn('BANK_TRANSFER');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertSame('BANK_TRANSFER', $repository->getApiloPaymentTypeId(3));
|
|
}
|
|
|
|
public function testIsActiveReturnsOneForActivePayment(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', 'status', ['id' => 2])
|
|
->willReturn('1');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertSame(1, $repository->isActive(2));
|
|
}
|
|
|
|
public function testIsActiveReturnsZeroForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('get');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertSame(0, $repository->isActive(0));
|
|
}
|
|
|
|
public function testFindActiveByIdReturnsNormalizedData(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_payment_methods', '*', [
|
|
'AND' => [
|
|
'id' => 3,
|
|
'status' => 1,
|
|
],
|
|
])
|
|
->willReturn([
|
|
'id' => '3',
|
|
'name' => ' Przelew ',
|
|
'description' => 'Opis',
|
|
'status' => '1',
|
|
'apilo_payment_type_id' => '5',
|
|
]);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$result = $repository->findActiveById(3);
|
|
|
|
$this->assertIsArray($result);
|
|
$this->assertSame(3, $result['id']);
|
|
$this->assertSame('Przelew', $result['name']);
|
|
$this->assertSame(1, $result['status']);
|
|
$this->assertSame(5, $result['apilo_payment_type_id']);
|
|
}
|
|
|
|
public function testFindActiveByIdReturnsNullForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('get');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertNull($repository->findActiveById(0));
|
|
}
|
|
|
|
public function testAllActiveReturnsEmptyOnNull(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('select')->willReturn(null);
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertSame([], $repository->allActive());
|
|
}
|
|
|
|
public function testGetApiloPaymentTypeIdReturnsNullForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('get');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertNull($repository->getApiloPaymentTypeId(0));
|
|
}
|
|
|
|
public function testForTransportReturnsEmptyForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('query');
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$this->assertSame([], $repository->forTransport(0));
|
|
}
|
|
|
|
public function testForTransportReturnsRows(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$capturedParams = null;
|
|
|
|
$mockDb->expects($this->once())
|
|
->method('query')
|
|
->willReturnCallback(function ($sql, $params = []) use (&$capturedParams) {
|
|
$this->assertStringContainsString('pp_shop_transport_payment_methods', $sql);
|
|
$capturedParams = $params;
|
|
|
|
return new class {
|
|
public function fetchAll()
|
|
{
|
|
return [[
|
|
'id' => '9',
|
|
'name' => 'Karta',
|
|
'description' => 'Opis',
|
|
'status' => 1,
|
|
'apilo_payment_type_id' => '4',
|
|
]];
|
|
}
|
|
};
|
|
});
|
|
|
|
$repository = new PaymentMethodRepository($mockDb);
|
|
$rows = $repository->forTransport(12);
|
|
|
|
$this->assertSame([':transport_id' => 12], $capturedParams);
|
|
$this->assertCount(1, $rows);
|
|
$this->assertSame(9, $rows[0]['id']);
|
|
$this->assertSame(4, $rows[0]['apilo_payment_type_id']);
|
|
}
|
|
}
|