diff --git a/Model/Observer/HoldPlacedOrderObserver.php b/Model/Observer/HoldPlacedOrderObserver.php new file mode 100644 index 0000000..f5a1e4b --- /dev/null +++ b/Model/Observer/HoldPlacedOrderObserver.php @@ -0,0 +1,27 @@ +getEvent()->getOrder(); + + $this->placedOrderHolder->hold($order); + } +} diff --git a/Plugin/OrderCancellation.php b/Plugin/OrderCancellation.php new file mode 100644 index 0000000..99d070a --- /dev/null +++ b/Plugin/OrderCancellation.php @@ -0,0 +1,127 @@ +quoteRepository->get((int) $cartId); + + $payment = $quote->getPayment(); + + // Abort if the payment method is not relevant. + if ($payment->getMethod() !== 'affirm_gateway') { + throw $e; + } + + $errorMessagePrefix = 'Unable to cancel payment: '; + + /** @var \Magento\Sales\Model\Order|null */ + $order = $this->placedOrderHolder->retrieve(); + + // Abort if the order object is not available + if (!$order) { + throw new RuntimeException( + $errorMessagePrefix . "Order data unavailable. Reserved order ID: {$quote->getReservedOrderId()}", + $e->getCode(), + $e + ); + } + + // Abort if the order object is not relevant for transaction. + if ($order->getIncrementId() !== $quote->getReservedOrderId()) { + throw new RuntimeException( + $errorMessagePrefix . "Available order data ({$order->getIncrementId()}, {$order->getId()}) doesn't match the quote value: {$quote->getReservedOrderId()}", + $e->getCode(), + $e + ); + } + + // Cancel the order in case when it was saved. + if ($order->getId()) { + $order->cancel(); + + $this->orderRepository->save($order); + + throw $e; + } + + /** @var \Magento\Sales\Model\Order\Payment|null */ + $orderPayment = $order->getPayment(); + + // Abort if the order lacks payment information. + if (!$orderPayment) { + throw $e; + } + + $methodInstance = $orderPayment->getMethodInstance(); + $methodInstance->setStore($order->getStoreId()); + + $errorMessage = ""; + + if (!$methodInstance->canRefund()) { + $errorMessage = "Transaction can not be refunded."; + } + + if (!$orderPayment->getCreatedTransaction()) { + $errorMessage = "Transaction information is missing."; + } + + if (!$orderPayment->getCreatedInvoice()) { + $errorMessage = "Invoice is missing."; + } + + if ($errorMessage) { + throw new RuntimeException( + $errorMessagePrefix . $errorMessage, + $e->getCode(), + $e + ); + } + + $creditmemo = $this->creditmemoFactory->createByOrder($order); + $creditmemo->setInvoice($orderPayment->getCreatedInvoice()); + + $orderPayment->setCreditmemo($creditmemo); + $orderPayment->setParentTransactionId($orderPayment->getCreatedTransaction()->getTxnId()); + + $methodInstance->refund($orderPayment, $orderPayment->getAmountPaid()); + + throw $e; + } + } +} diff --git a/Service/PlacedOrderHolder.php b/Service/PlacedOrderHolder.php new file mode 100644 index 0000000..d55710a --- /dev/null +++ b/Service/PlacedOrderHolder.php @@ -0,0 +1,26 @@ +order) { + throw new \DomainException('Order is already held'); + } + + $this->order = $order; + } + + public function retrieve(): ?OrderInterface + { + return $this->order; + } +} diff --git a/etc/di.xml b/etc/di.xml index b040202..ac5965b 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -321,6 +321,10 @@ + + + + diff --git a/etc/events.xml b/etc/events.xml index 808bddb..3b0508d 100644 --- a/etc/events.xml +++ b/etc/events.xml @@ -16,4 +16,8 @@ + + +