Use Finite with Payment as well

This commit is contained in:
Alexandre 2014-04-25 21:45:03 +08:00
parent 7f228cb8d4
commit 5592df94e1
16 changed files with 213 additions and 38 deletions

8
composer.lock generated
View file

@ -4873,12 +4873,12 @@
"source": {
"type": "git",
"url": "https://github.com/yohang/Finite.git",
"reference": "0596a7bc31c4cb9eee83d20d7625cdc934b1120b"
"reference": "865dd79b2ab3da054587feeb686b438de0229bbd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/yohang/Finite/zipball/0596a7bc31c4cb9eee83d20d7625cdc934b1120b",
"reference": "0596a7bc31c4cb9eee83d20d7625cdc934b1120b",
"url": "https://api.github.com/repos/yohang/Finite/zipball/865dd79b2ab3da054587feeb686b438de0229bbd",
"reference": "865dd79b2ab3da054587feeb686b438de0229bbd",
"shasum": ""
},
"require": {
@ -4935,7 +4935,7 @@
"transition",
"workflow"
],
"time": "2014-04-21 09:48:32"
"time": "2014-04-25 12:31:21"
}
],
"packages-dev": [

View file

@ -65,12 +65,18 @@ class PurchaseStep extends CheckoutStep
}
$payment = $order->getPayment();
$previousState = $order->getPayment()->getState();
$payment->setState($status->getStatus());
$previousState = $payment->getState();
$nextState = $status->getStatus();
$stateMachine = $this->get('finite.factory')->get($payment, 'sylius_payment');
if (null !== $transition = $stateMachine->getTransitionToState($nextState)) {
$stateMachine->apply($transition);
}
$this->dispatchCheckoutEvent(SyliusCheckoutEvents::PURCHASE_PRE_COMPLETE, $order);
if ($previousState !== $payment->getState()) {
if ($previousState !== $nextState) {
$this->dispatchEvent(
SyliusPaymentEvents::PRE_STATE_CHANGE,
new GenericEvent($order->getPayment(), array('previous_state' => $previousState))
@ -79,7 +85,7 @@ class PurchaseStep extends CheckoutStep
$this->getDoctrine()->getManager()->flush();
if ($previousState !== $payment->getState()) {
if ($previousState !== $nextState) {
$this->dispatchEvent(
SyliusPaymentEvents::POST_STATE_CHANGE,
new GenericEvent($order->getPayment(), array('previous_state' => $previousState))

View file

@ -55,6 +55,7 @@ abstract class Kernel extends BaseKernel
new \Sylius\Bundle\CoreBundle\SyliusCoreBundle(),
new \Sylius\Bundle\WebBundle\SyliusWebBundle(),
new \Finite\Bundle\FiniteBundle\FiniteFiniteBundle(),
new \Sylius\Bundle\ResourceBundle\SyliusResourceBundle(),
new \Sonata\BlockBundle\SonataBlockBundle(),
@ -86,7 +87,6 @@ abstract class Kernel extends BaseKernel
new \HWI\Bundle\OAuthBundle\HWIOAuthBundle(),
new \Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
new \WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
new \Finite\Bundle\FiniteBundle\FiniteFiniteBundle(),
);
if (in_array($this->environment, array('dev', 'test'))) {

View file

@ -12,6 +12,7 @@
namespace spec\Sylius\Bundle\CoreBundle\Checkout\Step;
use Doctrine\Common\Persistence\ObjectManager;
use Finite\Factory\FactoryInterface;
use Payum\Core\PaymentInterface;
use Payum\Core\Registry\RegistryInterface;
use Payum\Core\Security\HttpRequestVerifierInterface;
@ -24,7 +25,9 @@ use Sylius\Component\Cart\Provider\CartProviderInterface;
use Sylius\Component\Core\Model\Order;
use Sylius\Component\Core\SyliusCheckoutEvents;
use Sylius\Component\Payment\Model\Payment;
use Sylius\Component\Payment\PaymentTransitions;
use Sylius\Component\Payment\SyliusPaymentEvents;
use Sylius\Component\Resource\StateMachine\StateMachineInterface;
use Symfony\Bridge\Doctrine\RegistryInterface as DoctrinRegistryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@ -51,7 +54,8 @@ class PurchaseStepSpec extends ObjectBehavior
ObjectManager $objectManager,
Session $session,
FlashBagInterface $flashBag,
TranslatorInterface $translator
TranslatorInterface $translator,
FactoryInterface $factory
) {
$requestStack->getCurrentRequest()->willReturn($request);
$session->getFlashBag()->willReturn($flashBag);
@ -71,6 +75,7 @@ class PurchaseStepSpec extends ObjectBehavior
$container->get('doctrine')->willReturn($doctrine);
$container->has('doctrine')->willReturn(true);
$container->get('translator')->willReturn($translator);
$container->get('finite.factory')->willReturn($factory);
$this->setName('purchase');
@ -88,9 +93,11 @@ class PurchaseStepSpec extends ObjectBehavior
}
function it_must_dispatch_pre_and_post_payment_state_changed_if_state_changed(
$factory,
ProcessContextInterface $context,
PaymentInterface $payment,
EventDispatcherInterface $eventDispatcher
EventDispatcherInterface $eventDispatcher,
StateMachineInterface $sm
) {
$paymentModel = new Payment();
$paymentModel->setState(Payment::STATE_NEW);
@ -105,6 +112,10 @@ class PurchaseStepSpec extends ObjectBehavior
}
);
$factory->get($paymentModel, 'sylius_payment')->willReturn($sm);
$sm->getTransitionToState('completed')->willReturn(PaymentTransitions::SYLIUS_COMPLETE);
$sm->apply(PaymentTransitions::SYLIUS_COMPLETE)->shouldBeCalled();
$eventDispatcher
->dispatch(
SyliusCheckoutEvents::PURCHASE_INITIALIZE,
@ -148,9 +159,11 @@ class PurchaseStepSpec extends ObjectBehavior
}
function it_must_not_dispatch_pre_and_post_payment_state_changed_if_state_not_changed(
$factory,
ProcessContextInterface $context,
PaymentInterface $payment,
EventDispatcherInterface $eventDispatcher
EventDispatcherInterface $eventDispatcher,
StateMachineInterface $sm
) {
$paymentModel = new Payment();
$paymentModel->setState(Payment::STATE_COMPLETED);
@ -165,6 +178,10 @@ class PurchaseStepSpec extends ObjectBehavior
}
);
$factory->get($paymentModel, 'sylius_payment')->willReturn($sm);
$sm->getTransitionToState('completed')->willReturn(null);
$sm->apply(PaymentTransitions::SYLIUS_COMPLETE)->shouldNotBeCalled();
$eventDispatcher
->dispatch(
SyliusCheckoutEvents::PURCHASE_INITIALIZE,

View file

@ -23,7 +23,7 @@ finite_finite:
from: [new, pending]
to: processing
complete:
from: [pending, processing]
from: [new, pending, processing]
to: completed
fail:
from: [pending, processing]

View file

@ -0,0 +1,40 @@
<?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\PayumBundle\Payum\Action;
use Finite\Factory\FactoryInterface;
use Payum\Core\Action\PaymentAwareAction;
/**
* @author Alexandre Bacco <alexandre.bacco@gmail.com>
*/
abstract class AbstractPaymentStateAwareAction extends PaymentAwareAction
{
/**
* @var FactoryInterface
*/
protected $factory;
public function __construct(FactoryInterface $factory)
{
$this->factory = $factory;
}
protected function updatePaymentState($payment, $previousState, $nextState)
{
$stateMachine = $this->factory->get($payment, 'sylius_payment');
if (null !== $transition = $stateMachine->getTransitionToState($nextState)) {
$stateMachine->apply($transition);
}
}
}

View file

@ -12,11 +12,12 @@
namespace Sylius\Bundle\PayumBundle\Payum\Be2bill\Action;
use Doctrine\Common\Persistence\ObjectManager;
use Finite\Factory\FactoryInterface;
use Payum\Be2Bill\Api;
use Payum\Bundle\PayumBundle\Request\ResponseInteractiveRequest;
use Payum\Core\Action\PaymentAwareAction;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\NotifyRequest;
use Sylius\Bundle\PayumBundle\Payum\Action\AbstractPaymentStateAwareAction;
use Sylius\Bundle\PayumBundle\Payum\Request\StatusRequest;
use Sylius\Component\Order\Repository\OrderRepositoryInterface;
use Sylius\Component\Payment\SyliusPaymentEvents;
@ -28,7 +29,7 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* @author Alexandre Bacco <alexandre.bacco@gmail.com>
*/
class NotifyAction extends PaymentAwareAction
class NotifyAction extends AbstractPaymentStateAwareAction
{
/**
* @var Api
@ -55,8 +56,16 @@ class NotifyAction extends PaymentAwareAction
*/
protected $identifier;
public function __construct(Api $api, OrderRepositoryInterface $orderRepository, EventDispatcherInterface $eventDispatcher, ObjectManager $objectManager, $identifier)
{
public function __construct(
Api $api,
OrderRepositoryInterface $orderRepository,
EventDispatcherInterface $eventDispatcher,
ObjectManager $objectManager,
FactoryInterface $factory,
$identifier
) {
parent::__construct($factory);
$this->api = $api;
$this->orderRepository = $orderRepository;
$this->eventDispatcher = $eventDispatcher;
@ -96,8 +105,6 @@ class NotifyAction extends PaymentAwareAction
throw new BadRequestHttpException('Request amount cannot be verified against payment amount.');
}
$previousState = $payment->getState();
// Actually update payment details
$details = array_merge($payment->getDetails(), $details);
$payment->setDetails($details);
@ -105,9 +112,12 @@ class NotifyAction extends PaymentAwareAction
$status = new StatusRequest($order);
$this->payment->execute($status);
$payment->setState($status->getStatus());
$previousState = $payment->getState();
$nextState = $status->getStatus();
if ($previousState !== $payment->getState()) {
$this->updatePaymentState($payment, $previousState, $nextState);
if ($previousState !== $nextState) {
$this->eventDispatcher->dispatch(
SyliusPaymentEvents::PRE_STATE_CHANGE,
new GenericEvent($payment, array('previous_state' => $previousState))

View file

@ -12,17 +12,18 @@
namespace Sylius\Bundle\PayumBundle\Payum\Paypal\Action;
use Doctrine\Common\Persistence\ObjectManager;
use Payum\Core\Action\PaymentAwareAction;
use Finite\Factory\FactoryInterface;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\SecuredNotifyRequest;
use Payum\Core\Request\SyncRequest;
use Sylius\Bundle\PayumBundle\Payum\Action\AbstractPaymentStateAwareAction;
use Sylius\Bundle\PayumBundle\Payum\Request\StatusRequest;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Payment\SyliusPaymentEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
class NotifyOrderAction extends PaymentAwareAction
class NotifyOrderAction extends AbstractPaymentStateAwareAction
{
/**
* @var EventDispatcherInterface
@ -37,9 +38,12 @@ class NotifyOrderAction extends PaymentAwareAction
/**
* @param EventDispatcherInterface $eventDispatcher
* @param ObjectManager $objectManager
* @param FactoryInterface $factory
*/
public function __construct(EventDispatcherInterface $eventDispatcher, ObjectManager $objectManager)
public function __construct(EventDispatcherInterface $eventDispatcher, ObjectManager $objectManager, FactoryInterface $factory)
{
parent::__construct($factory);
$this->eventDispatcher = $eventDispatcher;
$this->objectManager = $objectManager;
}
@ -63,7 +67,11 @@ class NotifyOrderAction extends PaymentAwareAction
$status = new StatusRequest($payment);
$this->payment->execute($status);
$payment->setState($status->getStatus());
$previousState = $payment->getState();
$nextState = $status->getStatus();
$this->updatePaymentState($payment, $previousState, $nextState);
if ($previousState !== $payment->getState()) {
$this->eventDispatcher->dispatch(

View file

@ -41,6 +41,7 @@
<service id="sylius.payum.paypal.action.notify_order" class="%sylius.payum.paypal.action.notify_order.class%">
<argument type="service" id="event_dispatcher" />
<argument type="service" id="sylius.manager.payment" />
<argument type="service" id="finite.factory" />
</service>
<service id="sylius.payum.stripe.action.capture_order_using_credit_card" class="%sylius.payum.stripe.action.capture_order_using_credit_card.class%" />
@ -60,6 +61,7 @@
<argument type="service" id="sylius.repository.order" />
<argument type="service" id="event_dispatcher" />
<argument type="service" id="sylius.manager.payment" />
<argument type="service" id="finite.factory" />
<argument>id</argument>
</service>

View file

@ -30,7 +30,8 @@
"sylius/payment-bundle": "0.10.*@dev",
"sylius/resource-bundle": "0.10.*@dev",
"payum/payum-bundle": "0.8.*",
"payum/payum": "0.8.*"
"payum/payum": "0.8.*",
"yohang/finite": "~1.1@dev"
},
"config": {
"bin-dir": "bin"

View file

@ -12,6 +12,7 @@
namespace spec\Sylius\Bundle\PayumBundle\Payum\Paypal\Action;
use Doctrine\Common\Persistence\ObjectManager;
use Finite\Factory\FactoryInterface;
use Payum\Core\PaymentInterface;
use Payum\Core\Request\ModelRequestInterface;
use Payum\Core\Request\SecuredNotifyRequest;
@ -20,7 +21,9 @@ use Prophecy\Argument;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Payment\Model\Payment;
use Sylius\Component\Payment\Model\PaymentInterface as PaymentModelInterface;
use Sylius\Component\Payment\PaymentTransitions;
use Sylius\Component\Payment\SyliusPaymentEvents;
use Sylius\Component\Resource\StateMachine\StateMachineInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class NotifyOrderActionSpec extends ObjectBehavior
@ -28,9 +31,10 @@ class NotifyOrderActionSpec extends ObjectBehavior
function let(
EventDispatcherInterface $eventDispatcher,
ObjectManager $objectManager,
PaymentInterface $payment
PaymentInterface $payment,
FactoryInterface $factory
) {
$this->beConstructedWith($eventDispatcher, $objectManager);
$this->beConstructedWith($eventDispatcher, $objectManager, $factory);
$this->setPayment($payment);
}
@ -79,19 +83,22 @@ class NotifyOrderActionSpec extends ObjectBehavior
}
function it_must_not_dispatch_pre_and_post_payment_state_changed_if_state_not_changed(
$factory,
SecuredNotifyRequest $request,
OrderInterface $order,
PaymentModelInterface $paymentModel,
PaymentInterface $payment,
EventDispatcherInterface $eventDispatcher
EventDispatcherInterface $eventDispatcher,
StateMachineInterface $sm
) {
$request->getModel()->willReturn($order);
$order->getPayment()->willReturn($paymentModel);
$paymentModel->getState()->willReturn(Payment::STATE_COMPLETED);
$paymentModel->setState(Argument::type('string'))->will(function ($args) use ($paymentModel) {
$paymentModel->getState()->willReturn($args[0]);
});
$factory->get($paymentModel, 'sylius_payment')->willReturn($sm);
$sm->getTransitionToState('completed')->willReturn(null);
$sm->apply(PaymentTransitions::SYLIUS_COMPLETE)->shouldNotBeCalled();
$payment->execute(Argument::type('Payum\Core\Request\SyncRequest'))->willReturn(null);
@ -121,19 +128,24 @@ class NotifyOrderActionSpec extends ObjectBehavior
}
function it_must_dispatch_pre_and_post_payment_state_changed_if_state_changed(
$factory,
SecuredNotifyRequest $request,
OrderInterface $order,
PaymentModelInterface $paymentModel,
PaymentInterface $payment,
EventDispatcherInterface $eventDispatcher,
ObjectManager $objectManager
ObjectManager $objectManager,
StateMachineInterface $sm
) {
$request->getModel()->willReturn($order);
$order->getPayment()->willReturn($paymentModel);
$paymentModel->getState()->willReturn(Payment::STATE_COMPLETED);
$paymentModel->setState(Argument::type('string'))->will(function ($args) use ($paymentModel) {
$paymentModel->getState()->willReturn($args[0]);
$paymentModel->getState()->willReturn(Payment::STATE_PENDING);
$factory->get($paymentModel, 'sylius_payment')->willReturn($sm);
$sm->getTransitionToState('cancelled')->willReturn(PaymentTransitions::SYLIUS_CANCEL);
$sm->apply(PaymentTransitions::SYLIUS_CANCEL)->shouldBeCalled()->will(function ($args) use($paymentModel) {
$paymentModel->getState()->willReturn(Payment::STATE_CANCELLED);
});
$payment->execute(Argument::type('Payum\Core\Request\SyncRequest'))->willReturn(null);

View file

@ -25,6 +25,9 @@
<parameter key="sylius.event_subscriber.load_metadata.class">Sylius\Bundle\ResourceBundle\EventListener\LoadMetadataSubscriber</parameter>
<parameter key="sylius.event_subscriber.kernel_controller.class">Sylius\Bundle\ResourceBundle\EventListener\KernelControllerSubscriber</parameter>
<!-- Sylius State Machine -->
<parameter key="finite.state_machine.class">Sylius\Component\Resource\StateMachine\StateMachine</parameter>
</parameters>
<services>

View file

@ -34,6 +34,7 @@ use Sylius\Component\Payment\Model\PaymentMethodInterface;
use Sylius\Component\Shipping\Calculator\DefaultCalculators;
use Sylius\Component\Shipping\Model\RuleInterface;
use Sylius\Component\Shipping\Model\ShippingCategoryInterface;
use Sylius\Component\Shipping\ShipmentTransitions;
use Sylius\Component\Taxation\Model\TaxRateInterface;
use Sylius\Component\Taxonomy\Model\TaxonInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -261,7 +262,7 @@ class DataContext extends BehatContext implements KernelAwareInterface
$order->setCurrency('EUR');
$order->complete();
$shipmentProcessor->updateShipmentStates($order->getShipments(), ShipmentInterface::STATE_READY, ShipmentInterface::STATE_CHECKOUT);
$shipmentProcessor->updateShipmentStates($order->getShipments(), ShipmentTransitions::SYLIUS_PREPARE, ShipmentInterface::STATE_CHECKOUT);
$manager->persist($order);

View file

@ -0,0 +1,41 @@
<?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\Component\Resource\StateMachine;
use Finite\StateMachine\StateMachine as BaseStateMachine;
/**
* Sylius State Machine
*
* @author Alexandre Bacco <alexandre.bacco@gmail.com>
*/
class StateMachine extends BaseStateMachine implements StateMachineInterface
{
/**
* @{inheritDoc}
*/
public function getTransitionToState($toState, $fromState = null)
{
if (null === $fromState) {
$fromState = $this->getCurrentState()->getName();
}
foreach ($this->getTransitions() as $transitionName) {
$transition = $this->getTransition($transitionName);
if (in_array($fromState, $transition->getInitialStates()) && $toState === $transition->getState()) {
return $transition->getName();
}
}
return null;
}
}

View file

@ -0,0 +1,33 @@
<?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\Component\Resource\StateMachine;
use Finite\StateMachine\StateMachineInterface as BaseStateMachineInterface;
/**
* Sylius State Machine
*
* @author Alexandre Bacco <alexandre.bacco@gmail.com>
*/
interface StateMachineInterface extends BaseStateMachineInterface
{
/**
* Returns the possible transition between given states
* Returns null if no transition is possible
*
* @param string $toState
* @param string|null $fromState
*
* @return string|null
*/
public function getTransitionToState($toState, $fromState = null);
}

View file

@ -23,7 +23,8 @@
"php": ">=5.3.3",
"doctrine/collections": "~1.0",
"doctrine/common": "~2.3"
"doctrine/common": "~2.3",
"yohang/finite": "~1.1@dev"
},
"require-dev": {
"phpspec/phpspec": "~2.0"