Rethinking automated recurring contributions (Code attached)

2013-07-12 11:11
Written by

I have previously blogged ( and chatted about (,29234.0.html about the fun and joy related to supporting automated recurring transactions in a production environment, and started the process of restructuring that portion of the code.   I have made much more progress and have been using the code attached on production for about 2 weeks now.   I think this approach (which I have implemented for makes a good model for any payment processor that offers automated recurring contributions.  You can download the code (works with version 4.3.4) HERE

My primary goals were as follows:

1) Auditability.   In a production environement it is essential to have a history of all key communication with a third-party system.  This should be easily searchable by an administrator or other authorized person.  

2) Testability.  It must be possible to test the core functionality without involving the third-party payment processing system or a web browser. 

3) Repeatable, For example: If a message gets handled improperly (such as a bug in the API, some other issue that messes up the resulting contribution) it should be possible to delete the generated contribution record, and re-create it based on the data from the payment processor message log table. 

My secondary goals:

4) Standardize core behavior accross various payment processors that offer automated recurring payments.  Simpilfy creation of new payment processors. 

5) Eliminate what my clients consider odd accounting for automated recurring payments in light of 4.3.x.   In 4.3, any "pending/pay later" status contributions  show as a tranaction in the "Accounts Receivable" Financial Account. When this contribution status is updated to "completed" another transaction is created to represent the movement from Accounts Receivable to the Asset Financial Account. (In this case the Payment Proccessing Account).   With a one-off contribution,this is the proper and expected behavior.  However, with automated recurring contributions this creates oddness for the bookkeeper. For example: They set up an automated recurring contribution of $200 per month for 12 months. (From the bookkeeper's point of view, the person "owes" $2400. ) After the first 6 payments are completed, the bookkeeper will observe that the first installment of $200. was handled as a "receivable" (because of the result of it switching from pending to completed) but none of the other installments are treated that way.  So in the code I wrote ALL installments are treated uniformly: As a contribution that started out in the "completed" status. What I do is create a brand-new completed contribution for the first installment, then delete the original pending contribution.  ( The other option I thought about was treating the entire $2400 as a receivable, then reducing the Accounts Receivable by $200 each month. But this idea seemed much more complex to implement) 

Looking forward to getting feedback on the code and ideas here. 




could you publish your code in github or another source code repository? is this meant to be an extension that you can enable or is the aim to change the core?


I cannot see a way to make this into an extension as the payment processor is part of core. ( I am using 99% of the code that ships with core, the only core logic that is overriden is the processing of the IPN/Slient Post URL messages.)   

Should the payment processor be part of core? Should it be an extension like all other processors?

The 'odd accounting' mentioned in 5) above is a bug that was inadvertently created by the use of Pending status with slightly different semantics in the case of a first recurring payment versus a one-off payment. This is not something specific to

We had a fix for this bug prepared for the 4.3.5 release but the logic of the upgrade code was complex enough and the impact on production data significant enough that we decided we needed to test upgrading some production databases before releasing it. It should come out in 4.3.6.

Sarah, any help you could provide in this testing would be appreciated (see

This code is now available as a native CiviCRM extension (and lives on GitHub).  See