2

I've been looking at a lot of posts but nowhere have I found a solution to my question. There doesn't same to be a single place on the internet that explains how to properly add a new payment gateway to the Sylius Payum Bundle.

I'm using the latest sylius 0.10.* version and I'd like to add a new payment gateway (Rabobank Omnikassa, a Dutch payment endpoint).

There's some info on how to add a PaymentFactory for the PayumPayumBundle, however the folder structure of this bundle is nothing like SyliusPayumBundle. I've created my own Acme\Bundle\PayumBundle which overrides from the SyliusPayumBundle.

I would like to set it up in a similar fashion to the PaypalExpressCheckoutPaymentFactory.

config/payum.yml

Here I'm just testing a few things to get Sylius to find my stuff.

payum:
    contexts:
        rabobank:
            storages:
                Sylius\Component\Core\Model\Order:
                    doctrine:
                        driver: orm
                Sylius\Component\Core\Model\Payment:
                    doctrine:
                        driver: orm

            custom:
                actions:
                    - Shopfish\Bundle\PayumBundle\Payum\Rabobank\Action\CapturePaymentAction
                    - Shopfish\Bundle\PayumBundle\Payum\Rabobank\Action\NotifyOrderAction

config/services.xml

I'm not sure what service tags to use where..

<parameters>
    <parameter key="shopfish.payum.rabobank.action.capture_payment.class">Shopfish\Bundle\PayumBundle\Payum\Rabobank\Action\CapturePaymentAction</parameter>
    <parameter key="shopfish.payum.rabobank.action.notify_order.class">Shopfish\Bundle\PayumBundle\Payum\Rabobank\Action\NotifyOrderAction</parameter>
    <parameter key="shopfish.payum.rabobank.action.payment_status.class">Shopfish\Bundle\PayumBundle\Payum\Rabobank\Action\PaymentStatusAction</parameter>
</parameters>

<services>
    <!-- Rabobank Omnikassa -->
    <service id="shopfish.payum.rabobank.action.capture_payment" class="%shopfish.payum.rabobank.action.capture_payment.class%" public="false">
        <tag name="payum.action" factory="omnipay" />
    </service>

    <service id="shopfish.payum.rabobank.action.notify_order" class="%shopfish.payum.rabobank.action.notify_order.class%" public="false">
        <argument type="service" id="event_dispatcher" />
        <argument type="service" id="sylius.manager.payment" />
        <argument type="service" id="finite.factory" />

        <tag name="payum.action" factory="paypal_express_checkout_nvp" />
    </service>
</services>

config/config.yml

And ofcourse I'm registering the gateway in the config.yml file

sylius_payment:
    gateways:
        rabobank: Rabobank Omnikassa

Exception: Invalid configuration for path

It doesn't seem to recognize Rabobank as a valid type. Where does one register a new type?

InvalidConfigurationException: Invalid configuration for path "payum.contexts.rabobank.omnipay": Given type Rabobank is not supported. These types AuthorizeNet_AIM, AuthorizeNet_SIM, Buckaroo, CardSave, Dummy, Eway_Rapid, GoCardless, Manual, Migs_ThreeParty, Migs_TwoParty, Mollie, MultiSafepay, Netaxept, NetBanx, PayFast, Payflow_Pro, PaymentExpress_PxPay, PaymentExpress_PxPost, PayPal_Express, PayPal_Pro, Pin, SagePay_Direct, SagePay_Server, SecurePay_DirectPost, Stripe, TargetPay_Directebanking, TargetPay_Ideal, TargetPay_Mrcash, TwoCheckout, WorldPay are supported.

Registering the Payment Factory

In this file you can see how they're registering the factories in Payum. I'd like to do the same in Sylius from within my own Bundle.

What are good steps to take from here?

Mirage
  • 992
  • 1
  • 7
  • 26

1 Answers1

3

There are two ways to add custom payment solution to Payum\Sylius.

  • The quickest is using custom factory. That what you did, but you have to add a services to actions section not classes. The tag payum.action could be used with this approach like <tag name="payum.action" context="rabobank" />. I didnot use factory custom in the tag because in this case actions will be added to all contexts created by custom factory. It is not what we want.

  • Second way is to create a payment factory. For that you have to implement PaymentFactoryInterface and register it to Payum extension. You have to choose this if you need some options to be configured before you able to create a payment. The tag payum.action could be used with this approach like <tag name="payum.action" context="rabobank" /> or <tag name="payum.action" factory="rabobank" />. The difference is: first tag adds an action only to one context where second one adds action to all contexts that were created by a factory.

Some general suggestions:

There's some info on how to add a PaymentFactory for the PayumBundle, however the folder structure of this bundle is nothing like SyliusPayumBundle.

