diff --git a/Helper/Data.php b/Helper/Data.php index 5f3b0f6..6fdd3f5 100644 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -1265,4 +1265,28 @@ public function getConfigValue($key, $store, $storeCode=null) return $this->scopeConfig->getValue($path, $store, $storeCode); } + /** + * Checks if a transaction has already been processed based on the transaction additional info (JSON blob). + * + * @param $payment + * @param string $resultField The key in the transaction's additional information to check (e.g., 'settle_result'). + * @param string $expectedStatus The status value to check for (case-insensitive). + * @param bool $checkCaptured Optional. If true, also checks if the transaction is marked as captured. + * @return bool + */ + public function isTransactionProcessed($payment, $resultField, $expectedStatus, $checkCaptured = false){ + $transactionAdditionalInfo = $payment->getTransactionAdditionalInfo(); + $resultData = isset($transactionAdditionalInfo[$resultField]) + ? json_decode($transactionAdditionalInfo[$resultField], true) + : null; + + // Check if the status matches the expected value (case-insensitive) + $isProcessed = $resultData && strcasecmp($resultData['status'], $expectedStatus) === 0; + + if ($checkCaptured) { + $isProcessed = $isProcessed || !empty($transactionAdditionalInfo['captured']); + } + + return $isProcessed; + } } diff --git a/Model/Payment/Method/Bread.php b/Model/Payment/Method/Bread.php index 0711022..92a7ec1 100644 --- a/Model/Payment/Method/Bread.php +++ b/Model/Payment/Method/Bread.php @@ -254,6 +254,19 @@ public function void(\Magento\Payment\Model\InfoInterface $payment) throw new \Magento\Framework\Exception\LocalizedException(__('Void action is not available.')); } + $transactionAdditionalInfo = $payment->getTransactionAdditionalInfo(); + $cancelResult = isset($transactionAdditionalInfo['cancel_result']) + ? json_decode($transactionAdditionalInfo['cancel_result'], true) + : null; + + if ($this->helper->isTransactionProcessed($payment, $cancelResult, 'CANCELLED', true)) { + $this->breadLogger->info(sprintf( + 'Transaction ID %s has already cancelled. Skipping further processing.', + $payment->getTxnId() + )); + return $this; + } + return $this->_place($payment, 0, self::ACTION_VOID); } @@ -275,6 +288,19 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount throw new \Magento\Framework\Exception\LocalizedException(__('Authorize action is not available.')); } + $transactionAdditionalInfo = $payment->getTransactionAdditionalInfo(); + $authorizeResult = isset($transactionAdditionalInfo['authorize_result']) + ? json_decode($transactionAdditionalInfo['authorize_result'], true) + : null; + + if ($this->helper->isTransactionProcessed($payment, $authorizeResult, 'AUTHORIZED', true)) { + $this->breadLogger->info(sprintf( + 'Transaction ID %s has already authorized. Skipping further processing.', + $payment->getTxnId() + )); + return $this; + } + $order = $payment->getOrder(); if ($order->getOrderCurrencyCode() !== $order->getBaseCurrencyCode()) { $amount = $order->getGrandTotal(); @@ -375,11 +401,25 @@ public function canVoid() { public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) { if ($this->adminOrderHelper->isAdminOrder()) { - return; // Bypass logic for admin order creation + return $this; // Bypass logic for admin order creation } if (!$this->canCapture()) { throw new \Magento\Framework\Exception\LocalizedException(__('Capture action is not available.')); } + + $transactionAdditionalInfo = $payment->getTransactionAdditionalInfo(); + $settleResult = isset($transactionAdditionalInfo['settle_result']) + ? json_decode($transactionAdditionalInfo['settle_result'], true) + : null; + + if ($this->helper->isTransactionProcessed($payment, $settleResult, 'SETTLED', true)) { + $this->breadLogger->info(sprintf( + 'Transaction ID %s has already been captured and settled. Skipping further processing.', + $payment->getTxnId() + )); + return $this; + } + $apiVersion = $this->helper->getApiVersion(); $order = $payment->getOrder(); @@ -459,6 +499,19 @@ public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount) throw new \Magento\Framework\Exception\LocalizedException(__('Refund action is not available.')); } + $transactionAdditionalInfo = $payment->getTransactionAdditionalInfo(); + $refundResult = isset($transactionAdditionalInfo['refund_result']) + ? json_decode($transactionAdditionalInfo['refund_result'], true) + : null; + + if ($this->helper->isTransactionProcessed($payment, $refundResult, 'REFUNDED', true)) { + $this->breadLogger->info(sprintf( + 'Transaction ID %s has already refunded. Skipping further processing.', + $payment->getTxnId() + )); + return $this; + } + $order = $payment->getOrder(); if ($order->getOrderCurrencyCode() !== $order->getBaseCurrencyCode()) { $amount = $order->getGrandTotal(); diff --git a/Model/Payment/Method/Rbc.php b/Model/Payment/Method/Rbc.php index 6b4e2aa..cb4cd66 100644 --- a/Model/Payment/Method/Rbc.php +++ b/Model/Payment/Method/Rbc.php @@ -247,6 +247,19 @@ public function void(\Magento\Payment\Model\InfoInterface $payment) throw new \Magento\Framework\Exception\LocalizedException(__('Void action is not available.')); } + $transactionAdditionalInfo = $payment->getTransactionAdditionalInfo(); + $cancelResult = isset($transactionAdditionalInfo['cancel_result']) + ? json_decode($transactionAdditionalInfo['cancel_result'], true) + : null; + + if ($this->helper->isTransactionProcessed($payment, $cancelResult, 'CANCELLED', true)) { + $this->breadLogger->info(sprintf( + 'Transaction ID %s has already cancelled. Skipping further processing.', + $payment->getTxnId() + )); + return $this; + } + return $this->_place($payment, 0, self::ACTION_VOID); } @@ -265,6 +278,19 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount throw new \Magento\Framework\Exception\LocalizedException(__('Authorize action is not available.')); } + $transactionAdditionalInfo = $payment->getTransactionAdditionalInfo(); + $authorizeResult = isset($transactionAdditionalInfo['authorize_result']) + ? json_decode($transactionAdditionalInfo['authorize_result'], true) + : null; + + if ($this->helper->isTransactionProcessed($payment, $authorizeResult, 'AUTHORIZED', true)) { + $this->breadLogger->info(sprintf( + 'Transaction ID %s has already authorized. Skipping further processing.', + $payment->getTxnId() + )); + return $this; + } + $order = $payment->getOrder(); if ($order->getOrderCurrencyCode() !== $order->getBaseCurrencyCode()) { $amount = $order->getGrandTotal(); @@ -367,6 +393,20 @@ public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) if (!$this->canCapture()) { throw new \Magento\Framework\Exception\LocalizedException(__('Capture action is not available.')); } + + $transactionAdditionalInfo = $payment->getTransactionAdditionalInfo(); + $settleResult = isset($transactionAdditionalInfo['settle_result']) + ? json_decode($transactionAdditionalInfo['settle_result'], true) + : null; + + if ($this->helper->isTransactionProcessed($payment, $settleResult, 'SETTLED', true)) { + $this->breadLogger->info(sprintf( + 'Transaction ID %s has already been captured and settled. Skipping further processing.', + $payment->getTxnId() + )); + return $this; + } + $apiVersion = $this->helper->getApiVersion(); $order = $payment->getOrder(); @@ -443,6 +483,19 @@ public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount) throw new \Magento\Framework\Exception\LocalizedException(__('Refund action is not available.')); } + $transactionAdditionalInfo = $payment->getTransactionAdditionalInfo(); + $refundResult = isset($transactionAdditionalInfo['refund_result']) + ? json_decode($transactionAdditionalInfo['refund_result'], true) + : null; + + if ($this->helper->isTransactionProcessed($payment, $refundResult, 'REFUNDED', true)) { + $this->breadLogger->info(sprintf( + 'Transaction ID %s has already refunded. Skipping further processing.', + $payment->getTxnId() + )); + return $this; + } + $order = $payment->getOrder(); if ($order->getOrderCurrencyCode() !== $order->getBaseCurrencyCode()) { $amount = $order->getGrandTotal();