function commerce_paypal_ec_paypal_ipn_process in Commerce PayPal 7.2
Payment method callback: process an IPN once it's been validated.
File
- modules/
ec/ commerce_paypal_ec.module, line 877 - Implements PayPal Express Checkout in Drupal Commerce checkout.
Code
function commerce_paypal_ec_paypal_ipn_process($order, $payment_method, &$ipn) {
// Do not perform any processing on EC transactions here that do not have
// transaction IDs, indicating they are non-payment IPNs such as those used
// for subscription signup requests.
if (empty($ipn['txn_id'])) {
return FALSE;
}
// Exit when we don't get a payment status we recognize.
if (!in_array($ipn['payment_status'], array(
'Failed',
'Voided',
'Pending',
'Completed',
'Refunded',
'Denied',
))) {
commerce_payment_redirect_pane_previous_page($order);
return FALSE;
}
// If this is a prior authorization capture IPN...
if (in_array($ipn['payment_status'], array(
'Voided',
'Completed',
)) && !empty($ipn['auth_id'])) {
// Ensure we can load the existing corresponding transaction.
$transaction = commerce_paypal_payment_transaction_load($ipn['auth_id']);
// If not, bail now because authorization transactions should be created by
// the Express Checkout API request itself.
if (!$transaction) {
watchdog('commerce_paypal_ec', 'IPN for Order @order_number ignored: authorization transaction already created.', array(
'@order_number' => $order->order_number,
), WATCHDOG_NOTICE);
return FALSE;
}
}
elseif (in_array($ipn['payment_status'], array(
'Failed',
'Refunded',
))) {
// Ensure there isn't already an existing corresponding transaction.
$transaction = commerce_paypal_payment_transaction_load($ipn['txn_id']);
// If so, bail now because the refund transaction was created by the Express
// Checkout API request itself.
if ($transaction) {
watchdog('commerce_paypal_ec', 'IPN for Order @order_number ignored: refund transaction already created.', array(
'@order_number' => $order->order_number,
), WATCHDOG_NOTICE);
return FALSE;
}
// Otherwise if this is a failed bank payment or refund, create a new
// payment transaction to log it to the order.
$transaction = commerce_payment_transaction_new('paypal_ec', $order->order_id);
$transaction->instance_id = $payment_method['instance_id'];
}
elseif (in_array($ipn['payment_status'], array(
'Completed',
'Denied',
)) && $ipn['payment_type'] === 'echeck') {
// E-checks use the same ipn transaction id, with an updated status. Check
// for existing transaction with a status that's not the same.
// Ensure there is an existing transaction.
$transaction = commerce_paypal_payment_transaction_load($ipn['txn_id']);
if (!$transaction) {
watchdog('commerce_paypal_ec', 'IPN for Order @order_number ignored: transaction not found.', array(
'@order_number' => $order->order_number,
), WATCHDOG_NOTICE);
return FALSE;
}
// The e-check status has updated, so change the transaction details.
if ($ipn['payment_status'] == 'Completed') {
$transaction->message = '<strong>' . t('eCheck payment successful') . '</strong>';
}
else {
$transaction->message = '<strong>' . t('eCheck payment denied') . '</strong>';
}
}
else {
// In other circumstances, exit the processing, because we handle those
// cases directly during API response processing.
watchdog('commerce_paypal_ec', 'IPN for Order @order_number ignored: this operation was accommodated in the direct API response.', array(
'@order_number' => $order->order_number,
), WATCHDOG_NOTICE);
return FALSE;
}
$transaction->remote_id = $ipn['txn_id'];
$transaction->amount = commerce_currency_decimal_to_amount($ipn['mc_gross'], $ipn['mc_currency']);
$transaction->currency_code = $ipn['mc_currency'];
$transaction->payload[REQUEST_TIME . '-ipn'] = $ipn;
if (!empty($transaction->message)) {
$transaction->message .= '<br />';
}
// Set the transaction's statuses based on the IPN's payment_status.
$transaction->remote_status = $ipn['payment_status'];
// If we didn't get an approval response code...
switch ($ipn['payment_status']) {
case 'Failed':
$transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
$transaction->message .= t("The payment has failed. This happens only if the payment was made from your customer’s bank account.");
break;
case 'Voided':
$transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
$transaction->message .= t('The authorization was voided.');
break;
case 'Pending':
$transaction->status = COMMERCE_PAYMENT_STATUS_PENDING;
$transaction->message .= commerce_paypal_ipn_pending_reason($ipn['pending_reason']);
break;
case 'Completed':
$transaction->status = COMMERCE_PAYMENT_STATUS_SUCCESS;
$transaction->message .= t('The payment has completed.');
break;
case 'Refunded':
$transaction->status = COMMERCE_PAYMENT_STATUS_SUCCESS;
$transaction->message .= t('Refund for transaction @txn_id', array(
'@txn_id' => $ipn['parent_txn_id'],
));
break;
case 'Denied':
$transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
$transaction->message .= t("The payment has been denied. This happens only if the payment was previously pending.");
break;
}
// Save the transaction information.
commerce_payment_transaction_save($transaction);
$ipn['transaction_id'] = $transaction->transaction_id;
watchdog('commerce_paypal_ec', 'IPN processed for Order @order_number with ID @txn_id.', array(
'@txn_id' => $ipn['txn_id'],
'@order_number' => $order->order_number,
), WATCHDOG_INFO);
}