diff --git a/Controller/Adminhtml/Utils/Send.php b/Controller/Adminhtml/Utils/Send.php index 31e894f4..678b1c18 100644 --- a/Controller/Adminhtml/Utils/Send.php +++ b/Controller/Adminhtml/Utils/Send.php @@ -1,6 +1,6 @@ _helper->createNewCase($order); // Post case to signifyd service - $this->_helper->postCaseToSignifyd($orderData); + $this->_helper->postCaseToSignifyd($orderData, $order); } catch (\Exception $ex) { $this->_logger->error($ex->getMessage()); } } - $this->messageManager->addSuccess(__('Success.')); + $this->messageManager->addSuccessMessage(__('Success.')); $resultRedirect = $this->resultRedirectFactory->create(); $resultRedirect->setPath($this->getComponentRefererUrl()); return $resultRedirect; } + } diff --git a/Controller/Webhooks/Index.php b/Controller/Webhooks/Index.php index 140551e4..b6e13cbe 100644 --- a/Controller/Webhooks/Index.php +++ b/Controller/Webhooks/Index.php @@ -1,6 +1,6 @@ null, "reason" => ''); - if (isset($request->score) && $case->getScore() != $request->score) { - $case->setScore($request->score); - $order->setSignifydScore($request->score); - $orderAction = $this->handleScoreChange($caseData) ?: $orderAction; - } - - if (isset($request->status) && $case->getSignifydStatus() != $request->status) { - $case->setSignifydStatus($request->status); - $orderAction = $this->handleStatusChange($caseData) ?: $orderAction; - } - - if (isset($request->guaranteeDisposition) && $case->getGuarantee() != $request->guaranteeDisposition) { - $case->setGuarantee($request->guaranteeDisposition); - $order->setSignifydGuarantee($request->guaranteeDisposition); - $orderAction = $this->handleGuaranteeChange($caseData) ?: $orderAction; - } - $case->setCode($request->caseId); - $case->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); - $case->save(); - - $order->setSignifydCode($request->caseId); - $order->save(); - $this->updateOrder($caseData, $orderAction); - } - - /** - * @param array $caseData - * @param string $orderAction - * @throws \Magento\Framework\Exception\LocalizedException - */ - protected function updateOrder($caseData, $orderAction) - { - /** @var $order \Magento\Sales\Model\Order */ - $order = $caseData['order']; - switch ($orderAction["action"]) { - case "hold": - if ($order->canHold()) { - $order->hold()->save(); - } - break; - case "unhold": - if ($order->canUnhold()) { - $order->unhold()->save(); - } - break; - case "cancel": - // Can't cancel if order is on hold - if ($order->canUnhold()) { - $order = $order->unhold(); - } - if ($order->canCancel()) { - $order->cancel()->save(); - } - break; - } - $order->addStatusHistoryComment("Signifyd set status to {$orderAction["action"]} because {$orderAction["reason"]}"); - $order->save(); - } - - /** - * @param $caseData - * @throws \Magento\Framework\Exception\LocalizedException - * @return string - */ - protected function handleScoreChange($caseData) - { - $threshHold = (int)$this->_coreConfig->getValue('signifyd/advanced/hold_orders_threshold'); - $holdBelowThreshold = $this->_coreConfig->getValue('signifyd/advanced/hold_orders'); - if ($holdBelowThreshold && $caseData['request']->score <= $threshHold) { - return array("action" => "hold", "reason" => "score threshold failure"); - } - return null; - } - - /** - * @param $caseData - * @throws \Magento\Framework\Exception\LocalizedException - * @return string - */ - protected function handleStatusChange($caseData) - { - $holdBelowThreshold = $this->_coreConfig->getValue('signifyd/advanced/hold_orders'); - if ($holdBelowThreshold && $caseData['request']->reviewDisposition == 'FRAUDULENT') { - return array("action" => "hold", "reason" => "review returned FRAUDULENT"); - } else { - if ($holdBelowThreshold && $caseData['request']->reviewDisposition == 'GOOD') { - return array("action" => "unhold", "reason" => "review returned GOOD"); - } - } - return null; - } - - /** - * @param $caseData - * @throws \Magento\Framework\Exception\LocalizedException - * @return string - */ - protected function handleGuaranteeChange($caseData) - { - $negativeAction = $this->_coreConfig->getValue('signifyd/advanced/guarantee_negative_action'); - $positiveAction = $this->_coreConfig->getValue('signifyd/advanced/guarantee_positive_action'); - - $request = $caseData['request']; - if ($request->guaranteeDisposition == 'DECLINED' && $negativeAction != 'nothing') { - return array("action" => $negativeAction, "reason" => "guarantee declined"); - } else { - if ($request->guaranteeDisposition == 'APPROVED' && $positiveAction != 'nothing') { - return array("action" => $positiveAction, "reason" => "guarantee approved"); - } - } - return null; - } - public function execute() { if (!$this->_api->enabled()) { - $this->_api->traceOut("This plugin is not currently enabled"); + $this->getResponse()->appendBody("This plugin is not currently enabled"); $this->Result400(); return; } @@ -256,7 +134,7 @@ public function execute() $hash = $request->getHeader('X-SIGNIFYD-SEC-HMAC-SHA256'); $topic = $request->getHeader('X-SIGNIFYD-TOPIC'); if ($hash == null) { - $this->_api->traceOut("You have successfully reached the webhook endpoint"); + $this->getResponse()->appendBody("You have successfully reached the webhook endpoint"); $this->Result200(); return; } @@ -270,10 +148,13 @@ public function execute() $request = json_decode($rawRequest); $caseData = $this->initRequest($request); - $this->updateCase($caseData); + $caseObj = $this->_objectManager->create('Signifyd\Connect\Model\Casedata'); + $caseObj->updateCase($caseData); $this->Result200(); + return; } else { $this->Result403(); + return; } } diff --git a/Cron/RetryCaseJob.php b/Cron/RetryCaseJob.php index 9f8b7f57..95acdb59 100644 --- a/Cron/RetryCaseJob.php +++ b/Cron/RetryCaseJob.php @@ -1,7 +1,7 @@ _objectManager = $objectManager; $this->_helper = $helper; $this->_logger = $logger; + $this->caseRetryObj = $caseRetryObj; } + /** + * Entry point to Cron job + * @return $this + */ public function execute() { $this->_logger->request("Starting retry job"); - $this->processRetryQueue(); + $this->retry(); return $this; } /** - * Run through up to $max items in the retry queue - * @param int $max The maximum numbers of items to process + * Main Retry Method to start retry cycle */ - public function processRetryQueue($max = 99999) + public function retry() { - /** @var $retryEntity \Signifyd\Connect\Model\CaseRetry */ - $retryEntity = $this->_objectManager->get('Signifyd\Connect\Model\CaseRetry'); - $failed_orders = $retryEntity->getCollection(); - $process_count = 0; - try { - foreach ($failed_orders as $failed_order) { - $this->_logger->request("Order up"); - /** @var $failed_order \Signifyd\Connect\Model\CaseRetry */ - if ($process_count++ >= $max) { - return; - } - $order = $this->_objectManager->get('Magento\Sales\Model\Order')->loadByIncrementId($failed_order->getOrderIncrement()); - - $this->_logger->request("Load"); - $orderData = $this->_helper->getCase($order); - if (!$this->_helper->doesCaseExist($order)) { - $this->_logger->request("No case"); - $orderData = $this->_helper->processOrderData($order); - $this->_helper->createNewCase($order); - } + $this->_logger->request("Main retry method called"); - $this->_logger->request("Start retry"); - if ($this->_helper->retryCase($orderData, $order)) { - $this->_logger->request("Completed retry " . $failed_order->getOrderIncrement()); - $failed_order->delete(); - } else { - $this->_logger->error("Failed retry " . $failed_order->getOrderIncrement()); - } + // Getting all the cases that were not submitted to Signifyd + $waitingCases = $this->caseRetryObj->getRetryCasesByStatus(CaseRetry::WAITING_SUBMISSION_STATUS); + foreach ($waitingCases as $case) { + $this->_logger->request("Signifyd: preparing for send case no: {$case['order_increment']}"); + $order = $this->_objectManager + ->get('Magento\Sales\Model\Order') + ->loadByIncrementId($case['order_increment']); + $caseData = $this->_helper->processOrderData($order); + $result = $this->_helper->postCaseToSignifyd($caseData, $order); + if($result){ + $caseObj = $this->_objectManager->create('Signifyd\Connect\Model\Casedata') + ->load($case->getOrderIncrement()) + ->setCode($result) + ->setMagentoStatus(CaseRetry::IN_REVIEW_STATUS) + ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $caseObj->save(); } - } catch (\Exception $e) { - $this->_logger->error($e->__toString()); } + + // Getting all the cases that are awaiting review from Signifyd + $inReviewCases = $this->caseRetryObj->getRetryCasesByStatus(CaseRetry::IN_REVIEW_STATUS); + foreach ($inReviewCases as $case) { + $this->_logger->request("Signifyd: preparing for review case no: {$case['order_increment']}"); + $order = $this->_objectManager + ->get('Magento\Sales\Model\Order') + ->loadByIncrementId($case['order_increment']); + $result = $this->caseRetryObj->processInReviewCase($case, $order); + if($result){} + } + + // Getting all the cases that need processing after the response was received + $inProcessingCases = $this->caseRetryObj->getRetryCasesByStatus(CaseRetry::PROCESSING_RESPONSE_STATUS); + foreach ($inProcessingCases as $case) { + $this->_logger->request("Signifyd: preparing for review case no: {$case['order_increment']}"); + $order = $this->_objectManager + ->get('Magento\Sales\Model\Order') + ->loadByIncrementId($case['order_increment']); + $this->caseRetryObj->processResponseStatus($case, $order); + } + + $this->_logger->request("Main retry method ended"); + return; } } diff --git a/Helper/LogHelper.php b/Helper/LogHelper.php index f69b33aa..62fec752 100644 --- a/Helper/LogHelper.php +++ b/Helper/LogHelper.php @@ -1,6 +1,6 @@ getRemoteIp()) { @@ -98,6 +104,11 @@ protected function getIPAddress(Order $order) return $this->filterIp($remoteAddressHelper->getRemoteAddress()); } + /** + * Filter the ip address + * @param $ip + * @return mixed + */ protected function filterIp($ip) { $matches = array(); @@ -115,6 +126,10 @@ protected function filterIp($ip) return preg_replace('/[^0-9a-zA-Z:\.]/', '', strtok(str_replace($ip, ',', "\n"), "\n")); } + /** + * Getting the version of Magento and the version of the extension + * @return array + */ protected function getVersions() { $version = array(); @@ -281,6 +296,11 @@ protected function makeUserAccount(Order $order) return $user; } + /** + * Loading the case + * @param Order $order + * @return \Signifyd\Connect\Model\Casedata + */ public function getCase(Order $order) { /** @var $case \Signifyd\Connect\Model\Casedata */ @@ -288,7 +308,12 @@ public function getCase(Order $order) $case->load($order->getIncrementId()); return $case; } - + + /** + * Check if the related case exists + * @param Order $order + * @return bool + */ public function doesCaseExist(Order $order) { /** @var $case \Signifyd\Connect\Model\Casedata */ @@ -296,7 +321,8 @@ public function doesCaseExist(Order $order) return !($case->isEmpty() || $case->isObjectNew()); } - /** Construct a new case object + /** + * Construct a new case object * @param $order Order * @return CaseModel */ @@ -312,7 +338,9 @@ public function processOrderData($order) } /** + * Saving the case to the database * @param $order + * @return \Signifyd\Connect\Model\Casedata */ public function createNewCase($order) { @@ -324,44 +352,25 @@ public function createNewCase($order) ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())) ->setEntriesText(""); $case->save(); + return $case; } /** * @param $caseData + * @return bool */ public function postCaseToSignifyd($caseData, $order) { $this->_logger->request("Sending: " . json_encode($caseData)); $id = $this->_api->createCase($caseData); - if ($id) { - $this->_logger->debug("Case sent. Id is $id"); - } else { - $this->_logger->error("Case failed to send."); - $this->addToRetryQueue($order); - } - } - public function retryCase($caseData, $order) - { - $this->_logger->request("Retrying: " . json_encode($caseData)); - $id = $this->_api->createCase($caseData); if ($id) { $this->_logger->debug("Case sent. Id is $id"); - return true; } else { - $this->_logger->error("Case failed to resend."); + $this->_logger->error("Case failed to send."); return false; } - } - private function addToRetryQueue($order) - { - $this->_logger->error("Add to retries: " . $order->getIncrementId()); - - $order_tag = $this->_objectManager->create('Signifyd\Connect\Model\CaseRetry') - ->setId($order->getIncrementId()) - ->setCreated(strftime('%Y-%m-%d %H:%M:%S', time())) - ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); - $order_tag->save(); + return $id; } } diff --git a/Helper/Retry.php b/Helper/Retry.php new file mode 100644 index 00000000..46a6c0db --- /dev/null +++ b/Helper/Retry.php @@ -0,0 +1,96 @@ +caseData = $caseData; + $this->api = $api; + $this->objectManager = $objectManager; + } + + /** + * @param $status + * @return mixed + */ + public function getRetryCasesByStatus($status) + { + $time = time(); + $lastTime = $time - 60*60*24*7; // not longer than 7 days + $firstTime = $time - 60*30; // longer than last 30 minuted + $from = date('Y-m-d H:i:s', $lastTime); + $to = date('Y-m-d H:i:s', $firstTime); + + $casesCollection = $this->caseData->getCollection(); + $casesCollection->addFieldToFilter('updated', array('from' => $from, 'to' => $to)); + $casesCollection->addFieldToFilter('magento_status', array('eq' => $status)); + + return $casesCollection; + } + + /** + * Process the cases that are in review + * @param $case + * @return bool + */ + public function processInReviewCase($case, $order) + { + if(empty($case->getCode())) return false; + try { + $caseData['request'] = $this->api->getCase($case->getCode()); + $caseData['case'] = $case; + $caseData['order'] = $order; + $caseObj = $this->objectManager->create('Signifyd\Connect\Model\Casedata'); + $caseObj->updateCase($caseData); + return true; + } catch (\Exception $e) { + $this->_logger->critical($e->__toString()); + return false; + } + } + + /** + * @param $case + * @param $order + * @return mixed + */ + public function processResponseStatus($case, $order) + { + $orderAction = array('action' => null, 'reason' => null); + $negativeAction = $this->scopeConfig->getValue('signifyd/advanced/guarantee_negative_action'); + $positiveAction = $this->scopeConfig->getValue('signifyd/advanced/guarantee_positive_action'); + + if ($case->getGuarantee() == 'DECLINED' && $negativeAction != 'nothing') { + $orderAction = array("action" => $negativeAction, "reason" => "guarantee declined"); + } else { + if ($case->getGuarantee() == 'APPROVED' && $positiveAction != 'nothing') { + $orderAction = array("action" => $positiveAction, "reason" => "guarantee approved"); + } + } + $caseData = array('order' => $order); + $caseObj = $this->objectManager->create('Signifyd\Connect\Model\Casedata'); + $result = $caseObj->updateOrder($caseData, $orderAction, $case); + return $result; + } +} \ No newline at end of file diff --git a/Helper/SignifydAPIMagento.php b/Helper/SignifydAPIMagento.php index b5e7a454..e5f067d7 100644 --- a/Helper/SignifydAPIMagento.php +++ b/Helper/SignifydAPIMagento.php @@ -1,6 +1,6 @@ _init('Signifyd\Connect\Model\ResourceModel\CaseRetry'); } + } diff --git a/Model/Casedata.php b/Model/Casedata.php index ab78d4da..bba7453e 100644 --- a/Model/Casedata.php +++ b/Model/Casedata.php @@ -1,18 +1,33 @@ _coreConfig = $coreConfig; + parent::__construct($context, $registry); + } + /** * Constructor * @@ -23,4 +38,191 @@ protected function _construct() parent::_construct(); $this->_init('Signifyd\Connect\Model\ResourceModel\Casedata'); } + + /** + * @param $caseData + * @return bool + */ + public function updateCase($caseData) + { + /** @var $case \Signifyd\Connect\Model\Casedata */ + $case = $caseData['case']; + $request = $caseData['request']; + $order = $caseData['order']; + $case->setMagentoStatus(CaseRetry::PROCESSING_RESPONSE_STATUS); + + $orderAction = array("action" => null, "reason" => ''); + if (isset($request->score) && $case->getScore() != $request->score) { + $case->setScore($request->score); + $order->setSignifydScore($request->score); + $orderAction = $this->handleScoreChange($caseData) ?: $orderAction; + } + + if (isset($request->status) && $case->getSignifydStatus() != $request->status) { + $case->setSignifydStatus($request->status); + $orderAction = $this->handleStatusChange($caseData) ?: $orderAction; + } + + if (isset($request->guaranteeDisposition) && $case->getGuarantee() != $request->guaranteeDisposition) { + $case->setGuarantee($request->guaranteeDisposition); + $order->setSignifydGuarantee($request->guaranteeDisposition); + $orderAction = $this->handleGuaranteeChange($caseData) ?: $orderAction; + } + + $case->setCode($request->caseId); + $case->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $order->setSignifydCode($request->caseId); + + try{ + $order->save(); + $case->save(); + $this->updateOrder($caseData, $orderAction, $case); + } catch (\Exception $e){ + $this->_logger->critical($e->__toString()); + return false; + } + + + return true; + } + + /** + * @param array $caseData + * @param string $orderAction + * @return bool + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function updateOrder($caseData, $orderAction, $case) + { + /** @var $order \Magento\Sales\Model\Order */ + $order = $caseData['order']; + switch ($orderAction["action"]) { + case "hold": + if ($order->canHold()) { + try { + $order->hold()->save(); + $case->setMagentoStatus(CaseRetry::COMPLETED_STATUS) + ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $case->save(); + } catch (\Exception $e){ + $this->_logger->debug($e->__toString()); + return false; + } + } else { + $case->setMagentoStatus(CaseRetry::COMPLETED_STATUS) + ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $case->save(); + } + break; + case "unhold": + if ($order->canUnhold()) { + try{ + $order->unhold()->save(); + $case->setMagentoStatus(CaseRetry::COMPLETED_STATUS) + ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $case->save(); + } catch (\Exception $e){ + $this->_logger->debug($e->__toString()); + return false; + } + } else { + $case->setMagentoStatus(CaseRetry::COMPLETED_STATUS) + ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $case->save(); + } + break; + case "cancel": + // Can't cancel if order is on hold + if ($order->canUnhold()) { + $order = $order->unhold(); + } + if ($order->canCancel()) { + try { + $order->cancel()->save(); + $case->setMagentoStatus(CaseRetry::COMPLETED_STATUS) + ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $case->save(); + } catch (\Exception $e) { + $this->_logger->debug($e->__toString()); + return false; + } + } else { + $case->setMagentoStatus(CaseRetry::COMPLETED_STATUS) + ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $case->save(); + } + break; + case null: + try { + $case->setMagentoStatus(CaseRetry::COMPLETED_STATUS) + ->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $case->save(); + } catch (\Exception $e) { + $this->_logger->debug($e->__toString()); + return false; + } + break; + } + if(!is_null($orderAction['action'])){ + $order->addStatusHistoryComment("Signifyd set status to {$orderAction["action"]} because {$orderAction["reason"]}"); + $order->save(); + } + + return true; + } + + /** + * @param $caseData + * @throws \Magento\Framework\Exception\LocalizedException + * @return string + */ + protected function handleScoreChange($caseData) + { + $threshHold = (int)$this->_coreConfig->getValue('signifyd/advanced/hold_orders_threshold'); + $holdBelowThreshold = $this->_coreConfig->getValue('signifyd/advanced/hold_orders'); + if ($holdBelowThreshold && $caseData['request']->score <= $threshHold) { + return array("action" => "hold", "reason" => "score threshold failure"); + } + return null; + } + + /** + * @param $caseData + * @throws \Magento\Framework\Exception\LocalizedException + * @return string + */ + protected function handleStatusChange($caseData) + { + $holdBelowThreshold = $this->_coreConfig->getValue('signifyd/advanced/hold_orders'); + if ($holdBelowThreshold && $caseData['request']->reviewDisposition == 'FRAUDULENT') { + return array("action" => "hold", "reason" => "review returned FRAUDULENT"); + } else { + if ($holdBelowThreshold && $caseData['request']->reviewDisposition == 'GOOD') { + return array("action" => "unhold", "reason" => "review returned GOOD"); + } + } + return null; + } + + /** + * @param $caseData + * @throws \Magento\Framework\Exception\LocalizedException + * @return string + */ + protected function handleGuaranteeChange($caseData) + { + $negativeAction = $this->_coreConfig->getValue('signifyd/advanced/guarantee_negative_action'); + $positiveAction = $this->_coreConfig->getValue('signifyd/advanced/guarantee_positive_action'); + + $request = $caseData['request']; + if ($request->guaranteeDisposition == 'DECLINED' && $negativeAction != 'nothing') { + return array("action" => $negativeAction, "reason" => "guarantee declined"); + } else { + if ($request->guaranteeDisposition == 'APPROVED' && $positiveAction != 'nothing') { + return array("action" => $positiveAction, "reason" => "guarantee approved"); + } + } + return null; + } + } diff --git a/Model/ResourceModel/CaseRetry.php b/Model/ResourceModel/CaseRetry.php index 33d42d88..d70f6f82 100644 --- a/Model/ResourceModel/CaseRetry.php +++ b/Model/ResourceModel/CaseRetry.php @@ -1,6 +1,6 @@ _init('Signifyd\Connect\Model\Casedata', 'Signifyd\Connect\Model\ResourceModel\Casedata'); + } + +} \ No newline at end of file diff --git a/Model/WebhookLink.php b/Model/WebhookLink.php index 82a99228..84f03447 100644 --- a/Model/WebhookLink.php +++ b/Model/WebhookLink.php @@ -1,6 +1,6 @@ _helper->processOrderData($order); // Add order to database - $this->_helper->createNewCase($order); + $case = $this->_helper->createNewCase($order); // Post case to signifyd service - $this->_helper->postCaseToSignifyd($orderData, $order); + $result = $this->_helper->postCaseToSignifyd($orderData, $order); + if($result){ + $case->setCode($result); + $case->setMagentoStatus(CaseRetry::IN_REVIEW_STATUS)->setUpdated(strftime('%Y-%m-%d %H:%M:%S', time())); + $case->save(); + } } catch (\Exception $ex) { $this->_logger->error($ex->getMessage()); } diff --git a/Setup/InstallSchema.php b/Setup/InstallSchema.php index 1ed9cdcf..341e6f9e 100644 --- a/Setup/InstallSchema.php +++ b/Setup/InstallSchema.php @@ -1,6 +1,6 @@ getVersion(), '1.3.5') < 0) { + // Get table Name + $tableName = $setup->getTable('signifyd_connect_case'); + // Check if the table already exists + if ($setup->getConnection()->isTableExists($tableName)) { + // Declare data + $columns = [ + 'magento_status' => [ + 'type' => Table::TYPE_TEXT, + 'LENGTH' => 255, + 'default' => 'waiting_submission', + 'nullable' => false, + 'comment' => 'Magento Status', + ] + ]; + + $connection = $setup->getConnection(); + foreach ($columns as $name => $definition) { + $connection->addColumn($tableName, $name, $definition); + } + + } + } + $setup->endSetup(); } } diff --git a/Ui/Component/Listing/Columns/CaseLink.php b/Ui/Component/Listing/Columns/CaseLink.php index 216d05e9..312d6851 100644 --- a/Ui/Component/Listing/Columns/CaseLink.php +++ b/Ui/Component/Listing/Columns/CaseLink.php @@ -1,6 +1,6 @@ - * * * * * + */15 * * * * diff --git a/etc/module.xml b/etc/module.xml index 51aa2182..af5f8381 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -5,7 +5,7 @@ */ --> - +