Skip to content

Commit

Permalink
Merge pull request #26620 from eileenmcnaughton/anet
Browse files Browse the repository at this point in the history
Switch to Payment.create & repeattransaction in Authorize.net
  • Loading branch information
seamuslee001 authored Jun 23, 2023
2 parents 8de0f3e + 86b1c2f commit 2ad8b9b
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 28 deletions.
1 change: 1 addition & 0 deletions CRM/Contribute/BAO/Contribution.php
Original file line number Diff line number Diff line change
Expand Up @@ -3816,6 +3816,7 @@ public static function isSingleLineItem($id) {
*/
public static function completeOrder($input, $recurringContributionID, $contributionID, $isPostPaymentCreate = FALSE) {
if (!$contributionID) {
CRM_Core_Error::deprecatedFunctionWarning('v3api Contribution.repeattransaction. This handling will be removed around 5.70 (calling this function directly has never been supported outside core anyway)');
return self::repeatTransaction($input, $recurringContributionID);
}
$transaction = new CRM_Core_Transaction();
Expand Down
100 changes: 73 additions & 27 deletions CRM/Core/Payment/AuthorizeNetIPN.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ public function __construct($inputData) {
parent::__construct();
}

/**
* @var string
*/
protected $transactionID;

/**
* @var string
*/
protected $contributionStatus;

/**
* Main IPN processing function.
*/
Expand All @@ -45,7 +55,7 @@ public function main() {
$x_subscription_id = $this->getRecurProcessorID();

if (!$this->isSuccess()) {
$errorMessage = ts('Subscription payment failed - %1', [1 => htmlspecialchars($input['response_reason_text'])]);
$errorMessage = ts('Subscription payment failed - %1', [1 => htmlspecialchars($this->getInput()['response_reason_text'])]);
ContributionRecur::update(FALSE)
->addWhere('id', '=', $this->getContributionRecurID())
->setValues([
Expand All @@ -56,11 +66,30 @@ public function main() {
\Civi::log('authorize_net')->info($errorMessage);
return;
}
if ($this->isSuccess() && ($this->getContributionStatus() !== 'Completed')) {
if ($this->getContributionStatus() !== 'Completed') {
ContributionRecur::update(FALSE)->addWhere('id', '=', $this->getContributionRecurID())
->setValues(['trxn_id' => $this->getRecurProcessorID()])->execute();
$contributionID = $this->getContributionID();
}
else {
$contribution = civicrm_api3('Contribution', 'repeattransaction', [
'contribution_recur_id' => $this->getContributionRecurID(),
'receive_date' => $this->getInput()['receive_date'],
'payment_processor_id' => $this->getPaymentProcessorID(),
'trxn_id' => $this->getInput()['trxn_id'],
'amount' => $this->getAmount(),
]);
$contributionID = $contribution['id'];
}
$this->recur();
civicrm_api3('Payment', 'create', [
'trxn_id' => $this->getInput()['trxn_id'],
'trxn_date' => $this->getInput()['receive_date'],
'payment_processor_id' => $this->getPaymentProcessorID(),
'contribution_id' => $contributionID,
'total_amount' => $this->getAmount(),
'is_send_contribution_notification' => $this->getContributionRecur()->is_email_receipt,
]);
$this->notify();
}
catch (CRM_Core_Exception $e) {
Civi::log('authorize_net')->debug($e->getMessage());
Expand All @@ -71,13 +100,11 @@ public function main() {
/**
* @throws \CRM_Core_Exception
*/
public function recur() {
public function notify() {
$recur = $this->getContributionRecur();
$input = $this->getInput();
$input['payment_processor_id'] = $this->getPaymentProcessorID();

$now = date('YmdHis');

$isFirstOrLastRecurringPayment = FALSE;
if ($this->isSuccess()) {
// Approved
Expand All @@ -93,7 +120,6 @@ public function recur() {
}
}

CRM_Contribute_BAO_Contribution::completeOrder($input, $recur->id, $this->getContributionStatus() !== 'Completed' ? $this->getContributionID() : NULL);
if ($isFirstOrLastRecurringPayment) {
//send recurring Notification email for user
CRM_Contribute_BAO_ContributionPage::recurringNotify($this->getContributionID(), TRUE,
Expand All @@ -117,7 +143,7 @@ public function getInput(): array {
$input['response_reason_text'] = $this->retrieve('x_response_reason_text', 'String', FALSE);
$input['subscription_paynum'] = $this->retrieve('x_subscription_paynum', 'Integer', FALSE, 0);
$input['trxn_id'] = $this->retrieve('x_trans_id', 'String', FALSE);
$input['receive_date'] = $this->retrieve('receive_date', 'String', FALSE, date('YmdHis', strtotime('now')));
$input['receive_date'] = $this->retrieve('receive_date', 'String', FALSE, date('YmdHis', time()));

if ($input['trxn_id']) {
$input['is_test'] = 0;
Expand All @@ -126,9 +152,11 @@ public function getInput(): array {
// Per CRM-17611 it would also not be passed back for a decline.
elseif ($this->isSuccess()) {
$input['is_test'] = 1;
$input['trxn_id'] = md5(uniqid(rand(), TRUE));
$input['trxn_id'] = $this->transactionID ?: md5(uniqid(mt_rand(), TRUE));
}
$this->transactionID = $input['trxn_id'];

// None of this is used...
$billingID = CRM_Core_BAO_LocationType::getBilling();
$params = [
'first_name' => 'x_first_name',
Expand All @@ -146,6 +174,17 @@ public function getInput(): array {
return $input;
}

/**
* Get amount.
*
* @return string
*
* @throws \CRM_Core_Exception
*/
protected function getAmount(): string {
return $this->retrieve('x_amount', 'String');
}

/**
* Was the transaction successful.
*
Expand Down Expand Up @@ -193,22 +232,26 @@ public function retrieve($name, $type, $abort = TRUE, $default = NULL) {
*/
protected function getContributionRecurObject(string $processorID, int $contactID, int $contributionID) {
// joining with contribution table for extra checks
$sql = "
$sql = '
SELECT cr.id, cr.contact_id
FROM civicrm_contribution_recur cr
INNER JOIN civicrm_contribution co ON co.contribution_recur_id = cr.id
WHERE cr.processor_id = '{$processorID}' AND
(cr.contact_id = $contactID OR co.id = $contributionID)
LIMIT 1";
$contRecur = CRM_Core_DAO::executeQuery($sql);
if (!$contRecur->fetch()) {
WHERE cr.processor_id = %1 AND
(cr.contact_id = %2 OR co.id = %3)
LIMIT 1';
$contributionRecur = CRM_Core_DAO::executeQuery($sql, [
1 => [$processorID, 'String'],
2 => [$contactID, 'Integer'],
3 => [$contributionID, 'Integer'],
]);
if (!$contributionRecur->fetch()) {
throw new CRM_Core_Exception('Could not find contributionRecur id');
}
if ($contactID != $contRecur->contact_id) {
$message = ts('Recurring contribution appears to have been re-assigned from id %1 to %2, continuing with %2.', [1 => $contactID, 2 => $contRecur->contact_id]);
CRM_Core_Error::debug_log_message($message);
if ($contactID != $contributionRecur->contact_id) {
$message = ts('Recurring contribution appears to have been re-assigned from id %1 to %2, continuing with %2.', [1 => $contactID, 2 => $contributionRecur->contact_id]);
\Civi::log('authorize_net')->warning($message);
}
return $contRecur;
return $contributionRecur;
}

/**
Expand Down Expand Up @@ -307,15 +350,18 @@ private function getContributionRecur(): CRM_Contribute_BAO_ContributionRecur {
* @throws \CRM_Core_Exception
*/
private function getContributionStatus(): string {
// Check if the contribution exists
// make sure contribution exists and is valid
$contribution = Contribution::get(FALSE)
->addWhere('id', '=', $this->getContributionID())
->addSelect('contribution_status_id:name')->execute()->first();
if (empty($contribution)) {
throw new CRM_Core_Exception('Failure: Could not find contribution record for ' . $this->getContributionID(), NULL, ['context' => 'Could not find contribution record: ' . $this->getContributionID() . ' in IPN request: ' . print_r($this->getInput(), TRUE)]);
if (!$this->contributionStatus) {
// Check if the contribution exists
// make sure contribution exists and is valid
$contribution = Contribution::get(FALSE)
->addWhere('id', '=', $this->getContributionID())
->addSelect('contribution_status_id:name')->execute()->first();
if (empty($contribution)) {
throw new CRM_Core_Exception('Failure: Could not find contribution record for ' . $this->getContributionID(), NULL, ['context' => 'Could not find contribution record: ' . $this->getContributionID() . ' in IPN request: ' . print_r($this->getInput(), TRUE)]);
}
$this->contributionStatus = $contribution['contribution_status_id:name'];
}
return $contribution['contribution_status_id:name'];
return $this->contributionStatus;
}

}
1 change: 1 addition & 0 deletions CRM/Financial/BAO/Payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ public static function create(array $params): CRM_Financial_DAO_FinancialTrxn {
'is_post_payment_create' => TRUE,
'is_email_receipt' => $params['is_send_contribution_notification'],
'trxn_date' => $params['trxn_date'],
'trxn_id' => $params['trxn_id'] ?? NULL,
'payment_instrument_id' => $paymentTrxnParams['payment_instrument_id'],
'payment_processor_id' => $paymentTrxnParams['payment_processor_id'] ?? '',
]);
Expand Down
2 changes: 1 addition & 1 deletion tests/phpunit/CRM/Core/Payment/AuthorizeNetIPNTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function testIPNPaymentRecurNoReceipt(): void {
'billing_middle_name' => '',
'billing_last_name' => 'Adams',
'billing_street_address-5' => time() . ' Lincoln St S',
'billing_city-5' => 'Maryknoll',
'billing_city-5' => 'Mary-knoll',
'billing_state_province_id-5' => 1031,
'billing_postal_code-5' => 10545,
'billing_country_id-5' => 1228,
Expand Down

0 comments on commit 2ad8b9b

Please sign in to comment.