Skip to content

Commit

Permalink
Add try catch to main loops on core ipn classes
Browse files Browse the repository at this point in the history
  • Loading branch information
eileenmcnaughton committed Sep 6, 2020
1 parent 98507fe commit 78f3919
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 187 deletions.
101 changes: 52 additions & 49 deletions CRM/Core/Payment/AuthorizeNetIPN.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,61 +35,66 @@ public function __construct($inputData) {
* @return bool|void
*/
public function main($component = 'contribute') {
try {
//we only get invoice num as a key player from payment gateway response.
//for ARB we get x_subscription_id and x_subscription_paynum
$x_subscription_id = $this->retrieve('x_subscription_id', 'String');
$ids = $objects = $input = [];

//we only get invoice num as a key player from payment gateway response.
//for ARB we get x_subscription_id and x_subscription_paynum
$x_subscription_id = $this->retrieve('x_subscription_id', 'String');
$ids = $objects = $input = [];
if ($x_subscription_id) {
// Presence of the id means it is approved.
$input['component'] = $component;

if ($x_subscription_id) {
// Presence of the id means it is approved.
$input['component'] = $component;
// load post vars in $input
$this->getInput($input, $ids);

// load post vars in $input
$this->getInput($input, $ids);
// load post ids in $ids
$this->getIDs($ids, $input);

// load post ids in $ids
$this->getIDs($ids, $input);

// Attempt to get payment processor ID from URL
if (!empty($this->_inputParameters['processor_id'])) {
$paymentProcessorID = $this->_inputParameters['processor_id'];
}
else {
// This is an unreliable method as there could be more than one instance.
// Recommended approach is to use the civicrm/payment/ipn/xx url where xx is the payment
// processor id & the handleNotification function (which should call the completetransaction api & by-pass this
// entirely). The only thing the IPN class should really do is extract data from the request, validate it
// & call completetransaction or call fail? (which may not exist yet).
Civi::log()->warning('Unreliable method used to get payment_processor_id for AuthNet IPN - this will cause problems if you have more than one instance');
$paymentProcessorTypeID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType',
'AuthNet', 'id', 'name'
);
$paymentProcessorID = (int) civicrm_api3('PaymentProcessor', 'getvalue', [
'is_test' => 0,
'options' => ['limit' => 1],
'payment_processor_type_id' => $paymentProcessorTypeID,
'return' => 'id',
]);
}
// Attempt to get payment processor ID from URL
if (!empty($this->_inputParameters['processor_id'])) {
$paymentProcessorID = $this->_inputParameters['processor_id'];
}
else {
// This is an unreliable method as there could be more than one instance.
// Recommended approach is to use the civicrm/payment/ipn/xx url where xx is the payment
// processor id & the handleNotification function (which should call the completetransaction api & by-pass this
// entirely). The only thing the IPN class should really do is extract data from the request, validate it
// & call completetransaction or call fail? (which may not exist yet).
Civi::log()->warning('Unreliable method used to get payment_processor_id for AuthNet IPN - this will cause problems if you have more than one instance');
$paymentProcessorTypeID = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_PaymentProcessorType',
'AuthNet', 'id', 'name'
);
$paymentProcessorID = (int) civicrm_api3('PaymentProcessor', 'getvalue', [
'is_test' => 0,
'options' => ['limit' => 1],
'payment_processor_type_id' => $paymentProcessorTypeID,
'return' => 'id',
]);
}

if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) {
return FALSE;
}
if (!empty($ids['paymentProcessor']) && $objects['contributionRecur']->payment_processor_id != $ids['paymentProcessor']) {
Civi::log()->warning('Payment Processor does not match the recurring processor id.', ['civi.tag' => 'deprecated']);
}
if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) {
return FALSE;
}
if (!empty($ids['paymentProcessor']) && $objects['contributionRecur']->payment_processor_id != $ids['paymentProcessor']) {
Civi::log()->warning('Payment Processor does not match the recurring processor id.', ['civi.tag' => 'deprecated']);
}

if ($component == 'contribute' && $ids['contributionRecur']) {
// check if first contribution is completed, else complete first contribution
$first = TRUE;
if ($objects['contribution']->contribution_status_id == 1) {
$first = FALSE;
if ($component == 'contribute' && $ids['contributionRecur']) {
// check if first contribution is completed, else complete first contribution
$first = TRUE;
if ($objects['contribution']->contribution_status_id == 1) {
$first = FALSE;
}
return $this->recur($input, $ids, $objects, $first);
}
return $this->recur($input, $ids, $objects, $first);
}
return TRUE;
}
catch (CRM_Core_Exception $e) {
Civi::log()->debug($e->getMessage());
echo 'Invalid or missing data';
}
return TRUE;
}

