Skip to content

Commit

Permalink
[REF] Provide standardised methods to get recurring contribution id &…
Browse files Browse the repository at this point in the history
… object

This adds methods to get the recurring contribution id & object that work from the paypal
express and from the paypal pro flows. In the paypal express flow it is
retrieved from a known value (and this flow is only ever hit for recurrings
as evidenced by the existing getsingle) and then set on the class. For paypal pro
it is optional and will be in the cheap-to-access POST array if relevant
  • Loading branch information
eileenmcnaughton committed May 14, 2021
1 parent 72445b0 commit 55f6a00
Showing 1 changed file with 63 additions and 25 deletions.
88 changes: 63 additions & 25 deletions CRM/Core/Payment/PayPalProIPN.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,41 @@ class CRM_Core_Payment_PayPalProIPN extends CRM_Core_Payment_BaseIPN {
*/
protected $_isPaymentExpress = FALSE;

/**
* Recurring contribution ID.
*
* @var int|null
*/
protected $contributionRecurID;

/**
* Recurring contribution object.
*
* @var \CRM_Contribute_BAO_ContributionRecur
*/
protected $contributionRecurObject;

/**
* Get the recurring contribution ID, if any.
*
* @return int|null
*
* @throws \CRM_Core_Exception
*/
public function getContributionRecurID(): ?int {
if (!$this->contributionRecurID && $this->getValue('r', FALSE)) {
$this->contributionRecurID = (int) $this->getValue('r', FALSE);
}
return $this->contributionRecurID;
}

/**
* @param int|null $contributionRecurID
*/
public function setContributionRecurID(?int $contributionRecurID): void {
$this->contributionRecurID = $contributionRecurID;
}

/**
* Component.
*
Expand Down Expand Up @@ -219,7 +254,7 @@ public function recur($input, $ids, $recur, $contribution, $first) {
$recur->start_date = $now;
}
else {
if ($input['paymentStatus'] != 'Completed') {
if ($input['paymentStatus'] !== 'Completed') {
throw new CRM_Core_Exception("Ignore all IPN payments that are not completed");
}

Expand Down Expand Up @@ -389,12 +424,12 @@ public function getPayPalPaymentProcessorID() {
public function main() {
CRM_Core_Error::debug_var('GET', $_GET, TRUE, TRUE);
CRM_Core_Error::debug_var('POST', $_POST, TRUE, TRUE);
$ids = $input = [];
try {
if ($this->_isPaymentExpress) {
$this->handlePaymentExpress();
return;
}
$ids = $input = [];
$this->_component = $input['component'] = self::getValue('m');
$input['invoice'] = self::getValue('i', TRUE);
// get the contribution and contact ids from the GET params
Expand All @@ -406,14 +441,14 @@ public function main() {
if ($this->_component == 'event') {
$ids['event'] = self::getValue('e', TRUE);
$ids['participant'] = self::getValue('p', TRUE);
$ids['contributionRecur'] = self::getValue('r', FALSE);
$ids['contributionRecur'] = $this->getContributionRecurID();
}
else {
// get the optional ids
//@ how can this not be broken retrieving from GET as we are dealing with a POST request?
// copy & paste? Note the retrieve function now uses data from _REQUEST so this will be included
$ids['membership'] = self::retrieve('membershipID', 'Integer', 'GET', FALSE);
$ids['contributionRecur'] = self::getValue('r', FALSE);
$ids['contributionRecur'] = $this->getContributionRecurID();
$ids['contributionPage'] = self::getValue('p', FALSE);
$ids['related_contact'] = self::retrieve('relatedContactID', 'Integer', 'GET', FALSE);
$ids['onbehalf_dupe_alert'] = self::retrieve('onBehalfDupeAlert', 'Integer', 'GET', FALSE);
Expand Down Expand Up @@ -472,14 +507,8 @@ public function main() {

$input['payment_processor_id'] = $paymentProcessorID;

if ($ids['contributionRecur']) {
$contributionRecur = new CRM_Contribute_BAO_ContributionRecur();
$contributionRecur->id = $ids['contributionRecur'];
if (!$contributionRecur->find(TRUE)) {
CRM_Core_Error::debug_log_message("Could not find contribution recur record: {$ids['ContributionRecur']} in IPN request: " . print_r($input, TRUE));
echo "Failure: Could not find contribution recur record: {$ids['ContributionRecur']}<p>";
return;
}
if ($this->getContributionRecurID()) {
$contributionRecur = $this->getContributionRecurObject();
// 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');
Expand All @@ -496,7 +525,7 @@ public function main() {
], $contribution, FALSE, FALSE);
}
catch (CRM_Core_Exception $e) {
Civi::log()->debug($e->getMessage());
Civi::log()->debug($e->getMessage() . ' input {input}', ['input' => $input]);
echo 'Invalid or missing data';
}
}
Expand Down Expand Up @@ -569,6 +598,7 @@ public function handlePaymentExpress() {
'return' => 'contact_id, id, payment_processor_id',
'invoice_id' => $input['invoice'],
]);
$this->setContributionRecurID((int) $contributionRecur['id']);

if ($input['txnType'] !== 'recurring_payment' && $input['txnType'] !== 'recurring_payment_profile_created') {
throw new CRM_Core_Exception('Paypal IPNS not handled other than recurring_payments');
Expand All @@ -580,7 +610,7 @@ public function handlePaymentExpress() {
}

$ids['contact'] = $contributionRecur['contact_id'];
$ids['contributionRecur'] = $contributionRecur['id'];
$ids['contributionRecur'] = $this->getContributionRecurID();
$result = civicrm_api3('contribution', 'getsingle', ['invoice_id' => $input['invoice'], 'contribution_test' => '']);

$ids['contribution'] = $result['id'];
Expand Down Expand Up @@ -611,16 +641,6 @@ public function handlePaymentExpress() {
throw new CRM_Core_Exception('Failure: Could not find contribution record for ' . (int) $contribution->id, NULL, ['context' => "Could not find contribution record: {$contribution->id} in IPN request: " . print_r($input, TRUE)]);
}

if (!empty($ids['contributionRecur'])) {
$contributionRecur = new CRM_Contribute_BAO_ContributionRecur();
$contributionRecur->id = $ids['contributionRecur'];
if (!$contributionRecur->find(TRUE)) {
CRM_Core_Error::debug_log_message("Could not find contribution recur record: {$ids['ContributionRecur']} in IPN request: " . print_r($input, TRUE));
echo "Failure: Could not find contribution recur record: {$ids['ContributionRecur']}<p>";
return FALSE;
}
}

$objects['contribution'] = &$contribution;

// CRM-19478: handle oddity when p=null is set in place of contribution page ID,
Expand All @@ -635,7 +655,7 @@ public function handlePaymentExpress() {
$contribution->loadRelatedObjects($input, $ids);
$objects = array_merge($objects, $contribution->_relatedObjects);

$this->recur($input, $ids, $objects['contributionRecur'], $objects['contribution'], $isFirst);
$this->recur($input, $ids, $this->getContributionRecurObject(), $objects['contribution'], $isFirst);
}

/**
Expand All @@ -653,4 +673,22 @@ public function transactionExists($trxn_id) {
}
}

/**
* Get the recurring contribution object.
*
* @return \CRM_Contribute_BAO_ContributionRecur
* @throws \CRM_Core_Exception
*/
protected function getContributionRecurObject(): CRM_Contribute_BAO_ContributionRecur {
if (!$this->contributionRecurObject) {
$contributionRecur = new CRM_Contribute_BAO_ContributionRecur();
$contributionRecur->id = $this->getContributionRecurID();
if (!$contributionRecur->find(TRUE)) {
throw new CRM_Core_Exception('Failure: Could not find contribution recur record');
}
return $this->contributionRecurObject = $contributionRecur;
}
return $this->contributionRecurObject;
}

}

0 comments on commit 55f6a00

Please sign in to comment.