Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further work on payment.create consolidation - always handle financials from payment.create #14673

Merged
merged 1 commit into from
Aug 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions CRM/Contribute/BAO/Contribution.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,16 @@ public static function add(&$params, $ids = []) {

//add Account details
$params['contribution'] = $contribution;
self::recordFinancialAccounts($params);
if (empty($params['is_post_payment_create'])) {
// If this is being called from the Payment.create api/ BAO then that Entity
// takes responsibility for the financial transactions. In fact calling Payment.create
// to add payments & having it call completetransaction and / or contribution.create
// to update related entities is the preferred flow.
// Note that leveraging this parameter for any other code flow is not supported and
// is likely to break in future and / or cause serious problems in your data.
// https://github.com/civicrm/civicrm-core/pull/14673
self::recordFinancialAccounts($params);
}

if (self::isUpdateToRecurringContribution($params)) {
CRM_Contribute_BAO_ContributionRecur::updateOnNewPayment(
Expand Down Expand Up @@ -946,19 +955,10 @@ public static function recordPaymentActivity($contributionId, $participantId, $t
* @return int
*/
public static function getToFinancialAccount($contribution, $params) {
$contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
$pendingStatus = [
array_search('Pending', $contributionStatuses),
array_search('In Progress', $contributionStatuses),
];
if (in_array(CRM_Utils_Array::value('contribution_status_id', $contribution), $pendingStatus)) {
return CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contribution['financial_type_id'], 'Accounts Receivable Account is');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This caused a test to fail & on review I think it would be always incorrect when adding a payment - the only way to reach this line of code

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a CiviContribute Component setting that determines if every contribution starts with an Accounts Receivable entry. If a payment is being created at time the contribution is being created then it will be subsequent to this Pay Later initial transaction. I think this line is in error in not checking the setting before deciding what to record first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JoeMurray that's a bit cryptic - what do you think the removed lines did? From my testing payments against 'Pending' or the unused 'In Progress' wound up having a from and to account of Accounts Receivable with this line in there

Copy link
Contributor

@pradpnayak pradpnayak Aug 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eileenmcnaughton this line AFAIK decides to_financial_account_id when a contribution is created or updated.

to_financial_account_id should be

  1. AR if contribution status is pending (dont recall about In Progress)
  2. Else it should grab from payment processor FA if payment is dont through payment processor
  3. Else it should grab from payment instrument if payment is not from payment processor

https://wiki.civicrm.org/confluence/pages/viewpage.action?pageId=390955013#CiviAccountsDataFlow-Onlinecompletedcontribution

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pradpnayak it's only called from functions that create payments so scenario 1 should be void - which is what is removed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eileenmcnaughton than it should be If payment-processor else payment-instrument

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pradpnayak it does an early return if (!empty($params['payment_processor'])) { so it doesn't need the 'else'

}
elseif (!empty($params['payment_processor'])) {
if (!empty($params['payment_processor'])) {
return CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contribution['payment_processor'], NULL, 'civicrm_payment_processor');
}
elseif (!empty($params['payment_instrument_id'])) {
if (!empty($params['payment_instrument_id'])) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not confident about the change in getToFinancialAccount(). As its against the DataFlow. But i will still give it a run today.

return CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($contribution['payment_instrument_id']);
}
else {
Expand Down Expand Up @@ -4490,10 +4490,16 @@ public static function isSingleLineItem($id) {
* @param CRM_Core_Transaction $transaction
* @param int $recur
* @param CRM_Contribute_BAO_Contribution $contribution
* @param bool $isPostPaymentCreate
* Is this being called from the payment.create api. If so the api has taken care of financial entities.
* Note that our goal is that this would only ever be called from payment.create and never handle financials (only
* transitioning related elements).
*
* @return array
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
*/
public static function completeOrder(&$input, &$ids, $objects, $transaction, $recur, $contribution) {
public static function completeOrder(&$input, &$ids, $objects, $transaction, $recur, $contribution, $isPostPaymentCreate = FALSE) {
$primaryContributionID = isset($contribution->id) ? $contribution->id : $objects['first_contribution']->id;
// The previous details are used when calculating line items so keep it before any code that 'does something'
if (!empty($contribution->id)) {
Expand Down Expand Up @@ -4613,6 +4619,7 @@ public static function completeOrder(&$input, &$ids, $objects, $transaction, $re
}

$contributionParams['id'] = $contribution->id;
$contributionParams['is_post_payment_create'] = $isPostPaymentCreate;

// CRM-19309 - if you update the contribution here with financial_type_id it can/will mess with $lineItem
// unsetting it here does NOT cause any other contribution test to fail!
Expand Down
12 changes: 5 additions & 7 deletions CRM/Financial/BAO/Payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,7 @@ public static function create($params) {

$isPaymentCompletesContribution = self::isPaymentCompletesContribution($params['contribution_id'], $params['total_amount']);

// For legacy reasons Pending payments are completed through completetransaction.
// @todo completetransaction should transition components but financial transactions
// should be handled through Payment.create.
$isSkipRecordingPaymentHereForLegacyHandlingReasons = ($contributionStatus == 'Pending' && $isPaymentCompletesContribution);

if (!$isSkipRecordingPaymentHereForLegacyHandlingReasons && $params['total_amount'] > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note that changing the contribution status requires making financial transactions to record that. I assume that this change is not making it so that no longer happens.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no the change is making it so that the payment.create action records financial transactions regardless of whether the payment completes the contribution or not - it was leaving that to the later Contribution.create only when the payment completed the transaction

if ($params['total_amount'] > 0) {
$balanceTrxnParams['to_financial_account_id'] = CRM_Contribute_BAO_Contribution::getToFinancialAccount($contribution, $params);
$balanceTrxnParams['from_financial_account_id'] = CRM_Financial_BAO_FinancialAccount::getFinancialAccountForFinancialTypeByRelationship($contribution['financial_type_id'], 'Accounts Receivable Account is');
$balanceTrxnParams['total_amount'] = $params['total_amount'];
Expand Down Expand Up @@ -148,7 +143,10 @@ public static function create($params) {
);
}
else {
civicrm_api3('Contribution', 'completetransaction', ['id' => $contribution['id']]);
civicrm_api3('Contribution', 'completetransaction', [
'id' => $contribution['id'],
'is_post_payment_create' => TRUE,
]);
// Get the trxn
$trxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
$ftParams = ['id' => $trxnId['financialTrxnId']];
Expand Down
11 changes: 10 additions & 1 deletion api/v3/Contribution.php
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,15 @@ function _civicrm_api3_contribution_completetransaction_spec(&$params) {
'optionGroupName' => 'accept_creditcard',
],
];
// At some point we will deprecate this api in favour of calling payment create which will in turn call this
// api if appropriate to transition related entities and send receipts - ie. financial responsibility should
// not exist in completetransaction. For now we just need to allow payment.create to force a bypass on the
// things it does itself.
$params['is_post_payment_create'] = [
'title' => 'Is this being called from payment create?',
'type' => CRM_Utils_Type::T_BOOLEAN,
'description' => 'The \'correct\' flow is to call payment.create for the financial side & for that to call completecontribution for the entity & receipt management. However, we need to still support completetransaction directly for legacy reasons',
];
}

/**
Expand Down Expand Up @@ -727,7 +736,7 @@ function _ipn_process_transaction(&$params, $contribution, $input, $ids, $firstC
$input['pan_truncation'] = CRM_Utils_Array::value('pan_truncation', $params);
$transaction = new CRM_Core_Transaction();
return CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects, $transaction,
!empty($contribution->contribution_recur_id), $contribution);
!empty($contribution->contribution_recur_id), $contribution, CRM_Utils_Array::value('is_post_payment_create', $params));
}

/**
Expand Down