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
{
// needed for Magento < 2.2.0 https://github.com/magento/magento2/pull/8413
$renderer = Phrase::getRenderer();
if($renderer instanceof Placeholder) {
if ($renderer instanceof Placeholder) {
$this->_areaList->getArea(Area::AREA_CRONTAB)->load(Area::PART_TRANSLATE);
}
......@@ -247,9 +247,7 @@ class Cron
foreach ($notifications as $notification) {
// set Cron processing to true
$notification->setProcessing(true);
$notification->setUpdatedAt(new \DateTime());
$notification->save();
$this->_updateNotification($notification, true, false);
}
// loop over the notifications
......@@ -260,21 +258,29 @@ class Cron
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
* before processing so we are sure the 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 is a recurring_contract notification wait an extra 5 minutes
before processing this to make sure the contract exists"
);
// set processing back to false
$notification->setProcessing(false);
$notification->setUpdatedAt($dateEnd);
$notification->save();
$this->_updateNotification($notification, false, false);
continue;
}
......@@ -311,7 +317,8 @@ class Cron
*/
if ($this->_order->getState() === \Magento\Sales\Model\Order::STATE_PENDING_PAYMENT ||
$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');
......@@ -328,7 +335,8 @@ class Cron
* refund/cancelled as well so if it is a split payment that failed cancel the order as well
*/
if ($previousAdyenEventCode != "AUTHORISATION : TRUE" ||
$this->_eventCode == Notification::ORDER_CLOSED) {
$this->_eventCode == Notification::ORDER_CLOSED
) {
$this->_holdCancelOrder(false);
} else {
$this->_order->setData('adyen_notification_event_code', $previousAdyenEventCode);
......@@ -349,12 +357,8 @@ class Cron
}
$this->_order->save();
// set done to true
$notification->setDone(true);
$notification->setProcessing(false);
$notification->setUpdatedAt(new \DateTime());
$notification->save();
$this->_updateNotification($notification, false, true);
$this->_adyenLogger->addAdyenNotificationCronjob(
sprintf("Notification %s is processed", $notification->getEntityId())
);
......@@ -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
*
......@@ -461,10 +494,10 @@ class Cron
// check if it is a full or partial refund
$amount = $this->_value;
$orderAmount = (int) $this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $currency);
$orderAmount = (int)$this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $currency);
$this->_adyenLogger->addAdyenNotificationCronjob(
'amount notification:'.$amount . ' amount order:'.$orderAmount
'amount notification:' . $amount . ' amount order:' . $orderAmount
);
if ($amount == $orderAmount) {
......@@ -487,7 +520,8 @@ class Cron
if (($this->_paymentMethod == "klarna" || $this->_paymentMethod == "afterpay_default" ||
$this->_paymentMethod == "openinvoice" || $this->_paymentMethod == "ratepay"
) && ($this->_klarnaReservationNumber != null &&
$this->_klarnaReservationNumber != "")) {
$this->_klarnaReservationNumber != "")
) {
$klarnaReservationNumberText = "<br /> reservationNumber: " . $this->_klarnaReservationNumber;
} else {
$klarnaReservationNumberText = "";
......@@ -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 ($this->_eventCode == Notification::MANUAL_REVIEW_ACCEPT
&& $this->_getFraudManualReviewAcceptStatus() != "") {
&& $this->_getFraudManualReviewAcceptStatus() != ""
) {
$manualReviewAcceptStatus = $this->_getFraudManualReviewAcceptStatus();
$this->_order->addStatusHistoryComment($comment, $manualReviewAcceptStatus);
$this->_adyenLogger->addAdyenNotificationCronjob('Created comment history for this notification with status change to: ' . $manualReviewAcceptStatus);
......@@ -543,7 +578,8 @@ class Cron
if ($this->_eventCode == Notification::AUTHORISATION
|| $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
......@@ -551,7 +587,8 @@ class Cron
*/
if (strcmp($this->_success, 'false') == 0 ||
strcmp($this->_success, '0') == 0 ||
strcmp($this->_success, '') == 0) {
strcmp($this->_success, '') == 0
) {
$previousAdyenEventCode = $this->_order->getData('adyen_notification_event_code');
if ($previousAdyenEventCode != "AUTHORISATION : TRUE") {
......@@ -684,6 +721,7 @@ class Cron
*/
protected function _processNotification()
{
$this->_adyenLogger->addAdyenNotificationCronjob('Processing the notification');
$_paymentCode = $this->_paymentMethodCode();
......@@ -752,7 +790,7 @@ class Cron
}
break;
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
$this->_order->setState(\Magento\Sales\Model\Order::STATE_NEW);
}
......@@ -774,20 +812,23 @@ class Cron
}
} else {
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(
'Order is already cancelled or holded so do nothing'
);
} else if ($this->_order->canCancel() || $this->_order->canHold()) {
$this->_adyenLogger->addAdyenNotificationCronjob('try to cancel the order');
$this->_holdCancelOrder(true);
} else {
$this->_adyenLogger->addAdyenNotificationCronjob('try to refund the order');
// refund
$this->_refundOrder();
//refund completed
$this->_setRefundAuthorized();
if ($this->_order->canCancel() || $this->_order->canHold()) {
$this->_adyenLogger->addAdyenNotificationCronjob('try to cancel the order');
$this->_holdCancelOrder(true);
} else {
$this->_adyenLogger->addAdyenNotificationCronjob('try to refund the order');
// refund
$this->_refundOrder();
//refund completed
$this->_setRefundAuthorized();
}
}
}
break;
......@@ -800,7 +841,8 @@ class Cron
$customerReference = $this->_order->getCustomerId();
$listRecurringContracts = null;
$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 {
$listRecurringContracts = $this->_adyenPaymentRequest->getRecurringContractsForShopper(
......@@ -817,7 +859,8 @@ class Cron
foreach ($listRecurringContracts as $rc) {
$recurringReferencesList[] = $rc['recurringDetailReference'];
if (isset($rc['recurringDetailReference']) &&
$rc['recurringDetailReference'] == $recurringDetailReference) {
$rc['recurringDetailReference'] == $recurringDetailReference
) {
$contractDetail = $rc;
}
}
......@@ -867,8 +910,7 @@ class Cron
$billingAgreement->setStoreId($this->_order->getStoreId());
$billingAgreement->importOrderPayment($this->_order->getPayment());
$message = __('Created billing agreement #%1.', $recurringDetailReference);
}
else {
} else {
$this->_adyenLogger->addAdyenNotificationCronjob("Using existing Billing Agreement");
$billingAgreement->setIsObjectChanged(true);
$message = __('Updated billing agreement #%1.', $recurringDetailReference);
......@@ -888,7 +930,7 @@ class Cron
throw new \Exception($message);
}
} catch(\Exception $exception) {
} catch (\Exception $exception) {
$message = $exception->getMessage();
}
......@@ -924,7 +966,7 @@ class Cron
if ($orderPayment->getId() > 0) {
$currency = $this->_order->getOrderCurrencyCode();
$amountRefunded = $amountRefunded = $orderPayment->getTotalRefunded() +
$amountRefunded = $amountRefunded = $orderPayment->getTotalRefunded() +
$this->_adyenHelper->originalAmount($this->_value, $currency);
$orderPayment->setUpdatedAt(new \DateTime());
$orderPayment->setTotalRefunded($amountRefunded);
......@@ -1009,7 +1051,8 @@ class Cron
if (($this->_paymentMethod == "c_cash" &&
$this->_getConfigData('create_shipment', 'adyen_cash', $this->_order->getStoreId())) ||
($this->_getConfigData('create_shipment', 'adyen_pos', $this->_order->getStoreId()) &&
$_paymentCode == "adyen_pos")) {
$_paymentCode == "adyen_pos")
) {
$this->_createShipment();
}
......@@ -1025,7 +1068,7 @@ class Cron
try {
$this->_orderSender->send($this->_order);
$this->_adyenLogger->addAdyenNotificationCronjob('Send orderconfirmation email to shopper');
} catch(\Exception $exception) {
} catch (\Exception $exception) {
$this->_adyenLogger->addAdyenNotificationCronjob(
"Exception in Send Mail in Magento. This is an issue in the the core of Magento" .
$exception->getMessage()
......@@ -1093,7 +1136,7 @@ class Cron
}
}
$createPendingInvoice = (bool) $this->_getConfigData(
$createPendingInvoice = (bool)$this->_getConfigData(
'create_pending_invoice', 'adyen_abstract', $this->_order->getStoreId()
);
......@@ -1158,7 +1201,8 @@ class Cron
* There will be a capture send to indicate if payment is successful
*/
if (($_paymentCode == "adyen_sepa" || $this->_paymentMethod == "sepadirectdebit") &&
$sepaFlow == "authcap") {
$sepaFlow == "authcap"
) {
$this->_adyenLogger->addAdyenNotificationCronjob(
'Manual Capture is applied for sepa because it is in authcap flow'
);
......@@ -1167,10 +1211,11 @@ class Cron
// payment method ideal, cash adyen_boleto or adyen_pos has direct capture
if ($_paymentCode == "adyen_pos" || (($_paymentCode == "adyen_sepa" ||
$this->_paymentMethod == "sepadirectdebit") && $sepaFlow != "authcap")) {
$this->_paymentMethod == "sepadirectdebit") && $sepaFlow != "authcap")
) {
$this->_adyenLogger->addAdyenNotificationCronjob(
'This payment method does not allow manual capture.(2) paymentCode:' .
$_paymentCode . ' paymentMethod:' . $this->_paymentMethod . ' sepaFLow:'.$sepaFlow
$_paymentCode . ' paymentMethod:' . $this->_paymentMethod . ' sepaFLow:' . $sepaFlow
);
return true;
}
......@@ -1185,13 +1230,13 @@ class Cron
return true;
}
// if PayPal capture modues is different from the default use this one
if (strcmp($this->_paymentMethod, 'paypal' ) === 0 && $captureModePayPal != "") {
if (strcmp($captureModePayPal, 'auto') === 0 ) {
if (strcmp($this->_paymentMethod, 'paypal') === 0 && $captureModePayPal != "") {
if (strcmp($captureModePayPal, 'auto') === 0) {
$this->_adyenLogger->addAdyenNotificationCronjob(
'This payment method is paypal and configured to work as auto capture'
);
return true;
} elseif (strcmp($captureModePayPal, 'manual') === 0 ) {
} elseif (strcmp($captureModePayPal, 'manual') === 0) {
$this->_adyenLogger->addAdyenNotificationCronjob(
'This payment method is paypal and configured to work as manual capture'
);
......@@ -1234,7 +1279,7 @@ class Cron
$manualCaptureAllowed = null;
$paymentMethod = $this->_paymentMethod;
switch($paymentMethod) {
switch ($paymentMethod) {
case 'cup':
case 'cartebancaire':
case 'visa':
......@@ -1311,7 +1356,7 @@ class Cron
);
// 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
$res = $this->_adyenOrderPaymentCollectionFactory
......@@ -1365,7 +1410,7 @@ class Cron
$autoCapture = $this->_isAutoCapture();
$createPendingInvoice = (bool) $this->_getConfigData(
$createPendingInvoice = (bool)$this->_getConfigData(
'create_pending_invoice', 'adyen_abstract', $this->_order->getStoreId()
);
......@@ -1395,7 +1440,7 @@ class Cron
$this->_setPaymentAuthorized();
$invoiceAutoMail = (bool) $this->_getConfigData(
$invoiceAutoMail = (bool)$this->_getConfigData(
'send_invoice_update_mail', 'adyen_abstract', $this->_order->getStoreId()
);
......@@ -1419,16 +1464,16 @@ class Cron
// if full amount is captured create invoice
$currency = $this->_order->getOrderCurrencyCode();
$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
if ($createInvoice == true && $amount == $orderAmount) {
$this->_adyenLogger->addAdyenNotificationCronjob(
'amount notification:'.$amount . ' amount order:'.$orderAmount
'amount notification:' . $amount . ' amount order:' . $orderAmount
);
$this->_createInvoice();
}
$status = $this->_getConfigData(
'payment_authorized', 'adyen_abstract', $this->_order->getStoreId()
);
......@@ -1462,7 +1507,7 @@ class Cron
$paidAmount = floatval(trim($paidAmount));
if ($paidAmount > $orginalAmount) {
$overpaidStatus = $this->_getConfigData(
$overpaidStatus = $this->_getConfigData(
'order_overpaid_status', 'adyen_boleto', $this->_order->getStoreId()
);
// check if there is selected a status if not fall back to the default
......
......@@ -37,12 +37,12 @@ class Notification extends \Magento\Framework\Model\AbstractModel
const ERROR = 'ERROR';
const REFUND = 'REFUND';
const REFUND_FAILED = 'REFUND_FAILED';
const CANCEL_OR_REFUND = 'CANCEL_OR_REFUND';
const CANCEL_OR_REFUND = 'CANCEL_OR_REFUND';
const CAPTURE = 'CAPTURE';
const CAPTURE_FAILED = 'CAPTURE_FAILED';
const CANCELLATION = 'CANCELLATION';
const POSAPPROVED = 'POS_APPROVED';
const HANDLED_EXTERNALLY = 'HANDLED_EXTERNALLY';
const HANDLED_EXTERNALLY = 'HANDLED_EXTERNALLY';
const MANUAL_REVIEW_ACCEPT = 'MANUAL_REVIEW_ACCEPT';
const MANUAL_REVIEW_REJECT = 'MANUAL_REVIEW_REJECT ';
const RECURRING_CONTRACT = "RECURRING_CONTRACT";
......@@ -86,11 +86,12 @@ class Notification extends \Magento\Framework\Model\AbstractModel
* @param $eventCode
* @param $success
* @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;
}
......@@ -148,7 +149,7 @@ class Notification extends \Magento\Framework\Model\AbstractModel
{
return $this->setData(self::ORIGINAL_REFERENCE, $originalReference);
}
/**
* Gets the Merchantreference for the notification.
*
......@@ -315,7 +316,7 @@ class Notification extends \Magento\Framework\Model\AbstractModel
{
return $this->setData(self::LIVE, $live);
}
/**
* Gets the AdditionalData for the notification.
*
......
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