diff --git a/features/order/managing_orders/order_details/seeing_order.feature b/features/order/managing_orders/order_details/seeing_order.feature index 367923c92f7..7c16f57baaf 100644 --- a/features/order/managing_orders/order_details/seeing_order.feature +++ b/features/order/managing_orders/order_details/seeing_order.feature @@ -16,7 +16,7 @@ Feature: Seeing basic information about an order And the customer chose "Free" shipping method with "Cash on Delivery" payment And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing basic information about an order When I view the summary of the order "#00000666" Then it should have been placed by the customer "lucy@teamlucifer.com" diff --git a/features/order/managing_orders/order_details/seeing_order_aggregated_discounts.feature b/features/order/managing_orders/order_details/seeing_order_aggregated_discounts.feature index 9d5028dd1a1..6dccd079700 100644 --- a/features/order/managing_orders/order_details/seeing_order_aggregated_discounts.feature +++ b/features/order/managing_orders/order_details/seeing_order_aggregated_discounts.feature @@ -16,7 +16,7 @@ Feature: Seeing aggregated discounts of an order And there is a customer "robin.hood@sherwood.com" that placed an order "#00000006" And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing shipping and order promotions, but the shipping promotion is not aggregated in summary's promotion total Given the customer bought 2 "Longbow" products And the customer chose "DHL" shipping method to "United States" with "Cash on Delivery" payment @@ -28,7 +28,7 @@ Feature: Seeing aggregated discounts of an order And the order's shipping total should be "$5.00" And the order's total should be "$285.00" - @ui + @api @ui Scenario: Seeing multiple order promotions aggregated in summary Given there is a promotion "Big order discount" And it gives "$70.00" discount to every order with quantity at least 3 diff --git a/features/order/managing_orders/order_details/seeing_order_aggregated_taxes.feature b/features/order/managing_orders/order_details/seeing_order_aggregated_taxes.feature index ca49b0fd83a..07a5a756a6e 100644 --- a/features/order/managing_orders/order_details/seeing_order_aggregated_taxes.feature +++ b/features/order/managing_orders/order_details/seeing_order_aggregated_taxes.feature @@ -20,7 +20,7 @@ Feature: Seeing aggregated taxes of an order And there is a customer "charles.the.great@medieval.com" that placed an order "#00000001" And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing aggregated taxes of products and shipping Given the customer bought a single "Composite bow" And the customer chose "DHL" shipping method to "United States" with "Offline" payment @@ -31,7 +31,7 @@ Feature: Seeing aggregated taxes of an order And the order's tax total should be "$25.30" And the order's total should be "$135.30" - @ui + @api @ui Scenario: Seeing aggregated taxes of multiple products from different tax rates and shipping Given the customer bought a single "Composite bow" And the customer bought a "Claymore" and a "Bastard sword" diff --git a/features/order/managing_orders/order_details/seeing_order_currency_on_show.feature b/features/order/managing_orders/order_details/seeing_order_currency_on_show.feature index 11e109949d3..49c8c6ee230 100644 --- a/features/order/managing_orders/order_details/seeing_order_currency_on_show.feature +++ b/features/order/managing_orders/order_details/seeing_order_currency_on_show.feature @@ -22,7 +22,7 @@ Feature: Seeing the currency an order has been placed in on it's details page And there is a customer "Satin" identified by an email "satin@teamlucifer.com" and a password "pswd" And I am logged in as an administrator - @ui + @api @ui Scenario: All prices are in the base currency when the client haven't chosen any other Given there is a customer "satin@teamlucifer.com" that placed an order "#00000666" And the customer bought a single "Angel T-Shirt" @@ -31,14 +31,14 @@ Feature: Seeing the currency an order has been placed in on it's details page And the customer chose "DHL" shipping method with "Cash on Delivery" payment When I view the summary of the order "#00000666" And I check "Angel T-Shirt" data - Then its discounted unit price should be $5.00 - And its unit price should be $20.00 - And its subtotal should be $5.00 - And its discount should be -$10.00 - And its tax should be $0.50 - And its total should be $5.50 - And the order's items total should be "$5.50" + Then the order's items total should be "$5.50" And the order's shipping total should be "$20.00" And the order's tax total should be "$0.50" And the order's promotion total should be "-$15.00" And the order's total should be "$25.50" + And its unit price should be $20.00 + And its total should be $5.50 + And its discounted unit price should be $5.00 + And its subtotal should be $5.00 + And its discount should be -$10.00 + And its tax should be $0.50 diff --git a/features/order/managing_orders/order_details/seeing_order_discounts.feature b/features/order/managing_orders/order_details/seeing_order_discounts.feature index a12e318b9e2..0334feb27f1 100644 --- a/features/order/managing_orders/order_details/seeing_order_discounts.feature +++ b/features/order/managing_orders/order_details/seeing_order_discounts.feature @@ -15,7 +15,7 @@ Feature: Seeing discounts of an order And there is a customer "lucy@teamlucifer.com" that placed an order "#00000666" And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing promotion discount on order while buying at least 3 items Given the promotion gives "$15.00" discount to every order with quantity at least 3 And the customer bought 4 "Angel T-Shirt" products @@ -26,7 +26,7 @@ Feature: Seeing discounts of an order And the order's promotion discount should be "-$15.00" from "Holiday promotion" promotion And the order's total should be "$141.00" - @ui + @api @ui Scenario: Seeing promotion discount on order's items while buying a product from a promoted taxon Given the promotion gives "$10.00" off on every product classified as "T-Shirts" And the customer bought a single "Angel T-Shirt" diff --git a/features/order/managing_orders/order_details/seeing_order_item_detailed_data.feature b/features/order/managing_orders/order_details/seeing_order_item_detailed_data.feature index 15c296d3a70..d3c3bf7c8d0 100644 --- a/features/order/managing_orders/order_details/seeing_order_item_detailed_data.feature +++ b/features/order/managing_orders/order_details/seeing_order_item_detailed_data.feature @@ -23,14 +23,14 @@ Feature: Seeing order item detailed data And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing details of item in one row Given I view the summary of the order "#00000666" - When I check "Iron Man T-Shirt" data + When I check "Marvel T-Shirt" data Then its code should be "IRON_MAN_T_SHIRT" And its unit price should be $49.00 - And its discounted unit price should be $44.00 + And its total should be $193.60 And its quantity should be 4 + And its discounted unit price should be $44.00 And its subtotal should be $176.00 And its tax should be $17.60 - And its total should be $193.60 diff --git a/features/order/managing_orders/order_details/seeing_order_item_included_taxes.feature b/features/order/managing_orders/order_details/seeing_order_item_included_taxes.feature index d9a17abab1e..5decf0c51f1 100644 --- a/features/order/managing_orders/order_details/seeing_order_item_included_taxes.feature +++ b/features/order/managing_orders/order_details/seeing_order_item_included_taxes.feature @@ -15,12 +15,12 @@ Feature: Seeing included in price taxes of order items And there is a customer "lucy@teamlucifer.com" that placed an order "#00000666" And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing included in price taxes of order items are not counted in taxes total Given the customer bought 2 "Winchester M1866" products And the customer chose "Free" shipping method to "United States" with "Offline" payment When I view the summary of the order "#00000666" And I check "Winchester M1866" data - Then its tax included in price should be $40.00 - And the order's tax total should be "$40.00" + Then the order's tax total should be "$40.00" And the order's total should be "$440.00" + And its tax included in price should be $40.00 diff --git a/features/order/managing_orders/order_details/seeing_order_item_taxes.feature b/features/order/managing_orders/order_details/seeing_order_item_taxes.feature index f538a6ee546..5eb3c596bbc 100644 --- a/features/order/managing_orders/order_details/seeing_order_item_taxes.feature +++ b/features/order/managing_orders/order_details/seeing_order_item_taxes.feature @@ -15,7 +15,7 @@ Feature: Seeing taxes of order items And there is a customer "lucy@teamlucifer.com" that placed an order "#00000666" And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing taxes of order items Given the customer bought a "PHP T-Shirt" and a "Symfony2 T-Shirt" And the customer chose "Free" shipping method to "United States" with "Offline" payment diff --git a/features/order/managing_orders/order_details/seeing_order_items_with_proper_names.feature b/features/order/managing_orders/order_details/seeing_order_items_with_proper_names.feature index 620b7dd0b61..24cc2ca4d13 100644 --- a/features/order/managing_orders/order_details/seeing_order_items_with_proper_names.feature +++ b/features/order/managing_orders/order_details/seeing_order_items_with_proper_names.feature @@ -15,7 +15,7 @@ Feature: Seeing order items with proper names And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing order items with proper names Given the product "Angel T-Shirt" was renamed to "Devil Cardigan" And the product "Angel Mug" was renamed to "Devil Glass" diff --git a/features/order/managing_orders/order_details/seeing_order_new_state_after_customers_checkout.feature b/features/order/managing_orders/order_details/seeing_order_new_state_after_customers_checkout.feature index b34d15e899c..ca8313c6180 100644 --- a/features/order/managing_orders/order_details/seeing_order_new_state_after_customers_checkout.feature +++ b/features/order/managing_orders/order_details/seeing_order_new_state_after_customers_checkout.feature @@ -12,7 +12,7 @@ Feature: Placing an order And there is a customer "sylius@example.com" that placed an order "#00000022" And I am logged in as an administrator - @ui + @api @ui Scenario: Verifying that order has new state right after checkout Given the customer bought 3 "Iron Maiden T-Shirt" products And the customer chose "Free" shipping method to "United States" with "Offline" payment diff --git a/features/order/managing_orders/order_details/seeing_order_payment_state_as_completed_if_free_order_coupon_was_applied.feature b/features/order/managing_orders/order_details/seeing_order_payment_state_as_completed_if_free_order_coupon_was_applied.feature index e44bea3a22c..95d4d9b147a 100644 --- a/features/order/managing_orders/order_details/seeing_order_payment_state_as_completed_if_free_order_coupon_was_applied.feature +++ b/features/order/managing_orders/order_details/seeing_order_payment_state_as_completed_if_free_order_coupon_was_applied.feature @@ -18,7 +18,7 @@ Feature: Seeing payment state as paid after checkout steps if order total is zer And the customer chose "Free" shipping method And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing payment state as paid on orders list When I browse orders Then the order "#00000666" should have order payment state "Paid" diff --git a/features/order/managing_orders/order_details/seeing_order_payment_state_as_completed_if_order_total_is_zero.feature b/features/order/managing_orders/order_details/seeing_order_payment_state_as_completed_if_order_total_is_zero.feature index 5bdeb1bdf0d..fcc8a32250b 100644 --- a/features/order/managing_orders/order_details/seeing_order_payment_state_as_completed_if_order_total_is_zero.feature +++ b/features/order/managing_orders/order_details/seeing_order_payment_state_as_completed_if_order_total_is_zero.feature @@ -16,12 +16,17 @@ Feature: Seeing payment state as paid after checkout steps if order total is zer And the customer chose "Free" shipping method And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing payment state as paid on orders list When I browse orders Then the order "#00000666" should have order payment state "Paid" - @ui + @api @no-ui + Scenario: Seeing payment state as paid on order's summary + When I view the summary of the order "#00000666" + Then I should be informed that there are no payments + + @ui @no-api Scenario: Seeing payment state as paid on order's summary When I view the summary of the order "#00000666" Then I should be informed that there are no payments diff --git a/features/order/managing_orders/order_details/seeing_order_shipment_state_after_checkout.feature b/features/order/managing_orders/order_details/seeing_order_shipment_state_after_checkout.feature index d28bd14aafa..c97a1e025ac 100644 --- a/features/order/managing_orders/order_details/seeing_order_shipment_state_after_checkout.feature +++ b/features/order/managing_orders/order_details/seeing_order_shipment_state_after_checkout.feature @@ -15,19 +15,19 @@ Feature: Seeing shipping states of an order after checkout steps And the customer chose "Free" shipping method with "Cash on Delivery" payment And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing ready order shipping state When I browse orders - Then order "#00000666" should have shipment state ready + Then order "#00000666" should have shipment state "ready" - @ui + @api @ui Scenario: Seeing shipped order shipping state Given this order has already been shipped When I browse orders - Then order "#00000666" should have shipment state shipped + Then order "#00000666" should have shipment state "shipped" - @ui + @api @ui Scenario: Seeing cancelled order shipping state Given the customer cancelled this order When I browse orders - Then order "#00000666" should have shipment state cancelled + Then order "#00000666" should have shipment state "cancelled" diff --git a/features/order/managing_orders/order_details/seeing_order_shipment_state_as_shipped_if_there_is_not_shipments_to_deliver.feature b/features/order/managing_orders/order_details/seeing_order_shipment_state_as_shipped_if_there_is_not_shipments_to_deliver.feature index 8bd9c553421..2d3201e533b 100644 --- a/features/order/managing_orders/order_details/seeing_order_shipment_state_as_shipped_if_there_is_not_shipments_to_deliver.feature +++ b/features/order/managing_orders/order_details/seeing_order_shipment_state_as_shipped_if_there_is_not_shipments_to_deliver.feature @@ -16,12 +16,12 @@ Feature: Seeing shipping states of an order as shipped if there are no shipments And the customer chose "Cash on Delivery" payment And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing shipping state as shipped on orders list When I browse orders Then the order "#00000666" should have order shipping state "Shipped" - @ui + @api @ui Scenario: Seeing shipping state as shipped on order's summary When I view the summary of the order "#00000666" Then it should have order's shipping state "Shipped" diff --git a/features/order/managing_orders/order_details/seeing_order_shipping_fees.feature b/features/order/managing_orders/order_details/seeing_order_shipping_fees.feature index 02ce1366227..12222dd7ee4 100644 --- a/features/order/managing_orders/order_details/seeing_order_shipping_fees.feature +++ b/features/order/managing_orders/order_details/seeing_order_shipping_fees.feature @@ -14,7 +14,7 @@ Feature: Seeing shipping fees of an order And the customer bought a single "Angel T-Shirt" And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing Free shipping of an order Given the customer chose "Free" shipping method to "United States" with "Offline" payment When I view the summary of the order "#00000666" @@ -24,7 +24,7 @@ Feature: Seeing shipping fees of an order And the order's shipping total should be "$0.00" And the order's total should be "$39.00" - @ui + @api @ui Scenario: Seeing shipping fee of an order Given the customer chose "DHL" shipping method to "United States" with "Offline" payment When I view the summary of the order "#00000666" diff --git a/features/order/managing_orders/order_details/seeing_order_shipping_taxes.feature b/features/order/managing_orders/order_details/seeing_order_shipping_taxes.feature index f4a9f8184d6..674116b518c 100644 --- a/features/order/managing_orders/order_details/seeing_order_shipping_taxes.feature +++ b/features/order/managing_orders/order_details/seeing_order_shipping_taxes.feature @@ -16,7 +16,7 @@ Feature: Seeing taxes of an order And there is a customer "lucy@teamlucifer.com" that placed an order "#00000666" And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing taxes of order items and shipping Given the customer bought a single "Symfony2 T-Shirt" And the customer chose "DHL" shipping method to "United States" with "Offline" payment @@ -28,7 +28,7 @@ Feature: Seeing taxes of an order And the order's tax total should be "$34.50" And the order's total should be "$184.50" - @ui + @api @ui Scenario: Seeing taxes of items and shipping from paid order Given the customer bought a single "Symfony2 T-Shirt" And the customer chose "DHL" shipping method to "United States" with "Offline" payment diff --git a/features/order/managing_orders/order_details/seeing_order_shipping_total_with_applied_promotion_and_taxes.feature b/features/order/managing_orders/order_details/seeing_order_shipping_total_with_applied_promotion_and_taxes.feature index 3182fbe1131..1e4d2d9ea80 100644 --- a/features/order/managing_orders/order_details/seeing_order_shipping_total_with_applied_promotion_and_taxes.feature +++ b/features/order/managing_orders/order_details/seeing_order_shipping_total_with_applied_promotion_and_taxes.feature @@ -19,7 +19,7 @@ Feature: Seeing shipping total with applied promotion and taxes And the customer bought a single "Gryffindor scarf" And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing taxes of order items and shipping with applied promotion Given the customer chose "Owl post" shipping method to "United States" with "Offline" payment When I view the summary of the order "#00000777" @@ -30,7 +30,7 @@ Feature: Seeing shipping total with applied promotion and taxes And the order's tax total should be "$24.15" And the order's total should be "$129.15" - @ui @domain + @api @ui @domain Scenario: Seeing taxes of order items and multiple shipments with applied promotion Given the store has "Pigeon post" shipping method with "$16.00" fee within the "US" zone And shipping method "Pigeon post" belongs to "Shipping Services" tax category diff --git a/features/order/managing_orders/order_details/seeing_order_with_different_promotions.feature b/features/order/managing_orders/order_details/seeing_order_with_different_promotions.feature index c445b117ed4..90b6d0e7809 100644 --- a/features/order/managing_orders/order_details/seeing_order_with_different_promotions.feature +++ b/features/order/managing_orders/order_details/seeing_order_with_different_promotions.feature @@ -17,21 +17,21 @@ Feature: Seeing order with different promotions And there is a customer "lucy@teamlucifer.com" that placed an order "#00000666" And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing prices and discount prices of order item Given the customer bought 2 "PHP T-Shirt" products And the customer bought a single "Symfony Mug" And the customer chose "Free" shipping method to "United States" with "Offline" payment When I view the summary of the order "#00000666" Then the "PHP T-Shirt" product's unit price should be "$60.00" - And the "PHP T-Shirt" product's item discount should be "-$20.00" - And the "PHP T-Shirt" product's order discount should be "~ -$3.34" And the "PHP T-Shirt" product's discounted unit price should be "$36.66" And the "PHP T-Shirt" product's quantity should be 2 + And the "PHP T-Shirt" product's item discount should be "-$20.00" + And the "PHP T-Shirt" product's order discount should be "~ -$3.34" And the "PHP T-Shirt" product's subtotal should be "$73.33" And the "Symfony Mug" product's unit price should be "$40.00" - And the "Symfony Mug" product's item discount should be "$0.00" - And the "Symfony Mug" product's order discount should be "~ -$3.33" And the "Symfony Mug" product's discounted unit price should be "$36.67" And the "Symfony Mug" product's quantity should be 1 + And the "Symfony Mug" product's item discount should be "$0.00" + And the "Symfony Mug" product's order discount should be "~ -$3.33" And the "Symfony Mug" product's subtotal should be "$36.67" diff --git a/features/order/managing_orders/order_details/seeing_order_with_items.feature b/features/order/managing_orders/order_details/seeing_order_with_items.feature index e720a348ac1..3d87782ae64 100644 --- a/features/order/managing_orders/order_details/seeing_order_with_items.feature +++ b/features/order/managing_orders/order_details/seeing_order_with_items.feature @@ -15,7 +15,7 @@ Feature: Seeing an order with its items And the customer chose "Free" shipping method to "United States" with "Cash on Delivery" payment And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing order items When I view the summary of the order "#00000666" Then it should have 2 items diff --git a/features/order/managing_orders/order_details/seeing_order_without_shipping_address.feature b/features/order/managing_orders/order_details/seeing_order_without_shipping_address.feature index 10c79ff59f9..a6c1513e8f7 100644 --- a/features/order/managing_orders/order_details/seeing_order_without_shipping_address.feature +++ b/features/order/managing_orders/order_details/seeing_order_without_shipping_address.feature @@ -16,10 +16,10 @@ Feature: Seeing an order without shipping address And the customer chose "Cash on Delivery" payment And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing basic information about an order When I view the summary of the order "#00000666" Then it should have been placed by the customer "lucy@teamlucifer.com" - And it should be billed to "Mike Ross", "350 5th Ave", "10118", "New York", "United States" + And it should have "Mike Ross", "350 5th Ave", "10118", "New York", "United States" as its billing address And it should be paid with "Cash on Delivery" And it should have no shipping address set diff --git a/features/order/managing_orders/order_details/seeing_province_created_manually_on_order_page.feature b/features/order/managing_orders/order_details/seeing_province_created_manually_on_order_page.feature index b035062a5d7..eab25f8a0ea 100644 --- a/features/order/managing_orders/order_details/seeing_province_created_manually_on_order_page.feature +++ b/features/order/managing_orders/order_details/seeing_province_created_manually_on_order_page.feature @@ -19,8 +19,8 @@ Feature: Seeing province created manually on order summary page And the customer chose "DHL" shipping method with "Cash on Delivery" payment And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing manually definied province on order summary page When I view the summary of the order "#00000666" Then I should see "East of England" as province in the shipping address - And I should see "East of England" ad province in the billing address + And I should see "East of England" as province in the billing address diff --git a/features/order/managing_orders/order_details/seeing_shipment_shipping_date.feature b/features/order/managing_orders/order_details/seeing_shipment_shipping_date.feature index e62f5d523b7..104606918ee 100644 --- a/features/order/managing_orders/order_details/seeing_shipment_shipping_date.feature +++ b/features/order/managing_orders/order_details/seeing_shipment_shipping_date.feature @@ -15,7 +15,7 @@ Feature: Seeing shipment shipping date And it is "20-02-2020 10:30:05" now And I am logged in as an administrator - @ui + @api @ui Scenario: Seeing shipped at date When I view the summary of the order "#00000777" And I ship this order diff --git a/src/Sylius/Behat/Client/ApiClientInterface.php b/src/Sylius/Behat/Client/ApiClientInterface.php index 7ae5bf4fbe0..a81f44a36d8 100644 --- a/src/Sylius/Behat/Client/ApiClientInterface.php +++ b/src/Sylius/Behat/Client/ApiClientInterface.php @@ -18,21 +18,24 @@ interface ApiClientInterface { - public function request(RequestInterface $request): Response; + public function request(RequestInterface $request, bool $forgetResponse = true): Response; - public function index(string $resource, array $queryParameters = []): Response; + /** + * @param array $queryParameters + */ + public function index(string $resource, array $queryParameters = [], bool $forgetResponse = false): Response; - public function showByIri(string $iri): Response; + public function showByIri(string $iri, bool $forgetResponse = false): Response; - public function subResourceIndex(string $resource, string $subResource, string $id): Response; + public function subResourceIndex(string $resource, string $subResource, string $id, array $queryParameters = [], bool $forgetResponse = false): Response; - public function show(string $resource, string $id): Response; + public function show(string $resource, string $id, bool $forgetResponse = false): Response; - public function create(?RequestInterface $request = null): Response; + public function create(?RequestInterface $request = null, bool $forgetResponse = false): Response; - public function update(): Response; + public function update(bool $forgetResponse = false): Response; - public function delete(string $resource, string $id): Response; + public function delete(string $resource, string $id, bool $forgetResponse = false): Response; public function filter(): Response; diff --git a/src/Sylius/Behat/Client/ApiPlatformClient.php b/src/Sylius/Behat/Client/ApiPlatformClient.php index efac2507423..feae4f3c2b2 100644 --- a/src/Sylius/Behat/Client/ApiPlatformClient.php +++ b/src/Sylius/Behat/Client/ApiPlatformClient.php @@ -23,6 +23,8 @@ final class ApiPlatformClient implements ApiClientInterface { private ?RequestInterface $request = null; + private ?Response $lastResponse = null; + public function __construct( private AbstractBrowser $client, private SharedStorageInterface $sharedStorage, @@ -32,33 +34,33 @@ public function __construct( ) { } - public function index(string $resource, array $queryParameters = []): Response + public function index(string $resource, array $queryParameters = [], bool $forgetResponse = false): Response { $this->request = $this ->requestFactory ->index($this->section, $resource, $this->authorizationHeader, $this->getToken(), $queryParameters) ; - return $this->request($this->request); + return $this->request($this->request, $forgetResponse); } - public function showByIri(string $iri): Response + public function showByIri(string $iri, bool $forgetResponse = false): Response { $request = $this->requestFactory->custom($iri, HttpRequest::METHOD_GET); $request->authorize($this->getToken(), $this->authorizationHeader); - return $this->request($request); + return $this->request($request, $forgetResponse); } - public function subResourceIndex(string $resource, string $subResource, string $id): Response + public function subResourceIndex(string $resource, string $subResource, string $id, array $queryParameters = [], bool $forgetResponse = false): Response { - $request = $this->requestFactory->subResourceIndex($this->section, $resource, $id, $subResource); + $request = $this->requestFactory->subResourceIndex($this->section, $resource, $id, $subResource, $queryParameters); $request->authorize($this->getToken(), $this->authorizationHeader); - return $this->request($request); + return $this->request($request, $forgetResponse); } - public function show(string $resource, string $id): Response + public function show(string $resource, string $id, bool $forgetResponse = false): Response { return $this->request( $this->requestFactory->show( @@ -68,25 +70,26 @@ public function show(string $resource, string $id): Response $this->authorizationHeader, $this->getToken(), ), + $forgetResponse ); } - public function create(?RequestInterface $request = null): Response + public function create(?RequestInterface $request = null, bool $forgetResponse = false): Response { - return $this->request($request ?? $this->request); + return $this->request($request ?? $this->request, $forgetResponse); } - public function update(): Response + public function update(bool $forgetResponse = false): Response { - return $this->request($this->request); + return $this->request($this->request, $forgetResponse); } - public function resend(): Response + public function resend(bool $forgetResponse = false): Response { - return $this->request($this->request); + return $this->request($this->request, $forgetResponse); } - public function delete(string $resource, string $id): Response + public function delete(string $resource, string $id, bool $forgetResponse = false): Response { return $this->request( $this->requestFactory->delete( @@ -96,6 +99,7 @@ public function delete(string $resource, string $id): Response $this->authorizationHeader, $this->getToken(), ), + $forgetResponse, ); } @@ -239,7 +243,11 @@ public function getContent(): array public function getLastResponse(): Response { - return $this->client->getResponse(); + if (null === $this->lastResponse) { + throw new \RuntimeException('There is no last response.'); + } + + return $this->lastResponse; } public function getToken(): ?string @@ -247,7 +255,7 @@ public function getToken(): ?string return $this->sharedStorage->has('token') ? $this->sharedStorage->get('token') : null; } - public function request(RequestInterface $request): Response + public function request(RequestInterface $request, bool $forgetResponse = false): Response { $this->setServerParameters(); @@ -260,7 +268,14 @@ public function request(RequestInterface $request): Response $request->content() ?? null, ); - return $this->getLastResponse(); + /** @var Response $response */ + $response = $this->client->getResponse(); + + if (false === $forgetResponse) { + $this->lastResponse = $response; + } + + return $response; } private function setServerParameters(): void diff --git a/src/Sylius/Behat/Client/RequestFactory.php b/src/Sylius/Behat/Client/RequestFactory.php index 69e745649e4..2b854925eba 100644 --- a/src/Sylius/Behat/Client/RequestFactory.php +++ b/src/Sylius/Behat/Client/RequestFactory.php @@ -47,10 +47,22 @@ public function index( return $builder->build(); } - public function subResourceIndex(string $section, string $resource, string $id, string $subResource): RequestInterface - { + public function subResourceIndex( + string $section, + string $resource, + string $id, + string $subResource, + array $queryParameters = [], + ): RequestInterface { $builder = RequestBuilder::create( - sprintf('%s/%s/%s/%s/%s', $this->apiUrlPrefix, $section, $resource, $id, $subResource), + sprintf('%s/%s/%s/%s/%s%s', + $this->apiUrlPrefix, + $section, + $resource, + $id, + $subResource, + $this->getQueryString($queryParameters), + ), HttpRequest::METHOD_GET, ); $builder->withHeader('HTTP_ACCEPT', self::LINKED_DATA_JSON_CONTENT_TYPE); diff --git a/src/Sylius/Behat/Client/RequestFactoryInterface.php b/src/Sylius/Behat/Client/RequestFactoryInterface.php index 9e5c8856595..4d221ce9068 100644 --- a/src/Sylius/Behat/Client/RequestFactoryInterface.php +++ b/src/Sylius/Behat/Client/RequestFactoryInterface.php @@ -22,11 +22,15 @@ public function index( ?string $token = null, ): RequestInterface; + /** + * @param array $queryParameters + */ public function subResourceIndex( string $section, string $resource, string $id, string $subResource, + array $queryParameters = [], ): RequestInterface; public function show( diff --git a/src/Sylius/Behat/Context/Api/Admin/ManagingOrdersContext.php b/src/Sylius/Behat/Context/Api/Admin/ManagingOrdersContext.php index df207f40c49..67d2557f096 100644 --- a/src/Sylius/Behat/Context/Api/Admin/ManagingOrdersContext.php +++ b/src/Sylius/Behat/Context/Api/Admin/ManagingOrdersContext.php @@ -21,15 +21,20 @@ use Sylius\Behat\Service\SecurityServiceInterface; use Sylius\Behat\Service\SharedSecurityServiceInterface; use Sylius\Behat\Service\SharedStorageInterface; +use Sylius\Component\Core\Model\AdjustmentInterface; use Sylius\Component\Core\Model\AdminUserInterface; use Sylius\Component\Core\Model\ChannelInterface; use Sylius\Component\Core\Model\CustomerInterface; use Sylius\Component\Core\Model\OrderInterface; +use Sylius\Component\Core\Model\OrderItemInterface; +use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\Component\Core\Model\ShippingMethodInterface; use Sylius\Component\Currency\Model\CurrencyInterface; use Sylius\Component\Order\OrderTransitions; use Sylius\Component\Payment\PaymentTransitions; use Sylius\Component\Shipping\ShipmentTransitions; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Intl\Countries; use Webmozart\Assert\Assert; final class ManagingOrdersContext implements Context @@ -217,6 +222,27 @@ public function iLimitNumberOfItemsTo(int $limit): void $this->client->filter(); } + /** + * @When I check :itemName data + */ + public function iCheckData(string $itemName): void + { + /** @var string $lastResponseContent */ + $lastResponseContent = $this->client->getLastResponse()->getContent(); + /** @var array{productName: string}[] $items */ + $items = json_decode($lastResponseContent, true)['items']; + + foreach ($items as $item) { + if ($item['productName'] === $itemName) { + $this->sharedStorage->set('item', $item); + + return; + } + } + + throw new \InvalidArgumentException(sprintf('There is no item with name "%s".', $itemName)); + } + /** * @Then I should see a single order from customer :customer */ @@ -232,6 +258,15 @@ public function iShouldSeeASingleOrderFromCustomer(CustomerInterface $customer): ); } + /** + * @Then it should( still) have a :state state + */ + public function itShouldHaveState(string $state): void + { + Assert::true($this->responseChecker->hasItemWithValue($this->client->getLastResponse(), 'state', $state)); + Assert::count($this->responseChecker->getCollection($this->client->getLastResponse()), 1); + } + /** * @Then I should see a single order in the list * @Then I should see :number orders in the list @@ -267,12 +302,13 @@ public function itsStateShouldBe(string $state): void } /** - * @Then it should have shipment in state :state + * @Then /^(it) should have shipment in state "([^"]+)"$/ + * @Then /^(order "[^"]+") should have shipment state "([^"]+)"$/ */ - public function itShouldHaveShipmentState(string $state): void + public function itShouldHaveShipmentState(OrderInterface $order, string $state): void { $shipmentIri = $this->responseChecker->getValue( - $this->client->show(Resources::ORDERS, $this->sharedStorage->get('order')->getTokenValue()), + $this->client->show(Resources::ORDERS, $order->getTokenValue()), 'shipments', )[0]; @@ -310,6 +346,7 @@ public function theOrderShouldHaveNumberOfPayments(int $number): void } /** + * @Then the order :order should have order payment state :orderPaymentState * @Then /^(this order) should have order payment state "([^"]+)"$/ */ public function theOrderShouldHavePaymentState(OrderInterface $order, string $paymentState): void @@ -418,6 +455,65 @@ public function theOrdersPromotionTotalShouldBe(int $promotionTotal): void ); } + /** + * @Then the order's promotion discount should be :promotionAmount from :promotionName promotion + */ + public function theOrdersPromotionDiscountShouldBeFromPromotion(string $promotionAmount, string $promotionName): void + { + $this->responseChecker->hasItemWithValues( + $this->getAdjustmentsResponseForOrder(true), + [ + 'type' => AdjustmentInterface::ORDER_PROMOTION_ADJUSTMENT, + 'label' => $promotionName, + 'amount' => $this->getTotalAsInt($promotionAmount), + ], + ); + } + + /** + * @Then the order's shipping promotion should be :promotionAmount + */ + public function theOrdersShippingPromotionDiscountShouldBe(string $promotionAmount): void + { + $this->responseChecker->hasItemWithValues( + $this->getAdjustmentsResponseForOrder(true), + [ + 'type' => AdjustmentInterface::ORDER_SHIPPING_PROMOTION_ADJUSTMENT, + 'amount' => $this->getTotalAsInt($promotionAmount), + ], + ); + } + + /** + * @Then there should be a shipping charge :shippingCharge for :shippingMethodName method + */ + public function thereShouldBeAShippingChargeForMethod(string $shippingCharge, string $shippingMethodName): void + { + $this->responseChecker->hasItemWithValues( + $this->getAdjustmentsResponseForOrder(true), + [ + 'type' => AdjustmentInterface::SHIPPING_ADJUSTMENT, + 'label' => $shippingMethodName, + 'amount' => $this->getTotalAsInt($shippingCharge), + ], + ); + } + + /** + * @Then there should be a shipping tax :shippingTax for :shippingMethodName method + */ + public function thereShouldBeAShippingTaxForMethod(string $shippingTax, string $shippingMethodName): void + { + $this->responseChecker->hasItemWithValues( + $this->getAdjustmentsResponseForOrder(true), + [ + 'type' => AdjustmentInterface::TAX_ADJUSTMENT, + 'label' => $shippingMethodName, + 'amount' => $this->getTotalAsInt($shippingTax), + ], + ); + } + /** * @Then /^(the administrator) should see that (order placed by "[^"]+") has "([^"]+)" currency$/ */ @@ -526,6 +622,387 @@ public function theAdministratorShouldSeeTheOrderWithTotalInOrderList(string $to Assert::same($firstItem['total'], $total); } + /** + * @Then it should have been placed by the customer :customer + */ + public function itShouldHaveBeenPlacedByTheCustomer(CustomerInterface $customer): void + { + Assert::same( + $this->responseChecker->getValue($this->client->getLastResponse(), 'customer'), + $this->iriConverter->getIriFromResource($customer), + ); + } + + /** + * @Then it should be shipped via the :shippingMethod shipping method + */ + public function itShouldBeShippedViaTheShippingMethod(ShippingMethodInterface $shippingMethod): void + { + Assert::same( + $this->responseChecker->getValue($this->client->getLastResponse(), 'shipments')[0]['method'], + $this->iriConverter->getIriFromResource($shippingMethod), + ); + } + + /** + * @Then it should be paid with :paymentMethod + */ + public function itShouldBePaidWith(PaymentMethodInterface $paymentMethod): void + { + Assert::same( + $this->responseChecker->getValue($this->client->getLastResponse(), 'payments')[0]['method'], + $this->iriConverter->getIriFromResource($paymentMethod), + ); + } + + /** + * @Then it should have no shipping address set + */ + public function itShouldHaveNoShippingAddressSet(): void + { + Assert::false($this->responseChecker->hasKey($this->client->getLastResponse(), 'shippingAddress')); + } + + /** + * @Then it should be shipped to :customerName, :street, :postcode, :city, :countryName + */ + public function itShouldBeShippedTo( + string $customerName, + string $street, + string $postcode, + string $city, + string $countryName, + ): void { + $shippingAddress = $this->responseChecker->getValue($this->client->getLastResponse(), 'shippingAddress'); + + $this->itShouldBeAddressedTo( + $shippingAddress, + $customerName, + $street, + $postcode, + $city, + $countryName, + ); + } + + /** + * @Then it should have :customerName, :street, :postcode, :city, :countryName as its billing address + */ + public function itShouldHaveAddressAsItBillingAddress( + string $customerName, + string $street, + string $postcode, + string $city, + string $countryName, + ): void { + $billingAddress = $this->responseChecker->getValue($this->client->getLastResponse(), 'billingAddress'); + + $this->itShouldBeAddressedTo( + $billingAddress, + $customerName, + $street, + $postcode, + $city, + $countryName, + ); + } + + /** + * @Then I should see :provinceName as province in the shipping address + */ + public function iShouldSeeAsProvinceInTheShippingAddress(string $provinceName): void + { + Assert::same( + $this->responseChecker->getValue($this->client->getLastResponse(), 'shippingAddress')['provinceName'], + $provinceName, + ); + } + + /** + * @Then I should see :provinceName as province in the billing address + */ + public function iShouldSeeAsProvinceInTheBillingAddress(string $provinceName): void + { + Assert::same( + $this->responseChecker->getValue($this->client->getLastResponse(), 'billingAddress')['provinceName'], + $provinceName, + ); + } + + /** + * @Then I should see the shipping date as :dateTime + */ + public function iShouldSeeTheShippingDateAs(string $dateTime): void + { + Assert::same( + $this->responseChecker->getValue($this->client->getLastResponse(), 'shippedAt'), + (new \DateTime($dateTime))->format('Y-m-d H:i:s'), + ); + } + + /** + * @Then /^(its) unit price should be ([^"]+)$/ + */ + public function itemUnitPriceShouldBe(array $orderItem, string $unitPrice): void + { + Assert::same($this->getTotalAsInt($unitPrice), $orderItem['unitPrice']); + } + + /** + * @Then /^(its) total should be ([^"]+)$/ + */ + public function itemTotalShouldBe(array $orderItem, string $total): void + { + Assert::same($this->getTotalAsInt($total), $orderItem['total']); + } + + /** + * @Then /^(its) code should be "([^"]+)"$/ + */ + public function itemCodeShouldBe(array $orderItem, string $code): void + { + Assert::endsWith($orderItem['variant'], $code); + } + + /** + * @Then /^(its) quantity should be ([^"]+)$/ + */ + public function itemQuantityShouldBe(array $orderItem, int $quantity): void + { + Assert::same($quantity, $orderItem['quantity']); + } + + /** + * @Then /^its discounted unit price should be ([^"]+)$/ + */ + public function itemDiscountedUnitPriceShouldBe(string $discountedUnitPrice): void + { + $this->responseChecker->hasItemWithValues( + $this->getAdjustmentsResponseForOrder(), + [ + 'type' => AdjustmentInterface::ORDER_ITEM_PROMOTION_ADJUSTMENT, + 'amount' => $this->getTotalAsInt($discountedUnitPrice), + ], + ); + } + + /** + * @Then /^its subtotal should be ([^"]+)$/ + */ + public function itemSubtotalShouldBe(string $subtotal): void + { + $orderItem = $this->sharedStorage->get('item'); + + $unitPromotionAdjustments = 0; + foreach ($this->responseChecker->getCollection($this->client->getLastResponse()) as $item) { + if (in_array($item['type'], [AdjustmentInterface::ORDER_UNIT_PROMOTION_ADJUSTMENT, AdjustmentInterface::ORDER_PROMOTION_ADJUSTMENT])) { + $unitPromotionAdjustments += $item['amount']; + } + } + + Assert::same($this->getTotalAsInt($subtotal), $orderItem['unitPrice'] * $orderItem['quantity'] + $unitPromotionAdjustments); + } + + /** + * @Then /^its discount should be ([^"]+)$/ + */ + public function theItemShouldHaveDiscount(string $discount): void + { + $this->responseChecker->hasItemWithValues( + $this->client->getLastResponse(), + [ + 'type' => AdjustmentInterface::ORDER_UNIT_PROMOTION_ADJUSTMENT, + 'amount' => $this->getTotalAsInt($discount), + ], + ); + } + + /** + * @Then /^its tax should be ([^"]+)$/ + */ + public function itemTaxShouldBe(string $tax): void + { + $this->responseChecker->hasItemWithValues( + $this->client->getLastResponse(), + [ + 'type' => AdjustmentInterface::TAX_ADJUSTMENT, + 'amount' => $this->getTotalAsInt($tax), + ], + ); + } + + /** + * @Then /^its tax included in price should be ([^"]+)$/ + */ + public function itsTaxIncludedInPriceShouldBe(string $tax): void + { + $unitPromotionAdjustments = $this->responseChecker->getCollectionItemsWithValue( + $this->getAdjustmentsResponseForOrder(), + 'type', + AdjustmentInterface::TAX_ADJUSTMENT + ); + $totalTax = 0; + + foreach ($unitPromotionAdjustments as $unitPromotionAdjustment) { + if (true === $unitPromotionAdjustment['neutral']) { + $totalTax += $unitPromotionAdjustment['amount']; + } + } + + Assert::same($this->getTotalAsInt($tax), $totalTax); + } + + /** + * @Then I should be informed that there are no payments + */ + public function iShouldSeeInformationAboutNoPayments(): void + { + Assert::same( + $this->responseChecker->getValue($this->client->getLastResponse(), 'payments'), + [], + ); + } + + /** + * @Then /^the order "[^"]+" should have order shipping state "([^"]+)"$/ + * @Then it should have order's shipping state :orderShippingState + */ + public function theOrderShouldHaveShippingState(string $orderShippingState): void + { + $ordersResponse = $this->client->index(Resources::ORDERS, forgetResponse: true); + + Assert::true( + $this->responseChecker->hasItemWithValue($ordersResponse, 'shippingState', strtolower($orderShippingState)), + sprintf('Order does not have %s shipping state', $orderShippingState), + ); + } + + /** + * @Then I should not see information about shipments + */ + public function iShouldNotSeeInformationAboutShipping(): void + { + Assert::same( + $this->responseChecker->getValue($this->client->getLastResponse(), 'shipments'), + [], + ); + } + + /** + * @Then the :productName product's unit price should be :price + */ + public function productUnitPriceShouldBe(string $productName, string $price): void + { + $this->iCheckData($productName); + $orderItem = $this->sharedStorage->get('item'); + Assert::same($this->getTotalAsInt($price), $orderItem['unitPrice']); + } + + /** + * @Then the :productName product's discounted unit price should be :price + */ + public function productDiscountedUnitPriceShouldBe(string $productName, string $price): void + { + $orderItem = $this->sharedStorage->get('item'); + Assert::same($this->getTotalAsInt($price), $orderItem['fullDiscountedUnitPrice']); + } + + /** + * @Then the :productName product's quantity should be :quantity + */ + public function productQuantityShouldBe(string $productName, int $quantity): void + { + $orderItem = $this->sharedStorage->get('item'); + Assert::same($quantity, $orderItem['quantity']); + } + + /** + * @Then the :productName product's item discount should be :price + */ + public function productItemDiscountShouldBe(string $productName, string $price): void + { + $orderItem = $this->sharedStorage->get('item'); + + $adjustments = $this->responseChecker->getCollectionItemsWithValue( + $this->getAdjustmentsResponseForOrder(true), + 'type', + AdjustmentInterface::ORDER_UNIT_PROMOTION_ADJUSTMENT + ); + + foreach ($adjustments as $adjustment) { + if (in_array($adjustment['order_item_unit']['@id'], $orderItem['units'])) { + Assert::same($this->getTotalAsInt($price), $adjustment['amount']); + + return; + } + } + } + + /** + * @Then the :productName product's order discount should be :price + */ + public function productOrderDiscountShouldBe(string $productName, string $price): void + { + $orderItem = $this->sharedStorage->get('item'); + + $adjustments = $this->responseChecker->getCollectionItemsWithValue( + $this->getAdjustmentsResponseForOrder(true), + 'type', + AdjustmentInterface::ORDER_PROMOTION_ADJUSTMENT + ); + + foreach ($adjustments as $adjustment) { + if (in_array($adjustment['order_item_unit']['@id'], $orderItem['units'])) { + Assert::same($this->getTotalAsInt(trim($price," ~")), $adjustment['amount']); + return; + } + } + } + + /** + * @Then the :productName product's subtotal should be :subTotal + */ + public function productSubtotalShouldBe(string $productName, string $subTotal): void + { + $orderItem = $this->sharedStorage->get('item'); + $response = $this->getAdjustmentsResponseForOrder(true); + + $unitPromotionAdjustments = 0; + foreach ($this->responseChecker->getCollection($response) as $adjustment) { + if (in_array($adjustment['type'], [AdjustmentInterface::ORDER_UNIT_PROMOTION_ADJUSTMENT, AdjustmentInterface::ORDER_PROMOTION_ADJUSTMENT])) { + if (in_array($adjustment['order_item_unit']['@id'], $orderItem['units'])) { + $unitPromotionAdjustments += $adjustment['amount']; + } + } + } + + Assert::same($this->getTotalAsInt($subTotal), $orderItem['unitPrice'] * $orderItem['quantity'] + $unitPromotionAdjustments); + } + + + /** + * @param array $address + */ + private function itShouldBeAddressedTo( + array $address, + string $customerName, + string $street, + string $postcode, + string $city, + string $countryName, + ): void { + Assert::same($address['firstName'] . ' ' . $address['lastName'], $customerName); + Assert::same($address['street'], $street); + Assert::same($address['postcode'], $postcode); + Assert::same($address['city'], $city); + Assert::same($address['countryCode'], $this->getCountryCodeFromName($countryName)); + } + + private function getCountryCodeFromName(string $name): string + { + return array_flip(Countries::getNames())[$name]; + } + private function getCurrencyCodeFromTotal(string $total): string { return match(true) { @@ -538,6 +1015,26 @@ private function getCurrencyCodeFromTotal(string $total): string private function getTotalAsInt(string $total): int { - return (int) round((float) trim($total, '$€£') * 100, 2); + if ($isMinus = str_starts_with($total, '-')) { + $total = substr($total, 1); + } + $amount = (int) round((float) trim($total, '$€£') * 100, 2); + + if ($isMinus) { + return $amount * -1; + } + return $amount; + } + + private function getAdjustmentsResponseForOrder(bool $forgetResponse = false): Response + { + $orderToken = $this->sharedStorage->get('order')->getTokenValue(); + + return $this->client->subResourceIndex( + Resources::ORDERS, + Resources::ADJUSTMENTS, + (string) $orderToken, + forgetResponse: $forgetResponse, + ); } } diff --git a/src/Sylius/Behat/Context/Api/Resources.php b/src/Sylius/Behat/Context/Api/Resources.php index b6874650827..aa7a0e45295 100644 --- a/src/Sylius/Behat/Context/Api/Resources.php +++ b/src/Sylius/Behat/Context/Api/Resources.php @@ -17,6 +17,8 @@ final class Resources { public const ADDRESSES = 'addresses'; + public const ADJUSTMENTS = 'adjustments'; + public const ADMINISTRATORS = 'administrators'; public const AVATAR_IMAGES = 'avatar-images'; @@ -45,7 +47,7 @@ final class Resources public const ORDER_ITEM_UNITS = 'order-item-units'; - public const ORDER_ITEMS = 'order-item-units'; + public const ORDER_ITEMS = 'order-items'; public const ORDERS = 'orders'; diff --git a/src/Sylius/Behat/Context/Ui/Admin/ManagingOrdersContext.php b/src/Sylius/Behat/Context/Ui/Admin/ManagingOrdersContext.php index aeadd339c35..147e879e3f7 100644 --- a/src/Sylius/Behat/Context/Ui/Admin/ManagingOrdersContext.php +++ b/src/Sylius/Behat/Context/Ui/Admin/ManagingOrdersContext.php @@ -815,7 +815,7 @@ public function iShouldSeeAsProvinceInTheShippingAddress($provinceName) } /** - * @Then I should see :provinceName ad province in the billing address + * @Then I should see :provinceName as province in the billing address */ public function iShouldSeeAdProvinceInTheBillingAddress($provinceName) { diff --git a/src/Sylius/Behat/Resources/config/suites/api/order/managing_orders.yml b/src/Sylius/Behat/Resources/config/suites/api/order/managing_orders.yml index d8db7e8b3b8..dd579e3ce44 100644 --- a/src/Sylius/Behat/Resources/config/suites/api/order/managing_orders.yml +++ b/src/Sylius/Behat/Resources/config/suites/api/order/managing_orders.yml @@ -19,11 +19,15 @@ default: - sylius.behat.context.setup.order - sylius.behat.context.setup.payment - sylius.behat.context.setup.product + - sylius.behat.context.setup.product_taxon - sylius.behat.context.setup.promotion - sylius.behat.context.setup.shipping - sylius.behat.context.setup.shop_api_security - sylius.behat.context.setup.taxation + - sylius.behat.context.setup.taxonomy - sylius.behat.context.setup.zone + + - Sylius\Calendar\Tests\Behat\Context\Setup\CalendarContext - sylius.behat.context.transform.address - sylius.behat.context.transform.cart diff --git a/src/Sylius/Bundle/ApiBundle/Controller/GetOrderAdjustmentsAction.php b/src/Sylius/Bundle/ApiBundle/Controller/GetOrderAdjustmentsAction.php new file mode 100644 index 00000000000..7400a71cc41 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/Controller/GetOrderAdjustmentsAction.php @@ -0,0 +1,43 @@ + $orderRepository + */ + public function __construct ( + private OrderRepositoryInterface $orderRepository, + ) { + } + + /** + * @return Collection + */ + public function __invoke(Request $request, string $tokenValue): Collection + { + /** @var OrderInterface $order */ + $order = $this->orderRepository->findOneBy(['tokenValue' => $tokenValue]); + $type = $request->query->get('type'); + + return $order->getAdjustmentsRecursively($type); + } +} diff --git a/src/Sylius/Bundle/ApiBundle/OpenApi/Documentation/OrderAdjustmentsTypeDocumentationModifier.php b/src/Sylius/Bundle/ApiBundle/OpenApi/Documentation/OrderAdjustmentsTypeDocumentationModifier.php new file mode 100644 index 00000000000..a2a998258f2 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/OpenApi/Documentation/OrderAdjustmentsTypeDocumentationModifier.php @@ -0,0 +1,55 @@ +getPaths(); + + $path = sprintf(self::PATH, $this->apiRoute); + $pathItem = $paths->getPath($path); + $operation = $pathItem->getGet(); + + $parameters = $operation->getParameters(); + $parameters[] = new Parameter( + name: 'type', + in: 'query', + description: 'Type of adjustments you want to get', + schema: [ + 'type' => 'string', + 'enum' => call_user_func([$this->adjustmentResourceClass, 'getAdjustmentTypeChoices']), + 'nullable' => true, + 'default' => null, + ], + ); + + $operation = $operation->withParameters($parameters); + $pathItem = $pathItem->withGet($operation); + $paths->addPath($path, $pathItem); + + return $docs->withPaths($paths); + } +} diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Adjustment.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Adjustment.xml index 1cc5c7d2973..234aeb71dd3 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Adjustment.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Adjustment.xml @@ -16,7 +16,18 @@ xsi:schemaLocation="https://api-platform.com/schema/metadata https://api-platform.com/schema/metadata/metadata-2.0.xsd" > - + + + GET + /admin/adjustments + + sylius.api.order_token_filter + + + admin:adjustment:read + + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Order.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Order.xml index 4686633b874..790cbf1fd3a 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Order.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/Order.xml @@ -78,6 +78,16 @@ + + GET + /admin/orders/{tokenValue}/adjustments + Sylius\Bundle\ApiBundle\Controller\GetOrderAdjustmentsAction + false + + admin:adjustment:read + + + GET /shop/orders/{tokenValue} @@ -417,12 +427,14 @@ + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/integrations/swagger.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/integrations/swagger.xml index af741660ac6..d8a2c60a8f6 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/integrations/swagger.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/integrations/swagger.xml @@ -81,5 +81,11 @@ %sylius.promotion_rules% + + + %sylius.security.new_api_route% + %sylius.model.adjustment.class% + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Order.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Order.xml index 69b4799befb..6c0a848d4d2 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Order.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Order.xml @@ -89,6 +89,12 @@ shop:order:account:read + + admin:order:read + shop:cart:read + shop:order:account:read + + admin:order:read shop:cart:read @@ -126,6 +132,12 @@ shop:order:account:read + + admin:order:read + shop:cart:read + shop:order:account:read + + admin:order:read shop:cart:read @@ -138,6 +150,12 @@ shop:order:account:read + + admin:order:read + shop:cart:read + shop:order:account:read + + admin:cart:update admin:order:read diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/OrderItem.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/OrderItem.xml index 9c2eaead0d1..d1d27428322 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/OrderItem.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/OrderItem.xml @@ -58,6 +58,7 @@ shop:cart:read + admin:order:read admin:order_item:read shop:order_item:read @@ -100,5 +101,9 @@ shop:order_item:read shop:cart:read + + admin:order:read + admin:order_item:read + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml index d88c2ea2b55..f53d6bd933f 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml @@ -74,6 +74,11 @@ + + + + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/filters.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/filters.xml index 0b842c9c102..5ee5e433acd 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/filters.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/filters.xml @@ -332,5 +332,12 @@ + + + + exact + + + diff --git a/src/Sylius/Component/Core/Model/Adjustment.php b/src/Sylius/Component/Core/Model/Adjustment.php index 3d655960b69..869a23cd019 100644 --- a/src/Sylius/Component/Core/Model/Adjustment.php +++ b/src/Sylius/Component/Core/Model/Adjustment.php @@ -41,4 +41,16 @@ public function setShipment(?ShipmentInterface $shipment): void $this->setAdjustable($this->shipment->getOrder()); } } + + public static function getAdjustmentTypeChoices(): array + { + return [ + self::ORDER_ITEM_PROMOTION_ADJUSTMENT, + self::ORDER_PROMOTION_ADJUSTMENT, + self::ORDER_SHIPPING_PROMOTION_ADJUSTMENT, + self::ORDER_UNIT_PROMOTION_ADJUSTMENT, + self::SHIPPING_ADJUSTMENT, + self::TAX_ADJUSTMENT, + ]; + } } diff --git a/src/Sylius/Component/Core/Model/AdjustmentInterface.php b/src/Sylius/Component/Core/Model/AdjustmentInterface.php index 71b0896ccc6..cece02bef62 100644 --- a/src/Sylius/Component/Core/Model/AdjustmentInterface.php +++ b/src/Sylius/Component/Core/Model/AdjustmentInterface.php @@ -32,4 +32,7 @@ interface AdjustmentInterface extends BaseAdjustmentInterface public function getShipment(): ?ShipmentInterface; public function setShipment(?ShipmentInterface $shipment): void; + + /** @return string[] */ + public static function getAdjustmentTypeChoices(): array; } diff --git a/src/Sylius/Component/Core/Model/Order.php b/src/Sylius/Component/Core/Model/Order.php index ad3b31fc512..137fe0bf1e2 100644 --- a/src/Sylius/Component/Core/Model/Order.php +++ b/src/Sylius/Component/Core/Model/Order.php @@ -411,6 +411,17 @@ public function getTaxTotal(): int return $taxTotal; } + public function getShippingTaxTotal(): int + { + $shippingTaxTotal = 0; + + foreach ($this->getAdjustments(AdjustmentInterface::SHIPPING_ADJUSTMENT) as $shippingAdjustment) { + $shippingTaxTotal += $shippingAdjustment->getAmount(); + } + + return $shippingTaxTotal; + } + public function getTaxExcludedTotal(): int { return array_reduce( @@ -453,6 +464,11 @@ public function getOrderPromotionTotal(): int ; } + public function getShippingPromotionTotal(): int + { + return $this->getAdjustmentsTotalRecursively(AdjustmentInterface::ORDER_SHIPPING_PROMOTION_ADJUSTMENT); + } + public function getTokenValue(): ?string { return $this->tokenValue; diff --git a/src/Sylius/Component/Core/Model/OrderInterface.php b/src/Sylius/Component/Core/Model/OrderInterface.php index 1ecc81d7900..d529cea4fc5 100644 --- a/src/Sylius/Component/Core/Model/OrderInterface.php +++ b/src/Sylius/Component/Core/Model/OrderInterface.php @@ -96,6 +96,8 @@ public function getLastPayment(?string $state = null): ?PaymentInterface; public function getTaxTotal(): int; + public function getShippingTaxTotal(): int; + public function getTaxExcludedTotal(): int; public function getTaxIncludedTotal(): int; @@ -104,6 +106,8 @@ public function getShippingTotal(): int; public function getOrderPromotionTotal(): int; + public function getShippingPromotionTotal(): int; + public function getItemsSubtotal(): int; public function getTokenValue(): ?string; diff --git a/tests/Api/Admin/OrdersTest.php b/tests/Api/Admin/OrdersTest.php index 089b4218b23..ed0218c5d07 100644 --- a/tests/Api/Admin/OrdersTest.php +++ b/tests/Api/Admin/OrdersTest.php @@ -43,6 +43,22 @@ public function it_gets_an_order(): void $this->assertResponse($response, 'admin/order/get_order_response', Response::HTTP_OK); } + /** @test */ + public function it_gets_adjustments_for_order(): void + { + $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'channel.yaml', 'cart.yaml', 'country.yaml', 'shipping_method.yaml', 'payment_method.yaml']); + $header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER); + + $tokenValue = 'nAWw2jewpA'; + + $this->placeOrder($tokenValue); + + $this->client->request(method: 'GET', uri: '/api/v2/admin/orders/nAWw2jewpA/adjustments', server: $header); + $response = $this->client->getResponse(); + + $this->assertResponse($response, 'admin/order/get_adjustments_for_a_given_order_response', Response::HTTP_OK); + } + /** @test */ public function it_gets_orders_for_customer(): void { diff --git a/tests/Api/Responses/Expected/admin/order/get_adjustments_for_a_given_order_response.json b/tests/Api/Responses/Expected/admin/order/get_adjustments_for_a_given_order_response.json new file mode 100644 index 00000000000..ca5581bbb42 --- /dev/null +++ b/tests/Api/Responses/Expected/admin/order/get_adjustments_for_a_given_order_response.json @@ -0,0 +1,19 @@ +{ + "@context": "/api/v2/contexts/Order", + "@id": "/api/v2/admin/orders", + "@type": "hydra:Collection", + "hydra:member": [ + { + "@id": "/api/v2/admin/adjustments/@integer@", + "@type": "Adjustment", + "id": @integer@, + "order": "/api/v2/admin/orders/nAWw2jewpA", + "type": "shipping", + "label": "UPS", + "amount": 500, + "neutral": false, + "locked": false + } + ], + "hydra:totalItems": 1 +} diff --git a/tests/Api/Responses/Expected/admin/order/get_order_response.json b/tests/Api/Responses/Expected/admin/order/get_order_response.json index 5781b99a399..5d49e710e3d 100644 --- a/tests/Api/Responses/Expected/admin/order/get_order_response.json +++ b/tests/Api/Responses/Expected/admin/order/get_order_response.json @@ -59,6 +59,12 @@ "unitPrice": 2000, "originalUnitPrice": 2000, "total": 6000, + "units": [ + "\/api\/v2\/admin\/order-item-units\/@integer@", + "\/api\/v2\/admin\/order-item-units\/@integer@", + "\/api\/v2\/admin\/order-item-units\/@integer@" + ], + "fullDiscountedUnitPrice": 2000, "subtotal": 6000 } ], @@ -67,8 +73,10 @@ "state": "new", "itemsSubtotal": 6000, "taxTotal": 0, - "taxIncludedTotal": 0, + "shippingTaxTotal": 500, "taxExcludedTotal": 0, + "taxIncludedTotal": 0, "shippingTotal": 500, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } diff --git a/tests/Api/Responses/Expected/admin/order/gets_orders_for_customer_response.json b/tests/Api/Responses/Expected/admin/order/gets_orders_for_customer_response.json index 3766159c110..5405ec6af0b 100644 --- a/tests/Api/Responses/Expected/admin/order/gets_orders_for_customer_response.json +++ b/tests/Api/Responses/Expected/admin/order/gets_orders_for_customer_response.json @@ -49,10 +49,12 @@ "state": "new", "itemsSubtotal": 0, "taxTotal": 0, + "shippingTaxTotal": 0, "taxExcludedTotal": 0, "taxIncludedTotal": 0, "shippingTotal": 0, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } ], "hydra:totalItems": 1, diff --git a/tests/Api/Responses/Expected/shop/add_item_response.json b/tests/Api/Responses/Expected/shop/add_item_response.json index cee4a63dd9b..b92c122c8aa 100644 --- a/tests/Api/Responses/Expected/shop/add_item_response.json +++ b/tests/Api/Responses/Expected/shop/add_item_response.json @@ -34,18 +34,20 @@ "id": @integer@, "quantity": 3, "unitPrice": 2000, + "originalUnitPrice": 2000, "total": 6000, "discountedUnitPrice": 2000, - "subtotal": 6000, - "originalUnitPrice": 2000 + "subtotal": 6000 } ], "itemsTotal": 6000, "total": 6500, "itemsSubtotal": 6000, "taxTotal": 0, - "taxIncludedTotal": 0, + "shippingTaxTotal": 500, "taxExcludedTotal": 0, + "taxIncludedTotal": 0, "shippingTotal": 500, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } diff --git a/tests/Api/Responses/Expected/shop/create_cart_response.json b/tests/Api/Responses/Expected/shop/create_cart_response.json index 8c04d0cc6ba..f4210b1395b 100644 --- a/tests/Api/Responses/Expected/shop/create_cart_response.json +++ b/tests/Api/Responses/Expected/shop/create_cart_response.json @@ -18,8 +18,10 @@ "state": "cart", "itemsSubtotal": 0, "taxTotal": 0, - "taxIncludedTotal": 0, + "shippingTaxTotal": 0, "taxExcludedTotal": 0, + "taxIncludedTotal": 0, "shippingTotal": 0, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } diff --git a/tests/Api/Responses/Expected/shop/create_cart_with_default_locale_response.json b/tests/Api/Responses/Expected/shop/create_cart_with_default_locale_response.json index 049409b8584..f683c2c4e75 100644 --- a/tests/Api/Responses/Expected/shop/create_cart_with_default_locale_response.json +++ b/tests/Api/Responses/Expected/shop/create_cart_with_default_locale_response.json @@ -18,8 +18,10 @@ "state": "cart", "itemsSubtotal": 0, "taxTotal": 0, - "taxIncludedTotal": 0, + "shippingTaxTotal": 0, "taxExcludedTotal": 0, + "taxIncludedTotal": 0, "shippingTotal": 0, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } diff --git a/tests/Api/Responses/Expected/shop/get_order_response.json b/tests/Api/Responses/Expected/shop/get_order_response.json index 55d4466e331..e1f81ec20c1 100644 --- a/tests/Api/Responses/Expected/shop/get_order_response.json +++ b/tests/Api/Responses/Expected/shop/get_order_response.json @@ -54,18 +54,20 @@ "id": @integer@, "quantity": 3, "unitPrice": 2000, + "originalUnitPrice": 2000, "total": 6000, "subtotal": 6000, - "discountedUnitPrice": 2000, - "originalUnitPrice": 2000 + "discountedUnitPrice": 2000 } ], "itemsTotal": 6000, "total": 6500, "itemsSubtotal": 6000, "taxTotal": 0, - "taxIncludedTotal": 0, + "shippingTaxTotal": 500, "taxExcludedTotal": 0, + "taxIncludedTotal": 0, "shippingTotal": 500, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } diff --git a/tests/Api/Responses/Expected/shop/order_completion/order_with_free_non_shippable_items_response.json b/tests/Api/Responses/Expected/shop/order_completion/order_with_free_non_shippable_items_response.json index b75089bdfea..0dba93faf3c 100644 --- a/tests/Api/Responses/Expected/shop/order_completion/order_with_free_non_shippable_items_response.json +++ b/tests/Api/Responses/Expected/shop/order_completion/order_with_free_non_shippable_items_response.json @@ -53,8 +53,10 @@ "state": "fulfilled", "itemsSubtotal": 0, "taxTotal": 0, + "shippingTaxTotal": 0, "taxExcludedTotal": 0, "taxIncludedTotal": 0, "shippingTotal": 0, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } diff --git a/tests/Api/Responses/Expected/shop/order_completion/order_with_non_shippable_items_response.json b/tests/Api/Responses/Expected/shop/order_completion/order_with_non_shippable_items_response.json index 7639fc71d38..6442925e14b 100644 --- a/tests/Api/Responses/Expected/shop/order_completion/order_with_non_shippable_items_response.json +++ b/tests/Api/Responses/Expected/shop/order_completion/order_with_non_shippable_items_response.json @@ -60,8 +60,10 @@ "state": "new", "itemsSubtotal": 3000, "taxTotal": 0, + "shippingTaxTotal": 0, "taxExcludedTotal": 0, "taxIncludedTotal": 0, "shippingTotal": 0, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } diff --git a/tests/Api/Responses/Expected/shop/order_completion/order_with_shippable_and_non_shippable_items_response.json b/tests/Api/Responses/Expected/shop/order_completion/order_with_shippable_and_non_shippable_items_response.json index 3ffc85d60d9..c381a9b6e7f 100644 --- a/tests/Api/Responses/Expected/shop/order_completion/order_with_shippable_and_non_shippable_items_response.json +++ b/tests/Api/Responses/Expected/shop/order_completion/order_with_shippable_and_non_shippable_items_response.json @@ -80,8 +80,10 @@ "state": "new", "itemsSubtotal": 9000, "taxTotal": 0, + "shippingTaxTotal": 1000, "taxExcludedTotal": 0, "taxIncludedTotal": 0, "shippingTotal": 1000, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } diff --git a/tests/Api/Responses/Expected/shop/updated_billing_address_on_order_response.json b/tests/Api/Responses/Expected/shop/updated_billing_address_on_order_response.json index ba5f6cb1d30..7f1783a36df 100644 --- a/tests/Api/Responses/Expected/shop/updated_billing_address_on_order_response.json +++ b/tests/Api/Responses/Expected/shop/updated_billing_address_on_order_response.json @@ -69,11 +69,13 @@ ], "itemsTotal": 6000, "total": 6500, - "itemsSubtotal": 6000, "state": "cart", + "itemsSubtotal": 6000, "taxTotal": 0, + "shippingTaxTotal": 500, "taxExcludedTotal": 0, "taxIncludedTotal": 0, "shippingTotal": 500, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 } diff --git a/tests/Api/Responses/Expected/shop/updated_payment_method_on_order_response.json b/tests/Api/Responses/Expected/shop/updated_payment_method_on_order_response.json index 3dd7847803f..ce70f297bde 100644 --- a/tests/Api/Responses/Expected/shop/updated_payment_method_on_order_response.json +++ b/tests/Api/Responses/Expected/shop/updated_payment_method_on_order_response.json @@ -65,8 +65,10 @@ "total": 6500, "itemsSubtotal": 6000, "taxTotal": 0, - "taxIncludedTotal": 0, + "shippingTaxTotal": 500, "taxExcludedTotal": 0, + "taxIncludedTotal": 0, "shippingTotal": 500, - "orderPromotionTotal": 0 + "orderPromotionTotal": 0, + "shippingPromotionTotal": 0 }