Hi Sergei,
I sent an email to the general Tryton mailing list on this subject but I thought I would try this discussion board as it is an audience more targeted to what I am interested in accomplishing. I apologise in advance for the length but hope it sparks some further discussion and keeps things moving along…
A colleague and I have gotten quite far along in developing exactly what was proposed here (a basic e-shop using Tryton as a back-end). I took my colleague’s prototype Flask application (which used Pickle as a face backend) and adapted it using flask-tryton, with the strategy of keeping as much as possible to stock Tryton modules on the back end. Indeed it has been quite easy to get to build an e-shop and we hope to contribute our efforts to be the basis of a standard GPLed solution that could be incorporated into the Tryton project in general.
Payment processing is indeed the most significant piece of the solution that is not yet provided in a ready-made solution which brought me to this discussion. As suggested I have installed account_payment to get familiar with it and intend in the next few days to develop a “process method” for an online web based payment gateway with the provider’s API calls being made directly between the client’s web browser and the provider, and the resulting token/result code/auth number/etc (or the decline result if that happens instead) then submitted to Tryton to store the payment record. We are in the final stages of devloping the part on cart checkout that talks to a payment gateway called “Beanstream” (a service that is used fairly commonly where I am located in Canada), and I’m now in the early stages of creating an “account_payment_beanstream” module.
As Sergi (pokoli) has confirmed I have discovered a payment does no accounting moves, but it can be associated with the “accounts receivable” move line of a posted invoice. This is where I run into some difficulty in understanding the workflow of account_payment (strictly working through the Tryton client at this point):
-
If I set an invoice to “paid” state, I cannot associate a payment to the applicable move line of the invoice (I think it is excluded from the domain because it has been reconciled).
-
If I leave the invoice in the “posted” state the AR payment line of the invoice can be selected for the payment record, and I can go through the manual process to put the payment into the “succeeded” state. However, the account moves are not made so the billing party still shows the outstanding balance. Furthermore the invoice is still in “posted” state but the “amount to pay” is zero. Apparently if there is a “succeeded” account_payment record it is counted against the balance owing on the invoice regardless of actual account moves! I cannot “pay” the invoice because I cannot enter any amount over zero, and entering zero doesn’t advance the invoice to “paid”!
-
I can create a payment without a line, then do the “pay” on the invoice which sets the right state and accounting moves, however I cannot go back and set the payment line because of problem #1 (if I do try and trick by most means I get the error “The value of the field “Line” on “Payment” is not valid according to its domain.”).
-
In the Tryton client with the “manual” process, I FINALLY figured out a “hack” way to make it work: I put the invoice into “posted”, then “lines to pay” shows the line I want and I create a payment from it. As soon as that happens the invoice cannot be paid unless I delete the payment or else approve->process->fail it. Once it is in FAILED state the invoice “amount to pay” comes back and I can set the invoice to “paid”, then I can go back to the payment and put it to “succeeded”. The end result appears to be OK! The accounting looks right, the invoice says “paid” and has 0 amount to pay (doesn’t count things twice and get negative or anything), and I have may payment record! However this is a really nonsense way to do it, and I suspect that what I have to do is code the invoice payment action to happen within my “beanstream” process method while in some way working around the issue of any non-failed payment record referring to the invoice’s AR account move line blocking me from doing so.
So, considering the scenario of a “web cart checkout” what is the appropriate solution to this conundrum? I get either correct accounting or correct payment record tracking–but not both, unless I perform some black magic! Here is what I am thinking of doing with my payment gateway process method:
-
The user finishes shopping and decides to “check out”. The application we have persists the user’s cart as a “sale” record in Tryton, which is kept in “draft” state until the payment is attempted.
-
Once the response from the payment provider is returned to the browser it is submitted to our application which creates a payment with a move line set to None and immediately sets it to “approved” and calls my new “process” method as described below:
-
If the result is “NOT APPROVED” or “DECLINED” (they are both failures but subtly different but the process here is the same) we set the payment to “failed” and the user can try again. NOTE that the sale is still in draft and there is no invoice yet so as to best handle “abandoned carts”. QUESTION: I notice payment records can be switched between success and failure at will, so there is the option of reusing the same record for retries. However I do not plan on doing that so I can keep information about declines for support and diagnostic purposes. Each attempt would be its own payment record. Would that be considered the best way of doing things?
-
If the result is “APPROVED” then the payment process would a) process the sale, b) post the created invoice, c) pay the invoice, d) change the draft payment record’s account move line from None to the AR line of the invoice and finally e) change the account_payment state to “succeeded”. QUESTION: If the user required multiple attempts to pay for the sale what would be the best way to organise the payment records such that failed attempts can be fairly easily linked to a sale–could I use payment groups for this purpose, where most payment groups would just be one payment but some might include some failed attempts as well and I would build some kind of reference between the sale and the payment group, or would it be better do ignore payment groups and reference each payment to the sale individually? I was thinking to use payment groups, but let me know if that is too strange of a way to do it.
Which brings me to the sales reference in that last point: Given the way a typical e-shop works where payment transactions are immediate (not batched) and generally approved before posting (or even creating) invoices they could potentially never be associated with an invoice (if a customer abandons the cart sale after transaction failure) but we would want to retain a complete transaction history for many good reasons. As such we have to build in some kind of reference to sales that does not rely on invoices or account moves. Here is what I am proposing: a very simple module (would I call it sale_payment or sale_account_payment, or account_payment_sale…I’m thinking the first one?) that creates a Many2Many relationship between sales and payment groups. Then my payment processing method would have this as a dependency and I would be able to implement something like discussed above–put all the payment attempts in a group that is linked to a sale, and optionally if the sale is completed I could optionally set the payment records’ move lines to link them to the invoice if desired.
The reasoning for many2many is as follows:
-
that simple module could be applicable to many use cases: if a batch payment method was used to process payment for multiple sales then it could choose to make one payment group for the batch that has references to many different sales
-
the same model would also handle the use case I have for my own consulting business, where virtually all my sales involve progress payments (either against one invoice or multiple invoices within the sale). Such payments are usually weeks apart so wouldn’t be processed as a batch. In this case I would probably have one sale that has references to many payment groups.
That is the direction I was thinking of but I wanted to make sure that is in line with the vision of the developers who created the sale and account_payment modules. I also noticed that serious consideration has been made to develop a payment module for stripe. I have not seen anything online for source codes or design proposals however, so I wanted to see where that was at and if it is that far along I wanted to make sure I follow the same patterns for consistency.
Thanks for reading this REALLY long post. If it is suggested it could be turned into a new blueprint discussion. Let me know!