Skip to content

Commit

Permalink
Merge pull request Sylius#7426 from lchrusciel/shipping-method-checko…
Browse files Browse the repository at this point in the history
…ut-api

[API] [Checkout] Get available shipping and payment methods
  • Loading branch information
pjedrzejewski committed Feb 9, 2017
2 parents 2c6920a + daaaf35 commit 32ea574
Show file tree
Hide file tree
Showing 20 changed files with 756 additions and 120 deletions.
@@ -0,0 +1,145 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sylius\Bundle\ApiBundle\Controller;

use FOS\RestBundle\View\View;
use FOS\RestBundle\View\ViewHandlerInterface;
use SM\Factory\FactoryInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\PaymentInterface;
use Sylius\Component\Core\OrderCheckoutTransitions;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class ShowAvailablePaymentMethodsController
{
/**
* @var FactoryInterface
*/
private $stateMachineFactory;

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

/**
* @var PaymentMethodsResolverInterface
*/
private $paymentMethodResolver;

/**
* @var ViewHandlerInterface
*/
private $restViewHandler;

/**
* @param FactoryInterface $stateMachineFactory
* @param OrderRepositoryInterface $orderRepository
* @param PaymentMethodsResolverInterface $paymentMethodResolver
* @param ViewHandlerInterface $restViewHandler
*/
public function __construct(
FactoryInterface $stateMachineFactory,
OrderRepositoryInterface $orderRepository,
PaymentMethodsResolverInterface $paymentMethodResolver,
ViewHandlerInterface $restViewHandler
) {
$this->stateMachineFactory = $stateMachineFactory;
$this->orderRepository = $orderRepository;
$this->paymentMethodResolver = $paymentMethodResolver;
$this->restViewHandler = $restViewHandler;
}

/**
* @param Request $request
*
* @return Response
*/
public function showAction(Request $request)
{
/** @var OrderInterface $cart */
$cart = $this->getCartOr404($request->attributes->get('orderId'));

if (!$this->isCheckoutTransitionPossible($cart, OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT)) {
throw new BadRequestHttpException('The payment methods cannot be resolved in the current state of cart!');
}

$payments = [];

foreach ($cart->getPayments() as $payment) {
$payments['payments'][] = [
'methods' => $this->getPaymentMethods($payment, $cart->getLocaleCode()),
];
}

return $this->restViewHandler->handle(View::create($payments));
}

/**
* @param mixed $cartId
*
* @return OrderInterface
*/
private function getCartOr404($cartId)
{
$cart = $this->orderRepository->findCartById($cartId);

if (null === $cart) {
throw new NotFoundHttpException(sprintf("The cart with %s id could not be found!", $cartId));
}

return $cart;
}

/**
* @param OrderInterface $cart
* @param string $transition
*
* @return bool
*/
private function isCheckoutTransitionPossible(OrderInterface $cart, $transition)
{
return $this->stateMachineFactory->get($cart, OrderCheckoutTransitions::GRAPH)->can($transition);
}

/**
* @param PaymentInterface $payment
* @param string $locale
*
* @return array
*/
private function getPaymentMethods(PaymentInterface $payment, $locale)
{
$paymentMethods = $this->paymentMethodResolver->getSupportedMethods($payment);

$rawPaymentMethods = [];

foreach ($paymentMethods as $paymentMethod) {
$rawPaymentMethods[] = [
'id' => $paymentMethod->getId(),
'code' => $paymentMethod->getCode(),
'name' => $paymentMethod->getTranslation($locale)->getName(),
'description' => $paymentMethod->getTranslation($locale)->getDescription(),
];
}

return $rawPaymentMethods;
}
}
@@ -0,0 +1,157 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sylius\Bundle\ApiBundle\Controller;

