vuestorefront / vue-storefront-1

The open-source frontend for any eCommerce. Built with a PWA and headless approach, using a modern JS stack. We have custom integrations with Magento, commercetools, Shopware and Shopify and total coverage is just a matter of time. The API approach also allows you to merge VSF with any third-party tool like CMS, payment gateways or analytics. Newest updates: https://blog.vuestorefront.io. Always Open Source, MIT license.
https://www.vuestorefront.io
MIT License
18 stars 13 forks source link

[RFC] Payment Gateway Integration #282

Open sandermangel opened 5 years ago

sandermangel commented 5 years ago

One of the more challenging parts of the checkout has been payment gateways. This RFC is an effort to streamline integrations, offering standardized workflows.

Since integrations like these touch the stack on every level and need tight integration in both the frontend, as well as the underlying e-commerce engine, a clear separation of concerns should be made. The frontend and middleware should be as agnostic as possible, containing little to no business logic.

This RFC focusses more on the high-level architecture than specific implementation details, although these are welcome of course.

Integration divided into actions

For a generic Payment Gateway, assuming we're dealing with online payments (Credit Card, Sofort, iDeal, etc), the integration can be divided into various actions. Below an overview of the actions with a short introduction into requirements and challenges.

1. Fetching payment methods

Payment methods are to be displayed in the frontend in the Checkout UI. These payment methods might be simple options or have their own UI like a Credit Card asking for card number and name. The methods to be displayed may vary depending on variables of the order being created; subtotal, billing country or the types of items.

2. Communication with Gateway

The selected payment method, with any user input added, is bundled with order details and send of to the Payment Gateway. Here it's important to note this has to be done encrypted. Optionally the user might need to be redirected to an external page to finalize the payment.

3. Payment status callback

Once the payment has been processed by the payment gateway a callback is done to the originating platform. This updates the order registering a payment, or a failure.

New proposed integration

The new flow has a clear separation of concerns where business logic is focussed in the underlying e-commerce platform, the middleware merely transforms data and the VueJS app handles presentation.

Payment Gateway Integration diagram

DaanKouters commented 5 years ago

This is very important (obviously) I'll post here what we came across with developing a payment integration as first pointers. I'll post more when i have the time

What we came across with building payment provider integration was: We had to store a order in the backendsystem to link the payment to be sure the order and payment are linked properly - don't know a better way tbh, it's common in payment integrations i guess. If payment fails the order is canceled. We hooked into the order-afterPlaced event, where we had the backend order id. What we did then is fetch order details again to hash data and get the increment id. The data we get with this extra call could be already provided by o2m (in this case) to prevent the extra backendsystem fetch action. The hash is to compare the VSF cart totals to the stored order grand_total. To be sure the correct amount is used to create the payment for this order.

Payment method in VSF has to be configured in Magento2 to accept an order with paymentmethod-code 'X' - therefore we had to add Paymentmethods mapping in config which makes it a bit less manageable to add payment methods to the shop (for non developers).

We integrated a payment API from Mollie (Dutch PSP) with multiple payment methods, we use the replaceMethods action to only provide payment methods from this PSP (for now). with the headless solutions and microservices out there, should it be possible to manage actions on a paymentmethod level or on a payment provider level?

Looking at PSP API's, the naming for actions (fetching methods, create payment, get payment status etc.) are not standarized. So we should add key variables for these actions. I see it like VSF provides all the actions / hooks and in the backend layer (VS-API) we use keys to map the actions to the PSP API endpoints. This should be a config setting for the module, mapping the VSF actions to the API endpoints.

dimasch commented 5 years ago

There is now no entry in m2 stating that the order has been paid, the response from the payment gateway is not saved in m2.

2019-07-17_22-42-10

Possible idea: Create order with invoice in status not paid before send the customer to their bank site. After receive from payment gateway invoice transition to payed

https://docs.magento.com/m2/ce/user_guide/sales/invoice-create.html https://webkul.com/blog/how-to-programmatically-create-invoice-in-magento2/

DaanKouters commented 5 years ago

hi @dimasch after placing the order in Magento (there is no invoice now), you can invoke the invoice method after user comes back. Or by a webhhook from a payment provider api.

When you invoke the invoice method you can update the order status.

What is the motivation to add an invoice upon placing the order with status not paid?

dimasch commented 5 years ago

Hi, @DaanKouters

What is the motivation to add an invoice upon placing the order with status not paid?

"invoice" - This is only my "possible" assumption. Only one goal - to save transaction_id to Magento2 order after approved a payment from gateway.

Tell me how to make it better? Simple REST Api endpoint for save transaction_id ? For example, the Braintree module save transaction_id out of the box https://github.com/danrcoull/vsf-payment-braintree

DaanKouters commented 5 years ago

hi @dimasch in our payment integration we added a magento mini module to save the transaction_id we receive from the payment provider. At this point a payment is created at the PSP for the placed order, there is no payment done yet. It's a simple API endpoint with order_id and transaction_id as payload to link these together. The transaction_id is saved as an order extension attribute.

But this point makes it very platform dependent. Don't know how we can come up with a solution for multiple backendsystems. We could save this kind of data in redis, there is also an order object saved already. But that's not a good idea, because when the redis cache is flushed you lost all this data. So that's out of the question imo.