diff --git a/doc/swagger.yml b/doc/swagger.yml index 835a85674..60603090c 100644 --- a/doc/swagger.yml +++ b/doc/swagger.yml @@ -394,7 +394,7 @@ paths: name: "content" required: true schema: - $ref: "#/definitions/CheckoutChoosePaymentMethodRequest" + $ref: "#/definitions/ChoosePaymentMethodRequest" responses: 204: description: "Payment method has been chosen." @@ -838,6 +838,51 @@ paths: security: - bearerAuth: [] + /orders/{token}/payment: + parameters: + - $ref: "#/parameters/CartToken" + get: + tags: + - "order" + summary: "Get available payment methods." + description: "This endpoint will show you available payment methods for an order." + operationId: "showAvailablePaymentMethods" + responses: + 200: + description: "Get available payment methods." + schema: + $ref: "#/definitions/AvailablePaymentMethods" + 400: + description: "Invalid input, validation failed." + schema: + $ref: "#/definitions/GeneralError" + /orders/{token}/payment/{id}: + parameters: + - $ref: "#/parameters/CartToken" + put: + tags: + - "order" + summary: "Choosing cart payment method." + description: "This endpoint will allow you to update an order payment method." + operationId: "updatePaymentMethod" + parameters: + - name: "id" + in: "path" + description: "Order number of payment for which payment method should be specified." + required: true + type: "string" + - in: "body" + name: "content" + required: true + schema: + $ref: "#/definitions/ChoosePaymentMethodRequest" + responses: + 204: + description: "Payment method has been chosen." + 400: + description: "Invalid input, validation failed." + schema: + $ref: "#/definitions/GeneralError" /me: get: tags: @@ -1116,7 +1161,7 @@ definitions: type: "string" description: "Code of chosen shipping method." example: "DHL" - CheckoutChoosePaymentMethodRequest: + ChoosePaymentMethodRequest: type: "object" description: "Body of request used to choose payment method." required: @@ -1808,6 +1853,20 @@ definitions: description: "Date the order was completed in ISO 8601 format." type: "string" format: "date-time" + paymentState: + description: "Current payment state of an order." + type: "string" + example: "awaiting_payment" + enum: + - "cart" + - "awaiting_payment" + - "partially_authorized" + - "authorized" + - "partially_paid" + - "cancelled" + - "paid" + - "partially_refunded" + - "refunded" items: type: "array" items: diff --git a/spec/Command/Order/UpdatePaymentMethodSpec.php b/spec/Command/Order/UpdatePaymentMethodSpec.php new file mode 100644 index 000000000..8eaa45c76 --- /dev/null +++ b/spec/Command/Order/UpdatePaymentMethodSpec.php @@ -0,0 +1,30 @@ +beConstructedWith('ORDERTOKEN', 1, 'CASH_ON_DELIVERY_METHOD'); + } + + function it_has_order_token(): void + { + $this->orderToken()->shouldReturn('ORDERTOKEN'); + } + + function it_has_identifier_of_payment(): void + { + $this->paymentId()->shouldReturn(1); + } + + function it_has_payment_method_defined(): void + { + $this->paymentMethodCode()->shouldReturn('CASH_ON_DELIVERY_METHOD'); + } +} diff --git a/spec/Factory/Order/PlacedOrderViewFactorySpec.php b/spec/Factory/Order/PlacedOrderViewFactorySpec.php index 757f44058..5c617f133 100644 --- a/spec/Factory/Order/PlacedOrderViewFactorySpec.php +++ b/spec/Factory/Order/PlacedOrderViewFactorySpec.php @@ -11,6 +11,7 @@ use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\OrderItemInterface; use Sylius\Component\Core\OrderCheckoutStates; +use Sylius\Component\Core\OrderPaymentStates; use Sylius\ShopApiPlugin\Factory\AddressBook\AddressViewFactoryInterface; use Sylius\ShopApiPlugin\Factory\Cart\AdjustmentViewFactoryInterface; use Sylius\ShopApiPlugin\Factory\Cart\CartItemViewFactoryInterface; @@ -64,6 +65,7 @@ function it_creates_a_placed_order_view( $cart->getCurrencyCode()->willReturn('GBP'); $cart->getCheckoutState()->willReturn(OrderCheckoutStates::STATE_COMPLETED); $cart->getCheckoutCompletedAt()->willReturn(new \DateTime('2019-02-15T15:00:00+00:00')); + $cart->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT); $cart->getTokenValue()->willReturn('ORDER_TOKEN'); $cart->getNumber()->willReturn('ORDER_NUMBER'); $cart->getShippingTotal()->willReturn(500); @@ -99,6 +101,7 @@ function it_creates_a_placed_order_view( $placedOrderView->locale = 'en_GB'; $placedOrderView->checkoutState = OrderCheckoutStates::STATE_COMPLETED; $placedOrderView->checkoutCompletedAt = '2019-02-15T15:00:00+00:00'; + $placedOrderView->paymentState = OrderPaymentStates::STATE_AWAITING_PAYMENT; $placedOrderView->items = [new ItemView()]; $placedOrderView->totals = new TotalsView(); diff --git a/spec/Handler/Order/UpdatePaymentMethodHandlerSpec.php b/spec/Handler/Order/UpdatePaymentMethodHandlerSpec.php new file mode 100644 index 000000000..f36b4d252 --- /dev/null +++ b/spec/Handler/Order/UpdatePaymentMethodHandlerSpec.php @@ -0,0 +1,168 @@ +beConstructedWith($orderRepository, $paymentMethodRepository); + } + + function it_assigns_chosen_payment_method_to_specified_payment( + OrderRepositoryInterface $orderRepository, + OrderInterface $order, + PaymentMethodRepositoryInterface $paymentMethodRepository, + PaymentMethodInterface $paymentMethod, + PaymentInterface $payment + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); + $order->getState()->willReturn(OrderInterface::STATE_NEW); + $order->getPayments()->willReturn(new ArrayCollection([$payment->getWrappedObject()])); + $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT); + $paymentMethodRepository->findOneBy(['code' => 'CASH_ON_DELIVERY_METHOD'])->willReturn($paymentMethod); + $payment->setMethod($paymentMethod)->shouldBeCalled(); + $payment->getState()->willReturn(PaymentInterface::STATE_NEW); + + $this(new UpdatePaymentMethod('ORDERTOKEN', 0, 'CASH_ON_DELIVERY_METHOD')); + } + + function it_throws_an_exception_if_order_with_given_token_has_not_been_found( + OrderRepositoryInterface $orderRepository, + PaymentInterface $payment + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn(null); + $payment->setMethod(Argument::type(PaymentMethodInterface::class))->shouldNotBeCalled(); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('__invoke', [ + new UpdatePaymentMethod('ORDERTOKEN', 0, 'CASH_ON_DELIVERY_METHOD'), + ]) + ; + } + + function it_throws_an_exception_if_order_is_cart( + OrderRepositoryInterface $orderRepository, + OrderInterface $order, + PaymentMethodRepositoryInterface $paymentMethodRepository, + PaymentInterface $payment + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); + $order->getState()->willReturn(OrderInterface::STATE_CART); + + $paymentMethodRepository->findOneBy(Argument::any())->shouldNotBeCalled(); + $payment->setMethod(Argument::type(PaymentMethodInterface::class))->shouldNotBeCalled(); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('__invoke', [ + new UpdatePaymentMethod('ORDERTOKEN', 0, 'CASH_ON_DELIVERY_METHOD'), + ]) + ; + } + + function it_throws_an_exception_if_order_cannot_have_payment_updated( + OrderRepositoryInterface $orderRepository, + OrderInterface $order, + PaymentMethodRepositoryInterface $paymentMethodRepository, + PaymentInterface $payment + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); + $order->getState()->willReturn(OrderInterface::STATE_NEW); + $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_PAID); + + $paymentMethodRepository->findOneBy(Argument::any())->shouldNotBeCalled(); + $payment->setMethod(Argument::type(PaymentMethodInterface::class))->shouldNotBeCalled(); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('__invoke', [ + new UpdatePaymentMethod('ORDERTOKEN', 0, 'CASH_ON_DELIVERY_METHOD'), + ]) + ; + } + + function it_throws_an_exception_if_payment_method_with_given_code_has_not_been_found( + OrderRepositoryInterface $orderRepository, + OrderInterface $order, + PaymentMethodRepositoryInterface $paymentMethodRepository, + PaymentInterface $payment + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); + $order->getState()->willReturn(OrderInterface::STATE_NEW); + $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT); + $paymentMethodRepository->findOneBy(['code' => 'CASH_ON_DELIVERY_METHOD'])->willReturn(null); + + $payment->setMethod(Argument::type(PaymentMethodInterface::class))->shouldNotBeCalled(); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('__invoke', [ + new UpdatePaymentMethod('ORDERTOKEN', 0, 'CASH_ON_DELIVERY_METHOD'), + ]) + ; + } + + function it_throws_an_exception_if_ordered_payment_has_not_been_found( + OrderRepositoryInterface $orderRepository, + OrderInterface $order, + PaymentMethodRepositoryInterface $paymentMethodRepository, + PaymentMethodInterface $paymentMethod, + PaymentInterface $payment + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); + $order->getState()->willReturn(OrderInterface::STATE_NEW); + $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT); + $paymentMethodRepository->findOneBy(['code' => 'CASH_ON_DELIVERY_METHOD'])->willReturn($paymentMethod); + $order->getPayments()->willReturn(new ArrayCollection([])); + + $payment->setMethod(Argument::type(PaymentMethodInterface::class))->shouldNotBeCalled(); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('__invoke', [ + new UpdatePaymentMethod('ORDERTOKEN', 0, 'CASH_ON_DELIVERY_METHOD'), + ]) + ; + } + + function it_throws_an_exception_if_ordered_payment_is_not_new( + OrderRepositoryInterface $orderRepository, + OrderInterface $order, + PaymentMethodRepositoryInterface $paymentMethodRepository, + PaymentMethodInterface $paymentMethod, + PaymentInterface $payment + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN'])->willReturn($order); + $order->getState()->willReturn(OrderInterface::STATE_NEW); + $order->getPaymentState()->willReturn(OrderPaymentStates::STATE_AWAITING_PAYMENT); + $paymentMethodRepository->findOneBy(['code' => 'CASH_ON_DELIVERY_METHOD'])->willReturn($paymentMethod); + $order->getPayments()->willReturn(new ArrayCollection([$payment->getWrappedObject()])); + + $payment->getState()->willReturn(PaymentInterface::STATE_CART); + $payment->setMethod(Argument::type(PaymentMethodInterface::class))->shouldNotBeCalled(); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('__invoke', [ + new UpdatePaymentMethod('ORDERTOKEN', 0, 'CASH_ON_DELIVERY_METHOD'), + ]) + ; + } +} diff --git a/spec/Validator/Order/OrderExistsValidatorSpec.php b/spec/Validator/Order/OrderExistsValidatorSpec.php new file mode 100644 index 000000000..c76b98772 --- /dev/null +++ b/spec/Validator/Order/OrderExistsValidatorSpec.php @@ -0,0 +1,63 @@ +beConstructedWith($orderRepository); + + $this->initialize($executionContext); + } + + function it_does_not_add_constraint_if_order_exists( + OrderInterface $order, + OrderRepositoryInterface $orderRepository, + ExecutionContextInterface $executionContext + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN', 'state' => OrderInterface::STATE_NEW])->willReturn($order); + + $executionContext->addViolation(Argument::any())->shouldNotBeCalled(); + + $this->validate('ORDERTOKEN', new OrderExists(['state' => OrderInterface::STATE_NEW])); + } + + function it_does_not_add_constraint_if_order_exists_multi_state( + OrderInterface $order, + OrderRepositoryInterface $orderRepository, + ExecutionContextInterface $executionContext + ): void { + $orderRepository->findOneBy( + [ + 'tokenValue' => 'ORDERTOKEN', + 'state' => [OrderInterface::STATE_NEW, 'other_state'], + ])->willReturn($order); + + $executionContext->addViolation(Argument::any())->shouldNotBeCalled(); + + $this->validate('ORDERTOKEN', new OrderExists( + ['state' => [OrderInterface::STATE_NEW, 'other_state']] + )); + } + + function it_adds_constraint_if_order_does_not_exists( + OrderRepositoryInterface $orderRepository, + ExecutionContextInterface $executionContext + ): void { + $orderRepository->findOneBy(['tokenValue' => 'ORDERTOKEN', 'state' => OrderInterface::STATE_NEW])->willReturn(null); + + $executionContext->addViolation('sylius.shop_api.order.not_exists')->shouldBeCalled(); + + $this->validate('ORDERTOKEN', new OrderExists(['state' => OrderInterface::STATE_NEW])); + } +} diff --git a/src/Command/Order/UpdatePaymentMethod.php b/src/Command/Order/UpdatePaymentMethod.php new file mode 100644 index 000000000..6301818a6 --- /dev/null +++ b/src/Command/Order/UpdatePaymentMethod.php @@ -0,0 +1,41 @@ +orderToken = $orderToken; + $this->paymentId = $paymentId; + $this->paymentMethodCode = $paymentMethodCode; + } + + public function orderToken(): string + { + return $this->orderToken; + } + + /** @return string|int */ + public function paymentId() + { + return $this->paymentId; + } + + public function paymentMethodCode(): string + { + return $this->paymentMethodCode; + } +} diff --git a/src/Controller/Order/UpdatePaymentMethodAction.php b/src/Controller/Order/UpdatePaymentMethodAction.php new file mode 100644 index 000000000..227342afe --- /dev/null +++ b/src/Controller/Order/UpdatePaymentMethodAction.php @@ -0,0 +1,59 @@ +viewHandler = $viewHandler; + $this->bus = $bus; + $this->validator = $validator; + $this->validationErrorViewFactory = $validationErrorViewFactory; + } + + public function __invoke(Request $request): Response + { + $updateRequest = new UpdatePaymentMethodRequest($request); + + $validationResults = $this->validator->validate($updateRequest); + if (0 !== count($validationResults)) { + return $this->viewHandler->handle( + View::create($this->validationErrorViewFactory->create($validationResults), + Response::HTTP_BAD_REQUEST + ) + ); + } + + $this->bus->dispatch($updateRequest->getCommand()); + + return $this->viewHandler->handle(View::create(null, Response::HTTP_NO_CONTENT)); + } +} diff --git a/src/Factory/Order/PlacedOrderViewFactory.php b/src/Factory/Order/PlacedOrderViewFactory.php index 66d6c869f..00f4f6b6c 100644 --- a/src/Factory/Order/PlacedOrderViewFactory.php +++ b/src/Factory/Order/PlacedOrderViewFactory.php @@ -66,6 +66,7 @@ public function create(OrderInterface $order, string $localeCode): PlacedOrderVi $placedOrderView->locale = $localeCode; $placedOrderView->checkoutState = $order->getCheckoutState(); $placedOrderView->checkoutCompletedAt = $order->getCheckoutCompletedAt()->format('c'); + $placedOrderView->paymentState = $order->getPaymentState(); $placedOrderView->totals = $this->totalViewFactory->create($order); $placedOrderView->tokenValue = $order->getTokenValue(); $placedOrderView->number = $order->getNumber(); diff --git a/src/Handler/Order/UpdatePaymentMethodHandler.php b/src/Handler/Order/UpdatePaymentMethodHandler.php new file mode 100644 index 000000000..9e50d3ff5 --- /dev/null +++ b/src/Handler/Order/UpdatePaymentMethodHandler.php @@ -0,0 +1,52 @@ +orderRepository = $orderRepository; + $this->paymentMethodRepository = $paymentMethodRepository; + } + + public function __invoke(UpdatePaymentMethod $choosePaymentMethod): void + { + /** @var OrderInterface $order */ + $order = $this->orderRepository->findOneBy(['tokenValue' => $choosePaymentMethod->orderToken()]); + + Assert::notNull($order, 'Order has not been found.'); + Assert::notSame(OrderInterface::STATE_CART, $order->getState(), 'Only orders can be updated.'); + Assert::same(OrderPaymentStates::STATE_AWAITING_PAYMENT, $order->getPaymentState(), 'Only awaiting payment orders can be updated.'); + + /** @var PaymentMethodInterface $paymentMethod */ + $paymentMethod = $this->paymentMethodRepository->findOneBy(['code' => $choosePaymentMethod->paymentMethodCode()]); + + Assert::notNull($paymentMethod, 'Payment method has not been found'); + Assert::true(isset($order->getPayments()[$choosePaymentMethod->paymentId()]), 'Can not find payment with given identifier.'); + + $payment = $order->getPayments()[$choosePaymentMethod->paymentId()]; + Assert::same(PaymentInterface::STATE_NEW, $payment->getState(), 'Payment should have new state'); + + $payment->setMethod($paymentMethod); + } +} diff --git a/src/Request/Order/UpdatePaymentMethodRequest.php b/src/Request/Order/UpdatePaymentMethodRequest.php new file mode 100644 index 000000000..8e801272a --- /dev/null +++ b/src/Request/Order/UpdatePaymentMethodRequest.php @@ -0,0 +1,43 @@ +token = $request->attributes->get('token'); + $this->paymentIdentifier = $request->attributes->get('paymentId'); + $this->paymentMethod = $request->request->get('method'); + } + + public function getCommand(): UpdatePaymentMethod + { + return new UpdatePaymentMethod($this->token, $this->paymentIdentifier, $this->paymentMethod); + } + + public function getOrderToken(): string + { + return $this->token; + } + + /** @return int|string */ + public function getPaymentId() + { + return $this->paymentIdentifier; + } +} diff --git a/src/Resources/config/routing/order.yml b/src/Resources/config/routing/order.yml index fa2215128..733f768da 100644 --- a/src/Resources/config/routing/order.yml +++ b/src/Resources/config/routing/order.yml @@ -9,3 +9,15 @@ sylius_shop_api_order_details: methods: [GET] defaults: _controller: sylius.shop_api_plugin.controller.order.show_order_details_action + +sylius_shop_api_order_available_payment_methods: + path: /orders/{token}/payment + methods: [GET] + defaults: + _controller: sylius.shop_api_plugin.controller.checkout.show_available_payment_methods_action + +sylius_shop_api_order_update_payment_method: + path: /orders/{token}/payment/{paymentId} + methods: [PUT] + defaults: + _controller: sylius.shop_api_plugin.controller.order.update_payment_method_action diff --git a/src/Resources/config/services/actions/order.xml b/src/Resources/config/services/actions/order.xml index e0d38092c..600cf23ff 100644 --- a/src/Resources/config/services/actions/order.xml +++ b/src/Resources/config/services/actions/order.xml @@ -19,5 +19,14 @@ + + + + + + + diff --git a/src/Resources/config/services/handler/order.xml b/src/Resources/config/services/handler/order.xml new file mode 100644 index 000000000..b3060fb39 --- /dev/null +++ b/src/Resources/config/services/handler/order.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/Resources/config/services/validators/order.xml b/src/Resources/config/services/validators/order.xml new file mode 100644 index 000000000..b1e4efe29 --- /dev/null +++ b/src/Resources/config/services/validators/order.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/src/Resources/config/validation/order/UpdatePaymentMethodRequest.xml b/src/Resources/config/validation/order/UpdatePaymentMethodRequest.xml new file mode 100644 index 000000000..616ca3e10 --- /dev/null +++ b/src/Resources/config/validation/order/UpdatePaymentMethodRequest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/Validator/Constraints/OrderExists.php b/src/Validator/Constraints/OrderExists.php new file mode 100644 index 000000000..ad0542477 --- /dev/null +++ b/src/Validator/Constraints/OrderExists.php @@ -0,0 +1,23 @@ +orderRepository = $orderRepository; + } + + public function validate($token, Constraint $constraint): void + { + Assert::isInstanceOf($constraint, OrderExists::class); + + if (null === $this->orderRepository->findOneBy(['tokenValue' => $token, 'state' => $constraint->state])) { + $this->context->addViolation($constraint->message); + } + } +} diff --git a/src/Validator/Order/PaymentNotPaidValidator.php b/src/Validator/Order/PaymentNotPaidValidator.php new file mode 100644 index 000000000..1641d8cf9 --- /dev/null +++ b/src/Validator/Order/PaymentNotPaidValidator.php @@ -0,0 +1,40 @@ +orderRepository = $orderRepository; + } + + public function validate($updatePayment, Constraint $constraint): void + { + /** @var OrderInterface|null $order */ + $order = $this->orderRepository->findOneBy(['tokenValue' => $updatePayment->getOrderToken()]); + if ($order === null) { + return; + } + + $payment = $order->getPayments()[$updatePayment->getPaymentId()] ?? null; + if ($payment === null) { + return; + } + + if (!in_array($payment->getState(), [PaymentInterface::STATE_NEW, PaymentInterface::STATE_CANCELLED])) { + $this->context->addViolation($constraint->message); + } + } +} diff --git a/src/View/Order/PlacedOrderView.php b/src/View/Order/PlacedOrderView.php index ae0ee106e..644a79212 100644 --- a/src/View/Order/PlacedOrderView.php +++ b/src/View/Order/PlacedOrderView.php @@ -28,6 +28,9 @@ class PlacedOrderView /** @var string */ public $checkoutCompletedAt; + /** @var string */ + public $paymentState; + /** @var array|ItemView[] */ public $items = []; diff --git a/tests/Controller/Order/OrderUpdatePaymentMethodApiTest.php b/tests/Controller/Order/OrderUpdatePaymentMethodApiTest.php new file mode 100644 index 000000000..e5ef5fc75 --- /dev/null +++ b/tests/Controller/Order/OrderUpdatePaymentMethodApiTest.php @@ -0,0 +1,89 @@ +loadFixturesFromFiles(['customer.yml', 'country.yml', 'address.yml', 'shop.yml', 'payment.yml', 'shipping.yml']); + $token = 'ORDERTOKENPLACED'; + $email = 'oliver@queen.com'; + + $this->logInUser($email, '123password'); + + $this->placeOrderForCustomerWithEmail($email, $token); + + $data = +<<client->request('PUT', $this->getPaymentUrl('ORDERTOKENPLACED') . '/0', [], [], self::CONTENT_TYPE_HEADER, $data); + + $response = $this->client->getResponse(); + $this->assertResponseCode($response, Response::HTTP_NO_CONTENT); + } + + /** + * @test + */ + public function it_does_not_allow_to_update_payment_method_on_paid_order(): void + { + $this->loadFixturesFromFiles(['customer.yml', 'country.yml', 'address.yml', 'shop.yml', 'payment.yml', 'shipping.yml']); + $token = 'ORDERTOKENPAID'; + $email = 'oliver@queen.com'; + + $this->logInUser($email, '123password'); + + $this->placeOrderForCustomerWithEmail($email, $token); + $this->markOrderAsPayed($token); + + $data = +<<client->request('PUT', $this->getPaymentUrl('ORDERTOKENPAID') . '/0', [], [], self::CONTENT_TYPE_HEADER, $data); + + $response = $this->client->getResponse(); + $this->assertResponseCode($response, Response::HTTP_BAD_REQUEST); + } + + private function markOrderAsPayed() + { + /** @var OrderInterface $order */ + $order = $this->get('sylius.repository.order')->findAll()[0]; + foreach ($order->getPayments() as $payment) { + $payment->setState(PaymentInterface::STATE_COMPLETED); + } + $order->setPaymentState(OrderPaymentStates::STATE_PAID); + + $this->get('sylius.manager.order')->flush(); + } + + private function getPaymentUrl(string $token): string + { + return sprintf('/shop-api/orders/%s/payment', $token); + } +} diff --git a/tests/Responses/Expected/order/order_details_response.json b/tests/Responses/Expected/order/order_details_response.json index ba458f78e..7c233f4eb 100644 --- a/tests/Responses/Expected/order/order_details_response.json +++ b/tests/Responses/Expected/order/order_details_response.json @@ -4,6 +4,7 @@ "locale": "en_GB", "checkoutState": "completed", "checkoutCompletedAt": "@string@.isDateTime()", + "paymentState": "awaiting_payment", "items": [ { "id": @integer@, diff --git a/tests/Responses/Expected/order/order_details_response_guest.json b/tests/Responses/Expected/order/order_details_response_guest.json index 397c879f8..a1d44cea6 100644 --- a/tests/Responses/Expected/order/order_details_response_guest.json +++ b/tests/Responses/Expected/order/order_details_response_guest.json @@ -4,6 +4,7 @@ "locale": "en_GB", "checkoutState": "completed", "checkoutCompletedAt": "@string@.isDateTime()", + "paymentState": "awaiting_payment", "items": [ { "id": @integer@, diff --git a/tests/Responses/Expected/order/orders_list_response.json b/tests/Responses/Expected/order/orders_list_response.json index 7b7ba7879..4068a47d7 100644 --- a/tests/Responses/Expected/order/orders_list_response.json +++ b/tests/Responses/Expected/order/orders_list_response.json @@ -5,6 +5,7 @@ "locale": "en_GB", "checkoutState": "completed", "checkoutCompletedAt": "@string@.isDateTime()", + "paymentState": "awaiting_payment", "items": [ { "id": @integer@,