Stripe support for Payment

Rational

Stripe provides a clean and simple API to charge credit card. As credit card is managed at browser level, the server (trytond) does not need to be PCI DSS compliant.

Proposition

We need to store the Stripe key on the journal payment of type “Stripe”.

We need also to store if needed the Customer to be able to make recurring charge without asking credit card each time. This will be stored on a new Model account.payment.stripe.customer (similar to SEPA mandate). If the record can not be deleted but instead it will be inactivated. In this case, it will be deleted on Stripe and the key will be erased periodically by a cron task.

We need a way to retrieve token for a payment if we do not have a Customer key. This process to not require PCI DSS will need to happen in the browser of the user. For that, we should deliver at an URL a minimal web page which display the Checkout form and retrieve the posted data. To ensure this form will only be used by allowed user, we will use a token in the form that will be generated by payment.
The same work-flow will be implemented for the Customer registration (but without any amount).
Of course this checkout method could completely be skipped in favour of a custom website implementation. The purpose of this checkout from client is for telemarketer or POS.

Tryton payments are processed by group but Strip API process one payment per post. So we need to desynchronise the Tryton processing and the post to get transactional integrity. A cron task will post charge for all Stripe payments which are in the state processing (using a generated UUID for idempotents). The Charge request will use the token stored on the payment or the Customer id. If the charge succeed then the payment is passed to succeeded also. If the charge fails depending on the error, the payment will be failed (card_error ) or retried later (technical issue).

Implementation

https://bugs.tryton.org/issue6259
https://hg.tryton.org/modules/account_payment_stripe

Future

  • Add support for refund
  • Manage dispute via web-hooks
  • Add ACH support
  • Manage payment methods
1 Like

It could be stored just like that without any specific security?

Yes the documentation says so. I guess it is because the Customer ID is linked to your account.
But any way, we will not expose it to any user using a field access.

I would like to support this project.

Regarding your data structure - wouldn’t you store the customer on the the party model but the credit card on another model?

1 Like

Should we consider an extra state for a payment in case a payment does not go through?

The Customer is indeed a token that allow to debit a card. So a Party could (even if it is not really useful) have many cards and so many Customer key.
The token for credit card can be used only once so I think it is correct to store it on the payment because it will be paid only once.

I do not understand what you mean?

I don’t think this is correct. It is possible to store a credit card. A customer record on the Stripe side can have multiple credit cards. It is possible to define which card to charge in the charge object [1].

On the stripe side there are 3 objects: customer, card and payment. I feel like we can decide whether we map these to 3 or 2 models on the Tryton side.

  1. map 3 models:
    party → customer
    card ( new model ) → card
    payment → payment

  2. map 2 models:
    card → customer/card
    payment → payment

With the second option, we could store the Stripe customer ID on the card model only and obviously map other “detail” fields from the party to the Stripe customer object.

[1] - Stripe API Reference

Apologies :); this is partly correct. I thought a token was a credit card, but it is indeed another object and indeed can only be used once [1].

[1] - Stripe API Reference

One thing I am not sure about is where to store Stripe API credentials.

Best practice is to store these in environment variables or conf file, but this does not make sense to me in regards to Tryton because of the fact that multiple databases can be run in a single instance and it is likely that each database should have different credentials.

It will be stored on the payment journal.

1 Like

Stripe is also capable of processing ACH payments, which are useful here in the US. If you can build this feature into the module as well I would be happy to contribute.

It is not planned but as far as I see it will be just a new way to register a Customer on a party like the Checkout will do.