Always create contribution before processing payment
Currently there are various different workflows within CiviCRM that handle the creation of contributions in different ways. Sometimes a contribution is created before calling the payment processor BUT sometimes a contribution is only created after the call to the payment processor - leaving no trace if the payment fails. It is agreed that the correct process is to always create a contribution before calling the payment processor but it will take some time before CiviCRM core actually does this in all cases.
To process a payment we call doPayment()
on the payment processor. Any processor that still implements doTransferCheckout()
or doDirectPayment()
should be updated to use doPayment()
.
doPayment
Payment processors should set payment_status_id
(which is really contribution_status_id
) in the returned array. The default is assumed to be Pending. In some cases the IPN will set the payment to "Completed" some time later.
This function adds some historical defaults ie. the assumption that if a 'doDirectPayment' processors comes back it completed the transaction & in fact doTransferCheckout would not traditionally come back.
Payment processors should throw exceptions and not return Error objects as they may have done with the old functions.
Contribution Records
Creating a contribution record is inconsistent! We should always create a contribution BEFORE calling doPayment. However currently:
-
Contribution Pages: Creates a contribution before calling doPayment.
-
Contribution Pages with Membership: Does NOT create a contribution. UNLESS auto-renew=TRUE in which case both a recurring contribution and a contribution is created before calling doPayment.
-
Event Registration: Creates a contribution before calling doPayment from CiviCRM 5.14 (see https://github.com/civicrm/civicrm-core/pull/13763, https://github.com/civicrm/civicrm-core/pull/13837 and https://github.com/civicrm/civicrm-core/pull/14435)
-
Contribution.transact API - is a mess! And does NOT create a contribution before doPayment, also does NOT use/save the parameters returned from doPayment - see https://github.com/civicrm/civicrm-core/pull/15340 for a proposed patch.
-
If we DO have a contribution ID, then the payment processor can (and should) update parameters on the contribution record as necessary.
-
$params['payment_status_id']
(alias for 'contribution_status_id') should be set to the ID (via pseudoconstant getkey) of Pending/Failed/Completed depending on the outcome of the payment. Warning: Anything other than Pending/Completed may not get handled correctly. -
If we DO NOT have a contribution ID, then the payment processor should return a $params array containing:
$params[
'payment_status_id' => {as above}
'trxn_id' => {trxn ref to link to record at payment processor}
'fee_amount' => {optional fee charged by processor}
'net_amount' => {optional / discouraged net amount (ie. amount minus fee))}
];