/**
Expand All @@ -107,9 +112,7 @@ public function recur($input, $ids, $objects, $first) {

// do a subscription check
if ($recur->processor_id != $input['subscription_id']) {
CRM_Core_Error::debug_log_message('Unrecognized subscription.');
echo 'Failure: Unrecognized subscription<p>';
return FALSE;
throw new CRM_Core_Exception('Unrecognized subscription.');
}

$contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
Expand Down
136 changes: 70 additions & 66 deletions CRM/Core/Payment/PayPalIPN.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ public function __construct($inputData) {
public function retrieve($name, $type, $abort = TRUE) {
$value = CRM_Utils_Type::validate(CRM_Utils_Array::value($name, $this->_inputParameters), $type, FALSE);
if ($abort && $value === NULL) {
Civi::log()->debug("PayPalIPN: Could not find an entry for $name");
echo "Failure: Missing Parameter<p>" . CRM_Utils_Type::escape($name, 'String');
throw new CRM_Core_Exception("PayPalIPN: Could not find an entry for $name");
}
return $value;
Expand Down Expand Up @@ -286,84 +284,90 @@ public function single($input, $ids, $objects, $recur = FALSE, $first = FALSE) {
* @throws \CiviCRM_API3_Exception
*/
public function main() {
$objects = $ids = $input = [];
$component = $this->retrieve('module', 'String');
$input['component'] = $component;
try {
$objects = $ids = $input = [];
$component = $this->retrieve('module', 'String');
$input['component'] = $component;

$ids['contact'] = $this->retrieve('contactID', 'Integer', TRUE);
$contributionID = $ids['contribution'] = $this->retrieve('contributionID', 'Integer', TRUE);
$membershipID = $this->retrieve('membershipID', 'Integer', FALSE);
$contributionRecurID = $this->retrieve('contributionRecurID', 'Integer', FALSE);
$ids['contact'] = $this->retrieve('contactID', 'Integer', TRUE);
$contributionID = $ids['contribution'] = $this->retrieve('contributionID', 'Integer', TRUE);
$membershipID = $this->retrieve('membershipID', 'Integer', FALSE);
$contributionRecurID = $this->retrieve('contributionRecurID', 'Integer', FALSE);

$this->getInput($input);
$this->getInput($input);

if ($component == 'event') {
$ids['event'] = $this->retrieve('eventID', 'Integer', TRUE);
$ids['participant'] = $this->retrieve('participantID', 'Integer', TRUE);
}
else {
// get the optional ids
$ids['membership'] = $membershipID;
$ids['contributionRecur'] = $contributionRecurID;
$ids['contributionPage'] = $this->retrieve('contributionPageID', 'Integer', FALSE);
$ids['related_contact'] = $this->retrieve('relatedContactID', 'Integer', FALSE);
$ids['onbehalf_dupe_alert'] = $this->retrieve('onBehalfDupeAlert', 'Integer', FALSE);
}
if ($component == 'event') {
$ids['event'] = $this->retrieve('eventID', 'Integer', TRUE);
$ids['participant'] = $this->retrieve('participantID', 'Integer', TRUE);
}
else {
// get the optional ids
$ids['membership'] = $membershipID;
$ids['contributionRecur'] = $contributionRecurID;
$ids['contributionPage'] = $this->retrieve('contributionPageID', 'Integer', FALSE);
$ids['related_contact'] = $this->retrieve('relatedContactID', 'Integer', FALSE);
$ids['onbehalf_dupe_alert'] = $this->retrieve('onBehalfDupeAlert', 'Integer', FALSE);
}

$paymentProcessorID = $this->getPayPalPaymentProcessorID($input, $ids);
$paymentProcessorID = $this->getPayPalPaymentProcessorID($input, $ids);

Civi::log()->debug('PayPalIPN: Received (ContactID: ' . $ids['contact'] . '; trxn_id: ' . $input['trxn_id'] . ').');
Civi::log()->debug('PayPalIPN: Received (ContactID: ' . $ids['contact'] . '; trxn_id: ' . $input['trxn_id'] . ').');

// Debugging related to possible missing membership linkage
if ($contributionRecurID && $this->retrieve('membershipID', 'Integer', FALSE)) {
$templateContribution = CRM_Contribute_BAO_ContributionRecur::getTemplateContribution($contributionRecurID);
$membershipPayment = civicrm_api3('MembershipPayment', 'get', [
'contribution_id' => $templateContribution['id'],
'membership_id' => $membershipID,
]);
$lineItems = civicrm_api3('LineItem', 'get', [
'contribution_id' => $templateContribution['id'],
'entity_id' => $membershipID,
'entity_table' => 'civicrm_membership',
]);
Civi::log()->debug('PayPalIPN: Received payment for membership ' . (int) $membershipID
. '. Original contribution was ' . (int) $contributionID . '. The template for this contribution is '
. $templateContribution['id'] . ' it is linked to ' . $membershipPayment['count']
. 'payments for this membership. It has ' . $lineItems['count'] . ' line items linked to this membership.'
. ' it is expected the original contribution will be linked by both entities to the membership.'
);
if (empty($membershipPayment['count']) && empty($lineItems['count'])) {
Civi::log()->debug('PayPalIPN: Will attempt to compensate');
$input['membership_id'] = $this->retrieve('membershipID', 'Integer', FALSE);
}
if ($contributionRecurID) {
$recurLinks = civicrm_api3('ContributionRecur', 'get', [
// Debugging related to possible missing membership linkage
if ($contributionRecurID && $this->retrieve('membershipID', 'Integer', FALSE)) {
$templateContribution = CRM_Contribute_BAO_ContributionRecur::getTemplateContribution($contributionRecurID);
$membershipPayment = civicrm_api3('MembershipPayment', 'get', [
'contribution_id' => $templateContribution['id'],
'membership_id' => $membershipID,
'contribution_recur_id' => $contributionRecurID,
]);
Civi::log()->debug('PayPalIPN: Membership should be linked to contribution recur record ' . $contributionRecurID
. ' ' . $recurLinks['count'] . 'links found'
$lineItems = civicrm_api3('LineItem', 'get', [
'contribution_id' => $templateContribution['id'],
'entity_id' => $membershipID,
'entity_table' => 'civicrm_membership',
]);
Civi::log()->debug('PayPalIPN: Received payment for membership ' . (int) $membershipID
. '. Original contribution was ' . (int) $contributionID . '. The template for this contribution is '
. $templateContribution['id'] . ' it is linked to ' . $membershipPayment['count']
. 'payments for this membership. It has ' . $lineItems['count'] . ' line items linked to this membership.'
. ' it is expected the original contribution will be linked by both entities to the membership.'
);
if (empty($membershipPayment['count']) && empty($lineItems['count'])) {
Civi::log()->debug('PayPalIPN: Will attempt to compensate');
$input['membership_id'] = $this->retrieve('membershipID', 'Integer', FALSE);
}
if ($contributionRecurID) {
$recurLinks = civicrm_api3('ContributionRecur', 'get', [
'membership_id' => $membershipID,
'contribution_recur_id' => $contributionRecurID,
]);
Civi::log()->debug('PayPalIPN: Membership should be linked to contribution recur record ' . $contributionRecurID
. ' ' . $recurLinks['count'] . 'links found'
);
}
}
if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) {
return;
}
}
if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) {
return;
}

self::$_paymentProcessor = &$objects['paymentProcessor'];
if ($component == 'contribute') {
if ($ids['contributionRecur']) {
// check if first contribution is completed, else complete first contribution
$first = TRUE;
$completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
if ($objects['contribution']->contribution_status_id == $completedStatusId) {
$first = FALSE;
self::$_paymentProcessor = &$objects['paymentProcessor'];
if ($component == 'contribute') {
if ($ids['contributionRecur']) {
// check if first contribution is completed, else complete first contribution
$first = TRUE;
$completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
if ($objects['contribution']->contribution_status_id == $completedStatusId) {
$first = FALSE;
}
$this->recur($input, $ids, $objects, $first);
return;
}
$this->recur($input, $ids, $objects, $first);
return;
}
$this->single($input, $ids, $objects);
}
catch (CRM_Core_Exception $e) {
Civi::log()->debug($e->getMessage());
echo 'Invalid or missing data';
}
$this->single($input, $ids, $objects);
}

/**
Expand Down
Loading

0 comments on commit 78f3919

Please sign in to comment.