ver. 0.306: hide transport methods with no available payment methods
When all payment methods for a transport are filtered out by min_order_amount/max_order_amount limits, the transport is now hidden from the basket. Prevents showing delivery options with empty payment method lists (e.g. "Kurier - płatność przy odbiorze" when COD exceeds max amount). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -36,7 +36,7 @@ composer test
|
||||
|
||||
PHPUnit 9.6 via `phpunit.phar`. Bootstrap: `tests/bootstrap.php`. Config: `phpunit.xml`.
|
||||
|
||||
Current suite: **734 tests, 2080 assertions**.
|
||||
Current suite: **739 tests, 2089 assertions**.
|
||||
|
||||
### Creating Updates
|
||||
See `docs/UPDATE_INSTRUCTIONS.md` for the full procedure. Updates are ZIP packages in `updates/0.XX/`. Never include `*.md` files, `updates/changelog.php`, or root `.htaccess` in update ZIPs.
|
||||
|
||||
@@ -323,7 +323,9 @@ class TransportRepository
|
||||
$transports[] = $tr;
|
||||
}
|
||||
|
||||
if ( \Shared\Helpers\Helpers::normalize_decimal( \Domain\Basket\BasketCalculator::summaryPrice( $basket, $coupon ) ) >= \Shared\Helpers\Helpers::normalize_decimal( $settings['free_delivery'] ) )
|
||||
$products_summary = (float)\Domain\Basket\BasketCalculator::summaryPrice( $basket, $coupon );
|
||||
|
||||
if ( \Shared\Helpers\Helpers::normalize_decimal( $products_summary ) >= \Shared\Helpers\Helpers::normalize_decimal( $settings['free_delivery'] ) )
|
||||
{
|
||||
for ( $i = 0; $i < count( $transports ); $i++ ) {
|
||||
if ( $transports[$i]['delivery_free'] == 1 ) {
|
||||
@@ -332,7 +334,39 @@ class TransportRepository
|
||||
}
|
||||
}
|
||||
|
||||
return $transports;
|
||||
// Ukryj transporty, dla których nie ma żadnej dostępnej formy płatności
|
||||
$paymentMethodRepo = new \Domain\PaymentMethod\PaymentMethodRepository( $this->db );
|
||||
$filtered = [];
|
||||
|
||||
foreach ( $transports as $tr )
|
||||
{
|
||||
$paymentMethods = $paymentMethodRepo->paymentMethodsByTransport( $tr['id'] );
|
||||
$order_total = $products_summary + (float)$tr['cost'];
|
||||
$has_available_pm = false;
|
||||
|
||||
foreach ( $paymentMethods as $pm )
|
||||
{
|
||||
$min = isset( $pm['min_order_amount'] ) ? (float)$pm['min_order_amount'] : null;
|
||||
$max = isset( $pm['max_order_amount'] ) ? (float)$pm['max_order_amount'] : null;
|
||||
$available = true;
|
||||
|
||||
if ( $min !== null && $min > 0 && $order_total < $min ) $available = false;
|
||||
if ( $max !== null && $max > 0 && $order_total > $max ) $available = false;
|
||||
|
||||
if ( $available )
|
||||
{
|
||||
$has_available_pm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $has_available_pm )
|
||||
{
|
||||
$filtered[] = $tr;
|
||||
}
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,14 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze.
|
||||
|
||||
---
|
||||
|
||||
## ver. 0.306 (2026-02-22) - Ukrywanie form dostawy bez dostepnych platnosci
|
||||
|
||||
- **FIX**: Formy dostawy, dla ktorych nie ma zadnej dostepnej formy platnosci (np. wszystkie odfiltrowane przez `min_order_amount`/`max_order_amount`), sa teraz ukrywane z listy w koszyku
|
||||
- **ZMIANA**: `TransportRepository::transportMethodsFront()` — po filtrze wagowym i korekcie darmowej dostawy, dodano filtr sprawdzajacy dostepnosc form platnosci per transport (z wykorzystaniem `PaymentMethodRepository::paymentMethodsByTransport()` z cache Redis)
|
||||
- **NEW**: 5 nowych testow jednostkowych (739 total, 2089 assertions)
|
||||
|
||||
---
|
||||
|
||||
## ver. 0.305 (2026-02-22) - Sortowanie permutacji + pasek darmowej dostawy
|
||||
|
||||
- **FIX**: Naprawa kolejnosci atrybutow permutacji — sortowanie po ID atrybutu (`usort` wg pierwszego segmentu przed `-`) we wszystkich miejscach: koszyk, kombinacje AJAX, `getPermutation()`, `BasketCalculator`. Zapewnia zgodnosc z `permutation_hash` generowanym przez `ksort`.
|
||||
|
||||
@@ -23,7 +23,7 @@ composer test # standard
|
||||
## Aktualny stan
|
||||
|
||||
```text
|
||||
OK (734 tests, 2080 assertions)
|
||||
OK (739 tests, 2089 assertions)
|
||||
```
|
||||
|
||||
Zweryfikowano: 2026-02-22 (ver. 0.304)
|
||||
|
||||
@@ -420,4 +420,197 @@ class TransportRepositoryTest extends TestCase
|
||||
|
||||
$this->assertEquals([], $repository->forPaymentMethod(0));
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// transportMethodsFront — filtrowanie po dostępności form płatności
|
||||
// =========================================================================
|
||||
|
||||
private function createMockDbForTransportMethodsFront(array $transports, array $paymentMethodsByTransportId): \medoo
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
|
||||
$mockDb->method('select')
|
||||
->willReturn($transports);
|
||||
|
||||
$mockDb->method('query')
|
||||
->willReturnCallback(function ($sql, $params) use ($paymentMethodsByTransportId) {
|
||||
$transportId = $params[':transport_id'] ?? 0;
|
||||
$rows = $paymentMethodsByTransportId[$transportId] ?? [];
|
||||
|
||||
return new class($rows) {
|
||||
private $rows;
|
||||
public function __construct($rows) { $this->rows = $rows; }
|
||||
public function fetchAll() { return $this->rows; }
|
||||
};
|
||||
});
|
||||
|
||||
return $mockDb;
|
||||
}
|
||||
|
||||
private function makeTransport(int $id, float $cost, int $deliveryFree = 0, $maxWp = null, int $default = 0): array
|
||||
{
|
||||
return [
|
||||
'id' => (string)$id, 'name' => 'Transport ' . $id, 'name_visible' => '',
|
||||
'description' => '', 'status' => '1', 'cost' => (string)$cost,
|
||||
'max_wp' => $maxWp !== null ? (string)$maxWp : null,
|
||||
'default' => (string)$default, 'delivery_free' => (string)$deliveryFree,
|
||||
'apilo_carrier_account_id' => null, 'o' => (string)$id,
|
||||
];
|
||||
}
|
||||
|
||||
private function makePaymentMethod(int $id, $minAmount = null, $maxAmount = null): array
|
||||
{
|
||||
return [
|
||||
'id' => $id, 'name' => 'Payment ' . $id, 'description' => '',
|
||||
'status' => 1, 'apilo_payment_type_id' => null,
|
||||
'min_order_amount' => $minAmount !== null ? (string)$minAmount : null,
|
||||
'max_order_amount' => $maxAmount !== null ? (string)$maxAmount : null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Transport z formą płatności przekraczającą max_order_amount powinien być ukryty
|
||||
*/
|
||||
public function testTransportMethodsFrontHidesTransportWhenAllPaymentsExceedMaxAmount(): void
|
||||
{
|
||||
global $settings;
|
||||
$settings = ['free_delivery' => 9999];
|
||||
$GLOBALS['mdb'] = $this->createMock(\medoo::class);
|
||||
|
||||
$transports = [
|
||||
$this->makeTransport(1, 15.00, 0, null, 1),
|
||||
$this->makeTransport(2, 20.00),
|
||||
];
|
||||
|
||||
$paymentMethods = [
|
||||
1 => [$this->makePaymentMethod(1)],
|
||||
2 => [$this->makePaymentMethod(3, null, 10.00)],
|
||||
];
|
||||
|
||||
$mockDb = $this->createMockDbForTransportMethodsFront($transports, $paymentMethods);
|
||||
$repository = new TransportRepository($mockDb);
|
||||
|
||||
// Pusty koszyk: summaryPrice=0, transport 2 cost=20, order_total=20, max=10 → ukryty
|
||||
$result = $repository->transportMethodsFront([], null);
|
||||
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertSame(1, $result[0]['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transport z formą płatności poniżej min_order_amount powinien być ukryty
|
||||
*/
|
||||
public function testTransportMethodsFrontHidesTransportWhenAllPaymentsBelowMinAmount(): void
|
||||
{
|
||||
global $settings;
|
||||
$settings = ['free_delivery' => 9999];
|
||||
$GLOBALS['mdb'] = $this->createMock(\medoo::class);
|
||||
|
||||
$transports = [
|
||||
$this->makeTransport(1, 10.00, 0, null, 1),
|
||||
$this->makeTransport(2, 10.00),
|
||||
];
|
||||
|
||||
$paymentMethods = [
|
||||
1 => [$this->makePaymentMethod(1)],
|
||||
2 => [$this->makePaymentMethod(3, 100.00, null)],
|
||||
];
|
||||
|
||||
$mockDb = $this->createMockDbForTransportMethodsFront($transports, $paymentMethods);
|
||||
$repository = new TransportRepository($mockDb);
|
||||
|
||||
// Pusty koszyk: summaryPrice=0, transport 2 cost=10, order_total=10, min=100 → ukryty
|
||||
$result = $repository->transportMethodsFront([], null);
|
||||
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertSame(1, $result[0]['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transport bez żadnych form płatności powinien być ukryty
|
||||
*/
|
||||
public function testTransportMethodsFrontHidesTransportWithNoPaymentMethods(): void
|
||||
{
|
||||
global $settings;
|
||||
$settings = ['free_delivery' => 9999];
|
||||
$GLOBALS['mdb'] = $this->createMock(\medoo::class);
|
||||
|
||||
$transports = [
|
||||
$this->makeTransport(1, 10.00, 0, null, 1),
|
||||
$this->makeTransport(2, 10.00),
|
||||
];
|
||||
|
||||
$paymentMethods = [
|
||||
1 => [$this->makePaymentMethod(1)],
|
||||
2 => [],
|
||||
];
|
||||
|
||||
$mockDb = $this->createMockDbForTransportMethodsFront($transports, $paymentMethods);
|
||||
$repository = new TransportRepository($mockDb);
|
||||
|
||||
$result = $repository->transportMethodsFront([], null);
|
||||
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertSame(1, $result[0]['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Oba transporty z dostępnymi płatnościami — oba widoczne
|
||||
*/
|
||||
public function testTransportMethodsFrontKeepsBothTransportsWhenPaymentsAvailable(): void
|
||||
{
|
||||
global $settings;
|
||||
$settings = ['free_delivery' => 9999];
|
||||
$GLOBALS['mdb'] = $this->createMock(\medoo::class);
|
||||
|
||||
$transports = [
|
||||
$this->makeTransport(1, 10.00, 0, null, 1),
|
||||
$this->makeTransport(2, 15.00),
|
||||
];
|
||||
|
||||
$paymentMethods = [
|
||||
1 => [$this->makePaymentMethod(1)],
|
||||
2 => [$this->makePaymentMethod(2), $this->makePaymentMethod(3, 50.00, null)],
|
||||
];
|
||||
|
||||
$mockDb = $this->createMockDbForTransportMethodsFront($transports, $paymentMethods);
|
||||
$repository = new TransportRepository($mockDb);
|
||||
|
||||
// Transport 2 ma 2 płatności: jedna bez limitów (dostępna), druga z min=50 (niedostępna)
|
||||
// Wystarczy 1 dostępna → transport widoczny
|
||||
$result = $repository->transportMethodsFront([], null);
|
||||
|
||||
$this->assertCount(2, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transport z wieloma płatnościami — przynajmniej jedna dostępna = transport widoczny
|
||||
*/
|
||||
public function testTransportMethodsFrontKeepsTransportIfAtLeastOnePaymentAvailable(): void
|
||||
{
|
||||
global $settings;
|
||||
$settings = ['free_delivery' => 9999];
|
||||
$GLOBALS['mdb'] = $this->createMock(\medoo::class);
|
||||
|
||||
$transports = [
|
||||
$this->makeTransport(1, 5.00, 0, null, 1),
|
||||
];
|
||||
|
||||
// 3 płatności: 2 niedostępne (min za wysoki, max za niski), 1 dostępna (brak limitów)
|
||||
$paymentMethods = [
|
||||
1 => [
|
||||
$this->makePaymentMethod(1, 100.00, null),
|
||||
$this->makePaymentMethod(2, null, 1.00),
|
||||
$this->makePaymentMethod(3),
|
||||
],
|
||||
];
|
||||
|
||||
$mockDb = $this->createMockDbForTransportMethodsFront($transports, $paymentMethods);
|
||||
$repository = new TransportRepository($mockDb);
|
||||
|
||||
$result = $repository->transportMethodsFront([], null);
|
||||
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertSame(1, $result[0]['id']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<b>ver. 0.305 - 22.02.2026</b><br />
|
||||
<b>ver. 0.306 - 22.02.2026</b><br />
|
||||
FIX - ukrywanie form dostawy gdy nie ma dostepnych form platnosci (filtrowanie po min/max kwoty zamowienia)
|
||||
<hr>
|
||||
<b>ver. 0.305 - 22.02.2026</b><br />
|
||||
FIX - naprawa kolejnosci atrybutow permutacji, NEW - pasek postepu darmowej dostawy w koszyku
|
||||
<hr>
|
||||
<b>ver. 0.304 - 22.02.2026</b><br />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?
|
||||
$current_ver = 305;
|
||||
$current_ver = 306;
|
||||
|
||||
for ($i = 1; $i <= $current_ver; $i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user