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

CRM-21187 Fix handling of currency when updating a contribution to be… #10982

Merged
merged 1 commit into from
Sep 19, 2017

Conversation

eileenmcnaughton
Copy link
Contributor

Overview

Fix handling of currency when updating a contribution to be completed. Currency value is not retained in the civicrm_financial_trxn table.

This is replicable via the api & potentially other flows. The currency id
of NULL is not accepted in financialTrxn BAO without it replacing with a
default, which is not appropriate on an update.

Before

The completetransaction pathway is used by multiple paths to update contributions when a payment comes in. For JIRA purposes I recreated via the api in a test that does the following

  1. create a pending contribution with currency = EURO
  2. call completetransaction to add an incoming payment
  3. the currency on the financial_trxn record is 'USD' rather than EUR

After

The completetransaction pathway is used by multiple paths to update contributions when a payment comes in. For JIRA purposes I recreated via the api in a test that does the following

  1. create a pending contribution with currency = EUR
  2. call completetransaction to add an incoming payment
  3. the currency on the financial_trxn record is EUR

Technical Details

Ensure no default is applied in the BAO when the id is provided. Pass correct currency in when first creating the trxn.

Comments
@pradpnayak @monishdeb I observed a related issue while looking at this - this subroutine should only entered if $params['refund_trxn_id'] or $params[''card_type_id'] or $params['pan_truncation'] is set. Probably it should be 2 separate ifs (ie. nesting inside $updated doesn't add much value )

        if (!$updated) {
          // Looks like we might have a data correction update.
          // This would be a case where a transaction id has been entered but it is incorrect &
          // the person goes back in & fixes it, as opposed to a new transaction.
          // Currently the UI doesn't support multiple refunds against a single transaction & we are only supporting
          // the data fix scenario.
          // CRM-17751.
          if (isset($params['refund_trxn_id'])) {
            $refundIDs = CRM_Core_BAO_FinancialTrxn::getRefundTransactionIDs($params['id']);
            if (!empty($refundIDs['financialTrxnId']) && $refundIDs['trxn_id'] != $params['refund_trxn_id']) {
              civicrm_api3('FinancialTrxn', 'create', array('id' => $refundIDs['financialTrxnId'], 'trxn_id' => $params['refund_trxn_id']));
            }
          }
          $cardType = CRM_Utils_Array::value('card_type_id', $params);
          $panTruncation = CRM_Utils_Array::value('pan_truncation', $params);
          CRM_Core_BAO_FinancialTrxn::updateCreditCardDetails($params['contribution']->id, $panTruncation, $cardType);
        }
      }

@yashodha
Copy link
Contributor

@eileenmcnaughton this works!

$mut->checkMailLog(array(
'email:::anthony_anderson@civicrm.org',
'is_monetary:::1',
'amount:::100.00',
Copy link
Contributor

Choose a reason for hiding this comment

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

Having a hard-coded value here renders the test brittle, would be preferable to have:
'amount:::' . $this->_params['amount'],
Same goes for the other values (email address might be a bit harder to get to). I realize this is not the style of the rest of the test, but worth mentioning IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah maybe - that part of the test is pretty tangental to what I was trying to test but since similar tests had it I kept it there. Once we drop php 5.3 support I think a good cleanup of the test classes would be in order (with traits)

@@ -3539,6 +3539,10 @@ public static function updateFinancialAccounts(&$params, $context = NULL) {
// & this can be removed
return;
}
if (empty($params['trxnParams']['currency'])) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this block also be added above line 3494? It seems there is a potential for early return there without having the currency code set. The above block has the same basic conditions: $context == 'changedStatus' and $currentContributionStatus == 'Completed'.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it's good NOT to set it there. The pass-by-reference is an antipattern here IMHO & we should not add extra params. The reason we add params lower down is specifically to pass the correct params to the FinancialTrxn::create function in the same section

@@ -3539,6 +3539,10 @@ public static function updateFinancialAccounts(&$params, $context = NULL) {
// & this can be removed
Copy link
Contributor

Choose a reason for hiding this comment

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

In general. the updateFinancialAccounts function is difficult to understand as:

  1. there are not enough 'business-level' comments in each of these conditions, ie. above line 3481:
    // When a pending or partially paid contribution is completed with another payment instrument
    // then there is nothing to do as the older contribution should keep the financial accounts it already has.

  2. and the conditions overlap by their similarity, ie.:

  • it is not immediately clear what is different between lines 3488 and 3510 and 3530,
  • or why the structure if the test if not more progressive, ie. outer test on $context only, then test on previousContributionStatus only, and finally test on currentContributionStatus. Concrete example: lines 3528 and 3530 could be deleted since we close an outer if ($context == 'changedStatus') test to re-open the same. Then the structure of tests inside would be clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree this is a difficult function to understand. There have been a number of improvements in this area over the course of the year - each one with associated unit tests, but there is still a way to go. I do think more people contributing refactorings here would be helpful.

SImply doing a pull request with comments to go into the code is also a good step

@eileenmcnaughton
Copy link
Contributor Author

@monishdeb @colemanw am keen to trade some review to get this & #10935 which relate to a processor I'm doing for CiviDesk merged. (there are a few other people that could review this but I wouldn't be able to merge it myself if they did under our interim rules)

@nganivet
Copy link
Contributor

@monishdeb @colemanw @eileenmcnaughton please tell me if I can help in that trade a do a couple reviews for you.

@@ -3539,6 +3539,10 @@ public static function updateFinancialAccounts(&$params, $context = NULL) {
// & this can be removed
return;
}
if (empty($params['trxnParams']['currency'])) {
// This is an update so original currency if none passed in.
$params['trxnParams']['currency'] = isset($params['currency']) ? $params['currency'] : $params['prevContribution']->currency;
Copy link
Member

@monishdeb monishdeb Sep 18, 2017

Choose a reason for hiding this comment

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

Or

$params['trxnParams']['currency'] = CRM_Utils_Array::value('currency', $params, $params['prevContribution']->currency);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@monishdeb I shied away from that because I didn't know whether $params['currency'] might be deliberately set to be empty & what the implications would be on altering it - you think I should be braver?

Copy link
Member

Choose a reason for hiding this comment

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

I don't feel any harm in it, as for update we should implicitly use previous currency value. Otherwise it might pick the default currency, set for the system, which will be inappropriate if it doesn't match $params['prevContribution']->currency. What ya say?

@monishdeb
Copy link
Member

Patch looks ok to me, except for the minor change I've asked.

… completed.

This is replicable via the api & potentially other flows. The currency id
of NULL is not accepted in financialTrxn BAO without it replacing with a
default, which is not appropriate on an update.
@eileenmcnaughton
Copy link
Contributor Author

eileenmcnaughton commented Sep 18, 2017

@monishdeb I've made the change & also added some todos to highlight the fact that passing $params by reference is an anti-pattern since it's not clear what the added parameters are used for outside the function (my belief is nothing). Hopefully we can work towards changing that in the interests of code predictability

@monishdeb
Copy link
Member

Works fine. Merging

@monishdeb monishdeb merged commit 787baa1 into civicrm:master Sep 19, 2017
@eileenmcnaughton eileenmcnaughton deleted the trxn_currency branch September 19, 2017 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants