Skip to content

Commit

Permalink
feature #11924 [Api] Change payment method after checkout (AdamKasp)
Browse files Browse the repository at this point in the history
This PR was merged into the 1.9-dev branch.

Discussion
----------

| Q               | A
| --------------- | -----
| Branch?         | master
| Bug fix?        | no
| New feature?    | yes
| BC breaks?      | no
| Related tickets | part of #11250 
| License         | MIT

<!--
 - Bug fixes must be submitted against the 1.7 branch (the lowest possible)
 - Features and deprecations must be submitted against the master branch
 - Make sure that the correct base branch is set

 To be sure you are not breaking any Backward Compatibilities, check the documentation:
 https://docs.sylius.com/en/latest/book/organization/backward-compatibility-promise.html
-->


Commits
-------

3788aae [Api] Change payment method after checkout
41582c7 [API][Payments] change endpoints and add missing specs
e94b15e Refactor change payment methods behats
33eeea3 [API][Payment Method] Refactor choose payment method handler
0be4481 Refactor orderItemMethodExtension
  • Loading branch information
GSadee committed Oct 21, 2020
2 parents 011bba5 + 0be4481 commit 48d4f50
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@paying_for_order
Feature: Changing the offline payment method after order confirmation
In order to try different payment methods
As a Guest
I want to be able to change the method after order confirmation

Background:
Given the store operates on a single channel in "United States"
And the store allows paying "Offline"
And the store allows paying "Cash on delivery"
And the store has a product "PHP T-Shirt" priced at "$19.99"
And the store ships everywhere for free

@ui
Scenario: Retrying the payment with different offline payment
Given I added product "PHP T-Shirt" to the cart
When I complete addressing step with email "[email protected]" and "United States" based billing address
And I have proceeded selecting "Free" shipping method
And I have proceeded selecting "Cash on delivery" payment method
And I have confirmed order
And I retry the payment with "Offline" payment method
Then I should have chosen "Offline" payment method

@ui
Scenario: Retrying the payment with different offline payment works correctly together with inventory
Given there is 1 unit of product "PHP T-Shirt" available in the inventory
And this product is tracked by the inventory
When I added product "PHP T-Shirt" to the cart
And I complete addressing step with email "[email protected]" and "United States" based billing address
And I have proceeded selecting "Free" shipping method
And I have proceeded selecting "Cash on delivery" payment method
And I have confirmed order
And I retry the payment with "Offline" payment method
Then I should have chosen "Offline" payment method

@api
Scenario: Changing chosen offline payment method to another offline payment method after checkout
Given I added product "PHP T-Shirt" to the cart
When I complete addressing step with email "[email protected]" and "United States" based billing address
And I proceed selecting "Free" shipping method
And I proceed selecting "Cash on delivery" payment method
And I confirm my order
And I change payment method to "Offline" after checkout
Then I should have chosen "Offline" payment method

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,6 @@ Feature: Preventing cart from being modified after checkout
When I try to change shipping method to "UPS"
Then I should be informed that cart is no longer available

@api
Scenario: Preventing from changing payment method after checkout
Given I added product "Sig Sauer P226" to the cart
And I specified the billing address as "Ankh Morpork", "Frost Alley", "90210", "United States" for "Jon Snow"
And I proceeded with "Free" shipping method and "Cash on Delivery" payment
And I confirmed my order
When I try to change payment method to "Helicopter Money" payment
Then I should be informed that cart is no longer available

