protected function PayPalController::processIpn in Ubercart 8.4
Processes Instant Payment Notifications from PayPal.
Parameters
array $ipn: The IPN data.
1 call to PayPalController::processIpn()
- PayPalController::ipn in payment/
uc_paypal/ src/ Controller/ PayPalController.php - Processes the IPN HTTP request.
File
- payment/
uc_paypal/ src/ Controller/ PayPalController.php, line 102
Class
- PayPalController
- Returns responses for PayPal routes.
Namespace
Drupal\uc_paypal\ControllerCode
protected function processIpn(array $ipn) {
$amount = $ipn['mc_gross'];
$email = !empty($ipn['business']) ? $ipn['business'] : $ipn['receiver_email'];
$txn_id = $ipn['txn_id'];
if (!isset($ipn['invoice'])) {
$this
->getLogger('uc_paypal')
->error('IPN attempted with invalid order ID.');
return;
}
// Extract order and cart IDs.
$order_id = $ipn['invoice'];
if (strpos($order_id, '-') > 0) {
list($order_id, $cart_id) = explode('-', $order_id);
$this->session
->set('uc_cart_id', $cart_id);
}
$order = Order::load($order_id);
if (!$order) {
$this
->getLogger('uc_paypal')
->error('IPN attempted for non-existent order @order_id.', [
'@order_id' => $order_id,
]);
return;
}
// @todo Send method name and order ID in the IPN URL?
$config = $this->paymentMethodManager
->createFromOrder($order)
->getConfiguration();
// Optionally log IPN details.
if (!empty($config['wps_debug_ipn'])) {
$this
->getLogger('uc_paypal')
->notice('Receiving IPN at URL for order @order_id. <pre>@debug</pre>', [
'@order_id' => $order_id,
'@debug' => print_r($ipn, TRUE),
]);
}
// Express Checkout IPNs may not have the WPS email stored. But if it is,
// make sure that the right account is being paid.
if (!empty($config['wps_email']) && mb_strtolower($email) != mb_strtolower($config['wps_email'])) {
$this
->getLogger('uc_paypal')
->error('IPN for a different PayPal account attempted.');
return;
}
// Determine server.
if (empty($ipn['test_ipn'])) {
$host = 'https://ipnpb.paypal.com/cgi-bin/webscr';
}
else {
$host = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
}
// POST IPN data back to PayPal to validate.
try {
$response = \Drupal::httpClient()
->request('POST', $host, [
'form_params' => [
'cmd' => '_notify-validate',
] + $ipn,
]);
} catch (TransferException $e) {
$this
->getLogger('uc_paypal')
->error('IPN validation failed with HTTP error %error.', [
'%error' => $e
->getMessage(),
]);
return;
}
// Check IPN validation response to determine if the IPN was valid..
if ($response
->getBody() != 'VERIFIED') {
$this
->getLogger('uc_paypal')
->error('IPN transaction failed verification.');
uc_order_comment_save($order_id, 0, $this
->t('An IPN transaction failed verification for this order.'), 'admin');
return;
}
// Check for a duplicate transaction ID.
$duplicate = (bool) $this->database
->queryRange('SELECT 1 FROM {uc_payment_paypal_ipn} WHERE txn_id = :id AND status <> :status', 0, 1, [
':id' => $txn_id,
':status' => 'Pending',
])
->fetchField();
if ($duplicate) {
if ($order
->getPaymentMethodId() != 'credit') {
$this
->getLogger('uc_paypal')
->notice('IPN transaction ID has been processed before.');
}
return;
}
$this->database
->insert('uc_payment_paypal_ipn')
->fields([
'order_id' => $order_id,
'txn_id' => $txn_id,
'txn_type' => $ipn['txn_type'],
'mc_gross' => $amount,
'status' => $ipn['payment_status'],
'receiver_email' => $email,
'payer_email' => $ipn['payer_email'],
'received' => $this->dateTime
->getRequestTime(),
])
->execute();
switch ($ipn['payment_status']) {
case 'Canceled_Reversal':
uc_order_comment_save($order_id, 0, $this
->t('PayPal has canceled the reversal and returned @amount @currency to your account.', [
'@amount' => uc_currency_format($amount, FALSE),
'@currency' => $ipn['mc_currency'],
]), 'admin');
break;
case 'Completed':
if (abs($amount - $order
->getTotal()) > 0.01) {
$this
->getLogger('uc_paypal')
->warning('Payment @txn_id for order @order_id did not equal the order total.', [
'@txn_id' => $txn_id,
'@order_id' => $order
->id(),
'link' => Link::createFromRoute($this
->t('view'), 'entity.uc_order.canonical', [
'uc_order' => $order
->id(),
])
->toString(),
]);
}
$comment = $this
->t('PayPal transaction ID: @txn_id', [
'@txn_id' => $txn_id,
]);
uc_payment_enter($order_id, 'paypal_wps', $amount, $order
->getOwnerId(), NULL, $comment);
uc_order_comment_save($order_id, 0, $this
->t('PayPal IPN reported a payment of @amount @currency.', [
'@amount' => uc_currency_format($amount, FALSE),
'@currency' => $ipn['mc_currency'],
]));
break;
case 'Denied':
uc_order_comment_save($order_id, 0, $this
->t("You have denied the customer's payment."), 'admin');
break;
case 'Expired':
uc_order_comment_save($order_id, 0, $this
->t('The authorization has failed and cannot be captured.'), 'admin');
break;
case 'Failed':
uc_order_comment_save($order_id, 0, $this
->t("The customer's attempted payment from a bank account failed."), 'admin');
break;
case 'Pending':
$order
->setStatusId('paypal_pending')
->save();
uc_order_comment_save($order_id, 0, $this
->t('Payment is pending at PayPal: @reason', [
'@reason' => $this
->pendingMessage($ipn['pending_reason']),
]), 'admin');
break;
// You, the merchant, refunded the payment.
case 'Refunded':
$comment = $this
->t('PayPal transaction ID: @txn_id', [
'@txn_id' => $txn_id,
]);
uc_payment_enter($order_id, 'paypal_wps', $amount, $order
->getOwnerId(), NULL, $comment);
break;
case 'Reversed':
$this
->getLogger('uc_paypal')
->error('PayPal has reversed a payment!');
uc_order_comment_save($order_id, 0, $this
->t('Payment has been reversed by PayPal: @reason', [
'@reason' => $this
->reversalMessage($ipn['reason_code']),
]), 'admin');
break;
case 'Processed':
uc_order_comment_save($order_id, 0, $this
->t('A payment has been accepted.'), 'admin');
break;
case 'Voided':
uc_order_comment_save($order_id, 0, $this
->t('The authorization has been voided.'), 'admin');
break;
}
}