- Kolorowe badge statusow na liscie zamowien (pp_shop_statuses.color) - Walidacja hex koloru z DB (regex), sanityzacja HTML transport - Polaczenie 2 zapytan SQL w jedno orderStatusData() - Path-based form submit w table-list.php (admin URL routing) - 11 nowych testow (750 total, 2114 assertions) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
424 lines
15 KiB
PHP
424 lines
15 KiB
PHP
<?php
|
|
namespace Tests\Unit\Domain\Order;
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
use Domain\Order\OrderRepository;
|
|
|
|
class OrderRepositoryTest extends TestCase
|
|
{
|
|
public function testOrderStatusesReturnsMappedArray(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('select')
|
|
->willReturnCallback(function ($table, $columns, $where) {
|
|
if ($table === 'pp_shop_statuses') {
|
|
return [
|
|
['id' => 0, 'status' => 'Nowe'],
|
|
['id' => 4, 'status' => 'W realizacji'],
|
|
];
|
|
}
|
|
|
|
return [];
|
|
});
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$statuses = $repository->orderStatuses();
|
|
|
|
$this->assertIsArray($statuses);
|
|
$this->assertSame('Nowe', $statuses[0]);
|
|
$this->assertSame('W realizacji', $statuses[4]);
|
|
}
|
|
|
|
public function testOrderStatusDataReturnsBothNamesAndColors(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('select')
|
|
->willReturnCallback(function ($table, $columns, $where) {
|
|
if ($table === 'pp_shop_statuses') {
|
|
return [
|
|
['id' => 0, 'status' => 'Nowe', 'color' => '#ff0000'],
|
|
['id' => 4, 'status' => 'W realizacji', 'color' => '#00ff00'],
|
|
['id' => 5, 'status' => 'Wysłane', 'color' => ''],
|
|
];
|
|
}
|
|
return [];
|
|
});
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$data = $repository->orderStatusData();
|
|
|
|
$this->assertArrayHasKey('names', $data);
|
|
$this->assertArrayHasKey('colors', $data);
|
|
$this->assertSame('Nowe', $data['names'][0]);
|
|
$this->assertSame('W realizacji', $data['names'][4]);
|
|
$this->assertSame('Wysłane', $data['names'][5]);
|
|
$this->assertSame('#ff0000', $data['colors'][0]);
|
|
$this->assertSame('#00ff00', $data['colors'][4]);
|
|
$this->assertArrayNotHasKey(5, $data['colors']);
|
|
}
|
|
|
|
public function testOrderStatusDataFiltersInvalidHexColors(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('select')
|
|
->willReturn([
|
|
['id' => 1, 'status' => 'OK', 'color' => '#abc'],
|
|
['id' => 2, 'status' => 'Bad', 'color' => 'red'],
|
|
['id' => 3, 'status' => 'XSS', 'color' => '#000" onclick="alert(1)'],
|
|
['id' => 4, 'status' => 'Valid', 'color' => '#AABBCC'],
|
|
]);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$data = $repository->orderStatusData();
|
|
|
|
$this->assertSame('#abc', $data['colors'][1]);
|
|
$this->assertArrayNotHasKey(2, $data['colors']);
|
|
$this->assertArrayNotHasKey(3, $data['colors']);
|
|
$this->assertSame('#AABBCC', $data['colors'][4]);
|
|
}
|
|
|
|
public function testOrderStatusDataReturnsEmptyOnDbFailure(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('select')->willReturn(false);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$data = $repository->orderStatusData();
|
|
|
|
$this->assertSame([], $data['names']);
|
|
$this->assertSame([], $data['colors']);
|
|
}
|
|
|
|
public function testNextAndPrevOrderIdReturnNullForInvalidInput(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('get');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
|
|
$this->assertNull($repository->nextOrderId(0));
|
|
$this->assertNull($repository->prevOrderId(0));
|
|
}
|
|
|
|
public function testListForAdminReturnsItemsAndTotal(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
|
|
$resultSetCount = new class {
|
|
public function fetchAll(): array
|
|
{
|
|
return [[3]];
|
|
}
|
|
};
|
|
|
|
$resultSetData = new class {
|
|
public function fetchAll(): array
|
|
{
|
|
return [
|
|
[
|
|
'id' => 11,
|
|
'number' => '2026/02/001',
|
|
'date_order' => '2026-02-15 10:00:00',
|
|
'client' => 'Jan Kowalski',
|
|
'order_email' => 'jan@example.com',
|
|
'address' => 'Testowa 1, 00-000 Warszawa',
|
|
'status' => 0,
|
|
'client_phone' => '111222333',
|
|
'transport' => 'Kurier',
|
|
'payment_method' => 'Przelew',
|
|
'summary' => '123.45',
|
|
'paid' => 1,
|
|
'total_orders' => 2,
|
|
],
|
|
];
|
|
}
|
|
};
|
|
|
|
$callIndex = 0;
|
|
$mockDb->method('query')
|
|
->willReturnCallback(function () use (&$callIndex, $resultSetCount, $resultSetData) {
|
|
$callIndex++;
|
|
return $callIndex === 1 ? $resultSetCount : $resultSetData;
|
|
});
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$result = $repository->listForAdmin([], 'date_order', 'DESC', 1, 15);
|
|
|
|
$this->assertSame(3, $result['total']);
|
|
$this->assertCount(1, $result['items']);
|
|
$this->assertSame(11, $result['items'][0]['id']);
|
|
$this->assertSame('2026/02/001', $result['items'][0]['number']);
|
|
$this->assertSame(2, $result['items'][0]['total_orders']);
|
|
$this->assertSame(1, $result['items'][0]['paid']);
|
|
}
|
|
|
|
// --- Frontend method tests ---
|
|
|
|
public function testFindIdByHashReturnsIdWhenFound(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('get')
|
|
->with('pp_shop_orders', 'id', ['hash' => 'abc123'])
|
|
->willReturn('42');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertSame(42, $repository->findIdByHash('abc123'));
|
|
}
|
|
|
|
public function testFindIdByHashReturnsNullWhenNotFound(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('get')->willReturn(null);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertNull($repository->findIdByHash('nonexistent'));
|
|
}
|
|
|
|
public function testFindIdByHashReturnsNullForEmptyHash(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('get');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertNull($repository->findIdByHash(''));
|
|
$this->assertNull($repository->findIdByHash(' '));
|
|
}
|
|
|
|
public function testFindHashByIdReturnsHashWhenFound(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('get')
|
|
->with('pp_shop_orders', 'hash', ['id' => 42])
|
|
->willReturn('abc123hash');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertSame('abc123hash', $repository->findHashById(42));
|
|
}
|
|
|
|
public function testFindHashByIdReturnsNullForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('get');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertNull($repository->findHashById(0));
|
|
$this->assertNull($repository->findHashById(-1));
|
|
}
|
|
|
|
public function testOrderDetailsFrontendByIdReturnsArrayWithProducts(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('get')
|
|
->willReturn(['id' => 1, 'number' => '2026/02/001', 'coupon_id' => null]);
|
|
$mockDb->method('select')
|
|
->willReturn([['product_id' => 10, 'name' => 'Test Product']]);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$result = $repository->orderDetailsFrontend(1);
|
|
|
|
$this->assertIsArray($result);
|
|
$this->assertSame(1, $result['id']);
|
|
$this->assertIsArray($result['products']);
|
|
$this->assertCount(1, $result['products']);
|
|
}
|
|
|
|
public function testOrderDetailsFrontendByHashReturnsArrayWithProducts(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('get')
|
|
->willReturn(['id' => 5, 'number' => '2026/02/005', 'hash' => 'testhash']);
|
|
$mockDb->method('select')
|
|
->willReturn([]);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$result = $repository->orderDetailsFrontend(null, 'testhash');
|
|
|
|
$this->assertIsArray($result);
|
|
$this->assertSame(5, $result['id']);
|
|
$this->assertIsArray($result['products']);
|
|
}
|
|
|
|
public function testOrderDetailsFrontendReturnsNullWhenNotFound(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('get')->willReturn(null);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertNull($repository->orderDetailsFrontend(999));
|
|
$this->assertNull($repository->orderDetailsFrontend(null, 'nonexistent'));
|
|
}
|
|
|
|
public function testGenerateOrderNumberFormatsCorrectly(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
|
|
$resultSet = new class {
|
|
public function fetchAll(): array
|
|
{
|
|
return [[5]];
|
|
}
|
|
};
|
|
|
|
$mockDb->method('query')->willReturn($resultSet);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$number = $repository->generateOrderNumber();
|
|
|
|
$expectedPrefix = date('Y/m') . '/';
|
|
$this->assertStringStartsWith($expectedPrefix, $number);
|
|
$this->assertSame($expectedPrefix . '006', $number);
|
|
}
|
|
|
|
// --- Order product CRUD tests ---
|
|
|
|
public function testGetOrderProductReturnsNullForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('get');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertNull($repository->getOrderProduct(0));
|
|
$this->assertNull($repository->getOrderProduct(-1));
|
|
}
|
|
|
|
public function testGetOrderProductReturnsArray(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->method('get')
|
|
->with('pp_shop_order_products', '*', ['id' => 5])
|
|
->willReturn(['id' => 5, 'order_id' => 1, 'name' => 'Test']);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$result = $repository->getOrderProduct(5);
|
|
|
|
$this->assertIsArray($result);
|
|
$this->assertSame(5, $result['id']);
|
|
}
|
|
|
|
public function testAddOrderProductReturnsNullForInvalidOrderId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('insert');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertNull($repository->addOrderProduct(0, ['name' => 'Test']));
|
|
}
|
|
|
|
public function testAddOrderProductInsertsAndReturnsId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())->method('insert')
|
|
->with('pp_shop_order_products', $this->callback(function ($data) {
|
|
return $data['order_id'] === 10
|
|
&& $data['product_id'] === 5
|
|
&& $data['name'] === 'Test Product'
|
|
&& $data['quantity'] === 2;
|
|
}));
|
|
$mockDb->method('id')->willReturn('99');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$result = $repository->addOrderProduct(10, [
|
|
'product_id' => 5,
|
|
'name' => 'Test Product',
|
|
'quantity' => 2,
|
|
'price_brutto' => 19.99,
|
|
]);
|
|
|
|
$this->assertSame(99, $result);
|
|
}
|
|
|
|
public function testUpdateOrderProductReturnsFalseForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('update');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertFalse($repository->updateOrderProduct(0, ['quantity' => 3]));
|
|
}
|
|
|
|
public function testUpdateOrderProductUpdatesFields(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())->method('update')
|
|
->with('pp_shop_order_products', $this->callback(function ($data) {
|
|
return $data['quantity'] === 3
|
|
&& $data['price_brutto'] === 25.50;
|
|
}), ['id' => 7]);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$result = $repository->updateOrderProduct(7, [
|
|
'quantity' => 3,
|
|
'price_brutto' => 25.50,
|
|
]);
|
|
|
|
$this->assertTrue($result);
|
|
}
|
|
|
|
public function testUpdateOrderProductReturnsFalseForEmptyData(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('update');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertFalse($repository->updateOrderProduct(7, []));
|
|
}
|
|
|
|
public function testDeleteOrderProductReturnsFalseForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('delete');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertFalse($repository->deleteOrderProduct(0));
|
|
}
|
|
|
|
public function testDeleteOrderProductCallsDelete(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())->method('delete')
|
|
->with('pp_shop_order_products', ['id' => 12]);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$this->assertTrue($repository->deleteOrderProduct(12));
|
|
}
|
|
|
|
public function testUpdateTransportCostDoesNothingForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('update');
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$repository->updateTransportCost(0, 15.0);
|
|
}
|
|
|
|
public function testUpdateTransportCostUpdatesOrder(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())->method('update')
|
|
->with('pp_shop_orders', ['transport_cost' => 12.50], ['id' => 5]);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$repository->updateTransportCost(5, 12.50);
|
|
}
|
|
|
|
public function testGenerateOrderNumberStartsAt001(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
|
|
$resultSet = new class {
|
|
public function fetchAll(): array
|
|
{
|
|
return [[null]];
|
|
}
|
|
};
|
|
|
|
$mockDb->method('query')->willReturn($resultSet);
|
|
|
|
$repository = new OrderRepository($mockDb);
|
|
$number = $repository->generateOrderNumber();
|
|
|
|
$expectedPrefix = date('Y/m') . '/';
|
|
$this->assertSame($expectedPrefix . '001', $number);
|
|
}
|
|
}
|