API4 Payment API
Overview
At the CiviCRM Sprint in Hamburg (June 2024) we discussed Order and Payment API4 implementation. Here are the notes for the Payment API4.
Payment API is a "simple" API that records a payment. A payment is typically for the same amount as the contribution total amount, but it can also be greater in the case of an overpayment or duplicate full payment or less than the contribution total amount. The payment is allocated or applied to each of the line items associated with the contribution. By default it is distributed proportionally among them based on the line item total amount (which includes the amount (qty*price) of the line item plus all tax(es) on that amount). The schema supports a payment being applied in a non-proportional way to line items, and the Payment API should support this. For example, if a contribution is for a parent's ticket for an event participant for a circus performance in New Zealand and a membership in a circus training organization in New Zealand, it should be possible to allocate a payment to just one of those line items.
At a technical level, a payment will typically result in one FinancialTrxn, one or more LineItem, one EntityFinancialTrxn for the contribution and one for each FinancialItem, one FinancialItem for each line item and another one for each tax on each line item. See https://wiki.civicrm.org/confluence/display/CRM/CiviAccounts+Data+Flow#CiviAccountsDataFlow-Newcontribution for more details.
Payment API does NOT handle anything related to interactions with any specific payment processor. Each payment processor integration is expected to call it after it has got a payment complete result from the payment processor. Additionally, it needs to be called to record a payment taken "manually".
It is not expected to be much different to the current implementation that we have for API3. But we don't want lose functionality.
API4 Payment will have native support for custom fields (this is not currently supported by API3).
Related: Order API: core#4367
Notifications
Notifications: By parameter default to not send
Methods
Payment.create
Additional Parameters:
- setNotificationForPayment: Default FALSE This will optionally send out a payment notification to the Contribution Contact ID.
- setNotificationForCompleteOrder: Default: TRUE This will optionally send out a payment notification to the Contribution Contact ID when the Contribution is Completed.
- disableActionsOnCompleteOrder: Default: FALSE This will disable actions that are triggered when the Contribution is Completed (such as "Membership Renewal", "Event Registration Confirmation", "Pledge fulfilled".
An initial draft can be found here: https://github.com/civicrm/civicrm-core/pull/28542 (though some changes are currently required).
Questions:
- Should the above parameters be called "CompleteOrder" or "CompleteContribution"?
- What is the difference between "Notification for Payment" and "Notification for "Complete Order"?
- We would like the ability to record a "negative payment" (which is not the same as a refund) by entering a negative amount. That currently works on API3 (although the payment status gets marked as "refunded".
**Implemented via **https://github.com/civicrm/civicrm-core/pull/30333
Payment.cancel
Payment.cancel: Exists. Voids the payment. Reverses financial trxn
Effectively the functionality will be the same as already exists in API3.
Payment.refund
Currently API3 uses Payment.create with a negative amount but we would like an API4 Refund API to separate functional logic and provide a separate "wrapper" for recording a Refund. This will allow for internal code to be improved/modified without impacting users of the Refund API.
A refund will always use an existing Payment ID (FinancialTrxn ID) as the "source" data to create a refund. The refund can be more than the original payment amount.
Parameters:
- Payment: Reference to the original FinancialTrxn ID.
- Amount: This can be more than the original amount if required.
Payment.failed(?)
This is not currently possible and would require schema changes. See #122
It would be useful to have.
Payment.get
This should be able to retrieve information about a payment (FinancialTrxn) given various "unique" parameters such as date, trxn_id, contribution_id etc.
Draft implementation here: https://github.com/civicrm/civicrm-core/pull/30353