To Have or Not To Have Financial Transactions

Published
2016-12-14 04:45
Written by

This little story about financial transactions has a couple of objectives:
1. share what we want to do for the benefit of each and everyone
2. find out if there are more organisations out there that would be interested
3. even better, organisations out there that want to co-fund and influence!

If you are interested and want to co-contribute, drop either Björn (endres@systopia.de) or me (erik.hommel@civicoop.org) a mail!

At the moment CiviCRM allows for the linking of a financial account to the financial type as a basis for data exporting to whatever software you are using for accounting. You can also attach an asset type financial account to a payment instrument. When creating, updating, cancelling or refunding a contribution the financial 'traffic' between the configured financial accounts is nicely recorded in the financial transactions table. We are not sure yet if changing the payment instrument also create nice financial transactions. All good stuff when exporting your financial transactions to accounting!

However, at Amnesty International Vlaanderen we do not have an account per financial type. We have income accounts per financial type/payment instrument/campaign. And we have cost accounts that go even a level deeper: they also look at the timeframe (so a different cost account (cocoa) when a campaign acquisition is in the actual acquisition year of the campaign or later. So the core CiviCRM functionality is not enough, although it is a good start. We need to be able to generate financial transactions at a more detailed level to be able to use the accounting batches in CiviCRM.

Youth for Christ UK has a similar problem. Here the correct financial account is determined mostly by a contribution's campaign – with a few exceptions. And the original account is not only determined by the payment instrument, but also the bank account involved.

So we want to develop something that will allow us to:

  • disable the creation of financial transactions completely. In a lot of cases there will be CiviCRM customers that do not use the financial transactions at all, and at the moment CiviCRM will then do a lot of creation and use system resources for absolutely nothing. So I should be able to switch it off. I should also be able to say I only want it to process for certain financial types, campaigns, payment instruments etc.
  • create some kind of hook or something that allows me to replace the 'standard' calculation of financial transactions based on financial accounts linked to financial types to a customized calculation and configuration.
  • configure the accounts in a way required for Amnesty International Vlaanderen. So I should be able to link a P/L account, a cost account for the acquisition year and a cost account for the following years to a campaign.
  • create financial transactions based on this specific account configuration. As CiviCRM uses contributions as the key financial item (for donations, membership payments, event payments and if I would create an extension that allows the selling of promotional items I would probably add a contribution of a specific financial type too) I would create those financial transactions whenever a contribution is added, updated or deleted.

This mainly details the Amnesty requirement, but Youth for Christ UK has very similar needs and will contribute to the development budget! As can be expected, that is why that will be a specific extension for each case :-). We want to have as little impact on core as possible, and enable everybody to create their own flavour!
 

Techy stuff

After some conceptual discussion (and Björn still working on the technical details and possibly changing everything again) we think we need to do only one core change at this point. This change will add a configuration setting to the CiviContribute Component settings generate financial transactions (name = generateFinancialTransactions) with the options:

 

  • none (which should lead to no financial transactions being generated whatsoever)
  • default (the default behaviour as we all know and love)
  • customized (your specific generation, which should implement the post hook on Contribution)

In the specific extension we will implement the post hook, check if the entity is Contribution, check if the setting is 'customized' and do our stuff. Obviously, if the above setting is set to 'none', the extension  shouldn't create any transactions either.

Oh yes, we do have a basic GitHub fork where we will be playing around: https://github.com/systopia/civicrm-core/tree/dev_txhooks_4.6.24

Comments

Should there be separate "customized" and default behaviors? If there's a hook, as a developer, I'd expect it should always be invoked when generating transactions. Also, I imagine that many organizations would be mostly default, with exceptions for certain distinct cases.  They'd want default behavior for the most part, with a hook available for the one or two spots that need customization.

I think it would be best as an on/off feature: transactions or no transactions.

Alternatively, if you like the idea of supporting non-transaction sites but don't want the overhead of making sure that situation works, you could merely set up the hook and have a "no transactions" extension that implements it and blanks out the transaction.

I believe it's possible to implement this using hooks. There would need to be a core change but we can change the way the _pre hook works in a backwards compatible way across all BAO entities and then it will be possible to prevent something from being saved from within an extension. I think the amount of work in getting core fixed (with tests) to support all entities with the new hook config would then be below 20 hours. 

 

Basically the change would be to make the calls to the _pre hook look like this

 

try {

CRM_Utils_Hook::pre();

}

catch (CRM_Hook_No_Save_Exception $e){

  return;

}

 

It would involve writing an exception class & doing a bunch of unit tests & I would suggest rolling it out across all or most entities.

 

With that in place a small extension could implement not-saving financial transactions.

 

I would have thought a custom scheme could be done by hook already? Although I think I saw some entities are actually missing the pre hook

It will be interesting to see how additional try/catch blocks of this nature affected performance of CiviCRM - my gut feel is that there might be some overhead to doing that, though I'm not sure where in CiviCRM we'd see that as a tangible effect.

What area might lead to the most entity updates in a single interaction?

NB - under the implementation I mentioned the 'setting' for create or not create would be enabling the no-transaction extension which would implement the pre hook & throw an NO_Save exception for certain types of entities.

 

The setting for a customised version would live within the extension itself - there is no need for core to know about that