From f16f5ce8f814e8699a41eb86312bfb46d2bba6e7 Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Sun, 22 Feb 2026 17:09:38 +0100 Subject: [PATCH] ver. 0.306: hide transport methods with no available payment methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- CLAUDE.md | 2 +- .../Domain/Transport/TransportRepository.php | 38 +++- docs/CHANGELOG.md | 8 + docs/TESTING.md | 2 +- .../Transport/TransportRepositoryTest.php | 193 ++++++++++++++++++ updates/changelog.php | 5 +- updates/versions.php | 2 +- 7 files changed, 244 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index f52df71..8712a0c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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. diff --git a/autoload/Domain/Transport/TransportRepository.php b/autoload/Domain/Transport/TransportRepository.php index de2afaf..c48306e 100644 --- a/autoload/Domain/Transport/TransportRepository.php +++ b/autoload/Domain/Transport/TransportRepository.php @@ -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; } /** diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 62d25e1..f089337 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -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`. diff --git a/docs/TESTING.md b/docs/TESTING.md index bb97968..8e1f110 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -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) diff --git a/tests/Unit/Domain/Transport/TransportRepositoryTest.php b/tests/Unit/Domain/Transport/TransportRepositoryTest.php index bf8f1ae..6dc5a47 100644 --- a/tests/Unit/Domain/Transport/TransportRepositoryTest.php +++ b/tests/Unit/Domain/Transport/TransportRepositoryTest.php @@ -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']); + } } diff --git a/updates/changelog.php b/updates/changelog.php index 1f5d55d..6363ece 100644 --- a/updates/changelog.php +++ b/updates/changelog.php @@ -1,4 +1,7 @@ -ver. 0.305 - 22.02.2026
+ver. 0.306 - 22.02.2026
+FIX - ukrywanie form dostawy gdy nie ma dostepnych form platnosci (filtrowanie po min/max kwoty zamowienia) +
+ver. 0.305 - 22.02.2026
FIX - naprawa kolejnosci atrybutow permutacji, NEW - pasek postepu darmowej dostawy w koszyku
ver. 0.304 - 22.02.2026
diff --git a/updates/versions.php b/updates/versions.php index ae71dcb..8d7024f 100644 --- a/updates/versions.php +++ b/updates/versions.php @@ -1,5 +1,5 @@