@api
Scenario: Preventing from adding product after checkout
Given I added product "Sig Sauer P226" to the cart
Expand Down
3 changes: 3 additions & 0 deletions src/Sylius/Behat/Context/Api/Shop/CheckoutContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ public function iConfirmMyOrder(): void
* @Given /^the (?:visitor|customer) has proceeded ("[^"]+" shipping method)$/
* @When /^the visitor try to proceed with ("[^"]+" shipping method) in the customer cart$/
* @When I try to change shipping method to :shippingMethod
* @Given I proceed selecting :shippingMethod shipping method
*/
public function iProceededWithShippingMethod(ShippingMethodInterface $shippingMethod): void
{
Expand Down Expand Up @@ -384,9 +385,11 @@ public function iCompleteTheShippingStepWithFirstShippingMethod(): void
* @When I choose :paymentMethod payment method
* @When I select :paymentMethod payment method
* @When I have proceeded selecting :paymentMethod payment method
* @When I proceed selecting :paymentMethod payment method
* @When /^the (?:customer|visitor) proceed with ("[^"]+" payment)$/
* @Given /^the (?:customer|visitor) has proceeded ("[^"]+" payment)$/
* @When I try to change payment method to :paymentMethod payment
* @When I change payment method to :paymentMethod after checkout
*/
public function iChoosePaymentMethod(PaymentMethodInterface $paymentMethod): void
{
Expand Down
15 changes: 15 additions & 0 deletions src/Sylius/Behat/Context/Api/Shop/OrderContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
use Sylius\Component\Addressing\Model\CountryInterface;
use Sylius\Component\Core\Formatter\StringInflector;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\PaymentMethod;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Component\Core\Model\PromotionInterface;
use Sylius\Component\Core\OrderCheckoutStates;
use Sylius\Component\Payment\Model\PaymentInterface;
use Symfony\Component\HttpFoundation\Request as HttpRequest;
use Symfony\Component\HttpFoundation\Response;
use Webmozart\Assert\Assert;
Expand Down Expand Up @@ -257,6 +259,19 @@ public function theShouldHaveUnitPriceDiscountedFor(ProductInterface $product, i
Assert::same(-$discount, $amount);
}

/**
* @Then I should have chosen :paymentMethod payment method
*/
public function iShouldHaveChosenPaymentMethodForMyOrder(PaymentMethod $paymentMethod): void
{
$paymentIri = $this->responseChecker->getValue($this->client->show($this->sharedStorage->get('cart_token')), 'payments')[0];

Assert::same(
$this->iriConverter->getIriFromItem($paymentMethod),
$this->responseChecker->getValue($this->client->showByIri($this->adminToShopIriConverter->convert($paymentIri)),'method')['@id']
);
}

private function getAdjustmentsForOrder(): array
{
$response = $this->client->subResourceIndex('adjustments', $this->sharedStorage->get('cart_token'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Behat\Behat\Context\Context;
use Sylius\Behat\Page\Shop\Order\ShowPageInterface;
use Sylius\Behat\Page\Shop\Order\ThankYouPageInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Webmozart\Assert\Assert;

Expand All @@ -23,40 +24,56 @@ final class CheckoutOrderDetailsContext implements Context
/** @var ShowPageInterface */
private $orderDetails;

public function __construct(ShowPageInterface $orderDetails)
/** @var ThankYouPageInterface */
private $thankYouPage;

public function __construct(ShowPageInterface $orderDetails, ThankYouPageInterface $thankYouPage)
{
$this->orderDetails = $orderDetails;
$this->thankYouPage = $thankYouPage;
}

/**
* @When /^I want to browse order details for (this order)$/
*/
public function iWantToBrowseOrderDetailsForThisOrder(OrderInterface $order)
public function iWantToBrowseOrderDetailsForThisOrder(OrderInterface $order): void
{
$this->orderDetails->open(['tokenValue' => $order->getTokenValue()]);
}

/**
* @When I try to pay with :paymentMethodName payment method
*/
public function iChangePaymentMethodTo($paymentMethodName)
public function iChangePaymentMethodTo(string $paymentMethodName): void
{
$this->orderDetails->choosePaymentMethod($paymentMethodName);
$this->orderDetails->pay();
}

/**
* @When I change payment method to :paymentMethodName after checkout
* @When I change payment method to :paymentMethodName
* @When I retry the payment with :paymentMethodName payment method
*/
public function iChangePaymentMethodAfterCheckout(string $paymentMethodName): void
{
$this->thankYouPage->goToTheChangePaymentMethodPage();
$this->orderDetails->choosePaymentMethod($paymentMethodName);
$this->orderDetails->pay();
}

/**
* @Then I should be able to pay (again)
*/
public function iShouldBeAbleToPay()
public function iShouldBeAbleToPay(): void
{
Assert::true($this->orderDetails->hasPayAction());
}

/**
* @Then I should not be able to pay (again)
*/
public function iShouldNotBeAbleToPay()
public function iShouldNotBeAbleToPay(): void
{
Assert::false($this->orderDetails->hasPayAction());
}
Expand All @@ -68,4 +85,13 @@ public function iShouldSeeAsNumberOfItems(int $quantity): void
{
Assert::same($this->orderDetails->getAmountOfItems(), $quantity);
}

/**
* @Then I should have chosen :paymentMethodName payment method
*/
public function iShouldHaveChosenPaymentMethod(string $paymentMethodName): void
{
$this->thankYouPage->goToTheChangePaymentMethodPage();
Assert::same($this->orderDetails->getChosenPaymentMethod(), $paymentMethodName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Behat\Behat\Context\Context;
use Sylius\Behat\Page\Shop\Account\Order\ShowPageInterface;
use Sylius\Behat\Page\Shop\Order\ShowPageInterface as OrderDetailsPage;
use Sylius\Behat\Page\Shop\Order\ThankYouPageInterface;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
Expand All @@ -28,17 +29,22 @@ final class CheckoutThankYouContext implements Context
/** @var ShowPageInterface */
private $orderShowPage;

/** @var OrderDetailsPage */
private $orderDetails;

/** @var OrderRepositoryInterface */
private $orderRepository;

public function __construct(
ThankYouPageInterface $thankYouPage,
ShowPageInterface $orderShowPage,
OrderRepositoryInterface $orderRepository
OrderRepositoryInterface $orderRepository,
OrderDetailsPage $orderDetails
) {
$this->thankYouPage = $thankYouPage;
$this->orderShowPage = $orderShowPage;
$this->orderRepository = $orderRepository;
$this->orderDetails = $orderDetails;
}

/**
Expand Down
13 changes: 13 additions & 0 deletions src/Sylius/Behat/Page/Shop/Order/ShowPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ public function getAmountOfItems(): int
return count($paymentItems);
}

public function getChosenPaymentMethod(): string
{
$paymentMethodItems = $this->getDocument()->findAll('css', '[data-test-payment-item]');

foreach ($paymentMethodItems as $method) {
if ($method->find('css', '[data-test-payment-method-select]')->hasAttribute('checked')) {
return $method->find('css', 'a')->getText();
}
}

return '';
}

protected function getDefinedElements(): array
{
return array_merge(parent::getDefinedElements(), [
Expand Down
2 changes: 2 additions & 0 deletions src/Sylius/Behat/Page/Shop/Order/ShowPageInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ public function choosePaymentMethod(string $paymentMethodName): void;
public function getNotifications(): array;

public function getAmountOfItems(): int;

public function getChosenPaymentMethod(): string;
}
4 changes: 3 additions & 1 deletion src/Sylius/Behat/Resources/config/services/contexts/ui.xml
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,14 @@

<service id="sylius.behat.context.ui.shop.checkout.thank_you" class="Sylius\Behat\Context\Ui\Shop\Checkout\CheckoutThankYouContext">
<argument type="service" id="sylius.behat.page.shop.order.thank_you" />
<argument type="service" id="sylius.behat.page.shop.account.order.show"></argument>
<argument type="service" id="sylius.behat.page.shop.account.order.show" />
<argument type="service" id="sylius.repository.order" />
<argument type="service" id="sylius.behat.page.shop.order.show" />
</service>

<service id="sylius.behat.context.ui.shop.checkout.order_details" class="Sylius\Behat\Context\Ui\Shop\Checkout\CheckoutOrderDetailsContext">
<argument type="service" id="sylius.behat.page.shop.order.show" />
<argument type="service" id="sylius.behat.page.shop.order.thank_you" />
</service>

<service id="sylius.behat.context.ui.shop.checkout.addressing" class="Sylius\Behat\Context\Ui\Shop\Checkout\CheckoutAddressingContext">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ default:

- sylius.behat.context.api.shop.cart
- sylius.behat.context.api.shop.checkout
- sylius.behat.context.api.shop.order

filters:
tags: "@paying_for_order && @api"
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Sylius\Component\Core\Repository\PaymentMethodRepositoryInterface;
use Sylius\Component\Core\Repository\PaymentRepositoryInterface;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
use Sylius\Component\Payment\Model\PaymentInterface;
use Webmozart\Assert\Assert;

/** @experimental */
Expand Down Expand Up @@ -58,13 +59,6 @@ public function __invoke(ChoosePaymentMethod $choosePaymentMethod): OrderInterfa

Assert::notNull($cart, 'Cart has not been found.');

$stateMachine = $this->stateMachineFactory->get($cart, OrderCheckoutTransitions::GRAPH);

Assert::true($stateMachine->can(
OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT),
'Order cannot have payment method assigned.'
);

/** @var PaymentMethodInterface|null $paymentMethod */
$paymentMethod = $this->paymentMethodRepository->findOneBy([
'code' => $choosePaymentMethod->paymentMethodCode,
Expand All @@ -74,9 +68,47 @@ public function __invoke(ChoosePaymentMethod $choosePaymentMethod): OrderInterfa
$payment = $this->paymentRepository->findOneByOrderId($choosePaymentMethod->paymentId, $cart->getId());
Assert::notNull($payment, 'Can not find payment with given identifier.');

if ($cart->getState() === OrderInterface::STATE_CART) {
return $this->choosePaymentMethodOnCheckout($cart, $payment, $paymentMethod);
}

if ($cart->getState() === OrderInterface::STATE_NEW) {
return $this->changePaymentMethod($cart, $payment, $paymentMethod);
}

throw new \InvalidArgumentException('Payment method can not be set');
}

private function choosePaymentMethodOnCheckout(
OrderInterface $cart,
PaymentInterface $payment,
PaymentMethodInterface $paymentMethod
): OrderInterface {
$stateMachine = $this->stateMachineFactory->get($cart, OrderCheckoutTransitions::GRAPH);

Assert::true($stateMachine->can(
OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT),
'Order cannot have payment method assigned.'
);

$payment->setMethod($paymentMethod);
$stateMachine->apply(OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT);

return $cart;
}

private function changePaymentMethod(
OrderInterface $order,
PaymentInterface $payment,
PaymentMethodInterface $paymentMethod
): OrderInterface {
Assert::same(
$payment->getState(),
PaymentInterface::STATE_NEW,
'Can not change payment method for this payment'
);
$payment->setMethod($paymentMethod);

return $order;
}
}
Loading

0 comments on commit 48d4f50

Please sign in to comment.