It should not be. SyliusPayumBundle is a thin integration layer between Sylius and PayumBundle.

I've created my own Acme\Bundle\PayumBundle which overrides from the SyliusPayumBundle.

You dont have to do that, everything should work fine without this.

I'm not sure what service tags to use where..

If you chose a custom factory you dont need tags, configure actions section correctly.

InvalidConfigurationException: Invalid configuration for path "payum.contexts.rabobank.omnipay":

Are you sure you posted right configs? I believe you cannot get this exception with what you posted. I expect different exception with different message.

And ofcourse I'm registering the gateway in the config.yml file

You also have to put some data in your payment_gateway table (If I recall the table name correctly).

In this file you can see how they're registering the factories in Payum. I'd like to do the same in Sylius from within my own Bundle.

Just do same in your bundle's build method.

Maksim Kotlyar
  • 3,821
  • 27
  • 31
  • Maksim, thanks for your well-put answer. Before I can accept it however I have a few uncertainties remaining. I've registered my PaymentFactory now and Sylius has found my `CapturePaymentAction` correctly. What I need to do however is redirect the user to the Rabobank payment gateway website with information about the payment. I saw an example on the Payum site with a `PaymentController` with a `prepareXXXPaymentAction()` in which the user seems to be redirected. I haven't found a way to incorporate this within Sylius yet, seeing how it's using the `PurchaseStep:display` method. Your thoughts? – Mirage Jun 03 '14 at 13:57
  • I'm still unsure if `CapturePaymentAction` is called **before** or **after** the actual payment is fulfilled on the website of the Rabobank Omnikassa. – Mirage Jun 03 '14 at 13:58
  • It has to be called before and afrer, all capture flow logic has to be kept in CaptureAction::execute method. See paypal's [capture action](https://github.com/Payum/Payum/blob/master/src/Payum/Paypal/ExpressCheckout/Nvp/Action/CaptureAction.php). The redirect is done while AuthorizeTokenRequest is executed. Or be2bill [capture action](https://github.com/Payum/Payum/blob/master/src/Payum/Paypal/ExpressCheckout/Nvp/Action/CaptureAction.php). It does post redirect but the main idea has to clear. P.S. All the data saved automatically, do not take care of that. – Maksim Kotlyar Jun 03 '14 at 18:32
  • Alright, so the "reportUrl" that Rabobank will post its updates on should also be Capture? Or is that another url? I can imagine that's `payum_notify_do`, just need to figure out how to render this URL from within an action. – Mirage Jun 04 '14 at 07:58
  • I am not familiar with Rabobank, to answer your comment I used this [doc](https://www.rabobank.nl/images/integratiehandleiding_rabo_omnikassa_en_version_7_1_april_2014_final_2_0_29637101.pdf?ra_resize=yes&ra_width=1024&ra_height=768&ra_toolbar=yes&ra_locationbar=yes). The return-url has to be same as capture one (you have to come back to capture action with updated data). report url is kind of paypal IPN, used for automatic reports. Search for NotifyAction in Sylius to learn how to impl it. – Maksim Kotlyar Jun 04 '14 at 08:03
  • Sweet, thanks! Looking at Paypal's NVP `CaptureAction` I see it executes a bunch of Requests on the `$this->payment`, such as `DoExpressCheckoutPaymentRequest`, how is this request "bound" to its action? The requests are all empty, which confuses me quite a bit. – Mirage Jun 04 '14 at 08:40
  • For example, `$this->payment->execute(new SyncRequest($model));`, I have no idea what's happening here because tracing back the `SyncRequest` it's just an empty class that extends `BaseModelRequest` like all other requests. – Mirage Jun 04 '14 at 08:43
  • **Update:** I think I've figured the empty requests out, it's merely used for the `Action::supports` function right? Like `$request instanceof SetExpressCheckoutRequest`, besides that there is no other use for the request other than defining a setting in the constructor. The only thing I'm still confused about now is the purpose and functioning of the `SyncRequest` request – Mirage Jun 04 '14 at 08:53
  • payment contains all actions and ask each one by one "Do you support such request?", For that it uses action->support method. Let's say one action says "Yes, I am support it" a payment call action's execute method and pass the request to it. Read this to better understand Payum philosophy: http://payum.forma-dev.com/documentation/0.8/Core/the-architecture – Maksim Kotlyar Jun 04 '14 at 10:34
  • > is the purpose and functioning of the SyncRequest request fetch data from payments side and update local model – Maksim Kotlyar Jun 04 '14 at 10:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/55068/discussion-between-melvin-valster-and-maksim-kotlyar). – Mirage Jun 04 '14 at 15:15