We will be off from 27/1 (Monday) to 31/1 (Friday) (GMT +7) for our Tet Holiday (Lunar New Year) in our country

Commit e63b0b71 authored by Rik ter Beek's avatar Rik ter Beek Committed by GitHub

Merge pull request #208 from Adyen/bugfix-duplicate-notifications

#204 Add duplicate check into notificaiton processing and fix formatting
parents 3b5965f5 6b75d486
...@@ -226,7 +226,7 @@ class Cron ...@@ -226,7 +226,7 @@ class Cron
{ {
// needed for Magento < 2.2.0 https://github.com/magento/magento2/pull/8413 // needed for Magento < 2.2.0 https://github.com/magento/magento2/pull/8413
$renderer = Phrase::getRenderer(); $renderer = Phrase::getRenderer();
if($renderer instanceof Placeholder) { if ($renderer instanceof Placeholder) {
$this->_areaList->getArea(Area::AREA_CRONTAB)->load(Area::PART_TRANSLATE); $this->_areaList->getArea(Area::AREA_CRONTAB)->load(Area::PART_TRANSLATE);
} }
...@@ -247,9 +247,7 @@ class Cron ...@@ -247,9 +247,7 @@ class Cron
foreach ($notifications as $notification) { foreach ($notifications as $notification) {
// set Cron processing to true // set Cron processing to true
$notification->setProcessing(true); $this->_updateNotification($notification, true, false);
$notification->setUpdatedAt(new \DateTime());
$notification->save();
} }
// loop over the notifications // loop over the notifications
...@@ -260,21 +258,29 @@ class Cron ...@@ -260,21 +258,29 @@ class Cron
sprintf("Processing notification %s", $notification->getEntityId()) sprintf("Processing notification %s", $notification->getEntityId())
); );
// ignore duplicate notification
if ($this->_isDuplicate($notification)) {
$this->_adyenLogger->addAdyenNotificationCronjob(
"This is a duplicate notification and will be ignored"
);
$this->_updateNotification($notification, false, true);
++$count;
continue;
}
/** /**
* If the event is a RECURRING_CONTRACT wait an extra 5 minutes * If the event is a RECURRING_CONTRACT wait an extra 5 minutes
* before processing so we are sure the RECURRING_CONTRACT * before processing so we are sure the RECURRING_CONTRACT
*/ */
if (trim($notification->getEventCode()) == Notification::RECURRING_CONTRACT && if (trim($notification->getEventCode()) == Notification::RECURRING_CONTRACT &&
strtotime($notification->getCreatedAt()) >= strtotime('-5 minutes', time())) { strtotime($notification->getCreatedAt()) >= strtotime('-5 minutes', time())
) {
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
"This is a recurring_contract notification wait an extra 5 minutes "This is a recurring_contract notification wait an extra 5 minutes
before processing this to make sure the contract exists" before processing this to make sure the contract exists"
); );
// set processing back to false // set processing back to false
$notification->setProcessing(false); $this->_updateNotification($notification, false, false);
$notification->setUpdatedAt($dateEnd);
$notification->save();
continue; continue;
} }
...@@ -311,7 +317,8 @@ class Cron ...@@ -311,7 +317,8 @@ class Cron
*/ */
if ($this->_order->getState() === \Magento\Sales\Model\Order::STATE_PENDING_PAYMENT || if ($this->_order->getState() === \Magento\Sales\Model\Order::STATE_PENDING_PAYMENT ||
$this->_order->getState() === \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW || $this->_order->getState() === \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW ||
$this->_eventCode == Notification::ORDER_CLOSED) { $this->_eventCode == Notification::ORDER_CLOSED
) {
$this->_adyenLogger->addAdyenNotificationCronjob('Going to cancel the order'); $this->_adyenLogger->addAdyenNotificationCronjob('Going to cancel the order');
...@@ -328,7 +335,8 @@ class Cron ...@@ -328,7 +335,8 @@ class Cron
* refund/cancelled as well so if it is a split payment that failed cancel the order as well * refund/cancelled as well so if it is a split payment that failed cancel the order as well
*/ */
if ($previousAdyenEventCode != "AUTHORISATION : TRUE" || if ($previousAdyenEventCode != "AUTHORISATION : TRUE" ||
$this->_eventCode == Notification::ORDER_CLOSED) { $this->_eventCode == Notification::ORDER_CLOSED
) {
$this->_holdCancelOrder(false); $this->_holdCancelOrder(false);
} else { } else {
$this->_order->setData('adyen_notification_event_code', $previousAdyenEventCode); $this->_order->setData('adyen_notification_event_code', $previousAdyenEventCode);
...@@ -349,12 +357,8 @@ class Cron ...@@ -349,12 +357,8 @@ class Cron
} }
$this->_order->save(); $this->_order->save();
// set done to true // set done to true
$notification->setDone(true); $this->_updateNotification($notification, false, true);
$notification->setProcessing(false);
$notification->setUpdatedAt(new \DateTime());
$notification->save();
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
sprintf("Notification %s is processed", $notification->getEntityId()) sprintf("Notification %s is processed", $notification->getEntityId())
); );
...@@ -366,6 +370,35 @@ class Cron ...@@ -366,6 +370,35 @@ class Cron
} }
} }
/**
* @param $notification
* @param $processing
* @param $done
*/
protected function _updateNotification($notification, $processing, $done)
{
if ($done) {
$notification->setDone(true);
}
$notification->setProcessing($processing);
$notification->setUpdatedAt(new \DateTime());
$notification->save();
}
/**
* Check if the notification is already executed if so this is a duplicate and ignore this one
*
* @param $notification
* @return bool
*/
protected function _isDuplicate($notification)
{
return $notification->isDuplicate(
$notification->getPspreference(), $notification->getEventCode(), $notification->getSuccess(),
$notification->getOriginalReference(), true
);
}
/** /**
* Declare private variables for processing notification * Declare private variables for processing notification
* *
...@@ -461,10 +494,10 @@ class Cron ...@@ -461,10 +494,10 @@ class Cron
// check if it is a full or partial refund // check if it is a full or partial refund
$amount = $this->_value; $amount = $this->_value;
$orderAmount = (int) $this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $currency); $orderAmount = (int)$this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $currency);
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
'amount notification:'.$amount . ' amount order:'.$orderAmount 'amount notification:' . $amount . ' amount order:' . $orderAmount
); );
if ($amount == $orderAmount) { if ($amount == $orderAmount) {
...@@ -487,7 +520,8 @@ class Cron ...@@ -487,7 +520,8 @@ class Cron
if (($this->_paymentMethod == "klarna" || $this->_paymentMethod == "afterpay_default" || if (($this->_paymentMethod == "klarna" || $this->_paymentMethod == "afterpay_default" ||
$this->_paymentMethod == "openinvoice" || $this->_paymentMethod == "ratepay" $this->_paymentMethod == "openinvoice" || $this->_paymentMethod == "ratepay"
) && ($this->_klarnaReservationNumber != null && ) && ($this->_klarnaReservationNumber != null &&
$this->_klarnaReservationNumber != "")) { $this->_klarnaReservationNumber != "")
) {
$klarnaReservationNumberText = "<br /> reservationNumber: " . $this->_klarnaReservationNumber; $klarnaReservationNumberText = "<br /> reservationNumber: " . $this->_klarnaReservationNumber;
} else { } else {
$klarnaReservationNumberText = ""; $klarnaReservationNumberText = "";
...@@ -520,7 +554,8 @@ class Cron ...@@ -520,7 +554,8 @@ class Cron
// if manual review is accepted and a status is selected. Change the status through this comment history item // if manual review is accepted and a status is selected. Change the status through this comment history item
if ($this->_eventCode == Notification::MANUAL_REVIEW_ACCEPT if ($this->_eventCode == Notification::MANUAL_REVIEW_ACCEPT
&& $this->_getFraudManualReviewAcceptStatus() != "") { && $this->_getFraudManualReviewAcceptStatus() != ""
) {
$manualReviewAcceptStatus = $this->_getFraudManualReviewAcceptStatus(); $manualReviewAcceptStatus = $this->_getFraudManualReviewAcceptStatus();
$this->_order->addStatusHistoryComment($comment, $manualReviewAcceptStatus); $this->_order->addStatusHistoryComment($comment, $manualReviewAcceptStatus);
$this->_adyenLogger->addAdyenNotificationCronjob('Created comment history for this notification with status change to: ' . $manualReviewAcceptStatus); $this->_adyenLogger->addAdyenNotificationCronjob('Created comment history for this notification with status change to: ' . $manualReviewAcceptStatus);
...@@ -543,7 +578,8 @@ class Cron ...@@ -543,7 +578,8 @@ class Cron
if ($this->_eventCode == Notification::AUTHORISATION if ($this->_eventCode == Notification::AUTHORISATION
|| $this->_eventCode == Notification::HANDLED_EXTERNALLY || $this->_eventCode == Notification::HANDLED_EXTERNALLY
|| ($this->_eventCode == Notification::CAPTURE && $_paymentCode == "adyen_pos")) { || ($this->_eventCode == Notification::CAPTURE && $_paymentCode == "adyen_pos")
) {
/* /*
* if current notification is authorisation : false and * if current notification is authorisation : false and
...@@ -551,7 +587,8 @@ class Cron ...@@ -551,7 +587,8 @@ class Cron
*/ */
if (strcmp($this->_success, 'false') == 0 || if (strcmp($this->_success, 'false') == 0 ||
strcmp($this->_success, '0') == 0 || strcmp($this->_success, '0') == 0 ||
strcmp($this->_success, '') == 0) { strcmp($this->_success, '') == 0
) {
$previousAdyenEventCode = $this->_order->getData('adyen_notification_event_code'); $previousAdyenEventCode = $this->_order->getData('adyen_notification_event_code');
if ($previousAdyenEventCode != "AUTHORISATION : TRUE") { if ($previousAdyenEventCode != "AUTHORISATION : TRUE") {
...@@ -684,6 +721,7 @@ class Cron ...@@ -684,6 +721,7 @@ class Cron
*/ */
protected function _processNotification() protected function _processNotification()
{ {
$this->_adyenLogger->addAdyenNotificationCronjob('Processing the notification'); $this->_adyenLogger->addAdyenNotificationCronjob('Processing the notification');
$_paymentCode = $this->_paymentMethodCode(); $_paymentCode = $this->_paymentMethodCode();
...@@ -752,7 +790,7 @@ class Cron ...@@ -752,7 +790,7 @@ class Cron
} }
break; break;
case Notification::OFFER_CLOSED: case Notification::OFFER_CLOSED:
if(!$this->_order->canCancel()) { if (!$this->_order->canCancel()) {
// Move the order from PAYMENT_REVIEW to NEW, so that can be cancelled // Move the order from PAYMENT_REVIEW to NEW, so that can be cancelled
$this->_order->setState(\Magento\Sales\Model\Order::STATE_NEW); $this->_order->setState(\Magento\Sales\Model\Order::STATE_NEW);
} }
...@@ -774,12 +812,14 @@ class Cron ...@@ -774,12 +812,14 @@ class Cron
} }
} else { } else {
if ($this->_order->isCanceled() || if ($this->_order->isCanceled() ||
$this->_order->getState() === \Magento\Sales\Model\Order::STATE_HOLDED) { $this->_order->getState() === \Magento\Sales\Model\Order::STATE_HOLDED
) {
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
'Order is already cancelled or holded so do nothing' 'Order is already cancelled or holded so do nothing'
); );
} else if ($this->_order->canCancel() || $this->_order->canHold()) { } else {
if ($this->_order->canCancel() || $this->_order->canHold()) {
$this->_adyenLogger->addAdyenNotificationCronjob('try to cancel the order'); $this->_adyenLogger->addAdyenNotificationCronjob('try to cancel the order');
$this->_holdCancelOrder(true); $this->_holdCancelOrder(true);
} else { } else {
...@@ -790,6 +830,7 @@ class Cron ...@@ -790,6 +830,7 @@ class Cron
$this->_setRefundAuthorized(); $this->_setRefundAuthorized();
} }
} }
}
break; break;
case Notification::RECURRING_CONTRACT: case Notification::RECURRING_CONTRACT:
...@@ -800,7 +841,8 @@ class Cron ...@@ -800,7 +841,8 @@ class Cron
$customerReference = $this->_order->getCustomerId(); $customerReference = $this->_order->getCustomerId();
$listRecurringContracts = null; $listRecurringContracts = null;
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
__('CustomerReference is: %1 and storeId is %2 and RecurringDetailsReference is %3', $customerReference, $storeId, $recurringDetailReference) __('CustomerReference is: %1 and storeId is %2 and RecurringDetailsReference is %3',
$customerReference, $storeId, $recurringDetailReference)
); );
try { try {
$listRecurringContracts = $this->_adyenPaymentRequest->getRecurringContractsForShopper( $listRecurringContracts = $this->_adyenPaymentRequest->getRecurringContractsForShopper(
...@@ -817,7 +859,8 @@ class Cron ...@@ -817,7 +859,8 @@ class Cron
foreach ($listRecurringContracts as $rc) { foreach ($listRecurringContracts as $rc) {
$recurringReferencesList[] = $rc['recurringDetailReference']; $recurringReferencesList[] = $rc['recurringDetailReference'];
if (isset($rc['recurringDetailReference']) && if (isset($rc['recurringDetailReference']) &&
$rc['recurringDetailReference'] == $recurringDetailReference) { $rc['recurringDetailReference'] == $recurringDetailReference
) {
$contractDetail = $rc; $contractDetail = $rc;
} }
} }
...@@ -867,8 +910,7 @@ class Cron ...@@ -867,8 +910,7 @@ class Cron
$billingAgreement->setStoreId($this->_order->getStoreId()); $billingAgreement->setStoreId($this->_order->getStoreId());
$billingAgreement->importOrderPayment($this->_order->getPayment()); $billingAgreement->importOrderPayment($this->_order->getPayment());
$message = __('Created billing agreement #%1.', $recurringDetailReference); $message = __('Created billing agreement #%1.', $recurringDetailReference);
} } else {
else {
$this->_adyenLogger->addAdyenNotificationCronjob("Using existing Billing Agreement"); $this->_adyenLogger->addAdyenNotificationCronjob("Using existing Billing Agreement");
$billingAgreement->setIsObjectChanged(true); $billingAgreement->setIsObjectChanged(true);
$message = __('Updated billing agreement #%1.', $recurringDetailReference); $message = __('Updated billing agreement #%1.', $recurringDetailReference);
...@@ -888,7 +930,7 @@ class Cron ...@@ -888,7 +930,7 @@ class Cron
throw new \Exception($message); throw new \Exception($message);
} }
} catch(\Exception $exception) { } catch (\Exception $exception) {
$message = $exception->getMessage(); $message = $exception->getMessage();
} }
...@@ -1009,7 +1051,8 @@ class Cron ...@@ -1009,7 +1051,8 @@ class Cron
if (($this->_paymentMethod == "c_cash" && if (($this->_paymentMethod == "c_cash" &&
$this->_getConfigData('create_shipment', 'adyen_cash', $this->_order->getStoreId())) || $this->_getConfigData('create_shipment', 'adyen_cash', $this->_order->getStoreId())) ||
($this->_getConfigData('create_shipment', 'adyen_pos', $this->_order->getStoreId()) && ($this->_getConfigData('create_shipment', 'adyen_pos', $this->_order->getStoreId()) &&
$_paymentCode == "adyen_pos")) { $_paymentCode == "adyen_pos")
) {
$this->_createShipment(); $this->_createShipment();
} }
...@@ -1025,7 +1068,7 @@ class Cron ...@@ -1025,7 +1068,7 @@ class Cron
try { try {
$this->_orderSender->send($this->_order); $this->_orderSender->send($this->_order);
$this->_adyenLogger->addAdyenNotificationCronjob('Send orderconfirmation email to shopper'); $this->_adyenLogger->addAdyenNotificationCronjob('Send orderconfirmation email to shopper');
} catch(\Exception $exception) { } catch (\Exception $exception) {
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
"Exception in Send Mail in Magento. This is an issue in the the core of Magento" . "Exception in Send Mail in Magento. This is an issue in the the core of Magento" .
$exception->getMessage() $exception->getMessage()
...@@ -1093,7 +1136,7 @@ class Cron ...@@ -1093,7 +1136,7 @@ class Cron
} }
} }
$createPendingInvoice = (bool) $this->_getConfigData( $createPendingInvoice = (bool)$this->_getConfigData(
'create_pending_invoice', 'adyen_abstract', $this->_order->getStoreId() 'create_pending_invoice', 'adyen_abstract', $this->_order->getStoreId()
); );
...@@ -1158,7 +1201,8 @@ class Cron ...@@ -1158,7 +1201,8 @@ class Cron
* There will be a capture send to indicate if payment is successful * There will be a capture send to indicate if payment is successful
*/ */
if (($_paymentCode == "adyen_sepa" || $this->_paymentMethod == "sepadirectdebit") && if (($_paymentCode == "adyen_sepa" || $this->_paymentMethod == "sepadirectdebit") &&
$sepaFlow == "authcap") { $sepaFlow == "authcap"
) {
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
'Manual Capture is applied for sepa because it is in authcap flow' 'Manual Capture is applied for sepa because it is in authcap flow'
); );
...@@ -1167,10 +1211,11 @@ class Cron ...@@ -1167,10 +1211,11 @@ class Cron
// payment method ideal, cash adyen_boleto or adyen_pos has direct capture // payment method ideal, cash adyen_boleto or adyen_pos has direct capture
if ($_paymentCode == "adyen_pos" || (($_paymentCode == "adyen_sepa" || if ($_paymentCode == "adyen_pos" || (($_paymentCode == "adyen_sepa" ||
$this->_paymentMethod == "sepadirectdebit") && $sepaFlow != "authcap")) { $this->_paymentMethod == "sepadirectdebit") && $sepaFlow != "authcap")
) {
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
'This payment method does not allow manual capture.(2) paymentCode:' . 'This payment method does not allow manual capture.(2) paymentCode:' .
$_paymentCode . ' paymentMethod:' . $this->_paymentMethod . ' sepaFLow:'.$sepaFlow $_paymentCode . ' paymentMethod:' . $this->_paymentMethod . ' sepaFLow:' . $sepaFlow
); );
return true; return true;
} }
...@@ -1185,13 +1230,13 @@ class Cron ...@@ -1185,13 +1230,13 @@ class Cron
return true; return true;
} }
// if PayPal capture modues is different from the default use this one // if PayPal capture modues is different from the default use this one
if (strcmp($this->_paymentMethod, 'paypal' ) === 0 && $captureModePayPal != "") { if (strcmp($this->_paymentMethod, 'paypal') === 0 && $captureModePayPal != "") {
if (strcmp($captureModePayPal, 'auto') === 0 ) { if (strcmp($captureModePayPal, 'auto') === 0) {
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
'This payment method is paypal and configured to work as auto capture' 'This payment method is paypal and configured to work as auto capture'
); );
return true; return true;
} elseif (strcmp($captureModePayPal, 'manual') === 0 ) { } elseif (strcmp($captureModePayPal, 'manual') === 0) {
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
'This payment method is paypal and configured to work as manual capture' 'This payment method is paypal and configured to work as manual capture'
); );
...@@ -1234,7 +1279,7 @@ class Cron ...@@ -1234,7 +1279,7 @@ class Cron
$manualCaptureAllowed = null; $manualCaptureAllowed = null;
$paymentMethod = $this->_paymentMethod; $paymentMethod = $this->_paymentMethod;
switch($paymentMethod) { switch ($paymentMethod) {
case 'cup': case 'cup':
case 'cartebancaire': case 'cartebancaire':
case 'visa': case 'visa':
...@@ -1311,7 +1356,7 @@ class Cron ...@@ -1311,7 +1356,7 @@ class Cron
); );
// get total amount of the order // get total amount of the order
$grandTotal = (int) $this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $orderCurrencyCode); $grandTotal = (int)$this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $orderCurrencyCode);
// check if total amount of the order is authorised // check if total amount of the order is authorised
$res = $this->_adyenOrderPaymentCollectionFactory $res = $this->_adyenOrderPaymentCollectionFactory
...@@ -1365,7 +1410,7 @@ class Cron ...@@ -1365,7 +1410,7 @@ class Cron
$autoCapture = $this->_isAutoCapture(); $autoCapture = $this->_isAutoCapture();
$createPendingInvoice = (bool) $this->_getConfigData( $createPendingInvoice = (bool)$this->_getConfigData(
'create_pending_invoice', 'adyen_abstract', $this->_order->getStoreId() 'create_pending_invoice', 'adyen_abstract', $this->_order->getStoreId()
); );
...@@ -1395,7 +1440,7 @@ class Cron ...@@ -1395,7 +1440,7 @@ class Cron
$this->_setPaymentAuthorized(); $this->_setPaymentAuthorized();
$invoiceAutoMail = (bool) $this->_getConfigData( $invoiceAutoMail = (bool)$this->_getConfigData(
'send_invoice_update_mail', 'adyen_abstract', $this->_order->getStoreId() 'send_invoice_update_mail', 'adyen_abstract', $this->_order->getStoreId()
); );
...@@ -1419,12 +1464,12 @@ class Cron ...@@ -1419,12 +1464,12 @@ class Cron
// if full amount is captured create invoice // if full amount is captured create invoice
$currency = $this->_order->getOrderCurrencyCode(); $currency = $this->_order->getOrderCurrencyCode();
$amount = $this->_value; $amount = $this->_value;
$orderAmount = (int) $this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $currency); $orderAmount = (int)$this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $currency);
// create invoice for the capture notification if you are on manual capture // create invoice for the capture notification if you are on manual capture
if ($createInvoice == true && $amount == $orderAmount) { if ($createInvoice == true && $amount == $orderAmount) {
$this->_adyenLogger->addAdyenNotificationCronjob( $this->_adyenLogger->addAdyenNotificationCronjob(
'amount notification:'.$amount . ' amount order:'.$orderAmount 'amount notification:' . $amount . ' amount order:' . $orderAmount
); );
$this->_createInvoice(); $this->_createInvoice();
} }
......
...@@ -86,11 +86,12 @@ class Notification extends \Magento\Framework\Model\AbstractModel ...@@ -86,11 +86,12 @@ class Notification extends \Magento\Framework\Model\AbstractModel
* @param $eventCode * @param $eventCode
* @param $success * @param $success
* @param $originalReference * @param $originalReference
* @return bool (true if the notification is a duplicate) * @param null $done
* @return bool
*/ */
public function isDuplicate($pspReference, $eventCode, $success, $originalReference) public function isDuplicate($pspReference, $eventCode, $success, $originalReference, $done = null)
{ {
$result = $this->getResource()->getNotification($pspReference, $eventCode, $success, $originalReference); $result = $this->getResource()->getNotification($pspReference, $eventCode, $success, $originalReference, $done);
return (empty($result)) ? false : true; return (empty($result)) ? false : true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment