diff --git a/Api/CleanupAdditionalInformationInterface.php b/Api/CleanupAdditionalInformationInterface.php new file mode 100644 index 0000000000..02803eecbd --- /dev/null +++ b/Api/CleanupAdditionalInformationInterface.php @@ -0,0 +1,42 @@ + + */ + +namespace Adyen\Payment\Api; + +use Magento\Sales\Api\Data\OrderPaymentInterface; + +interface CleanupAdditionalInformationInterface +{ + const FIELD_ACTION = 'action'; + const FIELD_ADDITIONAL_DATA = 'additionalData'; + const FIELD_DONATION_TOKEN = 'donationToken'; + const FIELD_FRONTEND_TYPE = 'frontendType'; + const FIELD_COMBO_CARD_TYPE = 'combo_card_type'; + const FIELD_CC_TYPE = 'cc_type'; + const FIELD_RESULT_CODE = 'resultCode'; + + const FIELDS_TO_BE_CLEANED_UP = [ + self::FIELD_ACTION, + self::FIELD_ADDITIONAL_DATA, + self::FIELD_DONATION_TOKEN, + self::FIELD_FRONTEND_TYPE, + self::FIELD_COMBO_CARD_TYPE, + self::FIELD_CC_TYPE, + self::FIELD_RESULT_CODE + ]; + + /** + * @param OrderPaymentInterface $orderPayment + * @return OrderPaymentInterface + */ + public function execute(OrderPaymentInterface $orderPayment): OrderPaymentInterface; +} diff --git a/Gateway/Validator/CheckoutResponseValidator.php b/Gateway/Validator/CheckoutResponseValidator.php index b2e59bbc5a..d15848b90c 100644 --- a/Gateway/Validator/CheckoutResponseValidator.php +++ b/Gateway/Validator/CheckoutResponseValidator.php @@ -90,8 +90,6 @@ private function validateResponse($responseSubject): void $paymentDataObjectInterface = SubjectReader::readPayment($responseSubject); $payment = $paymentDataObjectInterface->getPayment(); - $payment->setAdditionalInformation('3dActive', false); - // Handle empty result for unexpected cases if (empty($response['resultCode'])) { $this->handleEmptyResultCode($response); diff --git a/Helper/Webhook.php b/Helper/Webhook.php index d7378666a7..5a5010a354 100644 --- a/Helper/Webhook.php +++ b/Helper/Webhook.php @@ -54,8 +54,6 @@ 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; @@ -355,23 +353,16 @@ private function addNotificationDetailsHistoryComment(Order $order, Notification $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', + ' success: %5 %6', $type, $eventCode, $notification->getPspreference(), $notification->getPaymentMethod(), $success, - $klarnaReservationNumberText, - $boletoPaidAmountText + $klarnaReservationNumberText ); // If notification is pending status and pending status is set add the status change to the comment history @@ -471,31 +462,10 @@ private function updateOrderPaymentWithAdyenAttributes( if (isset($additionalData['authCode'])) { $payment->setAdditionalInformation('adyen_auth_code', $additionalData['authCode']); } - if (isset($additionalData['cardBin'])) { - $payment->setAdditionalInformation('adyen_card_bin', $additionalData['cardBin']); - } - if (isset($additionalData['expiryDate'])) { - $payment->setAdditionalInformation('adyen_expiry_date', $additionalData['expiryDate']); - } - if (isset($additionalData['issuerCountry'])) { - $payment - ->setAdditionalInformation('adyen_issuer_country', $additionalData['issuerCountry']); - } $payment->setAdyenPspReference($notification->getPspreference()); $payment->setAdditionalInformation('pspReference', $notification->getPspreference()); - if ($this->klarnaReservationNumber != "") { - $payment->setAdditionalInformation( - 'adyen_klarna_number', - $this->klarnaReservationNumber - ); - } - - if ($this->boletoPaidAmount != "") { - $payment->setAdditionalInformation('adyen_boleto_paid_amount', $this->boletoPaidAmount); - } - - if ($this->ratepayDescriptor !== "") { + if (!empty($this->ratepayDescriptor)) { $payment->setAdditionalInformation( 'adyen_ratepay_descriptor', $this->ratepayDescriptor diff --git a/Helper/Webhook/AuthorisationWebhookHandler.php b/Helper/Webhook/AuthorisationWebhookHandler.php index 44bf330173..1a963b6136 100644 --- a/Helper/Webhook/AuthorisationWebhookHandler.php +++ b/Helper/Webhook/AuthorisationWebhookHandler.php @@ -12,6 +12,7 @@ namespace Adyen\Payment\Helper\Webhook; +use Adyen\Payment\Api\CleanupAdditionalInformationInterface; use Adyen\Payment\Api\Repository\AdyenNotificationRepositoryInterface; use Adyen\Payment\Helper\AdyenOrderPayment; use Adyen\Payment\Helper\CaseManagement; @@ -41,6 +42,7 @@ class AuthorisationWebhookHandler implements WebhookHandlerInterface * @param PaymentMethods $paymentMethodsHelper * @param CartRepositoryInterface $cartRepository * @param AdyenNotificationRepositoryInterface $notificationRepository + * @param CleanupAdditionalInformationInterface $cleanupAdditionalInformation */ public function __construct( private readonly AdyenOrderPayment $adyenOrderPaymentHelper, @@ -52,7 +54,8 @@ public function __construct( private readonly Invoice $invoiceHelper, private readonly PaymentMethods $paymentMethodsHelper, private readonly CartRepositoryInterface $cartRepository, - private readonly AdyenNotificationRepositoryInterface $notificationRepository + private readonly AdyenNotificationRepositoryInterface $notificationRepository, + private readonly CleanupAdditionalInformationInterface $cleanupAdditionalInformation ) { } /** @@ -113,6 +116,9 @@ private function handleSuccessfulAuthorisation(Order $order, Notification $notif // Set authorized amount in sales_order_payment $order->getPayment()->setAmountAuthorized($order->getGrandTotal()); $order->getPayment()->setBaseAmountAuthorized($order->getBaseGrandTotal()); + + // Clean-up the data temporarily stored in `additional_information` + $this->cleanupAdditionalInformation->execute($order->getPayment()); } else { $this->orderHelper->addWebhookStatusHistoryComment($order, $notification); } @@ -186,6 +192,9 @@ private function handleFailedAuthorisation(Order $order, Notification $notificat $order->setState(Order::STATE_NEW); } + // Clean-up the data temporarily stored in `additional_information` + $this->cleanupAdditionalInformation->execute($order->getPayment()); + return $this->orderHelper->holdCancelOrder($order, true); } @@ -200,7 +209,7 @@ private function handleAutoCapture(Order $order, Notification $notification, boo { $this->invoiceHelper->createInvoice($order, $notification, true); if ($requireFraudManualReview) { - $order = $this->caseManagementHelper->markCaseAsPendingReview($order, $notification->getPspreference(), true); + $order = $this->caseManagementHelper->markCaseAsPendingReview($order, $notification->getPspreference(), true); } else { $order = $this->orderHelper->finalizeOrder($order, $notification); } diff --git a/Helper/Webhook/CancelOrRefundWebhookHandler.php b/Helper/Webhook/CancelOrRefundWebhookHandler.php index ce5f989311..9272ede827 100644 --- a/Helper/Webhook/CancelOrRefundWebhookHandler.php +++ b/Helper/Webhook/CancelOrRefundWebhookHandler.php @@ -12,6 +12,7 @@ namespace Adyen\Payment\Helper\Webhook; +use Adyen\Payment\Api\CleanupAdditionalInformationInterface; use Adyen\Payment\Helper\CaseManagement; use Adyen\Payment\Helper\Order; use Adyen\Payment\Helper\PaymentMethods; @@ -25,24 +26,18 @@ class CancelOrRefundWebhookHandler implements WebhookHandlerInterface { const MODIFICATION_ACTION = 'modification.action'; - /** @var AdyenLogger */ - private $adyenLogger; - - /** @var SerializerInterface */ - private $serializer; - - /** @var Order */ - private $orderHelper; - + /** + * @param AdyenLogger $adyenLogger + * @param SerializerInterface $serializer + * @param Order $orderHelper + * @param CleanupAdditionalInformationInterface $cleanupAdditionalInformation + */ public function __construct( - AdyenLogger $adyenLogger, - SerializerInterface $serializer, - Order $orderHelper - ) { - $this->adyenLogger = $adyenLogger; - $this->serializer = $serializer; - $this->orderHelper = $orderHelper; - } + private readonly AdyenLogger $adyenLogger, + private readonly SerializerInterface $serializer, + private readonly Order $orderHelper, + private readonly CleanupAdditionalInformationInterface $cleanupAdditionalInformation + ) { } /** * @throws LocalizedException @@ -93,6 +88,9 @@ public function handleWebhook(MagentoOrder $order, Notification $notification, s } } + // Clean-up the data temporarily stored in `additional_information` + $this->cleanupAdditionalInformation->execute($order->getPayment()); + return $order; } diff --git a/Helper/Webhook/CancellationWebhookHandler.php b/Helper/Webhook/CancellationWebhookHandler.php index db77462186..fc3850b0f8 100644 --- a/Helper/Webhook/CancellationWebhookHandler.php +++ b/Helper/Webhook/CancellationWebhookHandler.php @@ -12,6 +12,7 @@ namespace Adyen\Payment\Helper\Webhook; +use Adyen\Payment\Api\CleanupAdditionalInformationInterface; use Adyen\Payment\Helper\Order; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\Notification; @@ -20,16 +21,16 @@ class CancellationWebhookHandler implements WebhookHandlerInterface { - private Order $orderHelper; - private AdyenLogger $adyenLogger; - + /** + * @param Order $orderHelper + * @param AdyenLogger $adyenLogger + * @param CleanupAdditionalInformationInterface $cleanupAdditionalInformation + */ public function __construct( - Order $orderHelper, - AdyenLogger $adyenLogger - ) { - $this->orderHelper = $orderHelper; - $this->adyenLogger = $adyenLogger; - } + private readonly Order $orderHelper, + private readonly AdyenLogger $adyenLogger, + private readonly CleanupAdditionalInformationInterface $cleanupAdditionalInformation + ) { } /** * @throws LocalizedException @@ -67,6 +68,9 @@ public function handleWebhook( ); } + // Clean-up the data temporarily stored in `additional_information` + $this->cleanupAdditionalInformation->execute($order->getPayment()); + return $order; } } diff --git a/Helper/Webhook/OfferClosedWebhookHandler.php b/Helper/Webhook/OfferClosedWebhookHandler.php index 3e135009d9..db1f3e0547 100644 --- a/Helper/Webhook/OfferClosedWebhookHandler.php +++ b/Helper/Webhook/OfferClosedWebhookHandler.php @@ -13,6 +13,7 @@ namespace Adyen\Payment\Helper\Webhook; use Adyen\AdyenException; +use Adyen\Payment\Api\CleanupAdditionalInformationInterface; use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Order; use Adyen\Payment\Helper\PaymentMethods; @@ -22,37 +23,24 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Sales\Model\Order as MagentoOrder; - class OfferClosedWebhookHandler implements WebhookHandlerInterface { - /** @var PaymentMethods */ - private $paymentMethodsHelper; - - /** @var AdyenLogger */ - private $adyenLogger; - - /** @var Config */ - private $configHelper; - - /** @var Order */ - private $orderHelper; - - /** @var OrderPaymentResourceModel */ - protected $orderPaymentResourceModel; - + /** + * @param PaymentMethods $paymentMethodsHelper + * @param AdyenLogger $adyenLogger + * @param Config $configHelper + * @param Order $orderHelper + * @param OrderPaymentResourceModel $orderPaymentResourceModel + * @param CleanupAdditionalInformationInterface $cleanupAdditionalInformation + */ public function __construct( - PaymentMethods $paymentMethodsHelper, - AdyenLogger $adyenLogger, - Config $configHelper, - Order $orderHelper, - OrderPaymentResourceModel $orderPaymentResourceModel - ) { - $this->paymentMethodsHelper = $paymentMethodsHelper; - $this->adyenLogger = $adyenLogger; - $this->configHelper = $configHelper; - $this->orderHelper = $orderHelper; - $this->orderPaymentResourceModel = $orderPaymentResourceModel; - } + private readonly PaymentMethods $paymentMethodsHelper, + private readonly AdyenLogger $adyenLogger, + private readonly Config $configHelper, + private readonly Order $orderHelper, + private readonly OrderPaymentResourceModel $orderPaymentResourceModel, + private readonly CleanupAdditionalInformationInterface $cleanupAdditionalInformation + ) { } /** * @throws LocalizedException @@ -116,6 +104,9 @@ public function handleWebhook(MagentoOrder $order, Notification $notification, s $order->setState(MagentoOrder::STATE_NEW); } + // Clean-up the data temporarily stored in `additional_information` + $this->cleanupAdditionalInformation->execute($order->getPayment()); + $this->orderHelper->holdCancelOrder($order, true); return $order; diff --git a/Helper/Webhook/OrderClosedWebhookHandler.php b/Helper/Webhook/OrderClosedWebhookHandler.php index 385ab48083..4a3ff5d5b8 100644 --- a/Helper/Webhook/OrderClosedWebhookHandler.php +++ b/Helper/Webhook/OrderClosedWebhookHandler.php @@ -12,6 +12,7 @@ namespace Adyen\Payment\Helper\Webhook; +use Adyen\Payment\Api\CleanupAdditionalInformationInterface; use Adyen\Payment\Api\Data\OrderPaymentInterface; use Adyen\Payment\Helper\AdyenOrderPayment; use Adyen\Payment\Helper\Config; @@ -24,48 +25,24 @@ class OrderClosedWebhookHandler implements WebhookHandlerInterface { - /** @var AdyenOrderPayment */ - private $adyenOrderPaymentHelper; - - /** @var OrderHelper */ - private $orderHelper; - - /** @var Config */ - private $configHelper; - - /** @var AdyenLogger */ - private $adyenLogger; - - /** @var OrderPaymentCollectionFactory */ - private $adyenOrderPaymentCollectionFactory; - /** - * @var SerializerInterface - */ - private $serializer; - - /** - * @param AdyenOrderPayment $adyenOrderPayment + * @param AdyenOrderPayment $adyenOrderPaymentHelper * @param OrderHelper $orderHelper * @param Config $configHelper * @param OrderPaymentCollectionFactory $adyenOrderPaymentCollectionFactory * @param AdyenLogger $adyenLogger + * @param SerializerInterface $serializer + * @param CleanupAdditionalInformationInterface $cleanupAdditionalInformation */ public function __construct( - AdyenOrderPayment $adyenOrderPayment, - OrderHelper $orderHelper, - Config $configHelper, - OrderPaymentCollectionFactory $adyenOrderPaymentCollectionFactory, - AdyenLogger $adyenLogger, - SerializerInterface $serializer - ) { - $this->adyenOrderPaymentHelper = $adyenOrderPayment; - $this->orderHelper = $orderHelper; - $this->configHelper = $configHelper; - $this->adyenOrderPaymentCollectionFactory = $adyenOrderPaymentCollectionFactory; - $this->adyenLogger = $adyenLogger; - $this->serializer = $serializer; - } + private readonly AdyenOrderPayment $adyenOrderPaymentHelper, + private readonly OrderHelper $orderHelper, + private readonly Config $configHelper, + private readonly OrderPaymentCollectionFactory $adyenOrderPaymentCollectionFactory, + private readonly AdyenLogger $adyenLogger, + private readonly SerializerInterface $serializer, + private readonly CleanupAdditionalInformationInterface $cleanupAdditionalInformation + ) { } /** * @param MagentoOrder $order @@ -168,6 +145,9 @@ public function handleWebhook( ] ); } + + // Clean-up the data temporarily stored in `additional_information` + $this->cleanupAdditionalInformation->execute($order->getPayment()); } return $order; diff --git a/Model/AdyenNotificationRepository.php b/Model/AdyenNotificationRepository.php index 2542dcd83c..90dacb78f3 100644 --- a/Model/AdyenNotificationRepository.php +++ b/Model/AdyenNotificationRepository.php @@ -48,7 +48,8 @@ public function deleteByIds(array $entityIds): void */ public function save(NotificationInterface $entity): NotificationInterface { - $this->resourceModel->save($entity); + $resource = $this->objectManager->get($this->resourceModel); + $resource->save($entity); return $entity; } diff --git a/Model/CleanupAdditionalInformation.php b/Model/CleanupAdditionalInformation.php new file mode 100644 index 0000000000..a628f12114 --- /dev/null +++ b/Model/CleanupAdditionalInformation.php @@ -0,0 +1,52 @@ + + */ + +namespace Adyen\Payment\Model; + +use Adyen\Payment\Api\CleanupAdditionalInformationInterface; +use Adyen\Payment\Logger\AdyenLogger; +use Exception; +use Magento\Sales\Api\Data\OrderPaymentInterface; + +class CleanupAdditionalInformation implements CleanupAdditionalInformationInterface +{ + /** + * @param AdyenLogger $adyenLogger + */ + public function __construct( + private readonly AdyenLogger $adyenLogger + ) { } + + /** + * This method cleans-up the unnecessary fields in `additional_information` of OrderPayment object. + * + * @param OrderPaymentInterface $orderPayment + * @return OrderPaymentInterface + */ + public function execute(OrderPaymentInterface $orderPayment): OrderPaymentInterface + { + try { + foreach (self::FIELDS_TO_BE_CLEANED_UP as $field) { + $orderPayment->unsAdditionalInformation($field); + } + } catch (Exception $e) { + $this->adyenLogger->error( + sprintf( + "An error occurred while trying to cleanup additional information: %s", + $e->getMessage() + ) + ); + } + + return $orderPayment; + } +} diff --git a/Test/Unit/Helper/Webhook/AuthorisationWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/AuthorisationWebhookHandlerTest.php index 0e4f43d4a1..6429b5cfe8 100644 --- a/Test/Unit/Helper/Webhook/AuthorisationWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/AuthorisationWebhookHandlerTest.php @@ -2,9 +2,13 @@ namespace Adyen\Payment\Test\Unit\Helper\Webhook; +use Adyen\Payment\Api\CleanupAdditionalInformationInterface; use Adyen\Payment\Api\Repository\AdyenNotificationRepositoryInterface; use Adyen\Payment\Helper\AdyenOrderPayment; use Adyen\Payment\Model\AdyenAmountCurrency; +use Adyen\Payment\Model\Ui\AdyenCcConfigProvider; +use Adyen\Payment\Model\Ui\AdyenCcConfigProviderTest; +use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Adyen\Payment\Helper\Webhook\AuthorisationWebhookHandler; use Adyen\Payment\Model\Notification; @@ -135,7 +139,7 @@ public function testHandleSuccessfulAuthorisation($isAutoCapture): void ]); // Create mock instances for Order and Notification - $paymentMock = $this->createMock(Order::class); + $paymentMock = $this->createMock(Order\Payment::class); $storeId = 1; $this->orderMock->method('getStoreId')->willReturn($storeId); $this->orderMock->method('getPayment')->willReturn($paymentMock); @@ -189,7 +193,7 @@ public function testHandleSuccessfulAuthorisation($isAutoCapture): void /** * @throws ReflectionExceptionAlias */ - public function testHandleFailedAuthorisation(): void + public function testHandleFailedAuthorisationAlreadyProcessed(): void { $this->orderMock->expects($this->atLeastOnce()) ->method('getData') @@ -216,6 +220,41 @@ public function testHandleFailedAuthorisation(): void $this->assertInstanceOf(Order::class, $result); } + /** + * @throws ReflectionExceptionAlias + */ + public function testHandleFailedAuthorisation(): void + { + $orderPayment = $this->createMock(Order\Payment::class); + $orderPayment->method('getMethod')->willReturn(AdyenCcConfigProvider::CODE); + + $this->orderMock->method('getPayment')->willReturn($orderPayment); + + $this->orderMock->expects($this->atLeastOnce()) + ->method('getData') + ->willReturnMap([ + ['adyen_notification_event_code', null, false], + ['adyen_notification_payment_captured', null, false] + ]); + + // Create an instance of AuthorisationWebhookHandler + $webhookHandler = $this->createAuthorisationWebhookHandler(); + + $handleFailedAuthorisationMethod = $this->getPrivateMethod( + AuthorisationWebhookHandler::class, + 'handleFailedAuthorisation' + ); + + // Call the private method directly and provide required parameters + $result = $handleFailedAuthorisationMethod->invokeArgs( + $webhookHandler, + [$this->orderMock, $this->notificationMock] + ); + + // Assert the expected behavior based on the mocked logic and result + $this->assertInstanceOf(Order::class, $result); + } + /** * @throws ReflectionExceptionAlias */ @@ -380,7 +419,8 @@ protected function createAuthorisationWebhookHandler( $mockInvoiceHelper = null, $mockPaymentMethodsHelper = null, $mockCartRepositoryMock = null, - $adyenNotificationRepositoryMock = null + $adyenNotificationRepositoryMock = null, + $cleanupAdditionalInformation = null ): AuthorisationWebhookHandler { if (is_null($mockAdyenOrderPayment)) { $mockAdyenOrderPayment = $this->createMock(AdyenOrderPayment::class); @@ -417,10 +457,15 @@ protected function createAuthorisationWebhookHandler( if (is_null($mockCartRepositoryMock)) { $mockCartRepositoryMock = $this->createMock(CartRepositoryInterface::class); } + if (is_null($adyenNotificationRepositoryMock)) { $adyenNotificationRepositoryMock = $this->createMock(AdyenNotificationRepositoryInterface::class); } + if (is_null($cleanupAdditionalInformation)) { + $cleanupAdditionalInformation = $this->createMock(CleanupAdditionalInformationInterface::class); + } + return new AuthorisationWebhookHandler( $mockAdyenOrderPayment, $mockOrderHelper, @@ -431,7 +476,8 @@ protected function createAuthorisationWebhookHandler( $mockInvoiceHelper, $mockPaymentMethodsHelper, $mockCartRepositoryMock, - $adyenNotificationRepositoryMock + $adyenNotificationRepositoryMock, + $cleanupAdditionalInformation ); } } diff --git a/Test/Unit/Helper/Webhook/CancelOrRefundWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/CancelOrRefundWebhookHandlerTest.php index 457ec5a357..d24a0fc843 100644 --- a/Test/Unit/Helper/Webhook/CancelOrRefundWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/CancelOrRefundWebhookHandlerTest.php @@ -3,12 +3,14 @@ namespace Adyen\Payment\Test\Unit\Helper\Webhook; use Adyen\Payment\Helper\Webhook\CancelOrRefundWebhookHandler; +use Adyen\Payment\Model\CleanupAdditionalInformation; use Adyen\Payment\Model\Notification; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Adyen\Payment\Helper\Order as OrderHelper; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Webhook\PaymentStates; use Magento\Framework\Serialize\SerializerInterface; +use Magento\Quote\Api\Data\PaymentInterface; use Magento\Sales\Model\Order; class CancelOrRefundWebhookHandlerTest extends AbstractAdyenTestCase @@ -32,10 +34,13 @@ public function testHandleWebhookWithCancel(){ $notificationMock = $this->createMock(Notification::class); $orderId = 123; + $paymentMock = $this->createMock(Order\Payment::class); + $this->orderMock->method('getIncrementId')->willReturn($orderId); $this->orderMock->method('isCanceled')->willReturn(false); $this->orderMock->method('getState')->willReturn(Order::STATE_NEW); $this->orderMock->method('canCancel')->willReturn(true); + $this->orderMock->method('getPayment')->willReturn($paymentMock); $this->adyenLoggerMock->expects($this->once()) ->method('addAdyenNotification') @@ -61,11 +66,14 @@ public function testHandleWebhookWithRefund() $notificationMock = $this->createMock(Notification::class); $orderId = 123; + $paymentMock = $this->createMock(Order\Payment::class); + $this->orderMock->method('getIncrementId')->willReturn($orderId); $this->orderMock->method('isCanceled')->willReturn(false); $this->orderMock->method('getState')->willReturn(Order::STATE_NEW); $this->orderMock->method('canCancel')->willReturn(false); $this->orderMock->method('canHold')->willReturn(false); + $this->orderMock->method('getPayment')->willReturn($paymentMock); $this->adyenLoggerMock->expects($this->once()) ->method('addAdyenNotification') @@ -116,10 +124,13 @@ public function testHandleWebhookWithOrderAlreadyCanceled() $notificationMock = $this->createMock(Notification::class); $orderId = 123; + $paymentMock = $this->createMock(Order\Payment::class); + $this->orderMock->method('getIncrementId')->willReturn($orderId); $this->orderMock->method('isCanceled')->willReturn(true); $this->orderMock->method('getState')->willReturn(Order::STATE_NEW); $this->orderMock->method('canCancel')->willReturn(false); + $this->orderMock->method('getPayment')->willReturn($paymentMock); $this->adyenLoggerMock->expects($this->once()) ->method('addAdyenNotification') @@ -131,7 +142,7 @@ public function testHandleWebhookWithOrderAlreadyCanceled() ] ); - $webhookHandler = $this->createCancelOrRefundWebhookHandler($this->adyenLoggerMock,null,null); + $webhookHandler = $this->createCancelOrRefundWebhookHandler($this->adyenLoggerMock); $transitionState = PaymentStates::STATE_CANCELLED; @@ -143,7 +154,9 @@ public function testHandleWebhookWithOrderAlreadyCanceled() protected function createCancelOrRefundWebhookHandler( $mockAdyenLogger = null, $mockSerializer = null, - $mockOrderHelper = null + $mockOrderHelper = null, + $cleanupAdditionalInformation = null + ): CancelOrRefundWebhookHandler { if (is_null($mockAdyenLogger)) { @@ -155,11 +168,15 @@ protected function createCancelOrRefundWebhookHandler( if (is_null($mockOrderHelper)) { $mockOrderHelper = $this->createMock(OrderHelper::class); } + if (is_null($cleanupAdditionalInformation)) { + $cleanupAdditionalInformation = $this->createMock(CleanupAdditionalInformation::class); + } return new CancelOrRefundWebhookHandler( $mockAdyenLogger, $mockSerializer, - $mockOrderHelper + $mockOrderHelper, + $cleanupAdditionalInformation ); } diff --git a/Test/Unit/Helper/Webhook/CancellationWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/CancellationWebhookHandlerTest.php new file mode 100644 index 0000000000..d0fb57194f --- /dev/null +++ b/Test/Unit/Helper/Webhook/CancellationWebhookHandlerTest.php @@ -0,0 +1,68 @@ + + */ +namespace Adyen\Payment\Test\Unit\Helper\Webhook; + +use Adyen\Payment\Api\CleanupAdditionalInformationInterface; +use Adyen\Payment\Helper\Order; +use Adyen\Payment\Helper\Webhook\CancellationWebhookHandler; +use Adyen\Payment\Logger\AdyenLogger; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Adyen\Webhook\PaymentStates; +use Magento\Sales\Model\ResourceModel\Order\Invoice\Collection as InvoiceCollection; +use PHPUnit\Framework\MockObject\MockObject; +use Magento\Sales\Model\Order as MagentoOrder; + +class CancellationWebhookHandlerTest extends AbstractAdyenTestCase +{ + protected ?CancellationWebhookHandler $cancellationWebhookHandler; + protected Order|MockObject $orderHelperMock; + protected AdyenLogger|MockObject $adyenLoggerMock; + protected CleanupAdditionalInformationInterface|MockObject $cleanupAdditionalInformationMock; + + protected function setUp(): void + { + $this->orderHelperMock = $this->createMock(Order::class); + $this->adyenLoggerMock = $this->createMock(AdyenLogger::class); + $this->cleanupAdditionalInformationMock = $this->createMock(CleanupAdditionalInformationInterface::class); + + $this->cancellationWebhookHandler = new CancellationWebhookHandler( + $this->orderHelperMock, + $this->adyenLoggerMock, + $this->cleanupAdditionalInformationMock + ); + } + + protected function tearDown(): void + { + $this->cancellationWebhookHandler = null; + } + + public function testHandleWebhook(): void + { + $paymentMock = $this->createMock(MagentoOrder\Payment::class); + + $orderMock = $this->createMock(MagentoOrder::class); + $orderMock->method('getPayment')->willReturn($paymentMock); + $orderMock->expects($this->once()) + ->method('getInvoiceCollection') + ->willReturn([]); + + $this->orderHelperMock->expects($this->once())->method('holdCancelOrder')->willReturn($orderMock); + + $notificationMock = $this->createWebhook(); + $transitionState = PaymentStates::STATE_CANCELLED; + + $this->cleanupAdditionalInformationMock->expects($this->once())->method('execute'); + + $result = $this->cancellationWebhookHandler->handleWebhook($orderMock, $notificationMock, $transitionState); + $this->assertInstanceOf(MagentoOrder::class, $result); + } +} diff --git a/Test/Unit/Helper/Webhook/OfferClosedWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/OfferClosedWebhookHandlerTest.php index bff5cc75ec..c3d7f40d09 100644 --- a/Test/Unit/Helper/Webhook/OfferClosedWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/OfferClosedWebhookHandlerTest.php @@ -7,6 +7,7 @@ use Adyen\Payment\Helper\Order; use Adyen\Payment\Helper\PaymentMethods; use Adyen\Payment\Logger\AdyenLogger; +use Adyen\Payment\Model\CleanupAdditionalInformation; use Adyen\Payment\Model\Method\Adapter; use Adyen\Payment\Model\Notification; use Adyen\Payment\Model\ResourceModel\Order\Payment as OrderPaymentResourceModel; @@ -102,7 +103,13 @@ public function testHandleWebhookReturnsOrderWhenCapturedPaymentsExist() $this->orderPaymentResourceModel->method('getLinkedAdyenOrderPayments')->willReturn(['payment1', 'payment2']); // Create an instance of the OfferClosedWebhookHandler - $webhookHandler = $this->createOfferClosedWebhookHandler(null,null,null,null,$this->orderPaymentResourceModel); + $webhookHandler = $this->createOfferClosedWebhookHandler( + null, + null, + null, + null, + $this->orderPaymentResourceModel + ); // Call the handleWebhook method and assert that it returns the order $result = $webhookHandler->handleWebhook($order, $notification, 'PAYMENT_REVIEW'); @@ -114,7 +121,8 @@ protected function createOfferClosedWebhookHandler( $mockAdyenLogger = null, $mockConfigHelper = null, $mockOrderHelper = null, - $mockOrderPaymentResourceModel = null + $mockOrderPaymentResourceModel = null, + $cleanupAdditionalInformation = null ): OfferClosedWebhookHandler { if (is_null($mockOrderPaymentResourceModel)) { @@ -137,13 +145,17 @@ protected function createOfferClosedWebhookHandler( $mockPaymentMethodsHelper = $this->createMock(PaymentMethods::class); } + if (is_null($cleanupAdditionalInformation)) { + $cleanupAdditionalInformation = $this->createMock(CleanupAdditionalInformation::class); + } + return new OfferClosedWebhookHandler( $mockPaymentMethodsHelper, $mockAdyenLogger, $mockConfigHelper, $mockOrderHelper, - $mockOrderPaymentResourceModel + $mockOrderPaymentResourceModel, + $cleanupAdditionalInformation ); } - } diff --git a/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php index e5d9d5cbd3..a364705db7 100644 --- a/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php @@ -2,6 +2,7 @@ namespace Adyen\Payment\Test\Unit\Helper; +use Adyen\Payment\Model\CleanupAdditionalInformation; use Adyen\Payment\Model\ResourceModel\Order\Payment\Collection; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\Serialize\SerializerInterface; @@ -31,6 +32,7 @@ class OrderClosedWebhookHandlerTest extends AbstractAdyenTestCase private Collection $adyenOrderPaymentCollectionMock; private Order\Payment $adyenOrderPaymentMock; private OrderPaymentInterface $adyenOrderPaymentInterfaceMock; + private CleanupAdditionalInformation $cleanupAdditionalInformationMock; protected function setUp(): void { @@ -42,6 +44,7 @@ protected function setUp(): void $this->configHelperMock = $this->createMock(Config::class); $this->adyenLoggerMock = $this->createMock(AdyenLogger::class); $this->adyenOrderPaymentCollectionFactoryMock = $this->createGeneratedMock(OrderPaymentCollectionFactory::class, ['create']); + $this->cleanupAdditionalInformationMock = $this->createMock(CleanupAdditionalInformation::class); $this->adyenOrderPaymentMock = $this->createConfiguredMock(Order\Payment::class, [ 'getId' => 123 @@ -54,7 +57,8 @@ protected function setUp(): void $this->configHelperMock, $this->adyenOrderPaymentCollectionFactoryMock, $this->adyenLoggerMock, - $this->serializerMock + $this->serializerMock, + $this->cleanupAdditionalInformationMock ); } @@ -94,7 +98,7 @@ public function testHandleWebhookUnsuccessfulNotificationWithRefund() { $this->notificationMock->expects($this->once())->method('isSuccessful')->willReturn(false); - $this->orderMock->expects($this->once())->method('getPayment')->willReturn( + $this->orderMock->expects($this->exactly(2))->method('getPayment')->willReturn( $this->createConfiguredMock(MagentoOrderPaymentInterface::class, ['getEntityId' => 123]) ); diff --git a/Test/Unit/Helper/WebhookTest.php b/Test/Unit/Helper/WebhookTest.php index 527b7ab36e..c662dbeed3 100644 --- a/Test/Unit/Helper/WebhookTest.php +++ b/Test/Unit/Helper/WebhookTest.php @@ -572,13 +572,12 @@ public function testUpdateOrderPaymentWithAdyenAttributes() $method = $reflection->getMethod('updateOrderPaymentWithAdyenAttributes'); $method->setAccessible(true); - $paymentMock->expects($this->exactly(4)) + $paymentMock->expects($this->exactly(3)) ->method('setAdditionalInformation') ->willReturnMap([ ['adyen_avs_result', 'avs_result_value', $paymentMock], ['adyen_cvc_result', 'cvc_result_value', $paymentMock], - ['pspReference', 'pspReference', $paymentMock], - ['adyen_ratepay_descriptor', $this->anything(), $paymentMock], + ['pspReference', 'pspReference', $paymentMock] ]); $method->invokeArgs($webhook, [$paymentMock, $notificationMock, $additionalData]); diff --git a/Test/Unit/Model/AdyenNotificationRepositoryTest.php b/Test/Unit/Model/AdyenNotificationRepositoryTest.php index 89dd326218..fe61017aec 100644 --- a/Test/Unit/Model/AdyenNotificationRepositoryTest.php +++ b/Test/Unit/Model/AdyenNotificationRepositoryTest.php @@ -11,7 +11,9 @@ namespace Adyen\Payment\Test\Helper\Unit\Model; +use Adyen\Payment\Api\Data\NotificationInterface; use Adyen\Payment\Model\AdyenNotificationRepository; +use Adyen\Payment\Model\Notification as NotificationModel; use Adyen\Payment\Model\ResourceModel\Notification; use Adyen\Payment\Model\ResourceModel\Notification\CollectionFactory; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; @@ -80,4 +82,23 @@ public function testDeleteByIdsEmptyValues() $this->adyenNotificationRepository->deleteByIds($entityIds); } + + public function testSave() + { + $notification = $this->createMock(NotificationModel::class); + $resourceModel = $this->createMock(Notification::class); + + $resourceModel->expects($this->once()) + ->method('save') + ->with($notification) + ->willReturnSelf(); + + $this->objectManagerMock->expects($this->once()) + ->method('get') + ->with(self::RESOURCE_MODEL) + ->willReturn($resourceModel); + + $result = $this->adyenNotificationRepository->save($notification); + $this->assertInstanceOf(NotificationInterface::class, $result); + } } diff --git a/Test/Unit/Model/CleanupAdditionalInformationTest.php b/Test/Unit/Model/CleanupAdditionalInformationTest.php new file mode 100644 index 0000000000..687673aed9 --- /dev/null +++ b/Test/Unit/Model/CleanupAdditionalInformationTest.php @@ -0,0 +1,61 @@ + + */ + +namespace Adyen\Payment\Test\Helper\Unit\Model; + +use Adyen\Payment\Api\CleanupAdditionalInformationInterface; +use Adyen\Payment\Logger\AdyenLogger; +use Adyen\Payment\Model\CleanupAdditionalInformation; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Exception; +use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; + +class CleanupAdditionalInformationTest extends AbstractAdyenTestCase +{ + protected ?CleanupAdditionalInformation $cleanupAdditionalInformation; + protected Payment|MockObject $orderPaymentMock; + protected AdyenLogger|MockObject $adyenLoggerMock; + + public function setUp(): void + { + $this->orderPaymentMock = $this->createMock(Payment::class); + $this->adyenLoggerMock = $this->createMock(AdyenLogger::class); + + $this->cleanupAdditionalInformation = new CleanupAdditionalInformation( + $this->adyenLoggerMock + ); + } + + public function tearDown(): void + { + $this->cleanupAdditionalInformation = null; + } + + public function testExecute() + { + $this->orderPaymentMock + ->expects($this->exactly(count(CleanupAdditionalInformationInterface::FIELDS_TO_BE_CLEANED_UP))) + ->method('unsAdditionalInformation'); + + $result = $this->cleanupAdditionalInformation->execute($this->orderPaymentMock); + $this->assertInstanceOf(Payment::class, $result); + } + + public function testExecuteThrowsException() + { + $this->orderPaymentMock->method('unsAdditionalInformation')->willThrowException(new Exception()); + $this->adyenLoggerMock->expects($this->once())->method('error'); + + $result = $this->cleanupAdditionalInformation->execute($this->orderPaymentMock); + $this->assertInstanceOf(Payment::class, $result); + } +} diff --git a/etc/di.xml b/etc/di.xml index 1469dbf541..8b30d17f4f 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -1648,6 +1648,7 @@ +