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

dev/core#3784 fix contribution/membership/participant import matching on external id or contact id #24166

Merged

Conversation

highfalutin
Copy link
Contributor

Overview

Fixes 5.51 regression https://lab.civicrm.org/dev/core/-/issues/3784 and adds a test for it.

Before

When importing contributions, supposedly matching on external identifier or contact id, imported contributions are instead attached to contact ids 1-9.

After

Imported contributions are attached to the contacts specified by external id/contact id in the input CSV.

Comments

Thank you @eileenmcnaughton for the fabulous work on refactoring nightmarish import code. The code was relatively easy to read/trace through, so finding this bug wasn't too hard!

@civibot
Copy link

civibot bot commented Aug 6, 2022

(Standard links)

@civibot civibot bot added the master label Aug 6, 2022
@seamuslee001
Copy link
Contributor

this feels like the same sort of issue that @agileware-justin and folks hit but them on an participant import here #24153

@highfalutin
Copy link
Contributor Author

highfalutin commented Aug 6, 2022

this feels like the same sort of issue that @agileware-justin and folks hit but them on an participant import here #24153

Yep. I chose to make my fix a bit downstream from where @agileware-justin did. As far as the contribution import issue is concerned, the two fixes are redundant, but shouldn't be incompatible.

@highfalutin
Copy link
Contributor Author

Correction: after looking more closely, I don't think the two fixes are exactly redundant. The version here actually does a better job of fixing this issue, and a similar patch would do a better job of fixing the Participant issue as well. Also I think the test is worth keeping.

@@ -417,7 +417,8 @@ public function import($values): void {
$error = $this->checkContactDuplicate($paramValues);

if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) {
$matchedIDs = explode(',', $error['error_message']['params'][0]);
$matchedIDs = $error['error_message']['params'];
$matchedIDs = is_array($matchedIDs) ? $matchedIDs : [$matchedIDs];
Copy link
Contributor

Choose a reason for hiding this comment

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

Nothing wrong with this, but could also be expressed more succinctly as:

$matchedIDs = (array) $error['error_message']['params'];

Copy link
Member

Choose a reason for hiding this comment

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

@MegaphoneJon if you use the suggestion button then your suggestion can be committed (but you have to select both lines before you make your comment).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @MegaphoneJon. I incorporated this suggestion.

@agileware-fj
Copy link
Contributor

The version here actually does a better job of fixing this issue, and a similar patch would do a better job of fixing the Participant issue as well.

How? The other patch fixes both of these issues and any other location that's still relying on the deprecated function that this issue comes from.

Never mind that.

If a better job is to be done than reverting the change in interface of a function that is in a class for "deprecated" utilities that should be being phased out, then it should be achieved by removing the dependency on said function.

The test is good because it lays out knowing when this removal has been achieved successfully, but ultimately patching the consumer of a deprecated interface to deal with a change that should never have happened in that interface is fundamentally wrong.

@highfalutin
Copy link
Contributor Author

highfalutin commented Aug 8, 2022

No offense intended, @agileware-fj. I should have explained. We have the following code in both the Contribution parser and the Participant parser:

$error = $this->checkContactDuplicate($formatValues);
// ...
$matchedIDs = explode(',', $error['error_message']['params'][0]);

Looking upstream, it appears that $error['error_message']['params'] might be a multiple-item array of matches, if there's no match by contact id/external id and the algorithm resorts to matching by some other criteria. If so, we shouldn't just take the first array item and ignore the rest.

Also, $error['error_message']['params'][0] will never be a comma-separated string; the explode is just burning energy. So it's "better" to skip it.

This PR changes the above code to

$error = $this->checkContactDuplicate($formatValues);
// ...
$matchedIDs = (array) $error['error_message']['params'];

The test function tests whether match-to-contact on external identifier does what it's supposed to do. That should be a valuable test even after all the deprecated code is done away with.

I do hear your and @agileware-justin 's frustration about this ancient spaghetti code and the changes to it. My understanding is that the recent major refactoring is a step in the direction of eliminating the mess. Nobody would have wished for regressions, but the eventual payoff seems worth having to fix a couple bugs in the interim code.

Also of course I wish neither of us had had to discover the bug as a result of our clients' live imports failing. I recall Eileen putting out a loud call for RC testers on this one, for exactly that reason. If only I had heeded that request!

@highfalutin highfalutin force-pushed the contribution-import-with-external-id branch from 33f82a5 to a2f1966 Compare August 8, 2022 03:00
@highfalutin
Copy link
Contributor Author

Applied the fix to the other places it was needed (Membership import parser, elsewhere in Contribution import parser, and Participant import parser), used more succinct syntax suggested by @MegaphoneJon, and rebased on master.

@highfalutin highfalutin changed the title dev/core#3784 fix contribution import matching on external id or contact id dev/core#3784 fix contribution/membership/participant import matching on external id or contact id Aug 8, 2022
@agileware-fj
Copy link
Contributor

@highfalutin no offence was taken, just not convinced your assertion is correct and want it to be clear that just because the solutions overlap doesn't mean that they don't both apply.

The third thing that might need to be accounted for is if third party code is extending the CRM_Import_Parser class and calls checkContactDuplicate (which as far as I know is not actually deprecated, just calls into deprecated code). If it's followed the pattern laid out by the core classes then it will be expecting input that results in the same issue we see here. Hence the deprecated interface really still ought to (a) remain consistent (frozen as originally deprecated) and/or (b) start throwing warnings about incorrect usage if you try to index it – which sounds overly complicated for a deprecated function when you're already accounting for an implementation that sends an array anyway.

@totten
Copy link
Member

totten commented Aug 8, 2022

OK, I think there's a good case for merging both, so I've posted a PR with both (#24182 for 5.52). If that passes, then I think we can merge all three PRs (master's #24153 + #24166 and 5.52's #24182).

@totten totten added the merge ready PR will be merged after a few days if there are no objections label Aug 8, 2022
@eileenmcnaughton
Copy link
Contributor

I'm good with merging @totten's PR with both. With this PR there is a unit test so I can use that to remove the function call entirely from the Contribution import flow in master - and hopefully by the time the next rc is cut the DeprecatedUtils file will be entirely gone from core. However, for getting a release out with the bug fix I think Tim's approach is fine

Note that thrid party code is not supported for calling core functions 'just because they exist' - the expectation is that they will use the api & hooks

@eileenmcnaughton
Copy link
Contributor

I added a PR to mark a few more functions as deprecated since it seems that would have been clearer - #24185 - but our top level message is that the things that are documented in the developer docs as supported interfaces are the supported interfaces.....

@seamuslee001 seamuslee001 merged commit d243fc2 into civicrm:master Aug 9, 2022
@highfalutin highfalutin deleted the contribution-import-with-external-id branch August 9, 2022 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
master merge ready PR will be merged after a few days if there are no objections
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants