From 752f83b842b985d7d371ecf7565a7665fd99a40b Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 5 Mar 2025 14:59:28 +0100 Subject: [PATCH 1/8] [ECP-9593] Implement an abstract handler for order status history --- .../AbstractOrderStatusHistoryHandler.php | 55 +++++++++++++++++++ Helper/OrderStatusHistory.php | 37 +++++++++++++ etc/di.xml | 28 ++++++++-- 3 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 Gateway/Response/AbstractOrderStatusHistoryHandler.php create mode 100644 Helper/OrderStatusHistory.php diff --git a/Gateway/Response/AbstractOrderStatusHistoryHandler.php b/Gateway/Response/AbstractOrderStatusHistoryHandler.php new file mode 100644 index 000000000..01d26bf5a --- /dev/null +++ b/Gateway/Response/AbstractOrderStatusHistoryHandler.php @@ -0,0 +1,55 @@ + + */ + +namespace Adyen\Payment\Gateway\Response; + +use Adyen\AdyenException; +use Adyen\Payment\Helper\OrderStatusHistory; +use Magento\Payment\Gateway\Helper\SubjectReader; +use Magento\Payment\Gateway\Response\HandlerInterface; + +class AbstractOrderStatusHistoryHandler implements HandlerInterface +{ + /** + * @param string $eventType Indicates the API call event type (authorization, capture etc.) + * @param OrderStatusHistory $orderStatusHistoryHelper + */ + public function __construct( + protected readonly string $eventType, + protected readonly OrderStatusHistory $orderStatusHistoryHelper + ) { } + + /** + * @throws AdyenException + */ + public function handle(array $handlingSubject, array $responseCollection): void + { + if (empty($this->eventType)) { + throw new AdyenException( + __('Order status history can not be handled due to missing event type!') + ); + } + + $readPayment = SubjectReader::readPayment($handlingSubject); + $payment = $readPayment->getPayment(); + $order = $payment->getOrder(); + + // Temporary workaround to clean-up `hasOnlyGiftCards` key. It needs to be handled separately. + if (isset($responseCollection['hasOnlyGiftCards'])) { + unset($responseCollection['hasOnlyGiftCards']); + } + + foreach ($responseCollection as $response) { + $comment = $this->orderStatusHistoryHelper->buildComment($response, $this->eventType); + $order->addCommentToStatusHistory($comment, $order->getStatus()); + } + } +} diff --git a/Helper/OrderStatusHistory.php b/Helper/OrderStatusHistory.php new file mode 100644 index 000000000..795d040b5 --- /dev/null +++ b/Helper/OrderStatusHistory.php @@ -0,0 +1,37 @@ + + */ + +namespace Adyen\Payment\Helper; + +class OrderStatusHistory +{ + public function buildComment(array $response, string $actionName): String + { + $comment = __("Adyen %1 API response:", $actionName) . '
'; + + if (isset($response['resultCode'])) { + $comment .= __("Result Code: %1", $response['resultCode']) . '
'; + } + + // Modification responses contain `status` but not `resultCode`. + if (isset($response['status'])) { + $comment .= __("Status: %1", $response['status']) . '
'; + } + + if (isset($response['pspReference'])) { + $comment .= __("PSP reference: %1", $response['pspReference']); + } + + $comment .= '
'; + + return $comment; + } +} diff --git a/etc/di.xml b/etc/di.xml index 7f7dc2329..93b0d4e7f 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -1334,11 +1334,31 @@ Adyen\Payment\Gateway\Response\CheckoutPaymentsDetailsHandler Adyen\Payment\Gateway\Response\VaultDetailsHandler - Adyen\Payment\Gateway\Response\CheckoutPaymentCommentHistoryHandler + AdyenPaymentAuthorisationOrderStatusHistoryHandler Adyen\Payment\Gateway\Response\StateDataHandler + + + authorisation + + + + + capture + + + + + refund + + + + + cancellation + + @@ -1359,7 +1379,7 @@ Adyen\Payment\Gateway\Response\PaymentCaptureDetailsHandler - Adyen\Payment\Gateway\Response\PaymentCommentHistoryHandler + AdyenPaymentCaptureOrderStatusHistoryHandler @@ -1367,7 +1387,7 @@ Adyen\Payment\Gateway\Response\PaymentRefundDetailsHandler - Adyen\Payment\Gateway\Response\PaymentCommentHistoryRefundHandler + AdyenPaymentRefundOrderStatusHistoryHandler @@ -1375,7 +1395,7 @@ Adyen\Payment\Gateway\Response\PaymentCancelDetailsHandler - Adyen\Payment\Gateway\Response\PaymentCommentHistoryHandler + AdyenPaymentCancellationOrderStatusHistoryHandler From e505f017e238d6e80f43f83007240f5019cd00fb Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 10 Mar 2025 14:29:27 +0100 Subject: [PATCH 2/8] [ECP-9593] Revert changes related to CAPTURE response handler --- etc/di.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/di.xml b/etc/di.xml index 93b0d4e7f..6d52bc461 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -1379,7 +1379,7 @@ Adyen\Payment\Gateway\Response\PaymentCaptureDetailsHandler - AdyenPaymentCaptureOrderStatusHistoryHandler + Adyen\Payment\Gateway\Response\PaymentCommentHistoryHandler From 7b8d2139c4111d59db6356bf9555f2cb56cc463c Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 10 Mar 2025 14:30:05 +0100 Subject: [PATCH 3/8] [ECP-9593] Implement comment builder for webhooks --- Helper/PaymentResponseHandler.php | 115 ++++++++++++------------------ 1 file changed, 45 insertions(+), 70 deletions(-) diff --git a/Helper/PaymentResponseHandler.php b/Helper/PaymentResponseHandler.php index d74b3e1d6..218d31c1c 100644 --- a/Helper/PaymentResponseHandler.php +++ b/Helper/PaymentResponseHandler.php @@ -12,6 +12,7 @@ namespace Adyen\Payment\Helper; use Adyen\Model\Checkout\CancelOrderRequest; +use Adyen\Payment\Helper\Order as AdyenOrderHelper; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\ResourceModel\PaymentResponse\CollectionFactory as PaymentResponseCollectionFactory; use Exception; @@ -50,48 +51,35 @@ class PaymentResponseHandler ]; /** - * @var AdyenLogger + * @param AdyenLogger $adyenLogger + * @param Vault $vaultHelper + * @param Order $orderResourceModel + * @param Data $dataHelper + * @param Quote $quoteHelper + * @param AdyenOrderHelper $orderHelper + * @param OrderRepository $orderRepository + * @param HistoryFactory $orderHistoryFactory + * @param StateData $stateDataHelper + * @param PaymentResponseCollectionFactory $paymentResponseCollectionFactory + * @param Config $configHelper + * @param PaymentMethods $paymentMethodsHelper + * @param OrderStatusHistory $orderStatusHistoryHelper */ - private AdyenLogger $adyenLogger; - private Vault $vaultHelper; - private Order $orderResourceModel; - private Data $dataHelper; - private Quote $quoteHelper; - private \Adyen\Payment\Helper\Order $orderHelper; - private OrderRepository $orderRepository; - private HistoryFactory $orderHistoryFactory; - private StateData $stateDataHelper; - private PaymentResponseCollectionFactory $paymentResponseCollectionFactory; - private Config $configHelper; - private PaymentMethods $paymentMethodsHelper; - public function __construct( - AdyenLogger $adyenLogger, - Vault $vaultHelper, - Order $orderResourceModel, - Data $dataHelper, - Quote $quoteHelper, - \Adyen\Payment\Helper\Order $orderHelper, - OrderRepository $orderRepository, - HistoryFactory $orderHistoryFactory, - StateData $stateDataHelper, - PaymentResponseCollectionFactory $paymentResponseCollectionFactory, - Config $configHelper, - PaymentMethods $paymentMethodsHelper - ) { - $this->adyenLogger = $adyenLogger; - $this->vaultHelper = $vaultHelper; - $this->orderResourceModel = $orderResourceModel; - $this->dataHelper = $dataHelper; - $this->quoteHelper = $quoteHelper; - $this->orderHelper = $orderHelper; - $this->orderRepository = $orderRepository; - $this->orderHistoryFactory = $orderHistoryFactory; - $this->stateDataHelper = $stateDataHelper; - $this->paymentResponseCollectionFactory = $paymentResponseCollectionFactory; - $this->configHelper = $configHelper; - $this->paymentMethodsHelper = $paymentMethodsHelper; - } + private readonly AdyenLogger $adyenLogger, + private readonly Vault $vaultHelper, + private readonly Order $orderResourceModel, + private readonly Data $dataHelper, + private readonly Quote $quoteHelper, + private readonly AdyenOrderHelper $orderHelper, + private readonly OrderRepository $orderRepository, + private readonly HistoryFactory $orderHistoryFactory, + private readonly StateData $stateDataHelper, + private readonly PaymentResponseCollectionFactory $paymentResponseCollectionFactory, + private readonly Config $configHelper, + private readonly PaymentMethods $paymentMethodsHelper, + private readonly OrderStatusHistory $orderStatusHistoryHelper + ) { } public function formatPaymentResponse( string $resultCode, @@ -170,23 +158,6 @@ public function handlePaymentsDetailsResponse( return false; } - $paymentMethod = $paymentsDetailsResponse['paymentMethod']['brand'] ?? - $paymentsDetailsResponse['paymentMethod']['type'] ?? - ''; - - $pspReference = isset($paymentsDetailsResponse['pspReference']) ? - trim((string) $paymentsDetailsResponse['pspReference']) : - ''; - - $type = 'Adyen paymentsDetails response:'; - $comment = __( - '%1
authResult: %2
pspReference: %3
paymentMethod: %4', - $type, - $authResult, - $pspReference, - $paymentMethod - ); - $resultCode = $paymentsDetailsResponse['resultCode']; if (!empty($resultCode)) { $payment->setAdditionalInformation('resultCode', $resultCode); @@ -234,9 +205,15 @@ public function handlePaymentsDetailsResponse( * Otherwise keep the order state as pending_payment. */ $order = $this->orderHelper->setStatusOrderCreation($order); - $this->orderRepository->save($order); } + // Add order status history comment for /payments/details API response + $comment = $this->orderStatusHistoryHelper->buildApiResponseComment( + $paymentsDetailsResponse, + 'payments/details' + ); + $order->addCommentToStatusHistory($comment, $order->getStatus()); + // Cleanup state data if exists. try { $this->stateDataHelper->cleanQuoteStateData($order->getQuoteId(), $authResult); @@ -244,6 +221,10 @@ public function handlePaymentsDetailsResponse( $this->adyenLogger->error(__('Error cleaning the payment state data: %s', $exception->getMessage())); } + $paymentMethod = $paymentsDetailsResponse['paymentMethod']['brand'] ?? + $paymentsDetailsResponse['paymentMethod']['type'] ?? + ''; + switch ($resultCode) { case self::AUTHORISED: if (!empty($paymentsDetailsResponse['pspReference'])) { @@ -273,16 +254,18 @@ public function handlePaymentsDetailsResponse( // do nothing wait for the notification if (strpos((string) $paymentMethod, "bankTransfer") !== false) { - $comment .= "

Waiting for the customer to transfer the money."; + $pendingComment = "Waiting for the customer to transfer the money."; } elseif ($paymentMethod == "sepadirectdebit") { - $comment .= "

This request will be send to the bank at the end of the day."; + $pendingComment = "This request will be send to the bank at the end of the day."; } else { - $comment .= "

The payment result is not confirmed (yet). + $pendingComment = "The payment result is not confirmed (yet).
Once the payment is authorised, the order status will be updated accordingly.
If the order is stuck on this status, the payment can be seen as unsuccessful.
The order can be automatically cancelled based on the OFFER_CLOSED notification. Please contact Adyen Support to enable this."; } + + $order->addCommentToStatusHistory($pendingComment, $order->getStatus()); $this->adyenLogger->addAdyenResult('Do nothing wait for the notification'); $result = true; @@ -318,7 +301,7 @@ public function handlePaymentsDetailsResponse( if ($order->canCancel()) { // Proceed to set cancellation action flag and cancel the order $order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_CANCEL, true); - $this->dataHelper->cancelOrder($order); + $this->dataHelper->cancelOrder($order, $resultCode); } else { $this->adyenLogger->addAdyenResult('The order cannot be cancelled'); } @@ -337,14 +320,6 @@ public function handlePaymentsDetailsResponse( break; } - $history = $this->orderHistoryFactory->create() - ->setStatus($order->getStatus()) - ->setComment($comment) - ->setEntityName('order') - ->setOrder($order); - - $history->save(); - // needed because then we need to save $order objects $order->setAdyenResulturlEventCode($authResult); $this->orderResourceModel->save($order); From 848d53e8744a51802ae998fc706a4cbb3566ca50 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 10 Mar 2025 14:30:20 +0100 Subject: [PATCH 4/8] [ECP-9593] Refactor the renamed method --- Gateway/Response/AbstractOrderStatusHistoryHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gateway/Response/AbstractOrderStatusHistoryHandler.php b/Gateway/Response/AbstractOrderStatusHistoryHandler.php index 01d26bf5a..536c187a9 100644 --- a/Gateway/Response/AbstractOrderStatusHistoryHandler.php +++ b/Gateway/Response/AbstractOrderStatusHistoryHandler.php @@ -48,7 +48,7 @@ public function handle(array $handlingSubject, array $responseCollection): void } foreach ($responseCollection as $response) { - $comment = $this->orderStatusHistoryHelper->buildComment($response, $this->eventType); + $comment = $this->orderStatusHistoryHelper->buildApiResponseComment($response, $this->eventType); $order->addCommentToStatusHistory($comment, $order->getStatus()); } } From 37dcfde8109c94a9b6d86fe959ab0e2d54c2dfb3 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 10 Mar 2025 14:30:47 +0100 Subject: [PATCH 5/8] [ECP-9593] Improve order cancellation message and add optional reason --- Helper/Data.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Helper/Data.php b/Helper/Data.php index b5116c956..34cdb2048 100755 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -561,8 +561,9 @@ public function getLiveEndpointPrefix($storeId = null) * Cancels the order * * @param $order + * @param null $reason */ - public function cancelOrder($order) + public function cancelOrder($order, $reason = null) { $orderStatus = $this->configHelper->getAdyenAbstractConfigData('payment_cancelled'); $order->setActionFlag($orderStatus, true); @@ -577,12 +578,11 @@ public function cancelOrder($order) if ($order->canCancel()) { if ($this->orderManagement->cancel($order->getEntityId())) { //new canceling process try { - $orderStatusHistory = $this->orderStatusHistoryFactory->create() - ->setParentId($order->getEntityId()) - ->setEntityName('order') - ->setStatus(Order::STATE_CANCELED) - ->setComment(__('Order has been cancelled by "%1" payment response.', $order->getPayment()->getMethod())); - $this->orderManagement->addComment($order->getEntityId(), $orderStatusHistory); + $comment = __('Order has been cancelled.', $order->getPayment()->getMethod()); + if ($reason) { + $comment .= '
' . __("Reason: %1", $reason) . '
'; + } + $order->addCommentToStatusHistory($comment, $order->getStatus()); } catch (Exception $e) { $this->adyenLogger->addAdyenDebug( __('Order cancel history comment error: %1', $e->getMessage()), From a0785659d34e380fe056e6d945c60ccfb971028f Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 10 Mar 2025 14:31:23 +0100 Subject: [PATCH 6/8] [ECP-9593] Add comment builder for webhooks --- Helper/OrderStatusHistory.php | 113 ++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 5 deletions(-) diff --git a/Helper/OrderStatusHistory.php b/Helper/OrderStatusHistory.php index 795d040b5..a56633ad9 100644 --- a/Helper/OrderStatusHistory.php +++ b/Helper/OrderStatusHistory.php @@ -11,14 +11,34 @@ namespace Adyen\Payment\Helper; +use Adyen\Payment\Api\Data\NotificationInterface; +use Adyen\Payment\Model\Notification; +use Magento\Sales\Api\Data\OrderInterface; + class OrderStatusHistory { - public function buildComment(array $response, string $actionName): String + /** + * @param ChargedCurrency $chargedCurrencyHelper + * @param Data $adyenHelper + */ + public function __construct( + private readonly ChargedCurrency $chargedCurrencyHelper, + private readonly Data $adyenHelper + ) { } + + /** + * Builds the order status history comment based on the Checkout API response + * + * @param array $response + * @param string $actionName + * @return string + */ + public function buildApiResponseComment(array $response, string $actionName): string { - $comment = __("Adyen %1 API response:", $actionName) . '
'; + $comment = '' . __("Adyen %1 response", $actionName) . '
'; if (isset($response['resultCode'])) { - $comment .= __("Result Code: %1", $response['resultCode']) . '
'; + $comment .= __("Result code: %1", $response['resultCode']) . '
'; } // Modification responses contain `status` but not `resultCode`. @@ -27,11 +47,94 @@ public function buildComment(array $response, string $actionName): String } if (isset($response['pspReference'])) { - $comment .= __("PSP reference: %1", $response['pspReference']); + $comment .= __("PSP reference: %1", $response['pspReference']) . '
'; + } + + if ($paymentMethod = $response['paymentMethod']['brand'] ?? $response['paymentMethod']['type'] ?? null) { + $comment .= __("Payment method: %1", $paymentMethod) . '
'; } - $comment .= '
'; + if (isset($response['refusalReason'])) { + $comment .= __("Refusal reason: %1", $response['refusalReason']) . '
'; + } + + if (isset($response['errorCode'])) { + $comment .= __("Error code: %1", $response['errorCode']) . '
'; + } return $comment; } + + /** + * Builds the order status history comment based on the webhook + * + * @param OrderInterface $order + * @param NotificationInterface $notification + * @param string|null $klarnaReservationNumber + * @return string + */ + public function buildWebhookComment( + OrderInterface $order, + NotificationInterface $notification, + ?string $klarnaReservationNumber = null, + ): string { + $comment = '' . __( + "Adyen %1%2 webhook", + $this->getIsWebhookForPartialPayment($order, $notification) ? 'partial ': '', + $notification->getEventCode() + ) . '
'; + + if (!empty($notification->getPspreference())) { + $comment .= __("PSP reference: %1", $notification->getPspreference()) . '
'; + } + + if (!empty($notification->getPaymentMethod())) { + $comment .= __("Payment method: %1", $notification->getPaymentMethod()) . '
'; + } + + if (!empty($notification->getSuccess())) { + $status = $notification->isSuccessful() ? 'Successful' : 'Failed'; + $comment .= __("Event status: %1", $status) . '
'; + } + + if (!empty($notification->getReason())) { + $comment .= __("Reason: %1", $notification->getReason()) . '
'; + } + + if (isset($klarnaReservationNumber)) { + $comment .= __("Reservation number: %1", $klarnaReservationNumber) . '
'; + } + + return $comment; + } + + /** + * Identifies whether if the notification belongs to a partial modification or not + * + * @param OrderInterface $order + * @param NotificationInterface $notification + * @return bool + */ + private function getIsWebhookForPartialPayment( + OrderInterface $order, + NotificationInterface $notification + ): bool { + $isPartial = false; + + if (in_array($notification->getEventCode(), [Notification::REFUND, Notification::CAPTURE])) { + // check if it is a full or partial refund + $amount = $notification->getAmountValue(); + $orderAmountCurrency = $this->chargedCurrencyHelper->getOrderAmountCurrency($order, false); + $formattedOrderAmount = $this->adyenHelper->formatAmount( + $orderAmountCurrency->getAmount(), + $orderAmountCurrency->getCurrencyCode() + ); + + if ($amount !== $formattedOrderAmount) { + $isPartial = true; + } + } + + return $isPartial; + } } From 04d85016a2175a55c9e1a30a993b78d370ae355d Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 10 Mar 2025 14:32:21 +0100 Subject: [PATCH 7/8] [ECP-9593] Improve object handling on capture webhook handling process and revisit the comments --- Helper/Invoice.php | 17 +++-- Helper/Webhook.php | 83 ++---------------------- Helper/Webhook/CaptureWebhookHandler.php | 8 +-- 3 files changed, 22 insertions(+), 86 deletions(-) diff --git a/Helper/Invoice.php b/Helper/Invoice.php index 75183d1fd..30e6df3f4 100644 --- a/Helper/Invoice.php +++ b/Helper/Invoice.php @@ -219,11 +219,11 @@ public function createAdyenInvoice( * * @param Order $order * @param Notification $notification - * @return AdyenInvoice + * @return array + * @throws AdyenWebhookException * @throws AlreadyExistsException - * @throws Exception */ - public function handleCaptureWebhook(Order $order, Notification $notification): AdyenInvoice + public function handleCaptureWebhook(Order $order, Notification $notification): array { $invoiceFactory = $this->adyenInvoiceFactory->create(); $adyenInvoice = $this->adyenInvoiceResourceModel->getAdyenInvoiceByCaptureWebhook($order, $notification); @@ -280,12 +280,19 @@ public function handleCaptureWebhook(Order $order, Notification $notification): $magentoInvoice = $this->magentoInvoiceFactory->create()->load($adyenInvoiceObject->getInvoiceId()); if ($this->isFullInvoiceAmountManuallyCaptured($magentoInvoice)) { + /* + * Magento Invoice updates the Order object while paying the invoice. This creates two divergent + * Order objects. In the downstream, some information might be missing due to setting them on the + * wrong order object as the Order might be already updated in the upstream without persisting + * it to the database. Setting the order again on the Invoice makes sure we are dealing + * with the same order object always. + */ + $magentoInvoice->setOrder($order); $magentoInvoice->pay(); $this->invoiceRepository->save($magentoInvoice); - $this->magentoOrderResourceModel->save($magentoInvoice->getOrder()); } - return $adyenInvoiceObject; + return [$adyenInvoiceObject, $magentoInvoice, $order]; } /** diff --git a/Helper/Webhook.php b/Helper/Webhook.php index ddaac33fb..57b2b10db 100644 --- a/Helper/Webhook.php +++ b/Helper/Webhook.php @@ -51,34 +51,28 @@ class Webhook 'payment_authorized' => [Order::STATE_PROCESSING] ]; - // TODO::This property is not written but only is read. Check the usage. - private $boletoPaidAmount; private ?string $klarnaReservationNumber; private ?string $ratepayDescriptor; /** - * @param Data $adyenHelper * @param SerializerInterface $serializer * @param TimezoneInterface $timezone * @param Config $configHelper - * @param ChargedCurrency $chargedCurrency * @param AdyenLogger $logger * @param WebhookHandlerFactory $webhookHandlerFactory * @param OrderHelper $orderHelper * @param OrderRepository $orderRepository - * @param PaymentMethods $paymentMethodsHelper + * @param OrderStatusHistory $orderStatusHistoryHelper */ public function __construct( - private readonly Data $adyenHelper, private readonly SerializerInterface $serializer, private readonly TimezoneInterface $timezone, private readonly ConfigHelper $configHelper, - private readonly ChargedCurrency $chargedCurrency, private readonly AdyenLogger $logger, private readonly WebhookHandlerFactory $webhookHandlerFactory, private readonly OrderHelper $orderHelper, private readonly OrderRepository $orderRepository, - private readonly PaymentMethods $paymentMethodsHelper + private readonly OrderStatusHistory $orderStatusHistoryHelper ) { $this->klarnaReservationNumber = null; $this->ratepayDescriptor = null; @@ -287,76 +281,17 @@ private function declareVariables(Notification $notification): void private function addNotificationDetailsHistoryComment(Order $order, Notification $notification): Order { - $successResult = $notification->isSuccessful() ? 'true' : 'false'; - $reason = $notification->getReason(); - $success = (!empty($reason)) ? "$successResult
reason:$reason" : $successResult; - - $payment = $order->getPayment(); - $paymentMethodInstance = $payment->getMethodInstance(); - - $eventCode = $notification->getEventCode(); - if ($eventCode == Notification::REFUND || $eventCode == Notification::CAPTURE) { - // check if it is a full or partial refund - $amount = $notification->getAmountValue(); - $orderAmountCurrency = $this->chargedCurrency->getOrderAmountCurrency($order, false); - $formattedOrderAmount = $this->adyenHelper - ->formatAmount($orderAmountCurrency->getAmount(), $orderAmountCurrency->getCurrencyCode()); - - if ($amount == $formattedOrderAmount) { - $order->setData( - 'adyen_notification_event_code', - $eventCode . " : " . strtoupper($successResult) - ); - } else { - $order->setData( - 'adyen_notification_event_code', - "(PARTIAL) " . - $eventCode . " : " . strtoupper($successResult) - ); - } - } else { - $order->setData( - 'adyen_notification_event_code', - $eventCode . " : " . strtoupper($successResult) - ); - } - - // if payment method is klarna, ratepay or openinvoice/afterpay show the reservartion number - if ($this->paymentMethodsHelper->isOpenInvoice($paymentMethodInstance) && - !empty($this->klarnaReservationNumber)) { - $klarnaReservationNumberText = "
reservationNumber: " . $this->klarnaReservationNumber; - } else { - $klarnaReservationNumberText = ""; - } - - if ($this->boletoPaidAmount != null && $this->boletoPaidAmount != "") { - $boletoPaidAmountText = "
Paid amount: " . $this->boletoPaidAmount; - } else { - $boletoPaidAmountText = ""; - } - - $type = 'Adyen HTTP Notification(s):'; - $comment = __( - '%1
eventCode: %2
pspReference: %3
paymentMethod: %4
' . - ' success: %5 %6 %7', - $type, - $eventCode, - $notification->getPspreference(), - $notification->getPaymentMethod(), - $success, - $klarnaReservationNumberText, - $boletoPaidAmountText - ); + $comment = $this->orderStatusHistoryHelper->buildWebhookComment($order, $notification); // If notification is pending status and pending status is set add the status change to the comment history - if ($eventCode == Notification::PENDING) { + if ($notification->getEventCode() == Notification::PENDING) { $pendingStatus = $this->configHelper->getConfigData( 'pending_status', 'adyen_abstract', $order->getStoreId() ); if ($pendingStatus != "") { - $order->addStatusHistoryComment($comment, $pendingStatus); + $order->addCommentToStatusHistory($comment, $pendingStatus); $this->logger->addAdyenNotification( 'Created comment history for this notification with status change to: ' . $pendingStatus, array_merge( @@ -368,7 +303,7 @@ private function addNotificationDetailsHistoryComment(Order $order, Notification } } - $order->addStatusHistoryComment($comment, $order->getStatus()); + $order->addCommentToStatusHistory($comment, $order->getStatus()); $this->logger->addAdyenNotification( 'Created comment history for this notification', [ @@ -465,10 +400,6 @@ private function updateOrderPaymentWithAdyenAttributes( ); } - if ($this->boletoPaidAmount != "") { - $payment->setAdditionalInformation('adyen_boleto_paid_amount', $this->boletoPaidAmount); - } - if ($this->ratepayDescriptor !== "") { $payment->setAdditionalInformation( 'adyen_ratepay_descriptor', @@ -521,7 +452,7 @@ private function setNotificationError(Notification $notification, string $errorM private function addNotificationErrorComment(Order $order, string $errorMessage): Order { $comment = __('The order failed to update: %1', $errorMessage); - $order->addStatusHistoryComment($comment, $order->getStatus()); + $order->addCommentToStatusHistory($comment, $order->getStatus()); $this->orderRepository->save($order); return $order; } diff --git a/Helper/Webhook/CaptureWebhookHandler.php b/Helper/Webhook/CaptureWebhookHandler.php index 77914f851..9504a60b2 100644 --- a/Helper/Webhook/CaptureWebhookHandler.php +++ b/Helper/Webhook/CaptureWebhookHandler.php @@ -93,10 +93,9 @@ public function handleWebhook(MagentoOrder $order, Notification $notification, s return $order; } - // TODO Get functionality out of the invoiceHelper function, so we don't have to fetch the order from the db - $adyenInvoice = $this->invoiceHelper->handleCaptureWebhook($order, $notification); - // Refresh the order by fetching it from the db - $order = $this->orderHelper->fetchOrderByIncrementId($notification); + list($adyenInvoice, $magentoInvoice, $order) = + $this->invoiceHelper->handleCaptureWebhook($order, $notification); + $adyenOrderPayment = $this->adyenOrderPaymentFactory->create()->load($adyenInvoice->getAdyenPaymentOrderId(), OrderPaymentInterface::ENTITY_ID); $this->adyenOrderPaymentHelper->refreshPaymentCaptureStatus($adyenOrderPayment, $notification->getAmountCurrency()); $this->adyenLogger->addAdyenNotification( @@ -112,7 +111,6 @@ public function handleWebhook(MagentoOrder $order, Notification $notification, s ] ); - $magentoInvoice = $this->magentoInvoiceFactory->create()->load($adyenInvoice->getInvoiceId(), MagentoInvoice::ENTITY_ID); $this->adyenLogger->addAdyenNotification( sprintf('Notification %s updated invoice {invoiceId}', $notification->getEntityId()), array_merge( From e58a17c287e06818f3fc4674b5fd252504bd5e81 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 10 Mar 2025 15:30:14 +0100 Subject: [PATCH 8/8] [ECP-9593] Remove CheckoutPaymentCommentHistoryHandler class --- .../CheckoutPaymentCommentHistoryHandler.php | 47 ------- .../CheckoutPaymentsDetailsHandler.php | 4 + ...eckoutPaymentCommentHistoryHandlerTest.php | 122 ------------------ etc/di.xml | 1 - 4 files changed, 4 insertions(+), 170 deletions(-) delete mode 100644 Gateway/Response/CheckoutPaymentCommentHistoryHandler.php delete mode 100644 Test/Unit/Gateway/Response/CheckoutPaymentCommentHistoryHandlerTest.php diff --git a/Gateway/Response/CheckoutPaymentCommentHistoryHandler.php b/Gateway/Response/CheckoutPaymentCommentHistoryHandler.php deleted file mode 100644 index 1fc333259..000000000 --- a/Gateway/Response/CheckoutPaymentCommentHistoryHandler.php +++ /dev/null @@ -1,47 +0,0 @@ - - */ - -namespace Adyen\Payment\Gateway\Response; - -use Magento\Payment\Gateway\Helper\SubjectReader; -use Magento\Payment\Gateway\Response\HandlerInterface; - -class CheckoutPaymentCommentHistoryHandler implements HandlerInterface -{ - /** - * @param array $handlingSubject - * @param array $responseCollection - * @return $this - */ - public function handle(array $handlingSubject, array $responseCollection): self - { - $readPayment = SubjectReader::readPayment($handlingSubject); - $payment = $readPayment->getPayment(); - $comment = __("Adyen Result response:"); - - foreach ($responseCollection as $response) { - $responseCode = $response['resultCode'] ?? $response['response'] ?? ''; - - if (!empty($responseCode)) { - $comment .= '
' . __('authResult:') . ' ' . $responseCode; - $payment->getOrder()->setAdyenResulturlEventCode($responseCode); - } - - if (isset($response['pspReference'])) { - $comment .= '
' . __('pspReference:') . ' ' . $response['pspReference']; - } - $comment .= '
'; - } - - $payment->getOrder()->addStatusHistoryComment($comment, $payment->getOrder()->getStatus()); - return $this; - } -} diff --git a/Gateway/Response/CheckoutPaymentsDetailsHandler.php b/Gateway/Response/CheckoutPaymentsDetailsHandler.php index 1731b7db1..495bd480d 100644 --- a/Gateway/Response/CheckoutPaymentsDetailsHandler.php +++ b/Gateway/Response/CheckoutPaymentsDetailsHandler.php @@ -69,6 +69,10 @@ public function handle(array $handlingSubject, array $responseCollection) $payment->setTransactionId($response['pspReference']); } + if (isset($response['resultCode'])) { + $payment->getOrder()->setAdyenResulturlEventCode($response['resultCode']); + } + // do not close transaction, so you can do a cancel() and void $payment->setIsTransactionClosed(false); $payment->setShouldCloseParentTransaction(false); diff --git a/Test/Unit/Gateway/Response/CheckoutPaymentCommentHistoryHandlerTest.php b/Test/Unit/Gateway/Response/CheckoutPaymentCommentHistoryHandlerTest.php deleted file mode 100644 index fc6f90b54..000000000 --- a/Test/Unit/Gateway/Response/CheckoutPaymentCommentHistoryHandlerTest.php +++ /dev/null @@ -1,122 +0,0 @@ -checkoutPaymentCommentHistoryHandler = new CheckoutPaymentCommentHistoryHandler(); - - $orderAdapterMock = $this->createMock(OrderAdapterInterface::class); - $this->orderMock = $this->createMock(Order::class); - - $this->paymentMock = $this->createMock(Payment::class); - $this->paymentMock->method('getOrder')->willReturn($this->orderMock); - $this->paymentDataObject = new PaymentDataObject($orderAdapterMock, $this->paymentMock); - - $this->handlingSubject = [ - 'payment' => $this->paymentDataObject, - 'paymentAction' => "authorize", - 'stateObject' => null - ]; - } - public function testIfGeneralFlowIsHandledCorrectly() - { - // Prepare the sample response collection - $responseCollection = [ - 'hasOnlyGiftCards' => false, - 0 => [ - 'additionalData' => [], - 'amount' => [], - 'resultCode' => 'Authorised', - 'pspReference' => 'MDH54321', - 'paymentMethod' => [ - 'name' => 'giftcard', - 'type' => 'Givex', - ], - ], - 1 => [ - 'additionalData' => [], - 'amount' => [], - 'resultCode' => 'Authorised', - 'pspReference' => 'ABC12345', - 'paymentMethod' => [ - 'name' => 'card', - 'type' => 'CreditCard', - ], - ], - ]; - - // Set expectations for the mocked order object - $this->orderMock - ->expects($this->once()) - ->method('addStatusHistoryComment') - ->with( - $this->stringContains( - "authResult: Authorised
pspReference: MDH54321
" . - "
authResult: Authorised
pspReference: ABC12345
" - ), - $this->anything() - ); - - $this->checkoutPaymentCommentHistoryHandler->handle($this->handlingSubject, $responseCollection); - } - - public function testIfEmptyResponseCodeIsHandledCorrectly() - { - // Prepare a sample response collection without a resultCode - $responseCollection = [ - [ - 'pspReference' => '123456789' - ] - ]; - - // Set expectations for the mocked order object - $this->orderMock - ->expects($this->once()) - ->method('addStatusHistoryComment') - ->with( - $this->stringContains('pspReference: 123456789'), - $this->anything() - ); - - // Execute the handler - $this->checkoutPaymentCommentHistoryHandler->handle($this->handlingSubject, $responseCollection); - } - - public function testIfNoPspReferenceIsHandledCorrectly() - { - // Prepare a sample response collection without a pspReference - $responseCollection = [ - [ - 'resultCode' => 'Authorised' - ] - ]; - - // Set expectations for the mocked order object - $this->orderMock - ->expects($this->once()) - ->method('addStatusHistoryComment') - ->with( - $this->stringContains('authResult: Authorised'), - $this->anything() - ); - - // Execute the handler - $this->checkoutPaymentCommentHistoryHandler->handle($this->handlingSubject, $responseCollection); - } -} diff --git a/etc/di.xml b/etc/di.xml index 6d52bc461..357694bbe 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -1364,7 +1364,6 @@ Adyen\Payment\Gateway\Response\CheckoutPaymentsDetailsHandler Adyen\Payment\Gateway\Response\VaultDetailsHandler - Adyen\Payment\Gateway\Response\CheckoutPaymentCommentHistoryHandler