use FOS\RestBundle\View\View;
use FOS\RestBundle\View\ViewHandlerInterface;
use SM\Factory\FactoryInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\ShipmentInterface;
use Sylius\Component\Core\OrderCheckoutTransitions;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Sylius\Component\Registry\ServiceRegistryInterface;
use Sylius\Component\Shipping\Resolver\ShippingMethodsResolverInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
*/
final class ShowAvailableShippingMethodsController
{
/**
* @var FactoryInterface
*/
private $stateMachineFactory;

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

/**
* @var ShippingMethodsResolverInterface
*/
private $shippingMethodsResolver;

/**
* @var ViewHandlerInterface
*/
private $restViewHandler;

/**
* @var ServiceRegistryInterface
*/
private $calculators;

/**
* @param FactoryInterface $stateMachineFactory
* @param OrderRepositoryInterface $orderRepository
* @param ShippingMethodsResolverInterface $shippingMethodsResolver
* @param ViewHandlerInterface $restViewHandler
* @param ServiceRegistryInterface $calculators
*/
public function __construct(
FactoryInterface $stateMachineFactory,
OrderRepositoryInterface $orderRepository,
ShippingMethodsResolverInterface $shippingMethodsResolver,
ViewHandlerInterface $restViewHandler,
ServiceRegistryInterface $calculators
) {
$this->stateMachineFactory = $stateMachineFactory;
$this->orderRepository = $orderRepository;
$this->shippingMethodsResolver = $shippingMethodsResolver;
$this->restViewHandler = $restViewHandler;
$this->calculators = $calculators;
}

/**
* @param Request $request
*
* @return Response
*/
public function showAction(Request $request)
{
/** @var OrderInterface $cart */
$cart = $this->getCartOr404($request->attributes->get('orderId'));

if (!$this->isCheckoutTransitionPossible($cart, OrderCheckoutTransitions::TRANSITION_SELECT_SHIPPING)) {
throw new BadRequestHttpException('The shipment methods cannot be resolved in the current state of cart!');
}

$shipments = [];

foreach ($cart->getShipments() as $shipment) {
$shipments['shipments'][] = [
'methods' => $this->getCalculatedShippingMethods($shipment, $cart->getLocaleCode()),
];
}

return $this->restViewHandler->handle(View::create($shipments));
}

/**
* @param mixed $cartId
*
* @return OrderInterface
*/
private function getCartOr404($cartId)
{
$cart = $this->orderRepository->findCartById($cartId);

if (null === $cart) {
throw new NotFoundHttpException(sprintf("The cart with %s id could not be found!", $cartId));
}

return $cart;
}

/**
* @param OrderInterface $cart
* @param string $transition
*
* @return bool
*/
private function isCheckoutTransitionPossible(OrderInterface $cart, $transition)
{
return $this->stateMachineFactory->get($cart, OrderCheckoutTransitions::GRAPH)->can($transition);
}

/**
* @param ShipmentInterface $shipment
* @param string $locale
*
* @return array
*/
private function getCalculatedShippingMethods(ShipmentInterface $shipment, $locale)
{
$shippingMethods = $this->shippingMethodsResolver->getSupportedMethods($shipment);

$rawShippingMethods = [];

foreach ($shippingMethods as $shippingMethod) {
$calculator = $this->calculators->get($shippingMethod->getCalculator());

$rawShippingMethods[] = [
'id' => $shippingMethod->getId(),
'code' => $shippingMethod->getCode(),
'name' => $shippingMethod->getTranslation($locale)->getName(),
'description' => $shippingMethod->getTranslation($locale)->getDescription(),
'price' => $calculator->calculate($shipment, $shippingMethod->getConfiguration()),
];
}

return $rawShippingMethods;
}
}
17 changes: 17 additions & 0 deletions src/Sylius/Bundle/ApiBundle/Resources/config/routing/checkout.yml
@@ -1,6 +1,7 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
#

sylius_api_checkout_show:
path: /{id}
methods: [GET]
Expand All @@ -24,6 +25,14 @@ sylius_api_checkout_addressing:
graph: sylius_order_checkout
transition: address

sylius_api_checkout_available_shipping_methods:
path: /select-shipping/{orderId}
methods: [GET]
defaults:
_controller: sylius.controller.show_available_shipping_methods:showAction
_sylius:
serialization_version: $version

sylius_api_checkout_select_shipping:
path: /select-shipping/{orderId}
methods: [PUT]
Expand All @@ -39,6 +48,14 @@ sylius_api_checkout_select_shipping:
graph: sylius_order_checkout
transition: select_shipping

sylius_api_checkout_available_payment_methods:
path: /select-payment/{orderId}
methods: [GET]
defaults:
_controller: sylius.controller.show_available_payment_methods:showAction
_sylius:
serialization_version: $version

sylius_api_checkout_select_payment:
path: /select-payment/{orderId}
methods: [PUT, PATCH]
Expand Down
Expand Up @@ -22,26 +22,32 @@ sylius_api_payment_method_create:
serialization_version: $version

sylius_api_payment_method_update:
path: /{id}
path: /{code}
methods: [PUT, PATCH]
defaults:
_controller: sylius.controller.payment_method:updateAction
_sylius:
serialization_version: $version
criteria:
code: $code

sylius_api_payment_method_delete:
path: /{id}
path: /{code}
methods: [DELETE]
defaults:
_controller: sylius.controller.payment_method:deleteAction
_sylius:
serialization_version: $version
criteria:
code: $code
csrf_protection: false

sylius_api_payment_method_show:
path: /{id}
path: /{code}
methods: [GET]
defaults:
_controller: sylius.controller.payment_method:showAction
_sylius:
serialization_version: $version
criteria:
code: $code
1 change: 1 addition & 0 deletions src/Sylius/Bundle/ApiBundle/Resources/config/services.xml
Expand Up @@ -13,6 +13,7 @@

<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="services/controller.xml" />
<import resource="services/form.xml" />
<import resource="services/fixture.xml" />
<import resource="services/fixtures_factories.xml" />
Expand Down

0 comments on commit 32ea574

Please sign in to comment.