From ccc53cad33594a9b525d86c45147e0cd99a38534 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Fri, 3 Jan 2025 16:30:13 +0100 Subject: [PATCH 01/34] [ECP-9489] Fix dynamic property declaration issues --- Block/Checkout/Multishipping/Success.php | 59 +++------------- Gateway/Request/CheckoutDataBuilder.php | 30 ++------- Test/Unit/Controller/Webhook/IndexTest.php | 67 +++++-------------- Test/Unit/Helper/PaymentMethodsTest.php | 9 +++ .../Helper/PaymentResponseHandlerTest.php | 34 +++++----- Test/Unit/Helper/RequestsTest.php | 24 +++---- .../AuthorisationWebhookHandlerTest.php | 21 +++--- .../Webhook/CaptureWebhookHandlerTest.php | 4 ++ .../Webhook/OrderClosedWebhookHandlerTest.php | 21 +++--- .../Config/Backend/AutoConfigurationTest.php | 12 ++-- Test/Unit/Model/NotificationTest.php | 4 ++ 11 files changed, 112 insertions(+), 173 deletions(-) diff --git a/Block/Checkout/Multishipping/Success.php b/Block/Checkout/Multishipping/Success.php index 49593511a2..545436a23e 100644 --- a/Block/Checkout/Multishipping/Success.php +++ b/Block/Checkout/Multishipping/Success.php @@ -16,7 +16,6 @@ use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\PaymentMethods; use Adyen\Payment\Helper\PaymentResponseHandler; -use Adyen\Payment\Model\PaymentResponse; use Adyen\Payment\Model\ResourceModel\PaymentResponse\Collection; use Adyen\Payment\Model\Ui\AdyenCheckoutSuccessConfigProvider; use Magento\Framework\Api\SearchCriteriaBuilder; @@ -28,53 +27,17 @@ class Success extends \Magento\Multishipping\Block\Checkout\Success { - /** - * @var bool - */ - private $isAdyenPayment; - - /** - * @var PaymentResponse[] - */ - private $paymentResponseEntities; - - /** - * @var Data - */ - private $adyenHelper; - - /** - * @var StoreManagerInterface - */ - private $storeManager; - - /** - * @var SerializerInterface - */ - private $serializerInterface; - - /** - * @var AdyenCheckoutSuccessConfigProvider - */ - private $configProvider; - - /** - * @var OrderRepositoryInterface - */ - private $orderRepository; - - /** - * @var SearchCriteriaBuilder - */ - private $searchCriteriaBuilder; - - - private $configHelper; - - /** - * @var [] - */ - private $ordersInfo; + private bool $isAdyenPayment; + private ?array $paymentResponseEntities; + private ?array $ordersInfo; + private Data $adyenHelper; + private StoreManagerInterface $storeManager; + private SerializerInterface $serializerInterface; + private AdyenCheckoutSuccessConfigProvider $configProvider; + private OrderRepositoryInterface $orderRepository; + private SearchCriteriaBuilder $searchCriteriaBuilder; + private Config $configHelper; + private PaymentMethods $paymentMethodsHelper; public function __construct( Collection $paymentResponseCollection, diff --git a/Gateway/Request/CheckoutDataBuilder.php b/Gateway/Request/CheckoutDataBuilder.php index 4ba033008a..f51610eb80 100644 --- a/Gateway/Request/CheckoutDataBuilder.php +++ b/Gateway/Request/CheckoutDataBuilder.php @@ -20,6 +20,7 @@ use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider; use Adyen\Payment\Observer\AdyenCcDataAssignObserver; use Adyen\Payment\Observer\AdyenPaymentMethodDataAssignObserver; +use Magento\Catalog\Helper\Image; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Payment\Gateway\Data\PaymentDataObject; use Magento\Payment\Gateway\Helper\SubjectReader; @@ -36,35 +37,13 @@ class CheckoutDataBuilder implements BuilderInterface self::ADYEN_BOLETO ]; - /** - * @var Data - */ private Data $adyenHelper; - - /** - * @var CartRepositoryInterface - */ private CartRepositoryInterface $cartRepository; - - /** - * @var ChargedCurrency - */ private ChargedCurrency $chargedCurrency; - - /** - * @var StateData - */ private StateData $stateData; - - /** - * @var Config - */ private Config $configHelper; - - /** - * @var OpenInvoice - */ private OpenInvoice $openInvoiceHelper; + private Image $imageHelper; /** * CheckoutDataBuilder constructor. @@ -74,6 +53,7 @@ class CheckoutDataBuilder implements BuilderInterface * @param ChargedCurrency $chargedCurrency * @param Config $configHelper * @param OpenInvoice $openInvoiceHelper + * @param Image $imageHelper */ public function __construct( Data $adyenHelper, @@ -81,7 +61,8 @@ public function __construct( CartRepositoryInterface $cartRepository, ChargedCurrency $chargedCurrency, Config $configHelper, - OpenInvoice $openInvoiceHelper + OpenInvoice $openInvoiceHelper, + Image $imageHelper ) { $this->adyenHelper = $adyenHelper; $this->stateData = $stateData; @@ -89,6 +70,7 @@ public function __construct( $this->chargedCurrency = $chargedCurrency; $this->configHelper = $configHelper; $this->openInvoiceHelper = $openInvoiceHelper; + $this->imageHelper = $imageHelper; } /** diff --git a/Test/Unit/Controller/Webhook/IndexTest.php b/Test/Unit/Controller/Webhook/IndexTest.php index c32923c5a8..762193801b 100644 --- a/Test/Unit/Controller/Webhook/IndexTest.php +++ b/Test/Unit/Controller/Webhook/IndexTest.php @@ -21,58 +21,27 @@ use Magento\Framework\Controller\Result\JsonFactory; use Magento\Framework\Serialize\SerializerInterface; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use PHPUnit\Framework\MockObject\MockObject; class IndexTest extends AbstractAdyenTestCase { - /** - * @var Context|\PHPUnit\Framework\MockObject\MockObject - */ - private $contextMock; - - /** - * @var RequestInterface|\PHPUnit\Framework\MockObject\MockObject - */ - private $requestMock; - - /** - * @var ResponseInterface|\PHPUnit\Framework\MockObject\MockObject - */ - private $responseMock; - - /** - * @var JsonFactory|\PHPUnit\Framework\MockObject\MockObject - */ - private $resultJsonFactoryMock; - - /** - * @var Json|\PHPUnit\Framework\MockObject\MockObject - */ - private $resultJsonMock; - - /** - * @var Data|\PHPUnit\Framework\MockObject\MockObject - */ - private $adyenHelperMock; - - /** - * @var NotificationFactory|\PHPUnit\Framework\MockObject\MockObject - */ - private $notificationHelperMock; - - /** - * @var SerializerInterface|\PHPUnit\Framework\MockObject\MockObject - */ - private $serializerMock; - - /** - * @var AdyenLogger|\PHPUnit\Framework\MockObject\MockObject - */ - private $adyenLoggerMock; - - /** - * @var Index - */ - private $indexController; + private Context|MockObject $contextMock; + private MockObject|RequestInterface $requestMock; + private ResponseInterface|MockObject $responseMock; + private JsonFactory|MockObject $resultJsonFactoryMock; + private MockObject|Json $resultJsonMock; + private Data|MockObject $adyenHelperMock; + private MockObject|NotificationFactory $notificationHelperMock; + private SerializerInterface|MockObject $serializerMock; + private AdyenLogger|MockObject $adyenLoggerMock; + private Index $indexController; + private http|MockObject $httpMock; + private IpAddress|MockObject $ipAddressHelperMock; + private Config|MockObject $configHelperMock; + private RateLimiter|MockObject $rateLimiterHelperMock; + private HmacSignature|MockObject $hmacSignatureMock; + private NotificationReceiver|MockObject $notificationReceiverMock; + private RemoteAddress|MockObject $remoteAddressMock; protected function setUp(): void { diff --git a/Test/Unit/Helper/PaymentMethodsTest.php b/Test/Unit/Helper/PaymentMethodsTest.php index 3aa38586da..93fb3466bc 100644 --- a/Test/Unit/Helper/PaymentMethodsTest.php +++ b/Test/Unit/Helper/PaymentMethodsTest.php @@ -73,6 +73,15 @@ class PaymentMethodsTest extends AbstractAdyenTestCase private AdyenDataHelper $adyenDataHelperMock; private PaymentTokenRepositoryInterface $paymentTokenRepository; private SearchCriteriaBuilder $searchCriteriaBuilder; + private Address $billingAddressMock; + private AdyenAmountCurrency $amountCurrencyMock; + private MethodInterface $methodMock; + private Order $orderMock; + private Notification $notificationMock; + private Order\Payment $orderPaymentMock; + private Store $storeMock; + private Quote $quoteMock; + private ObjectManager $objectManager; protected function setUp(): void { diff --git a/Test/Unit/Helper/PaymentResponseHandlerTest.php b/Test/Unit/Helper/PaymentResponseHandlerTest.php index 0bff0bbf23..fba1bfb6a2 100644 --- a/Test/Unit/Helper/PaymentResponseHandlerTest.php +++ b/Test/Unit/Helper/PaymentResponseHandlerTest.php @@ -8,9 +8,9 @@ * * Author: Adyen */ + namespace Adyen\Payment\Test\Unit\Helper; -use Adyen\Client; use Adyen\Payment\Helper\PaymentResponseHandler; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Helper\Vault; @@ -22,6 +22,7 @@ use Magento\Framework\Exception\AlreadyExistsException; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Sales\Model\Order as MagentoOrder; use Magento\Sales\Model\Order\Payment; use Magento\Sales\Model\Order\Status\History; use Magento\Sales\Model\ResourceModel\Order; @@ -35,23 +36,26 @@ class PaymentResponseHandlerTest extends AbstractAdyenTestCase { - private $paymentMock; - private $orderMock; - private $adyenLoggerMock; - private $vaultHelperMock; - private $orderResourceModelMock; - private $dataHelperMock; - private $quoteHelperMock; - private $orderHelperMock; - private $orderRepositoryMock; - private $orderHistoryFactoryMock; - private $stateDataHelperMock; - private $paymentResponseHandler; + private Payment $paymentMock; + private MagentoOrder $orderMock; + private AdyenLogger $adyenLoggerMock; + private Vault $vaultHelperMock; + private Order $orderResourceModelMock; + private Data $dataHelperMock; + private Quote $quoteHelperMock; + private OrderHelper $orderHelperMock; + private OrderRepository $orderRepositoryMock; + private HistoryFactory $orderHistoryFactoryMock; + private StateData $stateDataHelperMock; + private PaymentResponseHandler $paymentResponseHandler; + private Config $configHelperMock; + private Collection $paymentResponseMockForFactory; + private CollectionFactory $paymentResponseCollectionFactoryMock; protected function setUp(): void { $this->paymentMock = $this->createMock(Payment::class); - $this->orderMock = $this->createMock(\Magento\Sales\Model\Order::class); + $this->orderMock = $this->createMock(MagentoOrder::class); $this->adyenLoggerMock = $this->createMock(AdyenLogger::class); $this->vaultHelperMock = $this->createMock(Vault::class); $this->orderResourceModelMock = $this->createMock(Order::class); @@ -221,7 +225,7 @@ public function testFormatPaymentResponseForUnknownResults() public function testHandlePaymentsDetailsResponseWithNullResultCode() { - $orderMock = $this->createMock(\Magento\Sales\Model\Order::class); + $orderMock = $this->createMock(MagentoOrder::class); $paymentsDetailsResponse = [ 'randomData' => 'someRandomValue' diff --git a/Test/Unit/Helper/RequestsTest.php b/Test/Unit/Helper/RequestsTest.php index 4520ceb081..8a893460fa 100644 --- a/Test/Unit/Helper/RequestsTest.php +++ b/Test/Unit/Helper/RequestsTest.php @@ -9,22 +9,23 @@ use Adyen\Payment\Helper\StateData; use Adyen\Payment\Helper\Vault; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Magento\Payment\Model\MethodInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Payment; use Magento\Framework\App\Request\Http; class RequestsTest extends AbstractAdyenTestCase { - /** @var Requests $sut */ - private $sut; - - /** @var Payment $paymentMock */ - private $paymentMock; - - /** - * @var Data $adyenHelperMock - */ + private Requests $sut; + private Payment $paymentMock; private Data $adyenHelperMock; + private \Magento\Quote\Model\Quote\Address $billingAddressMock; + private Order $order; + private MethodInterface $methodInstance; + private Payment $payment; + private Config $adyenConfigMock; + private Address $addressHelperMock; + private Http $requestInterfaceMock; protected function setUp(): void { @@ -34,11 +35,10 @@ protected function setUp(): void ->disableOriginalConstructor() ->getMock(); $this->order = $this->createMock(Order::class); - $this->methodInstance = $this->createMock(\Magento\Payment\Model\MethodInterface::class); + $this->methodInstance = $this->createMock(MethodInterface::class); $this->payment = $this->createMock(Payment::class); $this->payment->method('getMethodInstance')->willReturn($this->methodInstance); - $this->adyenConfigMock = $this->createMock(\Adyen\Payment\Helper\Config::class); - $this->vaultHelperMock = $this->createMock(\Adyen\Payment\Helper\Vault::class); + $this->adyenConfigMock = $this->createMock(Config::class); // Mock dependencies $this->adyenHelperMock = $this->createMock(Data::class); diff --git a/Test/Unit/Helper/Webhook/AuthorisationWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/AuthorisationWebhookHandlerTest.php index 7fa6307f74..fc0166351d 100644 --- a/Test/Unit/Helper/Webhook/AuthorisationWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/AuthorisationWebhookHandlerTest.php @@ -1,4 +1,5 @@ orderMock = $this->createOrder(); $this->adyenOrderPaymentMock = $this->createMock(AdyenOrderPayment::class); - $this->orderAmountCurrency = $this->createMock(AdyenAmountCurrency::class); - $this->chargedCurrencyMock = $this->createMock(ChargedCurrency::class); - $this->notificationMock = $this->createMock(Notification::class); $this->orderMock = $this->createMock(Order::class); $this->orderHelperMock = $this->createMock(OrderHelper::class); - $this->paymentMethodsMock = $this->createMock(PaymentMethods::class); $this->caseManagementMock = $this->createMock(CaseManagement::class); - $this->configMock = $this->createMock(Config::class); - $this->adyenLoggerMock = $this->createMock(AdyenLogger::class); - $this->serializerMock = $this->createMock(SerializerInterface::class); - $this->invoiceHelperMock = $this->createMock(Invoice::class); - $this->paymentMethodsHelperMock = $this->createMock(PaymentMethods::class); + $paymentMethod = 'ADYEN_CC'; $merchantReference = 'TestMerchant'; $pspReference = 'ABCD1234GHJK5678'; + $this->notificationMock = $this->createConfiguredMock(Notification::class, [ 'getPspreference' => $pspReference, 'getMerchantReference' => $merchantReference, @@ -126,7 +123,7 @@ public function testHandleSuccessfulAuthorisation($isAutoCapture): void ->method('isFullAmountAuthorized') ->willReturn(true); - $this->orderAmountCurrency = new AdyenAmountCurrency( + $orderAmountCurrency = new AdyenAmountCurrency( $orderAmount, 'EUR', null, @@ -135,7 +132,7 @@ public function testHandleSuccessfulAuthorisation($isAutoCapture): void ); $mockChargedCurrency = $this->createConfiguredMock(ChargedCurrency::class, [ - 'getOrderAmountCurrency' => $this->orderAmountCurrency + 'getOrderAmountCurrency' => $orderAmountCurrency ]); // Create mock instances for Order and Notification diff --git a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php index 6c73f95c0b..87d9246e30 100644 --- a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php @@ -9,8 +9,10 @@ use Adyen\Payment\Helper\Order; use Adyen\Payment\Helper\PaymentMethods; use Adyen\Payment\Logger\AdyenLogger; +use Adyen\Payment\Model\Notification; use Adyen\Payment\Model\Order\PaymentFactory; use Adyen\Payment\Helper\AdyenOrderPayment; +use Magento\Sales\Model\Order as MagentoOrder; use Magento\Sales\Model\Order\InvoiceFactory as MagentoInvoiceFactory; use Adyen\Payment\Model\Invoice as AdyenInvoice; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; @@ -20,6 +22,8 @@ class CaptureWebhookHandlerTest extends AbstractAdyenTestCase { protected CaptureWebhookHandler $captureWebhookHandler; + private MagentoOrder $order; + private Notification $notification; protected function setUp(): void { diff --git a/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php index 14e1da83c1..e8cf37f743 100644 --- a/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php @@ -3,7 +3,7 @@ use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\Serialize\SerializerInterface; -use PHPUnit\Framework\TestCase; +use Magento\TestFramework\Db\AbstractDb; use Adyen\Payment\Helper\Webhook\OrderClosedWebhookHandler; use Adyen\Payment\Helper\AdyenOrderPayment; use Adyen\Payment\Helper\Config; @@ -18,13 +18,18 @@ class OrderClosedWebhookHandlerTest extends AbstractAdyenTestCase { - private $orderClosedWebhookHandler; - private $adyenOrderPaymentHelperMock; - private $orderHelperMock; - private $configHelperMock; - private $adyenLoggerMock; - private $adyenOrderPaymentCollectionFactoryMock; - private $serializerMock; + private OrderClosedWebhookHandler $orderClosedWebhookHandler; + private AdyenOrderPayment $adyenOrderPaymentHelperMock; + private OrderHelper $orderHelperMock; + private Config $configHelperMock; + private AdyenLogger $adyenLoggerMock; + private OrderPaymentCollectionFactory $adyenOrderPaymentCollectionFactoryMock; + private SerializerInterface $serializerMock; + private Order $orderMock; + private Notification $notificationMock; + private AbstractDb $adyenOrderPaymentCollectionMock; + private Order\Payment $adyenOrderPaymentMock; + private OrderPaymentInterface $adyenOrderPaymentInterfaceMock; protected function setUp(): void { diff --git a/Test/Unit/Model/Config/Backend/AutoConfigurationTest.php b/Test/Unit/Model/Config/Backend/AutoConfigurationTest.php index 10af9c6977..160e7a3788 100644 --- a/Test/Unit/Model/Config/Backend/AutoConfigurationTest.php +++ b/Test/Unit/Model/Config/Backend/AutoConfigurationTest.php @@ -5,21 +5,23 @@ use Adyen\Payment\Helper\BaseUrlHelper; use Adyen\Payment\Helper\ManagementHelper; use Adyen\Payment\Model\Config\Backend\AutoConfiguration; -use Adyen\Payment\Helper\Data; -use Adyen\Payment\Helper\Config; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\App\Cache\TypeListInterface; use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Model\Context; use Magento\Framework\Registry; use Magento\Framework\UrlInterface; -use PHPUnit\Framework\TestCase; -use PHPUnit\Framework\MockObject\MockObject; class AutoConfigurationTest extends AbstractAdyenTestCase { protected AutoConfiguration $autoConfiguration; + private Context $contextMock; + private Registry $registryMock; + private ScopeConfigInterface $scopeConfigMock; + private TypeListInterface $typeListtMock; + private ManagementHelper $managementHelperMock; + private UrlInterface $urlMock; + private BaseUrlHelper $baseUrlHelperMock; protected function setUp(): void { diff --git a/Test/Unit/Model/NotificationTest.php b/Test/Unit/Model/NotificationTest.php index 738b9ca3ee..d300d02183 100644 --- a/Test/Unit/Model/NotificationTest.php +++ b/Test/Unit/Model/NotificationTest.php @@ -9,6 +9,10 @@ class NotificationTest extends AbstractAdyenTestCase { + private Context $contextMock; + private Registry $registryMock; + private Notification $notification; + protected function setUp(): void { $this->contextMock = $this->getMockBuilder(Context::class) From 7789747271378667a8062acf5743830d73841891 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 6 Jan 2025 11:08:18 +0100 Subject: [PATCH 02/34] [ECP-9489] Fix dynamic property declaration issues --- Helper/Vault.php | 2 + .../Http/Client/TransactionCancelTest.php | 13 +++--- .../Client/TransactionPaymentLinksTest.php | 14 ++++--- .../Http/Client/TransactionPaymentTest.php | 40 +++++++++---------- .../Request/CheckoutDataBuilderTest.php | 6 ++- .../ShopperInteractionDataBuilderTest.php | 22 +++++----- ...eckoutPaymentCommentHistoryHandlerTest.php | 1 + .../CheckoutPaymentsDetailsHandlerTest.php | 2 + .../Response/VaultDetailsHandlerTest.php | 2 + .../CheckoutResponseValidatorTest.php | 9 +++-- Test/Unit/Helper/StateDataTest.php | 28 ++++++++----- .../Webhook/OrderClosedWebhookHandlerTest.php | 7 ++-- .../Api/AdyenPaymentMethodsBalanceTest.php | 3 +- .../Resolver/RemoveAdyenStateDataTest.php | 26 ++++++------ .../Model/Resolver/SaveAdyenStateDataTest.php | 25 +++++------- Test/Unit/Setup/RecurringDataTest.php | 1 + 16 files changed, 110 insertions(+), 91 deletions(-) diff --git a/Helper/Vault.php b/Helper/Vault.php index 8360da3999..4b13fe5978 100644 --- a/Helper/Vault.php +++ b/Helper/Vault.php @@ -21,6 +21,7 @@ use Exception; use Magento\Payment\Model\InfoInterface; use Magento\Sales\Api\Data\OrderPaymentExtensionInterface; +use Magento\Sales\Api\Data\OrderPaymentExtensionInterfaceFactory; use Magento\Sales\Api\Data\OrderPaymentInterface; use Magento\Sales\Model\Order\Payment; use Magento\Vault\Api\Data\PaymentTokenFactoryInterface; @@ -60,6 +61,7 @@ class Vault private Config $config; private PaymentMethods $paymentMethodsHelper; private StateData $stateData; + private OrderPaymentExtensionInterfaceFactory $paymentExtensionFactory; public function __construct( AdyenLogger $adyenLogger, diff --git a/Test/Unit/Gateway/Http/Client/TransactionCancelTest.php b/Test/Unit/Gateway/Http/Client/TransactionCancelTest.php index f0fcbd35fd..f3cbda30fd 100644 --- a/Test/Unit/Gateway/Http/Client/TransactionCancelTest.php +++ b/Test/Unit/Gateway/Http/Client/TransactionCancelTest.php @@ -11,14 +11,16 @@ use Magento\Payment\Gateway\Http\TransferInterface; use Adyen\Service\Checkout; use Adyen\AdyenException; +use PHPUnit\Framework\MockObject\MockObject; class TransactionCancelTest extends AbstractAdyenTestCase { - private $adyenHelperMock; - private $idempotencyHelperMock; - private $transferObjectMock; - private $checkoutServiceMock; - private $transactionCancel; + private TransactionCancel $transactionCancel; + private Data|MockObject $adyenHelperMock; + private Idempotency|MockObject $idempotencyHelperMock; + private TransferInterface|MockObject $transferObjectMock; + private Checkout\ModificationsApi|MockObject $checkoutServiceMock; + private Client|MockObject $clientMock; protected function setUp(): void { @@ -32,6 +34,7 @@ protected function setUp(): void $this->checkoutServiceMock ->method('cancelAuthorisedPaymentByPspReference') ->willReturn(new PaymentCancelResponse(['status' => 'received'])); + $this->transactionCancel = new TransactionCancel( $this->adyenHelperMock, $this->idempotencyHelperMock diff --git a/Test/Unit/Gateway/Http/Client/TransactionPaymentLinksTest.php b/Test/Unit/Gateway/Http/Client/TransactionPaymentLinksTest.php index c52733c959..f6645d69a1 100644 --- a/Test/Unit/Gateway/Http/Client/TransactionPaymentLinksTest.php +++ b/Test/Unit/Gateway/Http/Client/TransactionPaymentLinksTest.php @@ -13,15 +13,17 @@ use Adyen\Client; use Adyen\Service\Checkout\PaymentLinksApi; use Magento\Payment\Gateway\Http\TransferInterface; +use PHPUnit\Framework\MockObject\MockObject; class TransactionPaymentLinksTest extends AbstractAdyenTestCase { - private $clientMock; - private $adyenHelperMock; - private $idempotencyHelperMock; - private $transferObjectMock; - private $transactionPaymentLinks; - private $paymentLinksApiMock; + private TransactionPaymentLinks $transactionPaymentLinks; + private Client|MockObject $clientMock; + private Data|MockObject $adyenHelperMock; + private Idempotency|MockObject $idempotencyHelperMock; + private TransferInterface|MockObject $transferObjectMock; + private PaymentLinksApi|MockObject $paymentLinksApiMock; + private ApplicationInfo|MockObject $applicationInfoMock; protected function setUp(): void { diff --git a/Test/Unit/Gateway/Http/Client/TransactionPaymentTest.php b/Test/Unit/Gateway/Http/Client/TransactionPaymentTest.php index 3b1be87465..57925f01bd 100644 --- a/Test/Unit/Gateway/Http/Client/TransactionPaymentTest.php +++ b/Test/Unit/Gateway/Http/Client/TransactionPaymentTest.php @@ -19,7 +19,6 @@ use Adyen\Payment\Model\PaymentResponse; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Adyen\Service\Checkout\PaymentsApi; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Adyen\Payment\Helper\Data; use Adyen\Payment\Model\PaymentResponseFactory; use Adyen\Payment\Model\ResourceModel\PaymentResponse as PaymentResponseResourceModel; @@ -30,22 +29,22 @@ use Magento\Store\Model\StoreManagerInterface; use Adyen\Payment\Helper\GiftcardPayment; use Magento\Payment\Gateway\Http\TransferInterface; +use PHPUnit\Framework\MockObject\MockObject; class TransactionPaymentTest extends AbstractAdyenTestCase { - private $adyenHelperMock; - private $paymentResponseFactoryMock; - private $paymentResponseResourceModelMock; - private $idempotencyHelperMock; - private $orderApiHelperMock; - private $storeManagerMock; - private $giftcardPaymentHelperMock; - private $transactionPayment; + private Data|MockObject$adyenHelperMock; + private PaymentResponseFactory|MockObject $paymentResponseFactoryMock; + private PaymentResponseResourceModel|MockObject $paymentResponseResourceModelMock; + private Idempotency|MockObject $idempotencyHelperMock; + private OrdersApi|MockObject $orderApiHelperMock; + private StoreManagerInterface|MockObject $storeManagerMock; + private GiftcardPayment|MockObject $giftcardPaymentHelperMock; + private TransactionPayment $transactionPayment; + private ApplicationInfo|MockObject $applicationInfoMock; protected function setUp(): void { - $objectManager = new ObjectManager($this); - $this->adyenHelperMock = $this->createMock(Data::class); $this->paymentResponseResourceModelMock = $this->createMock(PaymentResponseResourceModel::class); $this->idempotencyHelperMock = $this->createMock(Idempotency::class); @@ -63,17 +62,14 @@ protected function setUp(): void $this->applicationInfoMock = $this->createMock(ApplicationInfo::class); $this->adyenHelperMock->method('buildApplicationInfo')->willReturn($this->applicationInfoMock); - $this->transactionPayment = $objectManager->getObject( - TransactionPayment::class, - [ - 'adyenHelper' => $this->adyenHelperMock, - 'paymentResponseFactory' => $this->paymentResponseFactoryMock, - 'paymentResponseResourceModel' => $this->paymentResponseResourceModelMock, - 'idempotencyHelper' => $this->idempotencyHelperMock, - 'orderApiHelper' => $this->orderApiHelperMock, - 'storeManager' => $this->storeManagerMock, - 'giftcardPaymentHelper' => $this->giftcardPaymentHelperMock, - ] + $this->transactionPayment = new TransactionPayment( + $this->adyenHelperMock, + $this->paymentResponseFactoryMock, + $this->paymentResponseResourceModelMock, + $this->idempotencyHelperMock, + $this->orderApiHelperMock, + $this->storeManagerMock, + $this->giftcardPaymentHelperMock ); } diff --git a/Test/Unit/Gateway/Request/CheckoutDataBuilderTest.php b/Test/Unit/Gateway/Request/CheckoutDataBuilderTest.php index de72e28846..bcef5108eb 100644 --- a/Test/Unit/Gateway/Request/CheckoutDataBuilderTest.php +++ b/Test/Unit/Gateway/Request/CheckoutDataBuilderTest.php @@ -10,6 +10,7 @@ use Adyen\Payment\Helper\StateData; use Adyen\Payment\Model\Config\Source\ThreeDSFlow; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Magento\Catalog\Helper\Image; use Magento\Payment\Gateway\Data\PaymentDataObject; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Sales\Model\Order; @@ -26,6 +27,7 @@ class CheckoutDataBuilderTest extends AbstractAdyenTestCase protected ChargedCurrency|MockObject $chargedCurrencyMock; protected Config|MockObject $configMock; protected OpenInvoice|MockObject $openInvoiceMock; + protected Image|MockObject $imageMock; public function setUp(): void { @@ -35,6 +37,7 @@ public function setUp(): void $this->chargedCurrencyMock = $this->createMock(ChargedCurrency::class); $this->configMock = $this->createMock(Config::class); $this->openInvoiceMock = $this->createMock(OpenInvoice::class); + $this->imageMock = $this->createMock(Image::class); $this->checkoutDataBuilder = new CheckoutDataBuilder( $this->adyenHelperMock, @@ -42,7 +45,8 @@ public function setUp(): void $this->cartRepositoryMock, $this->chargedCurrencyMock, $this->configMock, - $this->openInvoiceMock + $this->openInvoiceMock, + $this->imageMock ); parent::setUp(); diff --git a/Test/Unit/Gateway/Request/ShopperInteractionDataBuilderTest.php b/Test/Unit/Gateway/Request/ShopperInteractionDataBuilderTest.php index 9b4d5fee33..ef7a927108 100644 --- a/Test/Unit/Gateway/Request/ShopperInteractionDataBuilderTest.php +++ b/Test/Unit/Gateway/Request/ShopperInteractionDataBuilderTest.php @@ -20,31 +20,31 @@ use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\App\Area; use Magento\Framework\App\State; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Model\Context; use Magento\Payment\Gateway\Data\PaymentDataObject; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; class ShopperInteractionDataBuilderTest extends AbstractAdyenTestCase { - private $shopperInteractionDataBuilder; - private $appState; - private $stateData; + private ShopperInteractionDataBuilder $shopperInteractionDataBuilder; + private State|MockObject $appState; + private StateData|MockObject $stateData; + private Context|MockObject $contextMock; protected function setUp(): void { - $this->objectManager = new ObjectManager($this); - $this->appState = $this->createMock(State::class); $this->stateData = $this->createPartialMock(StateData::class, [ 'getStateData' ]); + $this->contextMock = $this->createMock(Context::class); + $this->contextMock->method('getAppState')->willReturn($this->appState); - $this->shopperInteractionDataBuilder = $this->objectManager->getObject( - ShopperInteractionDataBuilder::class, [ - 'appState' => $this->appState, - 'stateData' => $this->stateData - ] + $this->shopperInteractionDataBuilder = new ShopperInteractionDataBuilder( + $this->contextMock, + $this->stateData ); } diff --git a/Test/Unit/Gateway/Response/CheckoutPaymentCommentHistoryHandlerTest.php b/Test/Unit/Gateway/Response/CheckoutPaymentCommentHistoryHandlerTest.php index fc6f90b549..16cba78cf1 100644 --- a/Test/Unit/Gateway/Response/CheckoutPaymentCommentHistoryHandlerTest.php +++ b/Test/Unit/Gateway/Response/CheckoutPaymentCommentHistoryHandlerTest.php @@ -15,6 +15,7 @@ class CheckoutPaymentCommentHistoryHandlerTest extends AbstractAdyenTestCase private CheckoutPaymentCommentHistoryHandler $checkoutPaymentCommentHistoryHandler; private Payment|MockObject $paymentMock; private Order|MockObject $orderMock; + private PaymentDataObject $paymentDataObject; private array $handlingSubject; public function setUp() : void diff --git a/Test/Unit/Gateway/Response/CheckoutPaymentsDetailsHandlerTest.php b/Test/Unit/Gateway/Response/CheckoutPaymentsDetailsHandlerTest.php index fa7143dea3..e018a00fba 100644 --- a/Test/Unit/Gateway/Response/CheckoutPaymentsDetailsHandlerTest.php +++ b/Test/Unit/Gateway/Response/CheckoutPaymentsDetailsHandlerTest.php @@ -16,6 +16,8 @@ class CheckoutPaymentsDetailsHandlerTest extends AbstractAdyenTestCase private CheckoutPaymentsDetailsHandler $checkoutPaymentsDetailsHandler; private Payment|MockObject $paymentMock; private Order|MockObject $orderMock; + private Data|MockObject $adyenHelperMock; + private PaymentDataObject $paymentDataObject; private array $handlingSubject; protected function setUp(): void diff --git a/Test/Unit/Gateway/Response/VaultDetailsHandlerTest.php b/Test/Unit/Gateway/Response/VaultDetailsHandlerTest.php index 206fdd275c..0b84eff95f 100644 --- a/Test/Unit/Gateway/Response/VaultDetailsHandlerTest.php +++ b/Test/Unit/Gateway/Response/VaultDetailsHandlerTest.php @@ -15,6 +15,8 @@ class VaultDetailsHandlerTest extends AbstractAdyenTestCase { private VaultDetailsHandler $vaultDetailsHandler; private Payment|MockObject $paymentMock; + private Vault|MockObject $vaultHelperMock; + private PaymentDataObject $paymentDataObject; private array $handlingSubject; public function setUp() : void diff --git a/Test/Unit/Gateway/Validator/CheckoutResponseValidatorTest.php b/Test/Unit/Gateway/Validator/CheckoutResponseValidatorTest.php index 5730c92cfe..1e0427254b 100644 --- a/Test/Unit/Gateway/Validator/CheckoutResponseValidatorTest.php +++ b/Test/Unit/Gateway/Validator/CheckoutResponseValidatorTest.php @@ -12,12 +12,15 @@ use Magento\Payment\Gateway\Validator\Result; use Magento\Payment\Gateway\Validator\ResultInterfaceFactory; use Magento\Sales\Model\Order\Payment; +use PHPUnit\Framework\MockObject\MockObject; class CheckoutResponseValidatorTest extends AbstractAdyenTestCase { - private $checkoutResponseValidator; - private $resultFactoryMock; - private $paymentDataObject; + private CheckoutResponseValidator $checkoutResponseValidator; + private ResultInterfaceFactory|MockObject $resultFactoryMock; + private PaymentDataObject $paymentDataObject; + private AdyenLogger|MockObject $adyenLoggerMock; + private Data|MockObject $adyenHelperMock; protected function setUp(): void { diff --git a/Test/Unit/Helper/StateDataTest.php b/Test/Unit/Helper/StateDataTest.php index 6f0a097878..8856255fa8 100644 --- a/Test/Unit/Helper/StateDataTest.php +++ b/Test/Unit/Helper/StateDataTest.php @@ -12,36 +12,44 @@ namespace Adyen\Payment\Test\Unit\Helper; use Adyen\Payment\Helper\StateData; +use Adyen\Payment\Helper\Util\CheckoutStateDataValidator; +use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\ResourceModel\StateData as StateDataResourceModel; use Adyen\Payment\Model\ResourceModel\StateData\Collection as StateDataCollection; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Adyen\Payment\Model\StateDataFactory; +use PHPUnit\Framework\MockObject\MockObject; class StateDataTest extends AbstractAdyenTestCase { - private $stateDataHelper; - private $stateDataCollectionMock; - private $stateDataFactoryMock; - private $stateDataResourceModelMock; + private StateData $stateDataHelper; + private StateDataCollection|MockObject $stateDataCollectionMock; + private StateDataFactory|MockObject $stateDataFactoryMock; + private StateDataResourceModel|MockObject $stateDataResourceModelMock; + private CheckoutStateDataValidator|MockObject $checkoutStateDataValidatorMock; + private AdyenLogger|MockObject $adyenLoggerMock; protected function setUp(): void { - $this->objectManager = new ObjectManager($this); $this->stateDataCollectionMock = $this->createMock(StateDataCollection::class); $this->stateDataResourceModelMock = $this->createMock(StateDataResourceModel::class); + $this->checkoutStateDataValidatorMock = $this->createMock(CheckoutStateDataValidator::class); + $this->adyenLoggerMock = $this->createMock(AdyenLogger::class); $stateDataMock = $this->createMock(\Adyen\Payment\Model\StateData::class); $this->stateDataFactoryMock = $this->createGeneratedMock(StateDataFactory::class, ['create']); $this->stateDataFactoryMock->method('create')->willReturn($stateDataMock); - $this->stateDataHelper = $this->objectManager->getObject(StateData::class, [ - 'stateDataCollection' => $this->stateDataCollectionMock, - 'stateDataResourceModel' => $this->stateDataResourceModelMock, - 'stateDataFactory' => $this->stateDataFactoryMock - ]); + $this->stateDataHelper = new StateData( + $this->stateDataCollectionMock, + $this->stateDataFactoryMock, + $this->stateDataResourceModelMock, + $this->checkoutStateDataValidatorMock, + $this->adyenLoggerMock + ); } public function testSaveStateDataSuccessful() diff --git a/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php index e8cf37f743..335e53b54a 100644 --- a/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/OrderClosedWebhookHandlerTest.php @@ -1,9 +1,10 @@ orderMock = $this->createMock(MagentoOrder::class); $this->notificationMock = $this->createMock(Notification::class); - $this->adyenOrderPaymentCollectionMock = $this->createMock(\Magento\Framework\Data\Collection\AbstractDb::class); + $this->adyenOrderPaymentCollectionMock = $this->createMock(Collection::class); $this->adyenOrderPaymentHelperMock = $this->createMock(AdyenOrderPayment::class); $this->orderHelperMock = $this->createMock(OrderHelper::class); $this->configHelperMock = $this->createMock(Config::class); diff --git a/Test/Unit/Model/Api/AdyenPaymentMethodsBalanceTest.php b/Test/Unit/Model/Api/AdyenPaymentMethodsBalanceTest.php index 3f818965fe..0f3bb5d027 100644 --- a/Test/Unit/Model/Api/AdyenPaymentMethodsBalanceTest.php +++ b/Test/Unit/Model/Api/AdyenPaymentMethodsBalanceTest.php @@ -18,13 +18,13 @@ class AdyenPaymentMethodsBalanceTest extends AbstractAdyenTestCase { - private StoreManager $storeManager; private Config $config; private Data $adyenHelper; private AdyenLogger $adyenLogger; private OrdersApi $ordersApi; private BalanceCheckResponse $response; + private Json $jsonSerializer; protected function setUp(): void { @@ -53,7 +53,6 @@ protected function setUp(): void 'initializeOrdersApi' => $this->ordersApi ]); $this->adyenLogger = $this->createMock(AdyenLogger::class); - $this->merchantAccount = 'my-merchant-account'; } public function testSuccessfulGetBalance() diff --git a/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php b/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php index d4aa022013..ad68f52f91 100644 --- a/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php +++ b/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php @@ -20,24 +20,22 @@ use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Quote\Model\QuoteIdMask; use Magento\Quote\Model\QuoteIdMaskFactory; +use PHPUnit\Framework\MockObject\MockObject; class RemoveAdyenStateDataTest extends AbstractAdyenTestCase { - private $removeAdyenStateDataResolver; - private $adyenStateDataHelperMock; - private $quoteIdMaskFactoryMock; - private $quoteIdMaskMock; - private $fieldMock; - private $contextMock; - private $infoMock; + private RemoveAdyenStateData $removeAdyenStateDataResolver; + private AdyenStateData|MockObject $adyenStateDataHelperMock; + private QuoteIdMaskFactory|MockObject $quoteIdMaskFactoryMock; + private QuoteIdMask|MockObject $quoteIdMaskMock; + private Field|MockObject $fieldMock; + private ContextInterface|MockObject $contextMock; + private ResolveInfo|MockObject $infoMock; public function setUp(): void { - $this->objectManager = new ObjectManager($this); - $this->adyenStateDataHelperMock = $this->createMock(AdyenStateData::class); $this->fieldMock = $this->createMock(Field::class); $this->contextMock = $this->createMock(ContextInterface::class); @@ -52,10 +50,10 @@ public function setUp(): void ]); $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock); - $this->removeAdyenStateDataResolver = $this->objectManager->getObject(RemoveAdyenStateData::class, [ - 'adyenStateData' => $this->adyenStateDataHelperMock, - 'quoteIdMaskFactory' => $this->quoteIdMaskFactoryMock - ]); + $this->removeAdyenStateDataResolver = new RemoveAdyenStateData( + $this->adyenStateDataHelperMock, + $this->quoteIdMaskFactoryMock + ); } public function testResolve() diff --git a/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php b/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php index 871e291f58..2ddd658938 100644 --- a/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php +++ b/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php @@ -18,24 +18,21 @@ use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Quote\Model\QuoteIdMask; use Magento\Quote\Model\QuoteIdMaskFactory; class SaveAdyenStateDataTest extends AbstractAdyenTestCase { - private $saveAdyenStateDataResolver; - private $adyenStateDataHelperMock; - private $quoteIdMaskFactoryMock; - private $quoteIdMaskMock; - private $fieldMock; - private $contextMock; - private $infoMock; + private SaveAdyenStateData $saveAdyenStateDataResolver; + private AdyenStateData $adyenStateDataHelperMock; + private QuoteIdMaskFactory $quoteIdMaskFactoryMock; + private QuoteIdMask $quoteIdMaskMock; + private Field $fieldMock; + private ContextInterface$contextMock; + private ResolveInfo $infoMock; public function setUp(): void { - $this->objectManager = new ObjectManager($this); - $this->adyenStateDataHelperMock = $this->createMock(AdyenStateData::class); $this->fieldMock = $this->createMock(Field::class); $this->contextMock = $this->createMock(ContextInterface::class); @@ -50,10 +47,10 @@ public function setUp(): void ]); $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock); - $this->saveAdyenStateDataResolver = $this->objectManager->getObject(SaveAdyenStateData::class, [ - 'adyenStateData' => $this->adyenStateDataHelperMock, - 'quoteIdMaskFactory' => $this->quoteIdMaskFactoryMock - ]); + $this->saveAdyenStateDataResolver = new SaveAdyenStateData( + $this->adyenStateDataHelperMock, + $this->quoteIdMaskFactoryMock + ); } public function testResolve() diff --git a/Test/Unit/Setup/RecurringDataTest.php b/Test/Unit/Setup/RecurringDataTest.php index 51f9a45ded..fa392f3e88 100644 --- a/Test/Unit/Setup/RecurringDataTest.php +++ b/Test/Unit/Setup/RecurringDataTest.php @@ -21,6 +21,7 @@ class RecurringDataTest extends AbstractAdyenTestCase { private RecurringData $recurringData; + private PaymentMethodsFactory $paymentMethodsFactoryMock; protected function setUp(): void { From 2cd445ae0c2e3253d1b0d680b257b3b64c240d52 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 6 Jan 2025 11:09:29 +0100 Subject: [PATCH 03/34] [ECP-9489] Implement PHPStan analyses on the main workflow --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b8c34adba7..64010cf632 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,6 +39,9 @@ jobs: - name: Code Sniffer run: vendor/bin/phpcs . + - name: PHPStan + run: vendor/bin/phpstan analyse . + - name: Run PHPUnit run: vendor/bin/phpunit --coverage-clover=build/clover.xml --log-junit=build/tests-log.xml -c Test/phpunit.xml Test/Unit From f201e8d23e91d6d267e4fc3028618b46d6b50502 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 6 Jan 2025 11:11:43 +0100 Subject: [PATCH 04/34] [ECP-9489] Add missing class import --- .../Providers/PayByLinkExpiredPaymentOrdersProviderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/Unit/Cron/Providers/PayByLinkExpiredPaymentOrdersProviderTest.php b/Test/Unit/Cron/Providers/PayByLinkExpiredPaymentOrdersProviderTest.php index cf082a93e0..e0e0bc25f0 100644 --- a/Test/Unit/Cron/Providers/PayByLinkExpiredPaymentOrdersProviderTest.php +++ b/Test/Unit/Cron/Providers/PayByLinkExpiredPaymentOrdersProviderTest.php @@ -15,7 +15,7 @@ use Magento\Sales\Api\OrderPaymentRepositoryInterface; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order\Payment as OrderPayment; -use PHPUnit_Framework_MockObject_MockObject as MockObject; +use PHPUnit\Framework\MockObject\MockObject; class PayByLinkExpiredPaymentOrdersProviderTest extends AbstractAdyenTestCase { From 501675f48fb61772d31aea80cd955ae17873617f Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 6 Jan 2025 15:13:43 +0100 Subject: [PATCH 05/34] [ECP-9489] Add missing argument for sprintf --- Helper/Webhook/RecurringContractWebhookHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Helper/Webhook/RecurringContractWebhookHandler.php b/Helper/Webhook/RecurringContractWebhookHandler.php index e228855b46..f490f87618 100644 --- a/Helper/Webhook/RecurringContractWebhookHandler.php +++ b/Helper/Webhook/RecurringContractWebhookHandler.php @@ -70,6 +70,7 @@ private function handleFailedNotification(MagentoOrder $order, Notification $not $this->adyenLogger->addAdyenNotification( sprintf( "Vault payment token with entity_id: %s disabled due to the failing %s webhook notification.", + $vaultToken->getEntityId(), $notification->getEventCode() ), [ From 77a1c9bd8569acce00f02bd33106dac26946c8a1 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 6 Jan 2025 15:13:58 +0100 Subject: [PATCH 06/34] [ECP-9489] Add missing return values --- Gateway/Request/ExpiryDateDataBuilder.php | 6 ++++-- Model/Config/Backend/DonationAmounts.php | 4 +++- Setup/Patch/Data/CreateStatusAuthorized.php | 7 +++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Gateway/Request/ExpiryDateDataBuilder.php b/Gateway/Request/ExpiryDateDataBuilder.php index 7050131e1e..69eea919c1 100644 --- a/Gateway/Request/ExpiryDateDataBuilder.php +++ b/Gateway/Request/ExpiryDateDataBuilder.php @@ -39,9 +39,10 @@ public function __construct( * @param array $buildSubject * @return array */ - public function build(array $buildSubject) + public function build(array $buildSubject): array { $expiryDate = null; + $request = []; $paymentFormFields = $this->request->getParam('payment'); $paymentExpiryDate = $buildSubject['payment']->getPayment()->getAdditionalInformation() [AdyenPayByLinkDataAssignObserver::PBL_EXPIRY_DATE]; @@ -60,7 +61,8 @@ public function build(array $buildSubject) ); $request['body']['expiresAt'] = $expiryDateTime->format(DATE_ATOM); - return $request; } + + return $request; } } diff --git a/Model/Config/Backend/DonationAmounts.php b/Model/Config/Backend/DonationAmounts.php index 82f6d63765..9122c49ca0 100644 --- a/Model/Config/Backend/DonationAmounts.php +++ b/Model/Config/Backend/DonationAmounts.php @@ -52,7 +52,7 @@ public function __construct( parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); } - public function validateBeforeSave() + public function validateBeforeSave(): DonationAmounts { if ( (bool)$this->getFieldsetDataValue('active') && @@ -64,6 +64,8 @@ public function validateBeforeSave() ) ); } + + return $this; } diff --git a/Setup/Patch/Data/CreateStatusAuthorized.php b/Setup/Patch/Data/CreateStatusAuthorized.php index a30495f719..049adcdb99 100644 --- a/Setup/Patch/Data/CreateStatusAuthorized.php +++ b/Setup/Patch/Data/CreateStatusAuthorized.php @@ -17,6 +17,7 @@ use Magento\Framework\Setup\Patch\DataPatchInterface; use Magento\Framework\App\Config\ReinitableConfigInterface; use Magento\Framework\App\Config\Storage\WriterInterface; +use Magento\Framework\Setup\Patch\PatchInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\StatusFactory; use Magento\Sales\Model\ResourceModel\Order\StatusFactory as StatusResourceFactory; @@ -50,7 +51,7 @@ public function __construct( $this->statusResourceFactory = $statusResourceFactory; } - public function apply() + public function apply(): PatchInterface { /** @var StatusResource $statusResource */ $statusResource = $this->statusResourceFactory->create(); @@ -64,7 +65,7 @@ public function apply() try { $statusResource->save($status); } catch (AlreadyExistsException $exception) { - return; + return $this; } $status->assignState(self::ADYEN_AUTHORIZED_STATUS, true, true); @@ -85,6 +86,8 @@ public function apply() // re-initialize otherwise it will cause errors $this->reinitableConfig->reinit(); + + return $this; } /** From 5cf2cf255ca0f8545979ba4f58ecee8e829469e0 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 6 Jan 2025 16:01:09 +0100 Subject: [PATCH 07/34] [ECP-9489] Use constructor argument instead of method for setting up the template --- .../ApplePayDomainAssociationFileButton.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/Model/Config/Adminhtml/ApplePayDomainAssociationFileButton.php b/Model/Config/Adminhtml/ApplePayDomainAssociationFileButton.php index 16de30dd46..cc2626fcac 100644 --- a/Model/Config/Adminhtml/ApplePayDomainAssociationFileButton.php +++ b/Model/Config/Adminhtml/ApplePayDomainAssociationFileButton.php @@ -18,7 +18,7 @@ class ApplePayDomainAssociationFileButton extends Field { - const APPLEPAY_BUTTON = 'Adyen_Payment::config/applepay_domain_association_file_button.phtml'; + protected $_template = 'Adyen_Payment::config/applepay_domain_association_file_button.phtml'; /** * @var Data @@ -39,20 +39,6 @@ public function __construct( parent::__construct($context, $data); } - /** - * @return $this|ApplePayDomainAssociationFileButton - */ - protected function _prepareLayout(): ApplePayDomainAssociationFileButton|static - { - parent::_prepareLayout(); - - if (!$this->getTemplate()) { - $this->setTemplate(static::APPLEPAY_BUTTON); - } - - return $this; - } - /** * @param AbstractElement $element * @return string From 60a9c7e1eb3ebaaa9e55584cbbe87222d2bcdff6 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Mon, 6 Jan 2025 16:01:55 +0100 Subject: [PATCH 08/34] [ECP-9489] Use repository instead of model class to save/load the entities --- Block/Checkout/Success.php | 14 +++-- Controller/Return/Index.php | 16 ++++- Helper/Invoice.php | 13 ++-- Helper/PaymentResponseHandler.php | 8 ++- Helper/Webhook/CaptureWebhookHandler.php | 50 ++++----------- Model/Api/AdyenDonations.php | 4 +- Model/Notification.php | 8 ++- .../SetOrderStateAfterPaymentObserver.php | 29 +++------ Test/Unit/Block/Checkout/SuccessTest.php | 63 +++++++++++++------ Test/Unit/Controller/Return/IndexTest.php | 10 ++- Test/Unit/Helper/InvoiceTest.php | 42 ++++++++----- .../Helper/PaymentResponseHandlerTest.php | 7 ++- .../Webhook/CaptureWebhookHandlerTest.php | 10 ++- .../SetOrderStateAfterPaymentObserverTest.php | 12 +++- 14 files changed, 166 insertions(+), 120 deletions(-) diff --git a/Block/Checkout/Success.php b/Block/Checkout/Success.php index 62c81084c7..c9f89c9a55 100644 --- a/Block/Checkout/Success.php +++ b/Block/Checkout/Success.php @@ -22,22 +22,25 @@ use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\View\Element\Template; use Magento\Framework\View\Element\Template\Context; +use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; -use Magento\Sales\Model\OrderFactory; use Magento\Store\Model\StoreManagerInterface; +use Magento\Sales\Model\OrderFactory; class Success extends Template { protected $order; protected CheckoutSession $checkoutSession; protected CustomerSession $customerSession; - protected OrderFactory $orderFactory; protected Data $adyenHelper; protected StoreManagerInterface $storeManager; private Config $configHelper; private SerializerInterface $serializerInterface; private AdyenCheckoutSuccessConfigProvider $configProvider; private QuoteIdToMaskedQuoteId $quoteIdToMaskedQuoteId; + private OrderRepositoryInterface $orderRepository; + /** @deprecated This property has been deprecated and will be removed on V10. */ + protected OrderFactory $orderFactory; public function __construct( Context $context, @@ -50,8 +53,11 @@ public function __construct( AdyenCheckoutSuccessConfigProvider $configProvider, StoreManagerInterface $storeManager, SerializerInterface $serializerInterface, + OrderRepositoryInterface $orderRepository, array $data = [] ) { + parent::__construct($context, $data); + $this->checkoutSession = $checkoutSession; $this->customerSession = $customerSession; $this->quoteIdToMaskedQuoteId = $quoteIdToMaskedQuoteId; @@ -61,7 +67,7 @@ public function __construct( $this->configProvider = $configProvider; $this->storeManager = $storeManager; $this->serializerInterface = $serializerInterface; - parent::__construct($context, $data); + $this->orderRepository = $orderRepository; } /** @@ -164,7 +170,7 @@ public function getEnvironment() public function getOrder() { if ($this->order == null) { - $this->order = $this->orderFactory->create()->load($this->checkoutSession->getLastOrderId()); + $this->order = $this->orderRepository->get($this->checkoutSession->getLastOrderId()); } return $this->order; } diff --git a/Controller/Return/Index.php b/Controller/Return/Index.php index c44fb5e5e2..7a1912824c 100755 --- a/Controller/Return/Index.php +++ b/Controller/Return/Index.php @@ -23,6 +23,8 @@ use Magento\Framework\App\Action\Context; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\OrderFactory; use Magento\Store\Model\StoreManagerInterface; @@ -60,6 +62,8 @@ class Index extends Action private Order\Payment $payment; private PaymentsDetails $paymentsDetailsHelper; private PaymentResponseHandler $paymentResponseHandler; + private CartRepositoryInterface $cartRepository; + private OrderRepositoryInterface $orderRepository; public function __construct( Context $context, @@ -70,7 +74,9 @@ public function __construct( Quote $quoteHelper, Config $configHelper, PaymentsDetails $paymentsDetailsHelper, - PaymentResponseHandler $paymentResponseHandler + PaymentResponseHandler $paymentResponseHandler, + CartRepositoryInterface $cartRepository, + OrderRepositoryInterface $orderRepository ) { parent::__construct($context); @@ -82,6 +88,8 @@ public function __construct( $this->configHelper = $configHelper; $this->paymentsDetailsHelper = $paymentsDetailsHelper; $this->paymentResponseHandler = $paymentResponseHandler; + $this->cartRepository = $cartRepository; + $this->orderRepository = $orderRepository; } /** @@ -112,7 +120,9 @@ public function execute(): void } if ($result) { - $this->session->getQuote()->setIsActive($setQuoteAsActive)->save(); + $quote = $this->session->getQuote(); + $quote->setIsActive($setQuoteAsActive); + $this->cartRepository->save($quote); // Add OrderIncrementId to redirect parameters for headless support. $redirectParams = $this->configHelper->getAdyenAbstractConfigData('custom_success_redirect_path', $storeId) @@ -205,7 +215,7 @@ private function cleanUpRedirectAction(): void (isset($paymentAction) && $paymentAction['type'] === 'redirect') ) { $this->payment->unsAdditionalInformation('action'); - $this->order->save(); + $this->orderRepository->save($this->order); } } } diff --git a/Helper/Invoice.php b/Helper/Invoice.php index 9738a76ff3..0d6fa6ebc4 100644 --- a/Helper/Invoice.php +++ b/Helper/Invoice.php @@ -30,6 +30,7 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\DB\Transaction; use Magento\Sales\Api\InvoiceRepositoryInterface; +use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Email\Container\InvoiceIdentity; use Magento\Sales\Model\Order\Email\Sender\InvoiceSender; @@ -76,7 +77,8 @@ public function __construct( protected readonly Config $configHelper, protected readonly InvoiceSender $invoiceSender, protected readonly Transaction $transaction, - protected readonly ChargedCurrency $chargedCurrencyHelper + protected readonly ChargedCurrency $chargedCurrencyHelper, + protected readonly OrderRepositoryInterface $orderRepository ) { parent::__construct($context); } @@ -277,7 +279,7 @@ public function handleCaptureWebhook(Order $order, Notification $notification): $this->adyenInvoiceResourceModel->save($adyenInvoiceObject); /** @var InvoiceModel $magentoInvoice */ - $magentoInvoice = $this->magentoInvoiceFactory->create()->load($adyenInvoiceObject->getInvoiceId()); + $magentoInvoice = $this->invoiceRepository->get($adyenInvoiceObject->getInvoiceId()); if ($this->isFullInvoiceAmountManuallyCaptured($magentoInvoice)) { $magentoInvoice->pay(); @@ -368,7 +370,8 @@ public function createInvoiceFromWebhook(Order $order, Notification $notificatio $invoice->setTransactionId($notification->getPspreference()); $invoice->register(); $invoice->pay(); - $invoice->save(); + + $this->invoiceRepository->save($invoice); $transactionSave = $this->transaction->addObject( $invoice @@ -391,13 +394,13 @@ public function createInvoiceFromWebhook(Order $order, Notification $notificatio __('Notified customer about invoice creation #%1.', $invoice->getId()) ); $order->setIsCustomerNotified(true); - $order->save(); + $this->orderRepository->save($order); } else { $order->addStatusHistoryComment( __('Created invoice #%1.', $invoice->getId()) ); $order->setIsCustomerNotified(false); - $order->save(); + $this->orderRepository->save($order); } //Create entry in adyen_invoice table diff --git a/Helper/PaymentResponseHandler.php b/Helper/PaymentResponseHandler.php index ca1df99836..162b92d677 100644 --- a/Helper/PaymentResponseHandler.php +++ b/Helper/PaymentResponseHandler.php @@ -20,6 +20,7 @@ use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\OrderStatusHistoryRepositoryInterface; use Magento\Sales\Model\Order\Status\HistoryFactory; use Magento\Sales\Model\OrderRepository; use Magento\Sales\Model\ResourceModel\Order; @@ -65,6 +66,7 @@ class PaymentResponseHandler private StateData $stateDataHelper; private PaymentResponseCollectionFactory $paymentResponseCollectionFactory; private Config $configHelper; + private OrderStatusHistoryRepositoryInterface $orderStatusHistoryRepository; public function __construct( AdyenLogger $adyenLogger, @@ -77,7 +79,8 @@ public function __construct( HistoryFactory $orderHistoryFactory, StateData $stateDataHelper, PaymentResponseCollectionFactory $paymentResponseCollectionFactory, - Config $configHelper + Config $configHelper, + OrderStatusHistoryRepositoryInterface $orderStatusHistoryRepository ) { $this->adyenLogger = $adyenLogger; $this->vaultHelper = $vaultHelper; @@ -90,6 +93,7 @@ public function __construct( $this->stateDataHelper = $stateDataHelper; $this->paymentResponseCollectionFactory = $paymentResponseCollectionFactory; $this->configHelper = $configHelper; + $this->orderStatusHistoryRepository = $orderStatusHistoryRepository; } public function formatPaymentResponse( @@ -331,7 +335,7 @@ public function handlePaymentsDetailsResponse( ->setEntityName('order') ->setOrder($order); - $history->save(); + $this->orderStatusHistoryRepository->save($history); // needed because then we need to save $order objects $order->setAdyenResulturlEventCode($authResult); diff --git a/Helper/Webhook/CaptureWebhookHandler.php b/Helper/Webhook/CaptureWebhookHandler.php index 77914f851d..3c72a137da 100644 --- a/Helper/Webhook/CaptureWebhookHandler.php +++ b/Helper/Webhook/CaptureWebhookHandler.php @@ -22,50 +22,23 @@ use Adyen\Payment\Model\Order\PaymentFactory; use Adyen\Webhook\PaymentStates; use Magento\Framework\Exception\AlreadyExistsException; +use Magento\Sales\Api\InvoiceRepositoryInterface; use Magento\Sales\Model\Order as MagentoOrder; use Magento\Sales\Model\Order\Invoice as MagentoInvoice; use Magento\Sales\Model\Order\InvoiceFactory as MagentoInvoiceFactory; class CaptureWebhookHandler implements WebhookHandlerInterface { - /** @var Invoice */ - private $invoiceHelper; - - /** @var PaymentFactory */ - private $adyenOrderPaymentFactory; - - /** @var AdyenOrderPayment */ - private $adyenOrderPaymentHelper; - - /** @var AdyenLogger */ - private $adyenLogger; - - /** @var MagentoInvoiceFactory */ - private $magentoInvoiceFactory; - - /** @var Order */ - private $orderHelper; - - /** @var PaymentMethods */ - private $paymentMethodsHelper; - public function __construct( - Invoice $invoiceHelper, - PaymentFactory $adyenOrderPaymentFactory, - AdyenOrderPayment $adyenOrderPaymentHelper, - AdyenLogger $adyenLogger, - MagentoInvoiceFactory $magentoInvoiceFactory, - Order $orderHelper, - PaymentMethods $paymentMethodsHelper - ) { - $this->invoiceHelper = $invoiceHelper; - $this->adyenOrderPaymentFactory = $adyenOrderPaymentFactory; - $this->adyenOrderPaymentHelper = $adyenOrderPaymentHelper; - $this->adyenLogger = $adyenLogger; - $this->magentoInvoiceFactory = $magentoInvoiceFactory; - $this->orderHelper = $orderHelper; - $this->paymentMethodsHelper = $paymentMethodsHelper; - } + private readonly Invoice $invoiceHelper, + private readonly PaymentFactory $adyenOrderPaymentFactory, + private readonly AdyenOrderPayment $adyenOrderPaymentHelper, + private readonly AdyenLogger $adyenLogger, + private readonly MagentoInvoiceFactory $magentoInvoiceFactory, + private readonly Order $orderHelper, + private readonly PaymentMethods $paymentMethodsHelper, + private readonly InvoiceRepositoryInterface $invoiceRepository + ) { } /** * @param MagentoOrder $order @@ -112,7 +85,8 @@ public function handleWebhook(MagentoOrder $order, Notification $notification, s ] ); - $magentoInvoice = $this->magentoInvoiceFactory->create()->load($adyenInvoice->getInvoiceId(), MagentoInvoice::ENTITY_ID); + $magentoInvoice = $this->invoiceRepository->get($adyenInvoice->getInvoiceId()); + $this->adyenLogger->addAdyenNotification( sprintf('Notification %s updated invoice {invoiceId}', $notification->getEntityId()), array_merge( diff --git a/Model/Api/AdyenDonations.php b/Model/Api/AdyenDonations.php index 46080f40ae..8c21aa9144 100644 --- a/Model/Api/AdyenDonations.php +++ b/Model/Api/AdyenDonations.php @@ -150,12 +150,12 @@ private function incrementTryCount(Order $order): void $order->getPayment()->setAdditionalInformation('donationTryCount', $this->donationTryCount); } - $order->save(); + $this->orderRepository->save($order); } private function removeDonationToken(Order $order): void { $order->getPayment()->unsAdditionalInformation('donationToken'); - $order->save(); + $this->orderRepository->save($order); } } diff --git a/Model/Notification.php b/Model/Notification.php index 3dae7ed20a..4419506f03 100755 --- a/Model/Notification.php +++ b/Model/Notification.php @@ -51,14 +51,18 @@ class Notification extends AbstractModel implements NotificationInterface const STATE_ADYEN_AUTHORIZED = "adyen_authorized"; const MAX_ERROR_COUNT = 5; + private ResourceModel\Notification|AbstractDb $notificationResourceModel; + public function __construct( Context $context, Registry $registry, AbstractResource $resource = null, AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], ) { parent::__construct($context, $registry, $resource, $resourceCollection, $data); + + $this->notificationResourceModel = $resourceCollection; } protected function _construct() @@ -74,7 +78,7 @@ protected function _construct() */ public function isDuplicate($done = null): bool { - $result = $this->getResource()->getNotification( + $result = $this->notificationResourceModel->getNotification( $this->getPspreference(), $this->getEventCode(), $this->getSuccess(), diff --git a/Observer/SetOrderStateAfterPaymentObserver.php b/Observer/SetOrderStateAfterPaymentObserver.php index c182ad8953..0a7a9b9965 100644 --- a/Observer/SetOrderStateAfterPaymentObserver.php +++ b/Observer/SetOrderStateAfterPaymentObserver.php @@ -20,33 +20,18 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Payment\Model\MethodInterface; +use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Payment; use Magento\Sales\Model\Order\StatusResolver; class SetOrderStateAfterPaymentObserver implements ObserverInterface { - /** - * @var StatusResolver - */ - private StatusResolver $statusResolver; - - /** - * @var Config - */ - private Config $configHelper; - - /** - * @param StatusResolver $statusResolver - * @param Config $configHelper - */ public function __construct( - StatusResolver $statusResolver, - Config $configHelper - ) { - $this->statusResolver = $statusResolver; - $this->configHelper = $configHelper; - } + private readonly StatusResolver $statusResolver, + private readonly Config $configHelper, + private readonly OrderRepositoryInterface $orderRepository + ) { } /** * @throws Exception @@ -85,7 +70,7 @@ private function handlePosPayment(Payment $payment): void $order->setStatus($status); $message = __("Pos payment initiated and waiting for payment"); $order->addCommentToStatusHistory($message, $status); - $order->save(); + $this->orderRepository->save($order); } } @@ -126,7 +111,7 @@ private function handlePaymentWithAction(Payment $payment): void ); $order->addCommentToStatusHistory($message, $status); - $order->save(); + $this->orderRepository->save($order); } } } diff --git a/Test/Unit/Block/Checkout/SuccessTest.php b/Test/Unit/Block/Checkout/SuccessTest.php index 63afcaaed6..e2c5db29e9 100644 --- a/Test/Unit/Block/Checkout/SuccessTest.php +++ b/Test/Unit/Block/Checkout/SuccessTest.php @@ -12,27 +12,39 @@ namespace Adyen\Payment\Test\Unit\Block\Checkout; use Adyen\Payment\Block\Checkout\Success; +use Adyen\Payment\Helper\Config; +use Adyen\Payment\Helper\Data; +use Adyen\Payment\Model\Ui\AdyenCheckoutSuccessConfigProvider; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Framework\View\Element\Template\Context; +use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\OrderFactory; use Magento\Checkout\Model\Session as CheckoutSession; use Magento\Customer\Model\Session as CustomerSession; use Magento\Quote\Model\QuoteIdToMaskedQuoteId; +use Magento\Store\Model\StoreManagerInterface; +use PHPUnit\Framework\MockObject\MockObject; class SuccessTest extends AbstractAdyenTestCase { - private $objectManager; - private $checkoutSessionMock; - private $customerSessionMock; - private $orderFactoryMock; - private $orderMock; - private $quoteIdToMaskedQuoteIdMock; - private $successBlock; + private Success $successBlock; + private CheckoutSession|MockObject $checkoutSessionMock; + private CustomerSession|MockObject $customerSessionMock; + private OrderFactory|MockObject $orderFactoryMock; + private Order|MockObject $orderMock; + private QuoteIdToMaskedQuoteId|MockObject $quoteIdToMaskedQuoteIdMock; + private OrderRepositoryInterface|MockObject $orderRepositoryMock; + private Context|MockObject $contextMock; + private Data|MockObject $adyenDataHelper; + private Config|MockObject $configMock; + private AdyenCheckoutSuccessConfigProvider|MockObject $adyenCheckoutSuccessConfigProviderMock; + private StoreManagerInterface|MockObject $storeManagerMock; + private SerializerInterface|MockObject $serializerMock; protected function setUp(): void { - $this->objectManager = new ObjectManager($this); $this->checkoutSessionMock = $this->createGeneratedMock( CheckoutSession::class, ['getLastOrderId'] @@ -44,15 +56,27 @@ protected function setUp(): void $this->orderFactoryMock = $this->createGeneratedMock(OrderFactory::class, ['create']); $this->orderMock = $this->createMock(Order::class); $this->quoteIdToMaskedQuoteIdMock = $this->createMock(QuoteIdToMaskedQuoteId::class); + $this->adyenDataHelper = $this->createMock(Data::class); + $this->contextMock = $this->createMock(Context::class); + $this->orderRepositoryMock = $this->createMock(OrderRepositoryInterface::class); + $this->configMock = $this->createMock(Config::class); + $this->adyenCheckoutSuccessConfigProviderMock = + $this->createMock(AdyenCheckoutSuccessConfigProvider::class); + $this->storeManagerMock = $this->createMock(StoreManagerInterface::class); + $this->serializerMock = $this->createMock(SerializerInterface::class); - $this->successBlock = $this->objectManager->getObject( - Success::class, - [ - 'checkoutSession' => $this->checkoutSessionMock, - 'customerSession' => $this->customerSessionMock, - 'orderFactory' => $this->orderFactoryMock, - 'quoteIdToMaskedQuoteId' => $this->quoteIdToMaskedQuoteIdMock - ] + $this->successBlock = new Success( + $this->contextMock, + $this->checkoutSessionMock, + $this->customerSessionMock, + $this->quoteIdToMaskedQuoteIdMock, + $this->orderFactoryMock, + $this->adyenDataHelper, + $this->configMock, + $this->adyenCheckoutSuccessConfigProviderMock, + $this->storeManagerMock, + $this->serializerMock, + $this->orderRepositoryMock ); } @@ -63,8 +87,7 @@ public function testGetMaskedQuoteIdSuccessful() $quoteId = 1; $this->checkoutSessionMock->method('getLastOrderId')->willReturn($orderId); - $this->orderFactoryMock->method('create')->willReturn($this->orderMock); - $this->orderMock->method('load')->willReturnSelf(); + $this->orderRepositoryMock->method('get')->with($orderId)->willReturn($this->orderMock); $this->orderMock->method('getQuoteId')->willReturn($quoteId); $this->quoteIdToMaskedQuoteIdMock->method('execute')->willReturn($maskedQuoteId); @@ -78,7 +101,7 @@ public function testGetMaskedQuoteIdException() $exception = new \Exception('Error during getMaskedQuoteId'); $this->checkoutSessionMock->method('getLastOrderId')->willReturn($orderId); - $this->orderFactoryMock->method('create')->willThrowException($exception); + $this->orderRepositoryMock->method('get')->with($orderId)->willThrowException($exception); $this->expectException(\Exception::class); $this->expectExceptionMessage('Error during getMaskedQuoteId'); diff --git a/Test/Unit/Controller/Return/IndexTest.php b/Test/Unit/Controller/Return/IndexTest.php index 700f6feec8..6c5750d925 100644 --- a/Test/Unit/Controller/Return/IndexTest.php +++ b/Test/Unit/Controller/Return/IndexTest.php @@ -26,6 +26,8 @@ use Magento\Framework\App\ResponseInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Message\ManagerInterface as MessageManagerInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Payment; use Magento\Sales\Model\OrderFactory; @@ -54,6 +56,8 @@ class IndexTest extends AbstractAdyenTestCase private $configHelperMock; private $paymentsDetailsHelperMock; private $paymentResponseHandlerMock; + private $cartRepositoryMock; + private $orderRepositoryMock; const STORE_ID = 1; @@ -69,6 +73,8 @@ protected function setUp(): void $this->configHelperMock = $this->createMock(Config::class); $this->paymentsDetailsHelperMock = $this->createMock(PaymentsDetails::class); $this->paymentResponseHandlerMock = $this->createMock(PaymentResponseHandler::class); + $this->cartRepositoryMock = $this->createMock(CartRepositoryInterface::class); + $this->orderRepositoryMock = $this->createMock(OrderRepositoryInterface::class); // Extra mock objects and methods $this->messageManagerMock = $this->createMock(MessageManagerInterface::class); @@ -114,7 +120,9 @@ protected function setUp(): void $this->quoteHelperMock, $this->configHelperMock, $this->paymentsDetailsHelperMock, - $this->paymentResponseHandlerMock + $this->paymentResponseHandlerMock, + $this->cartRepositoryMock, + $this->orderRepositoryMock ); } diff --git a/Test/Unit/Helper/InvoiceTest.php b/Test/Unit/Helper/InvoiceTest.php index de963e1dbc..8a72a7f9de 100644 --- a/Test/Unit/Helper/InvoiceTest.php +++ b/Test/Unit/Helper/InvoiceTest.php @@ -24,6 +24,7 @@ use Magento\Framework\Exception\AlreadyExistsException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; +use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order as MagentoOrder; use Magento\Sales\Model\Order\Invoice as InvoiceModel; @@ -405,20 +406,23 @@ public function testSendInvoiceMailCatchesException() } /** - * @param $contextMock - * @param $adyenLoggerMock - * @param $adyenDataHelperMock - * @param $invoiceRepositoryInterfaceMock - * @param $adyenInvoiceFactory - * @param $adyenInvoiceResourceModelMock - * @param $orderPaymentResourceModelMock - * @param $paymentFactoryMock - * @param $adyenInvoiceCollectionMock - * @param $magentoInvoiceFactoryMock - * @param $magentoOrderResourceModelMock - * @param $adyenConfigHelperMock - * @param $invoiceSenderMock - * @param $transactionMock + * @param null $contextMock + * @param null $adyenLoggerMock + * @param null $adyenDataHelperMock + * @param null $invoiceRepositoryInterfaceMock + * @param null $adyenInvoiceFactory + * @param null $adyenInvoiceResourceModelMock + * @param null $orderPaymentResourceModelMock + * @param null $paymentFactoryMock + * @param null $adyenInvoiceCollectionMock + * @param null $magentoInvoiceFactoryMock + * @param null $magentoOrderResourceModelMock + * @param null $adyenConfigHelperMock + * @param null $invoiceSenderMock + * @param null $transactionMock + * @param null $chargedCurrencyMock + * @param null $orderRepositoryMock + * * @return Invoice */ protected function createInvoiceHelper( @@ -436,7 +440,8 @@ protected function createInvoiceHelper( $adyenConfigHelperMock = null, $invoiceSenderMock = null, $transactionMock = null, - $chargedCurrencyMock = null + $chargedCurrencyMock = null, + $orderRepositoryMock = null ): Invoice { if (is_null($contextMock)) { @@ -499,6 +504,10 @@ protected function createInvoiceHelper( $chargedCurrencyMock = $this->createMock(ChargedCurrency::class); } + if (is_null($orderRepositoryMock)) { + $orderRepositoryMock = $this->createMock(OrderRepositoryInterface::class); + } + return new Invoice( $contextMock, $adyenLoggerMock, @@ -514,7 +523,8 @@ protected function createInvoiceHelper( $adyenConfigHelperMock, $invoiceSenderMock, $transactionMock, - $chargedCurrencyMock + $chargedCurrencyMock, + $orderRepositoryMock ); } } diff --git a/Test/Unit/Helper/PaymentResponseHandlerTest.php b/Test/Unit/Helper/PaymentResponseHandlerTest.php index fba1bfb6a2..9354d6e0a6 100644 --- a/Test/Unit/Helper/PaymentResponseHandlerTest.php +++ b/Test/Unit/Helper/PaymentResponseHandlerTest.php @@ -22,6 +22,7 @@ use Magento\Framework\Exception\AlreadyExistsException; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Sales\Api\OrderStatusHistoryRepositoryInterface; use Magento\Sales\Model\Order as MagentoOrder; use Magento\Sales\Model\Order\Payment; use Magento\Sales\Model\Order\Status\History; @@ -32,6 +33,7 @@ use Adyen\Payment\Model\ResourceModel\PaymentResponse\Collection; use Adyen\Payment\Model\ResourceModel\PaymentResponse\CollectionFactory; use Adyen\Payment\Helper\Config; +use PHPUnit\Framework\MockObject\MockObject; use ReflectionClass; class PaymentResponseHandlerTest extends AbstractAdyenTestCase @@ -51,6 +53,7 @@ class PaymentResponseHandlerTest extends AbstractAdyenTestCase private Config $configHelperMock; private Collection $paymentResponseMockForFactory; private CollectionFactory $paymentResponseCollectionFactoryMock; + private OrderStatusHistoryRepositoryInterface|MockObject $historyRepositoryMock; protected function setUp(): void { @@ -68,6 +71,7 @@ protected function setUp(): void ]); $this->stateDataHelperMock = $this->createMock(StateData::class); $this->configHelperMock = $this->createMock(Config::class); + $this->historyRepositoryMock = $this->createMock(OrderStatusHistoryRepositoryInterface::class); $this->paymentResponseMockForFactory = $this->createMock(Collection::class); @@ -98,7 +102,8 @@ protected function setUp(): void $this->orderHistoryFactoryMock, $this->stateDataHelperMock, $this->paymentResponseCollectionFactoryMock, - $this->configHelperMock + $this->configHelperMock, + $this->historyRepositoryMock ); } diff --git a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php index 87d9246e30..b9e4eedc37 100644 --- a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php @@ -12,6 +12,7 @@ use Adyen\Payment\Model\Notification; use Adyen\Payment\Model\Order\PaymentFactory; use Adyen\Payment\Helper\AdyenOrderPayment; +use Magento\Sales\Api\InvoiceRepositoryInterface; use Magento\Sales\Model\Order as MagentoOrder; use Magento\Sales\Model\Order\InvoiceFactory as MagentoInvoiceFactory; use Adyen\Payment\Model\Invoice as AdyenInvoice; @@ -47,7 +48,8 @@ private function createCaptureWebhookHandler( $adyenLogger = null, $magentoInvoiceFactory = null, $orderHelper = null, - $paymentMethodsHelper = null + $paymentMethodsHelper = null, + $invoiceRepository = null ): CaptureWebhookHandler { if($invoiceHelper == null) { @@ -71,6 +73,9 @@ private function createCaptureWebhookHandler( if($paymentMethodsHelper == null) { $paymentMethodsHelper = $this->createGeneratedMock(PaymentMethods::class); } + if($invoiceRepository == null) { + $invoiceRepository = $this->createGeneratedMock(InvoiceRepositoryInterface::class); + } return new CaptureWebhookHandler( invoiceHelper: $invoiceHelper, @@ -79,7 +84,8 @@ private function createCaptureWebhookHandler( adyenLogger: $adyenLogger, magentoInvoiceFactory: $magentoInvoiceFactory, orderHelper: $orderHelper, - paymentMethodsHelper: $paymentMethodsHelper + paymentMethodsHelper: $paymentMethodsHelper, + invoiceRepository: $invoiceRepository ); } diff --git a/Test/Unit/Observer/SetOrderStateAfterPaymentObserverTest.php b/Test/Unit/Observer/SetOrderStateAfterPaymentObserverTest.php index 06ca3b433f..09dc7e6a7c 100644 --- a/Test/Unit/Observer/SetOrderStateAfterPaymentObserverTest.php +++ b/Test/Unit/Observer/SetOrderStateAfterPaymentObserverTest.php @@ -19,6 +19,7 @@ use Magento\Framework\Event\Observer; use Magento\Framework\Exception\LocalizedException; use Magento\Payment\Model\MethodInterface; +use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Payment; use Magento\Sales\Model\Order\StatusResolver; @@ -31,6 +32,7 @@ class SetOrderStateAfterPaymentObserverTest extends AbstractAdyenTestCase private $orderMock; private $statusResolverMock; private $configHelperMock; + private $orderRepositoryMock; const STORE_ID = 1; @@ -41,6 +43,7 @@ public function setUp(): void $this->orderMock = $this->createMock(Order::class); $this->statusResolverMock = $this->createMock(Order\StatusResolver::class); $this->configHelperMock = $this->createMock(Config::class); + $this->orderRepositoryMock = $this->createMock(OrderRepositoryInterface::class); $paymentMethodInstanceMock = $this->createMock(Adapter::class); $this->paymentMock->method('getMethodInstance')->willReturn($paymentMethodInstanceMock); @@ -51,7 +54,8 @@ public function setUp(): void $this->setOrderStateAfterPaymentObserver = new SetOrderStateAfterPaymentObserver( $this->statusResolverMock, - $this->configHelperMock + $this->configHelperMock, + $this->orderRepositoryMock ); } @@ -132,7 +136,11 @@ public function testPosPaymentSuccessfulExecute() $eventObserver = $this->createMock(Observer::class); $eventObserver->method('getData')->with('payment')->willReturn($payment); - $observer = new SetOrderStateAfterPaymentObserver($statusResolver, $configHelperMock); + $observer = new SetOrderStateAfterPaymentObserver( + $statusResolver, + $configHelperMock, + $this->orderRepositoryMock + ); $observer->execute($eventObserver); } From d484e46f018902fe0b2f87557e28d57657b3d659 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 14 Jan 2025 11:43:45 +0100 Subject: [PATCH 09/34] [ECP-9489] Use object manager to load Invoice entity class --- Model/Notification.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Model/Notification.php b/Model/Notification.php index 4419506f03..4291150fe3 100755 --- a/Model/Notification.php +++ b/Model/Notification.php @@ -13,6 +13,7 @@ use Adyen\Payment\Api\Data\NotificationInterface; use DateTime; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Data\Collection\AbstractDb; use Magento\Framework\Model\AbstractModel; use Magento\Framework\Model\Context; @@ -51,18 +52,14 @@ class Notification extends AbstractModel implements NotificationInterface const STATE_ADYEN_AUTHORIZED = "adyen_authorized"; const MAX_ERROR_COUNT = 5; - private ResourceModel\Notification|AbstractDb $notificationResourceModel; - public function __construct( Context $context, Registry $registry, AbstractResource $resource = null, AbstractDb $resourceCollection = null, - array $data = [], + array $data = [] ) { parent::__construct($context, $registry, $resource, $resourceCollection, $data); - - $this->notificationResourceModel = $resourceCollection; } protected function _construct() @@ -78,7 +75,14 @@ protected function _construct() */ public function isDuplicate($done = null): bool { - $result = $this->notificationResourceModel->getNotification( + /* + * Load resource model Adyen\Payment\Model\ResourceModel\Notification manually + * as Magento\Framework\Model\AbstractModel::_getResource() method has been deprecated. + * ObjectManager has been used due to dependencies not being loaded timely manner on entity classes. + */ + $notificationResourceModel = ObjectManager::getInstance()->get($this->getResourceName()); + + $result = $notificationResourceModel->getNotification( $this->getPspreference(), $this->getEventCode(), $this->getSuccess(), From b1169fae0327c0011a61a26685383c5c8b1071b3 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 14 Jan 2025 13:44:22 +0100 Subject: [PATCH 10/34] [ECP-9489] Remove unused constructor argument --- Helper/Webhook/CaptureWebhookHandler.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/Helper/Webhook/CaptureWebhookHandler.php b/Helper/Webhook/CaptureWebhookHandler.php index 3c72a137da..1455328397 100644 --- a/Helper/Webhook/CaptureWebhookHandler.php +++ b/Helper/Webhook/CaptureWebhookHandler.php @@ -24,8 +24,6 @@ use Magento\Framework\Exception\AlreadyExistsException; use Magento\Sales\Api\InvoiceRepositoryInterface; use Magento\Sales\Model\Order as MagentoOrder; -use Magento\Sales\Model\Order\Invoice as MagentoInvoice; -use Magento\Sales\Model\Order\InvoiceFactory as MagentoInvoiceFactory; class CaptureWebhookHandler implements WebhookHandlerInterface { @@ -34,7 +32,6 @@ public function __construct( private readonly PaymentFactory $adyenOrderPaymentFactory, private readonly AdyenOrderPayment $adyenOrderPaymentHelper, private readonly AdyenLogger $adyenLogger, - private readonly MagentoInvoiceFactory $magentoInvoiceFactory, private readonly Order $orderHelper, private readonly PaymentMethods $paymentMethodsHelper, private readonly InvoiceRepositoryInterface $invoiceRepository From c350101ba73c561429652c0da866834e88f08e10 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 14 Jan 2025 13:55:42 +0100 Subject: [PATCH 11/34] [ECP-9489] Implement repository for Adyen Invoice model --- .../AdyenInvoiceRepositoryInterface.php | 56 +++++++++ Helper/Invoice.php | 115 +++++++++--------- Model/AdyenInvoiceRepository.php | 112 +++++++++++++++++ Model/ResourceModel/Invoice/Invoice.php | 28 ++++- etc/di.xml | 2 + 5 files changed, 254 insertions(+), 59 deletions(-) create mode 100644 Api/Repository/AdyenInvoiceRepositoryInterface.php create mode 100644 Model/AdyenInvoiceRepository.php diff --git a/Api/Repository/AdyenInvoiceRepositoryInterface.php b/Api/Repository/AdyenInvoiceRepositoryInterface.php new file mode 100644 index 0000000000..227926ca91 --- /dev/null +++ b/Api/Repository/AdyenInvoiceRepositoryInterface.php @@ -0,0 +1,56 @@ + + */ + +namespace Adyen\Payment\Api\Repository; + +use Adyen\Payment\Api\Data\InvoiceInterface; +use Adyen\Payment\Api\Data\NotificationInterface; +use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\Api\SearchResultsInterface; +use Magento\Framework\Exception\LocalizedException; + +interface AdyenInvoiceRepositoryInterface +{ + /** + * Retrieve adyen_invoice entities which match a specified criteria. + * + * @param SearchCriteriaInterface $searchCriteria + * @return SearchResultsInterface + * + * @throws LocalizedException + */ + public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface; + + /** + * Retrieve adyen_invoice entity by the given notification using the `pspreference` column. + * + * @param NotificationInterface $notification + * @return InvoiceInterface|null + */ + public function getByCaptureWebhook(NotificationInterface $notification): ?InvoiceInterface; + + /** + * Retrieve adyen_invoice entities by `adyen_order_payment_id`. + * + * @param int $adyenOrderPaymentId + * @return InvoiceInterface[]|null + */ + public function getByAdyenOrderPaymentId(int $adyenOrderPaymentId): ?array; + + /** + * Performs persist operations for a specified adyen_invoice. + * + * @param InvoiceInterface $entity The order ID. + * @return InvoiceInterface Order interface. + */ + public function save(InvoiceInterface $entity): InvoiceInterface; +} diff --git a/Helper/Invoice.php b/Helper/Invoice.php index 0d6fa6ebc4..407e29ec78 100644 --- a/Helper/Invoice.php +++ b/Helper/Invoice.php @@ -12,7 +12,9 @@ namespace Adyen\Payment\Helper; use Adyen\Payment\Api\Data\InvoiceInterface; +use Adyen\Payment\Api\Data\NotificationInterface; use Adyen\Payment\Api\Data\OrderPaymentInterface; +use Adyen\Payment\Api\Repository\AdyenInvoiceRepositoryInterface; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\Invoice as AdyenInvoice; use Adyen\Payment\Model\InvoiceFactory; @@ -61,6 +63,8 @@ class Invoice extends AbstractHelper * @param InvoiceSender $invoiceSender * @param Transaction $transaction * @param ChargedCurrency $chargedCurrencyHelper + * @param OrderRepositoryInterface $orderRepository + * @param AdyenInvoiceRepositoryInterface $adyenInvoiceRepository */ public function __construct( protected readonly Context $context, @@ -78,7 +82,8 @@ public function __construct( protected readonly InvoiceSender $invoiceSender, protected readonly Transaction $transaction, protected readonly ChargedCurrency $chargedCurrencyHelper, - protected readonly OrderRepositoryInterface $orderRepository + protected readonly OrderRepositoryInterface $orderRepository, + protected readonly AdyenInvoiceRepositoryInterface $adyenInvoiceRepository ) { parent::__construct($context); } @@ -117,9 +122,9 @@ public function createInvoice(Order $order, Notification $notification, bool $is // if amount is zero create a offline invoice $value = (int)$notification->getAmountValue(); if ($value == 0) { - $invoice->setRequestedCaptureCase(\Magento\Sales\Model\Order\Invoice::CAPTURE_OFFLINE); + $invoice->setRequestedCaptureCase(InvoiceModel::CAPTURE_OFFLINE); } else { - $invoice->setRequestedCaptureCase(\Magento\Sales\Model\Order\Invoice::NOT_CAPTURE); + $invoice->setRequestedCaptureCase(InvoiceModel::NOT_CAPTURE); } $invoice->register(); @@ -148,7 +153,7 @@ public function createInvoice(Order $order, Notification $notification, bool $is throw $e; } - $invoiceAutoMail = (bool)$this->scopeConfig->isSetFlag( + $invoiceAutoMail = $this->scopeConfig->isSetFlag( InvoiceIdentity::XML_PATH_EMAIL_ENABLED, ScopeInterface::SCOPE_STORE, $order->getStoreId() @@ -184,7 +189,6 @@ public function createInvoice(Order $order, Notification $notification, bool $is * @param int $captureAmountCents * @param int|null $invoiceId * @return AdyenInvoice - * @throws AlreadyExistsException */ public function createAdyenInvoice( Order\Payment $payment, @@ -210,7 +214,7 @@ public function createAdyenInvoice( $adyenInvoice->setInvoiceId($invoiceId); } - $this->adyenInvoiceResourceModel->save($adyenInvoice); + $this->adyenInvoiceRepository->save($adyenInvoice); return $adyenInvoice; } @@ -227,36 +231,37 @@ public function createAdyenInvoice( */ public function handleCaptureWebhook(Order $order, Notification $notification): AdyenInvoice { - $invoiceFactory = $this->adyenInvoiceFactory->create(); - $adyenInvoice = $this->adyenInvoiceResourceModel->getAdyenInvoiceByCaptureWebhook($order, $notification); - $chargedCurrency = $this->chargedCurrencyHelper->getOrderAmountCurrency($order, false); - $formattedAdyenOrderAmount = $this->adyenDataHelper->formatAmount( - $chargedCurrency->getAmount(), - $chargedCurrency->getCurrencyCode() - ); - $notificationAmount = $notification->getAmountValue(); - $isFullAmountCaptured = $formattedAdyenOrderAmount == $notificationAmount; + $adyenInvoice = $this->adyenInvoiceRepository->getByCaptureWebhook($notification); + // No adyen_invoice found, trying to process external capture attempt if (is_null($adyenInvoice) && $order->canInvoice()) { - if ($isFullAmountCaptured) { - $adyenInvoiceObject = $this->createInvoiceFromWebhook($order, $notification); - } else { - $order->addStatusHistoryComment(__(sprintf( - 'Partial %s webhook notification w/amount %s %s was processed, no invoice created. - Please create offline invoice.', - $notification->getEventCode(), - $notification->getAmountCurrency(), - $this->adyenDataHelper->originalAmount( - $notification->getAmountValue(), - $notification->getAmountCurrency()) - )), false); - throw new AdyenWebhookException(__(sprintf( - 'Unable to create adyen_invoice from CA partial capture linked to original reference %s, - psp reference %s, and order %s.', - $notification->getOriginalReference(), - $notification->getPspreference(), - $order->getIncrementId() - ))); + $chargedCurrency = $this->chargedCurrencyHelper->getOrderAmountCurrency($order, false); + $formattedAdyenOrderAmount = $this->adyenDataHelper->formatAmount( + $chargedCurrency->getAmount(), + $chargedCurrency->getCurrencyCode() + ); + $notificationAmount = $notification->getAmountValue(); + $isFullAmountCaptured = $formattedAdyenOrderAmount == $notificationAmount; + + if ($isFullAmountCaptured) { + $adyenInvoice = $this->createInvoiceFromWebhook($order, $notification); + } else { + $order->addStatusHistoryComment(__(sprintf( + 'Partial %s webhook notification w/amount %s %s was processed, no invoice created. + Please create offline invoice.', + $notification->getEventCode(), + $notification->getAmountCurrency(), + $this->adyenDataHelper->originalAmount( + $notification->getAmountValue(), + $notification->getAmountCurrency()) + )), false); + throw new AdyenWebhookException(__(sprintf( + 'Unable to create adyen_invoice from CA partial capture linked to original reference %s, + psp reference %s, and order %s.', + $notification->getOriginalReference(), + $notification->getPspreference(), + $order->getIncrementId() + ))); } } elseif (is_null($adyenInvoice) && !$order->canInvoice()) { throw new AdyenWebhookException(__(sprintf( @@ -268,18 +273,14 @@ public function handleCaptureWebhook(Order $order, Notification $notification): ))); } - /** @var AdyenInvoice $adyenInvoiceObject */ - $adyenInvoiceObject = $adyenInvoiceObject - ?? $invoiceFactory->load($adyenInvoice[InvoiceInterface::ENTITY_ID], InvoiceInterface::ENTITY_ID); - $additionalData = $notification->getAdditionalData(); - $acquirerReference = $additionalData[Notification::ADDITIONAL_DATA] ?? null; - $adyenInvoiceObject->setAcquirerReference($acquirerReference); - $adyenInvoiceObject->setStatus(InvoiceInterface::STATUS_SUCCESSFUL); - $this->adyenInvoiceResourceModel->save($adyenInvoiceObject); + $acquirerReference = $additionalData[NotificationInterface::ADDITIONAL_DATA] ?? null; + $adyenInvoice->setAcquirerReference($acquirerReference); + $adyenInvoice->setStatus(InvoiceInterface::STATUS_SUCCESSFUL); + $this->adyenInvoiceRepository->save($adyenInvoice); /** @var InvoiceModel $magentoInvoice */ - $magentoInvoice = $this->invoiceRepository->get($adyenInvoiceObject->getInvoiceId()); + $magentoInvoice = $this->invoiceRepository->get($adyenInvoice->getInvoiceId()); if ($this->isFullInvoiceAmountManuallyCaptured($magentoInvoice)) { $magentoInvoice->pay(); @@ -287,7 +288,7 @@ public function handleCaptureWebhook(Order $order, Notification $notification): $this->magentoOrderResourceModel->save($magentoInvoice->getOrder()); } - return $adyenInvoiceObject; + return $adyenInvoice; } /** @@ -296,22 +297,22 @@ public function handleCaptureWebhook(Order $order, Notification $notification): * @param Payment $adyenOrderPayment * @param InvoiceModel $invoice * @return float - * @throws AlreadyExistsException */ public function linkAndUpdateAdyenInvoices(Payment $adyenOrderPayment, InvoiceModel $invoice): float { - $invoiceFactory = $this->adyenInvoiceFactory->create(); $linkedAmount = 0; - $adyenInvoices = $this->adyenInvoiceResourceModel->getAdyenInvoicesByAdyenPaymentId($adyenOrderPayment[OrderPaymentInterface::ENTITY_ID]); + $adyenInvoices = $this->adyenInvoiceRepository->getByAdyenOrderPaymentId( + $adyenOrderPayment[OrderPaymentInterface::ENTITY_ID] + ); + if (!is_null($adyenInvoices)) { + /** @var AdyenInvoice $adyenInvoice */ foreach ($adyenInvoices as $adyenInvoice) { - if (is_null($adyenInvoice[AdyenInvoice::INVOICE_ID])) { - /** @var AdyenInvoice $adyenInvoiceObject */ - $adyenInvoiceObject = $invoiceFactory->load($adyenInvoice[InvoiceInterface::ENTITY_ID], InvoiceInterface::ENTITY_ID); - $adyenInvoiceObject->setInvoiceId($invoice->getEntityId()); - $this->adyenInvoiceResourceModel->save($adyenInvoiceObject); - $linkedAmount += $adyenInvoiceObject->getAmount(); + if (is_null($adyenInvoice->getInvoiceId())) { + $adyenInvoice->setInvoiceId($invoice->getEntityId()); + $this->adyenInvoiceRepository->save($adyenInvoice); + $linkedAmount += $adyenInvoice->getAmount(); } } } @@ -382,7 +383,7 @@ public function createInvoiceFromWebhook(Order $order, Notification $notificatio $transactionSave->save(); //Send Invoice mail to customer - $invoiceAutoMail = (bool)$this->scopeConfig->isSetFlag( + $invoiceAutoMail = $this->scopeConfig->isSetFlag( InvoiceIdentity::XML_PATH_EMAIL_ENABLED, ScopeInterface::SCOPE_STORE, $order->getStoreId() @@ -394,15 +395,15 @@ public function createInvoiceFromWebhook(Order $order, Notification $notificatio __('Notified customer about invoice creation #%1.', $invoice->getId()) ); $order->setIsCustomerNotified(true); - $this->orderRepository->save($order); } else { $order->addStatusHistoryComment( __('Created invoice #%1.', $invoice->getId()) ); $order->setIsCustomerNotified(false); - $this->orderRepository->save($order); } + $this->orderRepository->save($order); + //Create entry in adyen_invoice table $adyenInvoice = $this->createAdyenInvoice( $order->getPayment(), @@ -421,7 +422,7 @@ public function createInvoiceFromWebhook(Order $order, Notification $notificatio return $adyenInvoice; } - public function sendInvoiceMail(InvoiceModel $invoice) + public function sendInvoiceMail(InvoiceModel $invoice): void { try { $this->invoiceSender->send($invoice); diff --git a/Model/AdyenInvoiceRepository.php b/Model/AdyenInvoiceRepository.php new file mode 100644 index 0000000000..2345e05e72 --- /dev/null +++ b/Model/AdyenInvoiceRepository.php @@ -0,0 +1,112 @@ + + */ + +namespace Adyen\Payment\Model; + +use Adyen\AdyenException; +use Adyen\Payment\Api\Data\InvoiceInterface; +use Adyen\Payment\Api\Data\NotificationInterface; +use Adyen\Payment\Api\Repository\AdyenInvoiceRepositoryInterface; +use Adyen\Payment\Model\ResourceModel\Invoice\CollectionFactory; +use Adyen\Payment\Model\ResourceModel\Invoice\Invoice as InvoiceResourceModel; +use Adyen\Webhook\EventCodes; +use Magento\Framework\Api\Search\SearchResultFactory; +use Magento\Framework\Api\SearchCriteria\CollectionProcessor; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\Api\SearchResultsInterface; +use Magento\Framework\Exception\AlreadyExistsException; +use Magento\Framework\Exception\LocalizedException; + +class AdyenInvoiceRepository implements AdyenInvoiceRepositoryInterface +{ + /** + * @param SearchResultFactory $searchResultsFactory + * @param CollectionFactory $collectionFactory + * @param CollectionProcessor $collectionProcessor + * @param InvoiceResourceModel $resourceModel + * @param InvoiceFactory $adyenInvoiceFactory + * @param SearchCriteriaBuilder $searchCriteriaBuilder + */ + public function __construct( + private readonly SearchResultFactory $searchResultsFactory, + private readonly CollectionFactory $collectionFactory, + private readonly CollectionProcessor $collectionProcessor, + private readonly InvoiceResourceModel $resourceModel, + private readonly InvoiceFactory $adyenInvoiceFactory, + private readonly SearchCriteriaBuilder $searchCriteriaBuilder, + ) { } + + /** + * @param SearchCriteriaInterface $searchCriteria + * @return SearchResultsInterface + */ + public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface + { + $searchResult = $this->searchResultsFactory->create(); + $collection = $this->collectionFactory->create(); + $this->collectionProcessor->process($searchCriteria, $collection); + $searchResult->setItems($collection->getItems()); + $searchResult->setTotalCount($collection->getSize()); + + return $searchResult; + } + + /** + * @throws AlreadyExistsException + */ + public function save(InvoiceInterface $entity): InvoiceInterface + { + $this->resourceModel->save($entity); + + return $entity; + } + + /** + * @param NotificationInterface $notification + * @return InvoiceInterface|null + * @throws AdyenException + * @throws LocalizedException + */ + public function getByCaptureWebhook(NotificationInterface $notification): ?InvoiceInterface + { + if ($notification->getEventCode() !== EventCodes::CAPTURE) { + throw new AdyenException(sprintf( + 'Capture webhook is expected to get the adyen_invoice, %s notification given.', + $notification->getEventCode() + )); + } + + $adyenInvoiceId = $this->resourceModel->getIdByPspreference($notification->getPspreference()); + + if (empty($adyenInvoiceId)) { + return null; + } else { + $adyenInvoice = $this->adyenInvoiceFactory->create(); + $this->resourceModel->load($adyenInvoice, $adyenInvoiceId, 'entity_id'); + + return $adyenInvoice; + } + } + + /** + * @param int $adyenOrderPaymentId + * @return InvoiceInterface[]|null + */ + public function getByAdyenOrderPaymentId(int $adyenOrderPaymentId): ?array + { + $searchCriteria = $this->searchCriteriaBuilder + ->addFilter(InvoiceInterface::ADYEN_ORDER_PAYMENT_ID, $adyenOrderPaymentId) + ->create(); + + return $this->getList($searchCriteria)->getItems(); + } +} diff --git a/Model/ResourceModel/Invoice/Invoice.php b/Model/ResourceModel/Invoice/Invoice.php index 53d509e256..408e1aaaab 100644 --- a/Model/ResourceModel/Invoice/Invoice.php +++ b/Model/ResourceModel/Invoice/Invoice.php @@ -13,7 +13,7 @@ namespace Adyen\Payment\Model\ResourceModel\Invoice; use Adyen\Payment\Model\Notification; -use Adyen\Payment\Setup\UpgradeSchema; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; use Magento\Sales\Model\Order; @@ -24,7 +24,7 @@ class Invoice extends AbstractDb * * @return void */ - protected function _construct() + protected function _construct(): void { $this->_init('adyen_invoice', 'entity_id'); } @@ -32,6 +32,8 @@ protected function _construct() /** * Get all the adyen_invoice entries linked to the adyen_order_payment * + * @deprecated Use Adyen\Payment\Helper\Invoice::getAdyenInvoicesByAdyenPaymentId() method instead. + * * @param $adyenPaymentId * @return array|null */ @@ -50,6 +52,8 @@ public function getAdyenInvoicesByAdyenPaymentId($adyenPaymentId): ?array * Get the respective adyen_invoice entry by using the pspReference of the original payment, the pspReference of the capture * and the magento payment_id linked to this order * + * @deprecated Use AdyenInvoiceRepositoryInterface::getByCaptureWebhook() instead. + * * @param Order $order * @param Notification $notification * @return array|null @@ -72,4 +76,24 @@ public function getAdyenInvoiceByCaptureWebhook(Order $order, Notification $noti return empty($result) ? null : $result; } + + /** + * Gets the entity_id of the adyen_invoice by the given `pspreference` + * + * @param string $pspreference + * @return string + * @throws LocalizedException + */ + public function getIdByPspreference(string $pspreference): string + { + $connection = $this->getConnection(); + + $select = $connection->select() + ->from($this->getMainTable(), 'entity_id') + ->where('pspreference = :pspreference'); + + $bind = [':pspreference' => $pspreference]; + + return $connection->fetchOne($select, $bind); + } } diff --git a/etc/di.xml b/etc/di.xml index e7fc019f4f..019e6db119 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -1699,6 +1699,8 @@ + From c39e1096b14ef3668b5cea7864e8afb31965a2dc Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 14 Jan 2025 14:10:22 +0100 Subject: [PATCH 12/34] [ECP-9489] Remove unused constructor arguments --- Helper/Invoice.php | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Helper/Invoice.php b/Helper/Invoice.php index 407e29ec78..b20e2e8f66 100644 --- a/Helper/Invoice.php +++ b/Helper/Invoice.php @@ -20,9 +20,7 @@ use Adyen\Payment\Model\InvoiceFactory; use Adyen\Payment\Model\Notification; use Adyen\Payment\Model\Order\Payment; -use Adyen\Payment\Model\Order\PaymentFactory; use Adyen\Payment\Model\ResourceModel\Invoice\Collection; -use Adyen\Payment\Model\ResourceModel\Invoice\Invoice as AdyenInvoiceResourceModel; use Adyen\Payment\Model\ResourceModel\Order\Payment as OrderPaymentResourceModel; use Adyen\Payment\Exception\AdyenWebhookException; use Exception; @@ -37,7 +35,6 @@ use Magento\Sales\Model\Order\Email\Container\InvoiceIdentity; use Magento\Sales\Model\Order\Email\Sender\InvoiceSender; use Magento\Sales\Model\Order\Invoice as InvoiceModel; -use Magento\Sales\Model\Order\InvoiceFactory as MagentoInvoiceFactory; use Magento\Store\Model\ScopeInterface; /** @@ -53,13 +50,8 @@ class Invoice extends AbstractHelper * @param Data $adyenDataHelper * @param InvoiceRepositoryInterface $invoiceRepository * @param InvoiceFactory $adyenInvoiceFactory - * @param AdyenInvoiceResourceModel $adyenInvoiceResourceModel * @param OrderPaymentResourceModel $orderPaymentResourceModel - * @param PaymentFactory $adyenOrderPaymentFactory * @param Collection $adyenInvoiceCollection - * @param MagentoInvoiceFactory $magentoInvoiceFactory - * @param \Magento\Sales\Model\ResourceModel\Order $magentoOrderResourceModel - * @param Config $configHelper * @param InvoiceSender $invoiceSender * @param Transaction $transaction * @param ChargedCurrency $chargedCurrencyHelper @@ -72,13 +64,8 @@ public function __construct( protected readonly Data $adyenDataHelper, protected readonly InvoiceRepositoryInterface $invoiceRepository, protected readonly InvoiceFactory $adyenInvoiceFactory, - protected readonly AdyenInvoiceResourceModel $adyenInvoiceResourceModel, protected readonly OrderPaymentResourceModel $orderPaymentResourceModel, - protected readonly PaymentFactory $adyenOrderPaymentFactory, protected readonly Collection $adyenInvoiceCollection, - protected readonly MagentoInvoiceFactory $magentoInvoiceFactory, - protected readonly \Magento\Sales\Model\ResourceModel\Order $magentoOrderResourceModel, - protected readonly Config $configHelper, protected readonly InvoiceSender $invoiceSender, protected readonly Transaction $transaction, protected readonly ChargedCurrency $chargedCurrencyHelper, @@ -285,7 +272,7 @@ public function handleCaptureWebhook(Order $order, Notification $notification): if ($this->isFullInvoiceAmountManuallyCaptured($magentoInvoice)) { $magentoInvoice->pay(); $this->invoiceRepository->save($magentoInvoice); - $this->magentoOrderResourceModel->save($magentoInvoice->getOrder()); + $this->orderRepository->save($magentoInvoice->getOrder()); } return $adyenInvoice; From b085fb61439759277ac77409d60342afad67b9f9 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 14 Jan 2025 16:14:22 +0100 Subject: [PATCH 13/34] [ECP-9489] Fix unit tests --- Helper/Invoice.php | 4 +- Test/Unit/Helper/InvoiceTest.php | 149 +++++------------- .../Webhook/CaptureWebhookHandlerTest.php | 43 ++--- .../SetOrderStateAfterPaymentObserverTest.php | 4 +- 4 files changed, 53 insertions(+), 147 deletions(-) diff --git a/Helper/Invoice.php b/Helper/Invoice.php index b20e2e8f66..cb99cfb754 100644 --- a/Helper/Invoice.php +++ b/Helper/Invoice.php @@ -289,9 +289,7 @@ public function linkAndUpdateAdyenInvoices(Payment $adyenOrderPayment, InvoiceMo { $linkedAmount = 0; - $adyenInvoices = $this->adyenInvoiceRepository->getByAdyenOrderPaymentId( - $adyenOrderPayment[OrderPaymentInterface::ENTITY_ID] - ); + $adyenInvoices = $this->adyenInvoiceRepository->getByAdyenOrderPaymentId($adyenOrderPayment->getEntityId()); if (!is_null($adyenInvoices)) { /** @var AdyenInvoice $adyenInvoice */ diff --git a/Test/Unit/Helper/InvoiceTest.php b/Test/Unit/Helper/InvoiceTest.php index 8a72a7f9de..1c2c51e619 100644 --- a/Test/Unit/Helper/InvoiceTest.php +++ b/Test/Unit/Helper/InvoiceTest.php @@ -12,32 +12,29 @@ namespace Adyen\Payment\Test\Unit\Helper; use Adyen\Payment\Api\Data\InvoiceInterface; +use Adyen\Payment\Api\Repository\AdyenInvoiceRepositoryInterface; use Adyen\Payment\Helper\ChargedCurrency; -use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Invoice; use Adyen\Payment\Model\AdyenAmountCurrency; use Adyen\Payment\Model\InvoiceFactory; use Adyen\Payment\Model\Order\Payment; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Exception; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\AlreadyExistsException; use Magento\Framework\Exception\LocalizedException; -use Magento\Framework\Model\ResourceModel\Db\AbstractDb; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order as MagentoOrder; use Magento\Sales\Model\Order\Invoice as InvoiceModel; use Adyen\Payment\Logger\AdyenLogger; -use Adyen\Payment\Model\Order\PaymentFactory; use Adyen\Payment\Model\ResourceModel\Invoice\Collection; -use Adyen\Payment\Model\ResourceModel\Invoice\Invoice as AdyenInvoiceResourceModel; use Adyen\Payment\Model\ResourceModel\Order\Payment as OrderPaymentResourceModel; use Magento\Framework\App\Helper\Context; use Magento\Framework\DB\Transaction; use Magento\Sales\Api\InvoiceRepositoryInterface; use Magento\Sales\Model\Order\Email\Sender\InvoiceSender; -use Magento\Sales\Model\Order\InvoiceFactory as MagentoInvoiceFactory; use Adyen\Payment\Model\Invoice as AdyenInvoice; class InvoiceTest extends AbstractAdyenTestCase @@ -77,19 +74,12 @@ public function testCreateInvoice() $this->assertInstanceOf(InvoiceModel::class, $invoice); } - /** - * @throws AlreadyExistsException - */ public function testCreateAdyenInvoice() { $adyenInvoiceMockForFactory = $this->createMock(AdyenInvoice::class); $adyenInvoiceFactoryMock = $this->createGeneratedMock(InvoiceFactory::class, ['create']); $adyenInvoiceFactoryMock->method('create')->willReturn($adyenInvoiceMockForFactory); - $adyenInvoiceResourceModelMock = $this->createConfiguredMock(AdyenInvoiceResourceModel::class, [ - 'save' => $this->createMock(AbstractDb::class) - ]); - $orderPaymentResourceModelMock = $this->createConfiguredMock(OrderPaymentResourceModel::class, [ 'getOrderPaymentDetails' => [ 'entity_id' => 1000 @@ -102,7 +92,6 @@ public function testCreateAdyenInvoice() null, null, $adyenInvoiceFactoryMock, - $adyenInvoiceResourceModelMock, $orderPaymentResourceModelMock ); @@ -127,6 +116,8 @@ public function testCreateAdyenInvoice() */ public function testHandleCaptureWebhook() { + $magentoInvoiceId = 1; + $scopeConfigMock = $this->createConfiguredMock(ScopeConfigInterface::class, [ 'isSetFlag' => false ]); @@ -135,33 +126,32 @@ public function testHandleCaptureWebhook() ]); $adyenInvoiceMock = $this->createMock(AdyenInvoice::class); + $adyenInvoiceMock->method('getInvoiceId')->willReturn($magentoInvoiceId); + $adyenInvoiceFactory = $this->createGeneratedMock(InvoiceFactory::class, ['create']); $adyenInvoiceFactory->method('create')->willReturn($adyenInvoiceMock); + $orderMock = $this->createMock(MagentoOrder::class); + $invoiceLoadedMock = $this->createConfiguredMock(InvoiceModel::class, [ - 'getOrder' => $this->createMock(MagentoOrder::class) + 'getOrder' => $orderMock ]); $invoiceMock = $this->createConfiguredMock(InvoiceModel::class, [ - 'getId' => 1, - 'load' => $invoiceLoadedMock + 'getId' => $magentoInvoiceId, + 'load' => $invoiceLoadedMock, + 'getOrder' => $orderMock ]); + $magentoInvoiceRepositoryMock = $this->createMock(InvoiceRepositoryInterface::class); + $magentoInvoiceRepositoryMock->method('get')->with($magentoInvoiceId)->willReturn($invoiceMock); + $orderPaymentResourceModelMock = $this->createConfiguredMock(OrderPaymentResourceModel::class, [ 'getOrderPaymentDetails' => [ 'entity_id' => 1000 ] ]); - $magentoInvoiceFactoryMock = $this->createGeneratedMock(MagentoInvoiceFactory::class, ['create']); - $magentoInvoiceFactoryMock->method('create')->willReturn($invoiceMock); - - $magentoOrderResourceModelMock = $this->createGeneratedMock( - \Magento\Sales\Model\ResourceModel\Order::class, - ['save'] - ); - $magentoOrderResourceModelMock->method('save')->willReturn($invoiceMock); - $transactionMock = $this->createGeneratedMock(Transaction::class, ['addObject']); $transactionMock->method('addObject')->willReturn($invoiceMock); @@ -176,16 +166,11 @@ public function testHandleCaptureWebhook() $contextMock, null, null, - null, + $magentoInvoiceRepositoryMock, $adyenInvoiceFactory, - null, $orderPaymentResourceModelMock, null, null, - $magentoInvoiceFactoryMock, - $magentoOrderResourceModelMock, - null, - null, $transactionMock, $chargedCurrencyMock ); @@ -216,43 +201,35 @@ public function testHandleCaptureWebhook() $this->assertInstanceOf(AdyenInvoice::class, $adyenInvoice); } - /** - * @throws AlreadyExistsException - */ public function testLinkAndUpdateAdyenInvoices() { - $adyenInvoiceResourceModelMock = $this->createConfiguredMock(AdyenInvoiceResourceModel::class, [ - 'getAdyenInvoicesByAdyenPaymentId' => [ - ['invoice_id' => null, 'entity_id' => 99] - ], - 'save' => $this->createMock(AbstractDb::class) - ]); - - $adyenInvoiceLoadedMock = $this->createConfiguredMock(AdyenInvoice::class, [ + $adyenInvoiceMock = $this->createConfiguredMock(AdyenInvoice::class, [ 'getAmount' => 1000.0, 'getEntityId' => 99, ]); - $adyenInvoiceMockForFactory = $this->createConfiguredMock(AdyenInvoice::class, [ - 'load' => $adyenInvoiceLoadedMock - ]); - $adyenInvoiceFactory = $this->createGeneratedMock(InvoiceFactory::class, ['create']); - $adyenInvoiceFactory->method('create')->willReturn($adyenInvoiceMockForFactory); + + $adyenInvoiceRepositoryMock = $this->createMock(AdyenInvoiceRepositoryInterface::class); + $adyenInvoiceRepositoryMock->method('getByAdyenOrderPaymentId')->willReturn([$adyenInvoiceMock]); $invoiceHelper = $this->createInvoiceHelper( null, null, null, null, - $adyenInvoiceFactory, - $adyenInvoiceResourceModelMock + null, + null, + null, + null, + null, + null, + null, + $adyenInvoiceRepositoryMock ); $adyenOrderPaymentMock = $this->createMock(Payment::class); + $adyenOrderPaymentMock->method('getEntityId')->willReturn(1); + $invoiceMock = $this->createConfiguredMock(InvoiceModel::class, [ - 'getOrder' => $this->createMock(Order::class), - 'getGrandTotal' => 1000.0, - 'getOrderCurrencyCode' => 'EUR', - 'register' => $this->createMock(InvoiceModel::class), 'getEntityId' => 99 ]); @@ -285,8 +262,6 @@ public function testIsFullInvoiceAmountManuallyCaptured() null, null, null, - null, - null, $adyenInvoiceCollectionMock ); @@ -311,10 +286,6 @@ public function testCreateInvoiceFromWebhook() $adyenInvoiceFactoryMock = $this->createGeneratedMock(InvoiceFactory::class, ['create']); $adyenInvoiceFactoryMock->method('create')->willReturn($adyenInvoiceMockForFactory); - $adyenInvoiceResourceModelMock = $this->createConfiguredMock(AdyenInvoiceResourceModel::class, [ - 'save' => $this->createMock(AbstractDb::class) - ]); - $orderPaymentResourceModelMock = $this->createConfiguredMock(OrderPaymentResourceModel::class, [ 'getOrderPaymentDetails' => [ 'entity_id' => 1000 @@ -341,14 +312,9 @@ public function testCreateInvoiceFromWebhook() null, null, $adyenInvoiceFactoryMock, - $adyenInvoiceResourceModelMock, $orderPaymentResourceModelMock, null, null, - null, - null, - null, - null, $transactionMock ); @@ -384,7 +350,7 @@ public function testSendInvoiceMailCatchesException() $invoiceSenderMock ->expects($this->once()) ->method('send') - ->willThrowException(new \Exception('Test Exception Message')); + ->willThrowException(new Exception('Test Exception Message')); $invoiceHelper = $this->createInvoiceHelper( null, @@ -394,11 +360,6 @@ public function testSendInvoiceMailCatchesException() null, null, null, - null, - null, - null, - null, - null, $invoiceSenderMock ); @@ -411,18 +372,13 @@ public function testSendInvoiceMailCatchesException() * @param null $adyenDataHelperMock * @param null $invoiceRepositoryInterfaceMock * @param null $adyenInvoiceFactory - * @param null $adyenInvoiceResourceModelMock * @param null $orderPaymentResourceModelMock - * @param null $paymentFactoryMock * @param null $adyenInvoiceCollectionMock - * @param null $magentoInvoiceFactoryMock - * @param null $magentoOrderResourceModelMock - * @param null $adyenConfigHelperMock * @param null $invoiceSenderMock * @param null $transactionMock * @param null $chargedCurrencyMock * @param null $orderRepositoryMock - * + * @param null $adyenInvoiceRepositoryMock * @return Invoice */ protected function createInvoiceHelper( @@ -431,19 +387,14 @@ protected function createInvoiceHelper( $adyenDataHelperMock = null, $invoiceRepositoryInterfaceMock = null, $adyenInvoiceFactory = null, - $adyenInvoiceResourceModelMock = null, $orderPaymentResourceModelMock = null, - $paymentFactoryMock = null, $adyenInvoiceCollectionMock = null, - $magentoInvoiceFactoryMock = null, - $magentoOrderResourceModelMock = null, - $adyenConfigHelperMock = null, $invoiceSenderMock = null, $transactionMock = null, $chargedCurrencyMock = null, - $orderRepositoryMock = null + $orderRepositoryMock = null, + $adyenInvoiceRepositoryMock = null ): Invoice { - if (is_null($contextMock)) { $contextMock = $this->createMock(Context::class); } @@ -464,34 +415,14 @@ protected function createInvoiceHelper( $adyenInvoiceFactory = $this->createGeneratedMock(InvoiceFactory::class); } - if (is_null($adyenInvoiceResourceModelMock)) { - $adyenInvoiceResourceModelMock = $this->createMock(AdyenInvoiceResourceModel::class); - } - if (is_null($orderPaymentResourceModelMock)) { $orderPaymentResourceModelMock = $this->createMock(OrderPaymentResourceModel::class); } - if (is_null($paymentFactoryMock)) { - $paymentFactoryMock = $this->createGeneratedMock(PaymentFactory::class); - } - if (is_null($adyenInvoiceCollectionMock)) { $adyenInvoiceCollectionMock = $this->createMock(Collection::class); } - if (is_null($magentoInvoiceFactoryMock)) { - $magentoInvoiceFactoryMock = $this->createGeneratedMock(MagentoInvoiceFactory::class); - } - - if (is_null($magentoOrderResourceModelMock)) { - $magentoOrderResourceModelMock = $this->createMock(\Magento\Sales\Model\ResourceModel\Order::class); - } - - if (is_null($adyenConfigHelperMock)) { - $adyenConfigHelperMock = $this->createMock(Config::class); - } - if (is_null($invoiceSenderMock)) { $invoiceSenderMock = $this->createMock(InvoiceSender::class); } @@ -508,23 +439,23 @@ protected function createInvoiceHelper( $orderRepositoryMock = $this->createMock(OrderRepositoryInterface::class); } + if (is_null($adyenInvoiceRepositoryMock)) { + $adyenInvoiceRepositoryMock = $this->createMock(AdyenInvoiceRepositoryInterface::class); + } + return new Invoice( $contextMock, $adyenLoggerMock, $adyenDataHelperMock, $invoiceRepositoryInterfaceMock, $adyenInvoiceFactory, - $adyenInvoiceResourceModelMock, $orderPaymentResourceModelMock, - $paymentFactoryMock, $adyenInvoiceCollectionMock, - $magentoInvoiceFactoryMock, - $magentoOrderResourceModelMock, - $adyenConfigHelperMock, $invoiceSenderMock, $transactionMock, $chargedCurrencyMock, - $orderRepositoryMock + $orderRepositoryMock, + $adyenInvoiceRepositoryMock ); } } diff --git a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php index b9e4eedc37..b3b67ab28c 100644 --- a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php @@ -12,13 +12,12 @@ use Adyen\Payment\Model\Notification; use Adyen\Payment\Model\Order\PaymentFactory; use Adyen\Payment\Helper\AdyenOrderPayment; +use Magento\Sales\Api\Data\InvoiceInterface; use Magento\Sales\Api\InvoiceRepositoryInterface; use Magento\Sales\Model\Order as MagentoOrder; -use Magento\Sales\Model\Order\InvoiceFactory as MagentoInvoiceFactory; use Adyen\Payment\Model\Invoice as AdyenInvoice; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Adyen\Payment\Model\Order\Payment; -use Magento\Sales\Model\Order\Invoice as MagentoInvoice; class CaptureWebhookHandlerTest extends AbstractAdyenTestCase { @@ -46,7 +45,6 @@ private function createCaptureWebhookHandler( $adyenOrderPaymentFactory = null, $adyenOrderPaymentHelper = null, $adyenLogger = null, - $magentoInvoiceFactory = null, $orderHelper = null, $paymentMethodsHelper = null, $invoiceRepository = null @@ -64,9 +62,6 @@ private function createCaptureWebhookHandler( if($adyenLogger == null) { $adyenLogger = $this->createGeneratedMock(AdyenLogger::class, ['addAdyenNotification', 'getInvoiceContext']); } - if($magentoInvoiceFactory == null) { - $magentoInvoiceFactory = $this->createGeneratedMock(MagentoInvoiceFactory::class, ['create', 'load']); - } if($orderHelper == null) { $orderHelper = $this->createGeneratedMock(Order::class, ['fetchOrderByIncrementId', 'finalizeOrder']); } @@ -82,7 +77,6 @@ private function createCaptureWebhookHandler( adyenOrderPaymentFactory: $adyenOrderPaymentFactory, adyenOrderPaymentHelper: $adyenOrderPaymentHelper, adyenLogger: $adyenLogger, - magentoInvoiceFactory: $magentoInvoiceFactory, orderHelper: $orderHelper, paymentMethodsHelper: $paymentMethodsHelper, invoiceRepository: $invoiceRepository @@ -105,7 +99,6 @@ public function testHandleWebhookWithAutoCapture() null, null, null, - null, $paymentMethodsHelperMock ); @@ -119,7 +112,11 @@ public function testHandleWebhookWithAutoCapture() public function testHandleWebhookWithoutAutoCapture() { // Mock methods - $invoice = $this->createConfiguredMock(AdyenInvoice::class, ['getAdyenPaymentOrderId' => 123, 'getInvoiceId' => 456]); + $adyenInvoice = $this->createConfiguredMock(AdyenInvoice::class, ['getAdyenPaymentOrderId' => 123, 'getInvoiceId' => 456]); + $magentoInvoice = $this->createMock(MagentoOrder\Invoice::class); + + $magentoInvoiceRepositoryMock = $this->createMock(InvoiceRepositoryInterface::class); + $magentoInvoiceRepositoryMock->method('get')->willReturn($magentoInvoice); // Mock the paymentMethodsHelper to return false for isAutoCapture $paymentMethodsHelperMock = $this->createMockWithMethods(PaymentMethods::class, ['isAutoCapture'], []); @@ -127,7 +124,7 @@ public function testHandleWebhookWithoutAutoCapture() // Set up expectations on the invoiceHelperMock $invoiceHelperMock = $this->createMockWithMethods(Invoice::class, ['handleCaptureWebhook'], []); - $invoiceHelperMock->expects($this->once())->method('handleCaptureWebhook')->willReturn($invoice); + $invoiceHelperMock->expects($this->once())->method('handleCaptureWebhook')->willReturn($adyenInvoice); // Set up a partial mock of orderHelper to expect a call to fetchOrderByIncrementId $orderHelperMock = $this->createGeneratedMock(Order::class, ['fetchOrderByIncrementId', 'finalizeOrder']); @@ -161,35 +158,15 @@ public function testHandleWebhookWithoutAutoCapture() ->method('refreshPaymentCaptureStatus') ->with($adyenOrderPaymentMock, $this->notification->getAmountCurrency()); - // Create a mock for the magentoInvoiceFactory - $magentoInvoiceFactoryMock = $this->createGeneratedMock(MagentoInvoiceFactory::class, ['create']); - - // Create a mock for MagentoInvoice - $magentoInvoiceMock = $this->getMockBuilder(MagentoInvoice::class) - ->setMethods(['load']) // Define the method you want to mock - ->disableOriginalConstructor() - ->getMock(); - - // Configure the load method of the magentoInvoiceMock to return the same mock - $magentoInvoiceMock->expects($this->once()) - ->method('load') - ->with(456, MagentoInvoice::ENTITY_ID) - ->willReturnSelf(); // Return the mock itself - - // Configure the magentoInvoiceFactoryMock to return the magentoInvoiceMock - $magentoInvoiceFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($magentoInvoiceMock); - $this->captureWebhookHandler = $this->createCaptureWebhookHandler( $invoiceHelperMock, $adyenOrderPaymentFactoryMock, $adyenOrderPaymentHelperMock, null, - $magentoInvoiceFactoryMock, $orderHelperMock, - $paymentMethodsHelperMock) - ; + $paymentMethodsHelperMock, + $magentoInvoiceRepositoryMock + ); // Test handleWebhook method $result = $this->captureWebhookHandler->handleWebhook($this->order, $this->notification, 'paid'); diff --git a/Test/Unit/Observer/SetOrderStateAfterPaymentObserverTest.php b/Test/Unit/Observer/SetOrderStateAfterPaymentObserverTest.php index 09dc7e6a7c..e399cdd4d3 100644 --- a/Test/Unit/Observer/SetOrderStateAfterPaymentObserverTest.php +++ b/Test/Unit/Observer/SetOrderStateAfterPaymentObserverTest.php @@ -102,10 +102,10 @@ public function testExecute($resultCode, $action, $changeStatus = true) if ($changeStatus) { $this->orderMock->expects($this->once())->method('setState'); - $this->orderMock->expects($this->once())->method('save'); + $this->orderRepositoryMock->expects($this->once())->method('save'); } else { $this->orderMock->expects($this->never())->method('setState'); - $this->orderMock->expects($this->never())->method('save'); + $this->orderRepositoryMock->expects($this->never())->method('save'); } $this->setOrderStateAfterPaymentObserver->execute($this->observerMock); From 100d6aa11397666842579ede694d90a557a6a7bb Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 14 Jan 2025 16:48:44 +0100 Subject: [PATCH 14/34] [ECP-9489] Use MaskedQuoteIdToQuoteIdInterface for resolving masked cartId --- Model/Api/GuestAdyenDonations.php | 26 +++++----- Model/Api/GuestAdyenGiftcard.php | 27 +++++----- Model/Api/GuestAdyenOrderPaymentStatus.php | 36 ++++++-------- .../Api/GuestAdyenPaymentMethodManagement.php | 30 +++++++----- Model/Api/GuestAdyenPaymentsDetails.php | 27 +++++----- Model/Api/GuestAdyenPosCloud.php | 32 ++++++------ Model/Api/GuestAdyenStateData.php | 27 +++++----- Model/Resolver/GetAdyenRedeemedGiftcards.php | 38 ++++---------- Model/Resolver/RemoveAdyenStateData.php | 30 +++--------- Model/Resolver/SaveAdyenStateData.php | 32 ++++-------- .../GuestPaymentInformationResetOrderId.php | 49 ++++--------------- 11 files changed, 134 insertions(+), 220 deletions(-) diff --git a/Model/Api/GuestAdyenDonations.php b/Model/Api/GuestAdyenDonations.php index b9e34303d0..e8b52ed362 100644 --- a/Model/Api/GuestAdyenDonations.php +++ b/Model/Api/GuestAdyenDonations.php @@ -16,23 +16,20 @@ use Adyen\Payment\Api\GuestAdyenDonationsInterface; use Adyen\Payment\Model\Sales\OrderRepository; use Magento\Framework\Exception\LocalizedException; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; class GuestAdyenDonations implements GuestAdyenDonationsInterface { - private AdyenDonations $adyenDonationsModel; - private QuoteIdMaskFactory $quoteIdMaskFactory; - private OrderRepository $orderRepository; - + /** + * @param AdyenDonations $adyenDonationsModel + * @param OrderRepository $orderRepository + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + */ public function __construct( - AdyenDonations $adyenDonationsModel, - QuoteIdMaskFactory $quoteIdMaskFactory, - OrderRepository $orderRepository - ) { - $this->adyenDonationsModel = $adyenDonationsModel; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - $this->orderRepository = $orderRepository; - } + private readonly AdyenDonations $adyenDonationsModel, + private readonly OrderRepository $orderRepository, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } /** * @param string $cartId @@ -43,8 +40,7 @@ public function __construct( */ public function donate(string $cartId, string $payload): void { - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); $order = $this->orderRepository->getOrderByQuoteId($quoteId); diff --git a/Model/Api/GuestAdyenGiftcard.php b/Model/Api/GuestAdyenGiftcard.php index 1784bc6b89..f0319e878c 100644 --- a/Model/Api/GuestAdyenGiftcard.php +++ b/Model/Api/GuestAdyenGiftcard.php @@ -14,25 +14,28 @@ use Adyen\Payment\Api\GuestAdyenGiftcardInterface; use Adyen\Payment\Helper\GiftcardPayment; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; class GuestAdyenGiftcard implements GuestAdyenGiftcardInterface { - private GiftcardPayment $giftcardPaymentHelper; - private QuoteIdMaskFactory $quoteIdMaskFactory; - + /** + * @param GiftcardPayment $giftcardPaymentHelper + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + */ public function __construct( - GiftcardPayment $giftcardPaymentHelper, - QuoteIdMaskFactory $quoteIdMaskFactory - ) { - $this->giftcardPaymentHelper = $giftcardPaymentHelper; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - } + private readonly GiftcardPayment $giftcardPaymentHelper, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } + /** + * @param string $cartId + * @return string + * @throws NoSuchEntityException + */ public function getRedeemedGiftcards(string $cartId): string { - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); return $this->giftcardPaymentHelper->fetchRedeemedGiftcards($quoteId); } diff --git a/Model/Api/GuestAdyenOrderPaymentStatus.php b/Model/Api/GuestAdyenOrderPaymentStatus.php index c51995ed70..27a0a6496e 100644 --- a/Model/Api/GuestAdyenOrderPaymentStatus.php +++ b/Model/Api/GuestAdyenOrderPaymentStatus.php @@ -17,35 +17,29 @@ use Adyen\Payment\Helper\PaymentResponseHandler; use Adyen\Payment\Logger\AdyenLogger; use Magento\Framework\Exception\NotFoundException; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Sales\Api\OrderRepositoryInterface; class GuestAdyenOrderPaymentStatus implements GuestAdyenOrderPaymentStatusInterface { - protected OrderRepositoryInterface $orderRepository; - protected AdyenLogger $adyenLogger; - protected Data $adyenHelper; - private QuoteIdMaskFactory $quoteIdMaskFactory; - private PaymentResponseHandler $paymentResponseHandler; - + /** + * @param OrderRepositoryInterface $orderRepository + * @param AdyenLogger $adyenLogger + * @param Data $adyenHelper + * @param PaymentResponseHandler $paymentResponseHandler + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + */ public function __construct( - OrderRepositoryInterface $orderRepository, - AdyenLogger $adyenLogger, - Data $adyenHelper, - PaymentResponseHandler $paymentResponseHandler, - QuoteIdMaskFactory $quoteIdMaskFactory - ) { - $this->orderRepository = $orderRepository; - $this->adyenLogger = $adyenLogger; - $this->adyenHelper = $adyenHelper; - $this->paymentResponseHandler = $paymentResponseHandler; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - } + protected readonly OrderRepositoryInterface $orderRepository, + protected readonly AdyenLogger $adyenLogger, + protected readonly Data $adyenHelper, + private readonly PaymentResponseHandler $paymentResponseHandler, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } public function getOrderPaymentStatus(string $orderId, string $cartId): string { - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); $order = $this->orderRepository->get($orderId); diff --git a/Model/Api/GuestAdyenPaymentMethodManagement.php b/Model/Api/GuestAdyenPaymentMethodManagement.php index e32d827247..959cf79980 100644 --- a/Model/Api/GuestAdyenPaymentMethodManagement.php +++ b/Model/Api/GuestAdyenPaymentMethodManagement.php @@ -11,31 +11,37 @@ namespace Adyen\Payment\Model\Api; +use Adyen\AdyenException; use Adyen\Payment\Api\GuestAdyenPaymentMethodManagementInterface; use Adyen\Payment\Helper\PaymentMethods; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; class GuestAdyenPaymentMethodManagement implements GuestAdyenPaymentMethodManagementInterface { - protected QuoteIdMaskFactory $quoteIdMaskFactory; - protected PaymentMethods $paymentMethodsHelper; - public function __construct( - QuoteIdMaskFactory $quoteIdMaskFactory, - PaymentMethods $paymentMethodsHelper - ) { - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - $this->paymentMethodsHelper = $paymentMethodsHelper; - } + private readonly PaymentMethods $paymentMethodsHelper, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } + /** + * @param string $cartId + * @param string|null $shopperLocale + * @param string|null $country + * @param string|null $channel + * @return string + * @throws AdyenException + * @throws LocalizedException + * @throws NoSuchEntityException + */ public function getPaymentMethods( string $cartId, ?string $shopperLocale = null, ?string $country = null, ?string $channel = null ): string { - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); return $this->paymentMethodsHelper->getPaymentMethods($quoteId, $country, $shopperLocale, $channel); } diff --git a/Model/Api/GuestAdyenPaymentsDetails.php b/Model/Api/GuestAdyenPaymentsDetails.php index da426e6476..0fe1f0bd79 100644 --- a/Model/Api/GuestAdyenPaymentsDetails.php +++ b/Model/Api/GuestAdyenPaymentsDetails.php @@ -16,24 +16,21 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\NotFoundException; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Sales\Api\OrderRepositoryInterface; class GuestAdyenPaymentsDetails implements GuestAdyenPaymentsDetailsInterface { - private OrderRepositoryInterface $orderRepository; - private QuoteIdMaskFactory $quoteIdMaskFactory; - private AdyenPaymentsDetails $adyenPaymentsDetails; - + /** + * @param OrderRepositoryInterface $orderRepository + * @param AdyenPaymentsDetails $adyenPaymentsDetails + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + */ public function __construct( - OrderRepositoryInterface $orderRepository, - QuoteIdMaskFactory $quoteIdMaskFactory, - AdyenPaymentsDetails $adyenPaymentsDetails - ) { - $this->orderRepository = $orderRepository; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - $this->adyenPaymentsDetails = $adyenPaymentsDetails; - } + private readonly OrderRepositoryInterface $orderRepository, + private readonly AdyenPaymentsDetails $adyenPaymentsDetails, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } /** * @param string $payload @@ -48,9 +45,7 @@ public function __construct( public function initiate(string $payload, string $orderId, string $cartId): string { $order = $this->orderRepository->get(intval($orderId)); - - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); if ($order->getQuoteId() != $quoteId) { throw new NotFoundException( diff --git a/Model/Api/GuestAdyenPosCloud.php b/Model/Api/GuestAdyenPosCloud.php index bd2363a090..56b711f3b3 100644 --- a/Model/Api/GuestAdyenPosCloud.php +++ b/Model/Api/GuestAdyenPosCloud.php @@ -14,43 +14,43 @@ use Adyen\Payment\Api\GuestAdyenPosCloudInterface; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\Sales\OrderRepository; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Payment\Gateway\Command\CommandPoolInterface; use Magento\Payment\Gateway\Data\PaymentDataObjectFactoryInterface; -use Magento\Quote\Model\QuoteIdMaskFactory; - +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; class GuestAdyenPosCloud extends AdyenPosCloud implements GuestAdyenPosCloudInterface { - protected AdyenLogger $adyenLogger; - protected OrderRepository $orderRepository; - protected PaymentDataObjectFactoryInterface $paymentDataObjectFactory; - private QuoteIdMaskFactory $quoteIdMaskFactory; - + /** + * @param CommandPoolInterface $commandPool + * @param OrderRepository $orderRepository + * @param PaymentDataObjectFactoryInterface $paymentDataObjectFactory + * @param AdyenLogger $adyenLogger + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + */ public function __construct( - CommandPoolInterface $commandPool, - OrderRepository $orderRepository, + CommandPoolInterface $commandPool, + OrderRepository $orderRepository, PaymentDataObjectFactoryInterface $paymentDataObjectFactory, - AdyenLogger $adyenLogger, - QuoteIdMaskFactory $quoteIdMaskFactory - ) - { + AdyenLogger $adyenLogger, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { parent::__construct( $commandPool, $orderRepository, $paymentDataObjectFactory, $adyenLogger ); - $this->quoteIdMaskFactory = $quoteIdMaskFactory; } /** * @param string $cartId * @return void + * @throws NoSuchEntityException */ public function payByCart(string $cartId): void { - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); $order = $this->orderRepository->getOrderByQuoteId($quoteId); $this->execute($order); } diff --git a/Model/Api/GuestAdyenStateData.php b/Model/Api/GuestAdyenStateData.php index b78c9b2dbe..2b3392e428 100644 --- a/Model/Api/GuestAdyenStateData.php +++ b/Model/Api/GuestAdyenStateData.php @@ -18,20 +18,18 @@ use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; class GuestAdyenStateData implements GuestAdyenStateDataInterface { - private StateDataHelper $stateDataHelper; - private QuoteIdMaskFactory $quoteIdMaskFactory; - + /** + * @param StateDataHelper $stateDataHelper + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + */ public function __construct( - StateDataHelper $stateDataHelper, - QuoteIdMaskFactory $quoteIdMaskFactory - ) { - $this->stateDataHelper = $stateDataHelper; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - } + private readonly StateDataHelper $stateDataHelper, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } /** * @param string $stateData @@ -61,14 +59,15 @@ public function remove(int $stateDataId, string $cartId): bool } /** + * @param string $cartId + * @return int * @throws InputException */ private function getQuoteIdFromMaskedCartId(string $cartId): int { - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); - - if (is_null($quoteId)) { + try { + $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); + } catch (NoSuchEntityException $e) { $errorMessage = __("An error occurred: missing required parameter :cartId!"); throw new InputException($errorMessage); } diff --git a/Model/Resolver/GetAdyenRedeemedGiftcards.php b/Model/Resolver/GetAdyenRedeemedGiftcards.php index 7581744625..4dd3f9f926 100644 --- a/Model/Resolver/GetAdyenRedeemedGiftcards.php +++ b/Model/Resolver/GetAdyenRedeemedGiftcards.php @@ -15,7 +15,8 @@ use Adyen\Payment\Exception\GraphQlAdyenException; use Adyen\Payment\Helper\GiftcardPayment; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; @@ -24,35 +25,16 @@ class GetAdyenRedeemedGiftcards implements ResolverInterface { - /** - * @var GiftcardPayment - */ - private GiftcardPayment $giftcardPayment; - - /** - * @var Json - */ - private Json $jsonSerializer; - - /** - * @var QuoteIdMaskFactory - */ - private QuoteIdMaskFactory $quoteIdMaskFactory; - /** * @param GiftcardPayment $giftcardPayment * @param Json $jsonSerializer - * @param QuoteIdMaskFactory $quoteIdMaskFactory + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId */ public function __construct( - GiftcardPayment $giftcardPayment, - Json $jsonSerializer, - QuoteIdMaskFactory $quoteIdMaskFactory - ) { - $this->giftcardPayment = $giftcardPayment; - $this->jsonSerializer = $jsonSerializer; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - } + private readonly GiftcardPayment $giftcardPayment, + private readonly Json $jsonSerializer, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } /** * @param Field $field @@ -63,6 +45,7 @@ public function __construct( * @return array * @throws GraphQlAdyenException * @throws GraphQlInputException + * @throws NoSuchEntityException */ public function resolve( Field $field, @@ -75,10 +58,7 @@ public function resolve( throw new GraphQlInputException(__('Required parameter "cartId" is missing')); } - $cartId = $args['cartId']; - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); - $quoteId = (int)$quoteId; + $quoteId = $this->maskedQuoteIdToQuoteId->execute($args['cartId']); try { $redeemedGiftcardsJson = $this->giftcardPayment->fetchRedeemedGiftcards($quoteId); diff --git a/Model/Resolver/RemoveAdyenStateData.php b/Model/Resolver/RemoveAdyenStateData.php index 494dc36c23..a8d3c0d257 100644 --- a/Model/Resolver/RemoveAdyenStateData.php +++ b/Model/Resolver/RemoveAdyenStateData.php @@ -21,31 +21,18 @@ use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; class RemoveAdyenStateData implements ResolverInterface { - /** - * @var AdyenStateData - */ - private AdyenStateData $adyenStateData; - - /** - * @var QuoteIdMaskFactory - */ - private QuoteIdMaskFactory $quoteIdMaskFactory; - /** * @param AdyenStateData $adyenStateData - * @param QuoteIdMaskFactory $quoteIdMaskFactory + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId */ public function __construct( - AdyenStateData $adyenStateData, - QuoteIdMaskFactory $quoteIdMaskFactory - ) { - $this->adyenStateData = $adyenStateData; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - } + private readonly AdyenStateData $adyenStateData, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } /** * @param Field $field @@ -73,11 +60,10 @@ public function resolve( throw new GraphQlInputException(__('Required parameter "cartId" is missing')); } - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($args['cartId'], 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($args['cartId']); try { - $result = $this->adyenStateData->remove((int) $args['stateDataId'], (int) $quoteId); + $result = $this->adyenStateData->remove((int) $args['stateDataId'], $quoteId); } catch (Exception $e) { throw new GraphQlAdyenException(__('An error occurred while removing the state data.'), $e); } @@ -89,5 +75,3 @@ public function resolve( return ['stateDataId' => $args['stateDataId']]; } } - - diff --git a/Model/Resolver/SaveAdyenStateData.php b/Model/Resolver/SaveAdyenStateData.php index 7fc1c2bee9..1399c44378 100644 --- a/Model/Resolver/SaveAdyenStateData.php +++ b/Model/Resolver/SaveAdyenStateData.php @@ -16,35 +16,23 @@ use Adyen\Payment\Exception\GraphQlAdyenException; use Adyen\Payment\Model\Api\AdyenStateData; use Exception; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; class SaveAdyenStateData implements ResolverInterface { - /** - * @var AdyenStateData - */ - private AdyenStateData $adyenStateData; - - /** - * @var QuoteIdMaskFactory - */ - private QuoteIdMaskFactory $quoteIdMaskFactory; - /** * @param AdyenStateData $adyenStateData - * @param QuoteIdMaskFactory $quoteIdMaskFactory + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId */ public function __construct( - AdyenStateData $adyenStateData, - QuoteIdMaskFactory $quoteIdMaskFactory - ) { - $this->adyenStateData = $adyenStateData; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - } + private readonly AdyenStateData $adyenStateData, + private readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } /** * @param Field $field @@ -55,6 +43,7 @@ public function __construct( * @return array * @throws GraphQlAdyenException * @throws GraphQlInputException + * @throws NoSuchEntityException */ public function resolve( Field $field, @@ -71,11 +60,10 @@ public function resolve( throw new GraphQlInputException(__('Required parameter "cartId" is missing')); } - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($args['cartId'], 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($args['cartId']); try { - $stateDataId = $this->adyenStateData->save($args['stateData'], (int) $quoteId); + $stateDataId = $this->adyenStateData->save($args['stateData'], $quoteId); } catch (Exception $e) { throw new GraphQlAdyenException(__('An error occurred while saving the state data.'), $e); } @@ -83,5 +71,3 @@ public function resolve( return ['stateDataId' => $stateDataId]; } } - - diff --git a/Plugin/GuestPaymentInformationResetOrderId.php b/Plugin/GuestPaymentInformationResetOrderId.php index dd4b56ad6d..244b5de1d8 100644 --- a/Plugin/GuestPaymentInformationResetOrderId.php +++ b/Plugin/GuestPaymentInformationResetOrderId.php @@ -16,51 +16,23 @@ use Exception; use Magento\Checkout\Api\GuestPaymentInformationManagementInterface; use Magento\Quote\Api\CartRepositoryInterface; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; class GuestPaymentInformationResetOrderId { - /** - * Quote repository. - * - * @var CartRepositoryInterface - */ - protected $quoteRepository; - - /** - * Payment methods helper - * - * @var PaymentMethods - */ - protected $paymentMethodsHelper; - - /** - * @var AdyenLogger - */ - protected $adyenLogger; - - /** - * @var QuoteIdMaskFactory - */ - protected $quoteIdMaskFactory; - /** * GuestPaymentInformationResetOrderId constructor. * @param CartRepositoryInterface $quoteRepository + * @param PaymentMethods $paymentMethodsHelper * @param AdyenLogger $adyenLogger - * @param QuoteIdMaskFactory $quoteIdMaskFactory + * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId */ public function __construct( - CartRepositoryInterface $quoteRepository, - QuoteIdMaskFactory $quoteIdMaskFactory, - PaymentMethods $paymentMethodsHelper, - AdyenLogger $adyenLogger - ) { - $this->quoteRepository = $quoteRepository; - $this->quoteIdMaskFactory = $quoteIdMaskFactory; - $this->paymentMethodsHelper = $paymentMethodsHelper; - $this->adyenLogger = $adyenLogger; - } + protected readonly CartRepositoryInterface $quoteRepository, + protected readonly PaymentMethods $paymentMethodsHelper, + protected readonly AdyenLogger $adyenLogger, + protected readonly MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + ) { } /** * @param GuestPaymentInformationManagementInterface $subject @@ -72,10 +44,9 @@ public function beforeSavePaymentInformationAndPlaceOrder( $cartId ) { try { - $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); - $quoteId = $quoteIdMask->getQuoteId(); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); $quote = $this->quoteRepository->get($quoteId); - $method = strval($quote->getPayment()->getMethod()); + $method = $quote->getPayment()->getMethod(); if ($this->paymentMethodsHelper->isAdyenPayment($method)) { $quote->setReservedOrderId(null); From f13e7df77ba4b8ee092a109a8e2b3cd81e5e1694 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 10:42:53 +0100 Subject: [PATCH 15/34] [ECP-9489] Fix unit tests --- .../ApplePayDomainAssociationFileButton.php | 5 ++ .../Model/Api/GuestAdyenDonationsTest.php | 32 +++------- .../GuestAdyenPaymentMethodManagementTest.php | 25 ++++---- .../Api/GuestAdyenPaymentsDetailsTest.php | 52 +++++----------- .../Unit/Model/Api/GuestAdyenPosCloudTest.php | 62 ++++++++++++------- .../Model/Api/GuestAdyenStateDataTest.php | 43 +++++-------- ...pplePayDomainAssociationFileButtonTest.php | 52 +++++++++++----- .../GetAdyenRedeemedGiftcardsTest.php | 52 +++++----------- .../Resolver/RemoveAdyenStateDataTest.php | 30 ++++----- .../Model/Resolver/SaveAdyenStateDataTest.php | 35 +++++------ 10 files changed, 172 insertions(+), 216 deletions(-) diff --git a/Model/Config/Adminhtml/ApplePayDomainAssociationFileButton.php b/Model/Config/Adminhtml/ApplePayDomainAssociationFileButton.php index cc2626fcac..c3404282bf 100644 --- a/Model/Config/Adminhtml/ApplePayDomainAssociationFileButton.php +++ b/Model/Config/Adminhtml/ApplePayDomainAssociationFileButton.php @@ -39,6 +39,11 @@ public function __construct( parent::__construct($context, $data); } + public function _construct() + { + parent::_construct(); + } + /** * @param AbstractElement $element * @return string diff --git a/Test/Unit/Model/Api/GuestAdyenDonationsTest.php b/Test/Unit/Model/Api/GuestAdyenDonationsTest.php index 716110d2ab..e9275a280e 100644 --- a/Test/Unit/Model/Api/GuestAdyenDonationsTest.php +++ b/Test/Unit/Model/Api/GuestAdyenDonationsTest.php @@ -16,6 +16,7 @@ use Adyen\Payment\Model\Api\GuestAdyenDonations; use Adyen\Payment\Model\Sales\OrderRepository; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Quote\Model\QuoteIdMask; use Magento\Quote\Model\QuoteIdMaskFactory; use Magento\Sales\Api\Data\OrderInterface; @@ -26,15 +27,8 @@ public function testFailingDonation() { $this->expectException(AdyenException::class); - $quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $quoteIdMaskMock->method('load') - ->willReturn($quoteIdMaskMock); - $quoteIdMaskMock->method('getQuoteId') - ->willReturn(1); - - $quoteIdMaskFactoryMock = $this->createGeneratedMock(QuoteIdMaskFactory::class, ['create']); - $quoteIdMaskFactoryMock->method('create') - ->willReturn($quoteIdMaskMock); + $maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteIdInterface::class); + $maskedQuoteIdToQuoteIdMock->expects($this->once())->method('execute')->willReturn(1); $adyenDonationsModelMock = $this->createPartialMock(AdyenDonations::class, []); @@ -42,8 +36,8 @@ public function testFailingDonation() $guestAdyenDonations = new GuestAdyenDonations( $adyenDonationsModelMock, - $quoteIdMaskFactoryMock, - $orderRepositoryMock + $orderRepositoryMock, + $maskedQuoteIdToQuoteIdMock ); $guestAdyenDonations->donate(1, ''); @@ -51,16 +45,8 @@ public function testFailingDonation() public function testSuccessfulDonation() { - $quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $quoteIdMaskMock->method('load') - ->willReturn($quoteIdMaskMock); - $quoteIdMaskMock->method('getQuoteId') - ->willReturn(1); - - $quoteIdMaskFactoryMock = $this->createGeneratedMock(QuoteIdMaskFactory::class, ['create']); - $quoteIdMaskFactoryMock->expects(self::atLeastOnce()) - ->method('create') - ->willReturn($quoteIdMaskMock); + $maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteIdInterface::class); + $maskedQuoteIdToQuoteIdMock->expects($this->once())->method('execute')->willReturn(1); $adyenDonationsModelMock = $this->createMock(AdyenDonations::class); @@ -70,8 +56,8 @@ public function testSuccessfulDonation() $guestAdyenDonations = new GuestAdyenDonations( $adyenDonationsModelMock, - $quoteIdMaskFactoryMock, - $orderRepositoryMock + $orderRepositoryMock, + $maskedQuoteIdToQuoteIdMock ); $guestAdyenDonations->donate(1, ''); diff --git a/Test/Unit/Model/Api/GuestAdyenPaymentMethodManagementTest.php b/Test/Unit/Model/Api/GuestAdyenPaymentMethodManagementTest.php index 8de2828bb6..1072f9037a 100644 --- a/Test/Unit/Model/Api/GuestAdyenPaymentMethodManagementTest.php +++ b/Test/Unit/Model/Api/GuestAdyenPaymentMethodManagementTest.php @@ -5,28 +5,28 @@ use Adyen\Payment\Model\Api\GuestAdyenPaymentMethodManagement; use Adyen\Payment\Helper\PaymentMethods; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; -use Magento\Quote\Model\QuoteIdMask; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +use PHPUnit\Framework\MockObject\MockObject; class GuestAdyenPaymentMethodManagementTest extends AbstractAdyenTestCase { - /** @var QuoteIdMaskFactory|\PHPUnit\Framework\MockObject\MockObject */ - private $quoteIdMaskFactoryMock; + /** @var MaskedQuoteIdToQuoteIdInterface|MockObject */ + private MaskedQuoteIdToQuoteIdInterface|MockObject $maskedQuoteIdToQuoteIdMock; - /** @var PaymentMethods|\PHPUnit\Framework\MockObject\MockObject */ - private $paymentMethodsHelperMock; + /** @var PaymentMethods|MockObject */ + private PaymentMethods|MockObject $paymentMethodsHelperMock; /** @var GuestAdyenPaymentMethodManagement */ - private $guestAdyenPaymentMethodManagement; + private GuestAdyenPaymentMethodManagement $guestAdyenPaymentMethodManagement; protected function setUp(): void { - $this->quoteIdMaskFactoryMock = $this->createGeneratedMock(QuoteIdMaskFactory::class, ['create']); + $this->maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteIdInterface::class); $this->paymentMethodsHelperMock = $this->createMock(PaymentMethods::class); $this->guestAdyenPaymentMethodManagement = new GuestAdyenPaymentMethodManagement( - $this->quoteIdMaskFactoryMock, - $this->paymentMethodsHelperMock + $this->paymentMethodsHelperMock, + $this->maskedQuoteIdToQuoteIdMock ); } @@ -39,10 +39,7 @@ public function testGetPaymentMethods() $channel = 'Web'; $expectedPaymentMethods = 'sample_payment_methods'; - $quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $quoteIdMaskMock->method('load')->willReturn($quoteIdMaskMock); - $quoteIdMaskMock->method('getQuoteId')->willReturn($quoteId); - $this->quoteIdMaskFactoryMock->method('create')->willReturn($quoteIdMaskMock); + $this->maskedQuoteIdToQuoteIdMock->expects($this->once())->method('execute')->willReturn($quoteId); $this->paymentMethodsHelperMock->expects($this->once()) ->method('getPaymentMethods') diff --git a/Test/Unit/Model/Api/GuestAdyenPaymentsDetailsTest.php b/Test/Unit/Model/Api/GuestAdyenPaymentsDetailsTest.php index 76d7873d8c..89b7dcd493 100644 --- a/Test/Unit/Model/Api/GuestAdyenPaymentsDetailsTest.php +++ b/Test/Unit/Model/Api/GuestAdyenPaymentsDetailsTest.php @@ -15,33 +15,29 @@ use Adyen\Payment\Model\Api\GuestAdyenPaymentsDetails; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\Exception\NotFoundException; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Quote\Model\QuoteIdMask; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\OrderRepositoryInterface; +use PHPUnit\Framework\MockObject\MockObject; class GuestAdyenPaymentsDetailsTest extends AbstractAdyenTestCase { - private $guestAdyenPaymentsDetails; - private $orderRepositoryMock; - private $quoteIdMaskFactoryMask; - private $adyenPaymentsDetailsMock; + private GuestAdyenPaymentsDetails $guestAdyenPaymentsDetails; + private OrderRepositoryInterface|MockObject $orderRepositoryMock; + private AdyenPaymentsDetails|MockObject $adyenPaymentsDetailsMock; + private MaskedQuoteIdToQuoteIdInterface|MockObject $maskedQuoteIdToQuoteIdMock; protected function setUp(): void { $this->orderRepositoryMock = $this->createMock(OrderRepositoryInterface::class); $this->adyenPaymentsDetailsMock = $this->createMock(AdyenPaymentsDetails::class); - $this->quoteIdMaskFactoryMask = $this->createGeneratedMock(QuoteIdMaskFactory::class, [ - 'create' - ]); - - $objectManager = new ObjectManager($this); - $this->guestAdyenPaymentsDetails = $objectManager->getObject(GuestAdyenPaymentsDetails::class, [ - 'orderRepository' => $this->orderRepositoryMock, - 'adyenPaymentsDetails' => $this->adyenPaymentsDetailsMock, - 'quoteIdMaskFactory' => $this->quoteIdMaskFactoryMask - ]); + $this->maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteIdInterface::class); + + $this->guestAdyenPaymentsDetails = new GuestAdyenPaymentsDetails( + $this->orderRepositoryMock, + $this->adyenPaymentsDetailsMock, + $this->maskedQuoteIdToQuoteIdMock + ); } public function testSuccessfulCall() @@ -53,15 +49,7 @@ public function testSuccessfulCall() $cartId = 99; $orderQuoteId = 99; - $quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, [ - 'load', - 'getQuoteId' - ]); - $quoteIdMaskMock->method('load')->willReturn($quoteIdMaskMock); - $quoteIdMaskMock->method('getQuoteId')->willReturn($cartId); - - $this->quoteIdMaskFactoryMask->method('create') - ->willReturn($quoteIdMaskMock); + $this->maskedQuoteIdToQuoteIdMock->expects($this->once())->method('execute')->willReturn($cartId); $orderMock = $this->createMock(OrderInterface::class); $orderMock->method('getQuoteId')->willReturn($orderQuoteId); @@ -89,16 +77,8 @@ public function testWrongCartId() $cartId = 99; $orderQuoteId = 200; - $quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, [ - 'load', - 'getQuoteId' - ]); - $quoteIdMaskMock->method('load')->willReturn($quoteIdMaskMock); - $quoteIdMaskMock->method('getQuoteId')->willReturn($cartId); - - $this->quoteIdMaskFactoryMask->method('create') - ->willReturn($quoteIdMaskMock); - + $this->maskedQuoteIdToQuoteIdMock->expects($this->once())->method('execute')->willReturn($cartId); + $orderMock = $this->createMock(OrderInterface::class); $orderMock->method('getQuoteId')->willReturn($orderQuoteId); diff --git a/Test/Unit/Model/Api/GuestAdyenPosCloudTest.php b/Test/Unit/Model/Api/GuestAdyenPosCloudTest.php index b2250c2b85..7ae54f89d9 100644 --- a/Test/Unit/Model/Api/GuestAdyenPosCloudTest.php +++ b/Test/Unit/Model/Api/GuestAdyenPosCloudTest.php @@ -6,50 +6,64 @@ use Adyen\Payment\Model\Sales\OrderRepository; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Payment\Gateway\Command\CommandPoolInterface; +use Magento\Payment\Gateway\CommandInterface; +use Magento\Payment\Model\InfoInterface; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Sales\Api\Data\OrderInterface; -use Magento\Quote\Model\QuoteIdMask; use Magento\Payment\Gateway\Data\PaymentDataObjectFactoryInterface; -use Magento\Quote\Model\QuoteIdMaskFactory; use Adyen\Payment\Model\Api\GuestAdyenPosCloud; +use PHPUnit\Framework\MockObject\MockObject; class GuestAdyenPosCloudTest extends AbstractAdyenTestCase { - private CommandPoolInterface $commandPoolMock; - protected AdyenLogger $adyenLoggerMock; - protected OrderRepository $orderRepositoryMock; - protected QuoteIdMaskFactory $quoteIdMaskFactoryMock; - protected PaymentDataObjectFactoryInterface $paymentDataObjectFactoryMock; protected GuestAdyenPosCloud $guestAdyenPosCloud; + private CommandPoolInterface|MockObject $commandPoolMock; + protected AdyenLogger|MockObject $adyenLoggerMock; + protected OrderRepository|MockObject $orderRepositoryMock; + protected PaymentDataObjectFactoryInterface|MockObject $paymentDataObjectFactoryMock; + private MaskedQuoteIdToQuoteIdInterface|MockObject $maskedQuoteIdToQuoteIdMock; protected function setUp(): void { $this->commandPoolMock = $this->createMock(CommandPoolInterface::class); $this->orderRepositoryMock = $this->createMock(OrderRepository::class); - $this->paymentDataObjectFactoryMock = $this->createMock(PaymentDataObjectFactoryInterface::class); + $this->paymentDataObjectFactoryMock = $this->createMock( + PaymentDataObjectFactoryInterface::class + ); $this->adyenLoggerMock = $this->createMock(AdyenLogger::class); - $this->quoteIdMaskFactoryMock = $this->createGeneratedMock(QuoteIdMaskFactory::class, ['create']); - $this->guestAdyenPosCloud = $this->getMockBuilder(GuestAdyenPosCloud::class) - ->setConstructorArgs([ - $this->commandPoolMock, - $this->orderRepositoryMock, - $this->paymentDataObjectFactoryMock, - $this->adyenLoggerMock, - $this->quoteIdMaskFactoryMock - ]) - ->onlyMethods(['execute']) - ->getMock(); + $this->maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteIdInterface::class); + + $this->guestAdyenPosCloud = new GuestAdyenPosCloud( + $this->commandPoolMock, + $this->orderRepositoryMock, + $this->paymentDataObjectFactoryMock, + $this->adyenLoggerMock, + $this->maskedQuoteIdToQuoteIdMock + ); } public function testPayByCartSuccessfully() { $catId = '123'; $quoteId = 11; - $quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $quoteIdMaskMock->method('load')->willReturn($quoteIdMaskMock); - $quoteIdMaskMock->method('getQuoteId')->willReturn($quoteId); - $this->quoteIdMaskFactoryMock->method('create')->willReturn($quoteIdMaskMock); + + $this->maskedQuoteIdToQuoteIdMock->expects($this->once())->method('execute')->willReturn($quoteId); + + $commandInterfaceMock = $this->createMock(CommandInterface::class); + $this->commandPoolMock->method('get') + ->with('authorize') + ->willReturn($commandInterfaceMock); + + $paymentInfoMock = $this->createMock(InfoInterface::class); + $orderMock = $this->createMock(OrderInterface::class); - $this->orderRepositoryMock->expects($this->once())->method('getOrderByQuoteId')->with($quoteId)->willReturn($orderMock); + $orderMock->method('getPayment')->willReturn($paymentInfoMock); + + $this->orderRepositoryMock->expects($this->once()) + ->method('getOrderByQuoteId') + ->with($quoteId) + ->willReturn($orderMock); + $this->guestAdyenPosCloud->payByCart($catId); } } diff --git a/Test/Unit/Model/Api/GuestAdyenStateDataTest.php b/Test/Unit/Model/Api/GuestAdyenStateDataTest.php index b440dc058d..fe11eb24ec 100644 --- a/Test/Unit/Model/Api/GuestAdyenStateDataTest.php +++ b/Test/Unit/Model/Api/GuestAdyenStateDataTest.php @@ -15,35 +15,25 @@ use Adyen\Payment\Model\Api\GuestAdyenStateData; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\Exception\InputException; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Quote\Model\QuoteIdMask; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +use PHPUnit\Framework\MockObject\MockObject; class GuestAdyenStateDataTest extends AbstractAdyenTestCase { - private $objectManager; - private $stateDataHelperMock; - private $quoteIdMaskFactoryMock; - private $quoteIdMaskMock; - private $guestAdyenStateDataModel; + private GuestAdyenStateData $guestAdyenStateDataModel; + private StateData|MockObject $stateDataHelperMock; + private MaskedQuoteIdToQuoteIdInterface|MockObject $maskedQuoteIdToQuoteIdMock; protected function setUp(): void { - $this->objectManager = new ObjectManager($this); - - $this->quoteIdMaskFactoryMock = $this->createGeneratedMock(QuoteIdMaskFactory::class, [ - 'create' - ]); + $this->maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteIdInterface::class); $this->stateDataHelperMock = $this->createMock(StateData::class); - $this->quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $this->quoteIdMaskMock->method('load')->willReturn($this->quoteIdMaskMock); - $this->quoteIdMaskMock->method('getQuoteId')->willReturn(1); - - $this->guestAdyenStateDataModel = $this->objectManager->getObject(GuestAdyenStateData::class, [ - 'quoteIdMaskFactory' => $this->quoteIdMaskFactoryMock, - 'stateDataHelper' => $this->stateDataHelperMock - ]); + $this->guestAdyenStateDataModel = new GuestAdyenStateData( + $this->stateDataHelperMock, + $this->maskedQuoteIdToQuoteIdMock + ); } public function testSaveSuccessful() @@ -51,10 +41,11 @@ public function testSaveSuccessful() $stateData = '{"stateData":"dummyData"}'; $cartId = 'ABC123456789'; + $this->maskedQuoteIdToQuoteIdMock->method('execute')->willReturn(1); + $stateDataMock = $this->createMock(\Adyen\Payment\Model\StateData::class); $stateDataMock->method('getEntityId')->willReturn(1); - $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock); $this->stateDataHelperMock->expects($this->once())->method('saveStateData')->willReturn($stateDataMock); $this->guestAdyenStateDataModel->save($stateData, $cartId); @@ -65,7 +56,8 @@ public function testRemoveSuccessful() $stateDataId = 1; $cartId = 'ABC123456789'; - $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock); + $this->maskedQuoteIdToQuoteIdMock->method('execute')->willReturn(1); + $this->stateDataHelperMock->expects($this->once())->method('removeStateData'); $this->guestAdyenStateDataModel->remove($stateDataId, $cartId); } @@ -77,11 +69,8 @@ public function testSaveException() $stateData = '{"stateData":"dummyData"}'; $cartId = ''; - $quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $quoteIdMaskMock->method('load')->willReturn($quoteIdMaskMock); - $quoteIdMaskMock->method('getQuoteId')->willReturn(null); + $this->maskedQuoteIdToQuoteIdMock->method('execute')->willThrowException(new NoSuchEntityException()); - $this->quoteIdMaskFactoryMock->method('create')->willReturn($quoteIdMaskMock); $this->guestAdyenStateDataModel->save($stateData, $cartId); } diff --git a/Test/Unit/Model/Config/Adminhtml/ApplePayDomainAssociationFileButtonTest.php b/Test/Unit/Model/Config/Adminhtml/ApplePayDomainAssociationFileButtonTest.php index f79be89c48..fe7bf73218 100644 --- a/Test/Unit/Model/Config/Adminhtml/ApplePayDomainAssociationFileButtonTest.php +++ b/Test/Unit/Model/Config/Adminhtml/ApplePayDomainAssociationFileButtonTest.php @@ -8,10 +8,17 @@ use Magento\Backend\Helper\Data; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\ObjectManager; +use Magento\Framework\App\State; use Magento\Framework\Data\Form\Element\AbstractElement; use Magento\Framework\Event\ManagerInterface; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\ReadInterface; use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\View\Element\Template\File\Resolver; +use Magento\Framework\View\Element\Template\File\Validator; use Magento\Framework\View\LayoutInterface; +use Magento\Framework\View\TemplateEngineInterface; +use Magento\Framework\View\TemplateEnginePool; use PHPUnit\Framework\MockObject\MockObject; class ApplePayDomainAssociationFileButtonTest extends AbstractAdyenTestCase @@ -34,18 +41,46 @@ public function setUp(): void $this->managerMock = $this->createMock(ManagerInterface::class); $this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class); + $resolverMock = $this->createMock(Resolver::class); + + $readInterfaceMock = $this->createMock(ReadInterface::class); + + $templateEngineMock = $this->createMock( TemplateEngineInterface::class); + $templateEngineMock->method('render')->willReturn(''); + $templateEnginePoolMock = $this->createMock(TemplateEnginePool::class); + $templateEnginePoolMock->method('get')->willReturn($templateEngineMock); + + $filesystemMock = $this->createMock(Filesystem::class); + $filesystemMock->method('getDirectoryRead')->willReturn($readInterfaceMock); + + $validatorMock = $this->createMock(Validator::class); + $validatorMock->method('isValid')->willReturn(true); + + $appStateMock = $this->createMock(State::class); + $this->contextMock = $this->createMock(Context::class); $this->contextMock->method('getScopeConfig')->willReturn($this->scopeConfigMock); $this->contextMock->method('getEventManager')->willReturn($this->managerMock); + $this->contextMock->method('getResolver')->willReturn($resolverMock); + $this->contextMock->method('getFilesystem')->willReturn($filesystemMock); + $this->contextMock->method('getValidator')->willReturn($validatorMock); + $this->contextMock->method('getAppState')->willReturn($appStateMock); + $this->contextMock->method('getEnginePool')->willReturn($templateEnginePoolMock); $this->backendHelperMock = $this->createMock(Data::class); - $this->layoutMock = $this->createMock(LayoutInterface::class); + + // Prepare test data argument + $data = [ + 'area' => 'backend' + ]; $this->applePayDomainAssociationFileButton = new ApplePayDomainAssociationFileButton( $this->contextMock, $this->backendHelperMock, - [] + $data ); + + // $this->applePayDomainAssociationFileButton->setTemplate('Adyen_Payment::config/applepay_domain_association_file_button.phtml'); } /** @@ -63,7 +98,7 @@ public function tearDown(): void */ public function testGetElementHtml() { - $expected = ''; + $expected = ''; $result = $this->applePayDomainAssociationFileButton ->render($this->createMock(AbstractElement::class)); @@ -71,17 +106,6 @@ public function testGetElementHtml() $this->assertEquals($expected, $result); } - /** - * Asserts return type of the button's backend model - * - * @return void - */ - public function testPrepareLayout() - { - $result = $this->applePayDomainAssociationFileButton->setLayout($this->layoutMock); - $this->assertInstanceOf(ApplePayDomainAssociationFileButton::class, $result); - } - /** * Asserts file download controller URL * diff --git a/Test/Unit/Model/Resolver/GetAdyenRedeemedGiftcardsTest.php b/Test/Unit/Model/Resolver/GetAdyenRedeemedGiftcardsTest.php index 3f491ec4a8..7bc11a98d6 100644 --- a/Test/Unit/Model/Resolver/GetAdyenRedeemedGiftcardsTest.php +++ b/Test/Unit/Model/Resolver/GetAdyenRedeemedGiftcardsTest.php @@ -20,30 +20,24 @@ use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Framework\Serialize\Serializer\Json; -use Magento\Quote\Model\QuoteIdMask; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +use PHPUnit\Framework\MockObject\MockObject; class GetAdyenRedeemedGiftcardsTest extends AbstractAdyenTestCase { - private $giftcardPaymentMock; - private $jsonSerializerMock; - private $quoteIdMaskFactoryMock; - private $quoteIdMaskMock; - private $getAdyenRedeemedGiftcards; - private $fieldMock; - private $contextMock; - private $resolveInfoMock; + private GetAdyenRedeemedGiftcards $getAdyenRedeemedGiftcards; + private GiftcardPayment|MockObject $giftcardPaymentMock; + private Json|MockObject $jsonSerializerMock; + private Field|MockObject $fieldMock; + private ContextInterface|MockObject $contextMock; + private ResolveInfo|MockObject $resolveInfoMock; + private MaskedQuoteIdToQuoteIdInterface|MockObject $maskedQuoteIdToQuoteIdMock; protected function setUp(): void { $this->giftcardPaymentMock = $this->createMock(GiftcardPayment::class); $this->jsonSerializerMock = $this->createMock(Json::class); - $this->quoteIdMaskFactoryMock = $this->createGeneratedMock( - QuoteIdMaskFactory::class, - ['create'] - ); - $this->quoteIdMaskMock = $this->createMock(QuoteIdMask::class); - $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock); + $this->maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteIdInterface::class); $this->fieldMock = $this->createMock(Field::class); $this->contextMock = $this->createMock(ContextInterface::class); @@ -52,7 +46,7 @@ protected function setUp(): void $this->getAdyenRedeemedGiftcards = new GetAdyenRedeemedGiftcards( $this->giftcardPaymentMock, $this->jsonSerializerMock, - $this->quoteIdMaskFactoryMock + $this->maskedQuoteIdToQuoteIdMock ); } @@ -64,14 +58,7 @@ public function testSuccessfulRetrievalOfRedeemedGiftCardDetailsWithValidCartId( $redeemedGiftcardsJson = '{"redeemedGiftcards": [], "remainingAmount": 100, "totalDiscount": 10}'; $redeemedGiftcardsData = json_decode($redeemedGiftcardsJson, true); - $this->quoteIdMaskMock->expects($this->once()) - ->method('load') - ->with($cartId, 'masked_id') - ->willReturn($this->quoteIdMaskMock); - - $this->quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $this->quoteIdMaskMock->method('load')->willReturn($this->quoteIdMaskMock); - $this->quoteIdMaskMock->method('getQuoteId')->willReturn(1); + $this->maskedQuoteIdToQuoteIdMock->expects($this->once())->method('execute')->willReturn($quoteId); $this->giftcardPaymentMock->expects($this->once()) ->method('fetchRedeemedGiftcards') @@ -101,15 +88,9 @@ public function testFailedRetrievalOfRedeemedGiftCards() $cartId = 'test_cart_id'; $args = ['cartId' => $cartId]; + $quoteId = 1; - $this->quoteIdMaskMock->expects($this->once()) - ->method('load') - ->with($cartId, 'masked_id') - ->willReturn($this->quoteIdMaskMock); - - $this->quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $this->quoteIdMaskMock->method('load')->willReturn($this->quoteIdMaskMock); - $this->quoteIdMaskMock->method('getQuoteId')->willReturn(1); + $this->maskedQuoteIdToQuoteIdMock->expects($this->once())->method('execute')->willReturn($quoteId); $this->giftcardPaymentMock->method('fetchRedeemedGiftcards') ->willThrowException(new Exception()); @@ -126,8 +107,3 @@ public function testFailedRetrievalOfRedeemedGiftCardsWithNullCartId() $this->getAdyenRedeemedGiftcards->resolve($this->fieldMock, $this->contextMock, $this->resolveInfoMock, [], $args); } } - - - - - diff --git a/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php b/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php index ad68f52f91..6bcc5bc07d 100644 --- a/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php +++ b/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php @@ -20,19 +20,17 @@ use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Quote\Model\QuoteIdMask; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use PHPUnit\Framework\MockObject\MockObject; class RemoveAdyenStateDataTest extends AbstractAdyenTestCase { private RemoveAdyenStateData $removeAdyenStateDataResolver; private AdyenStateData|MockObject $adyenStateDataHelperMock; - private QuoteIdMaskFactory|MockObject $quoteIdMaskFactoryMock; - private QuoteIdMask|MockObject $quoteIdMaskMock; private Field|MockObject $fieldMock; private ContextInterface|MockObject $contextMock; private ResolveInfo|MockObject $infoMock; + private MaskedQuoteIdToQuoteIdInterface|MockObject $maskedQuoteIdToQuoteIdMock; public function setUp(): void { @@ -41,18 +39,12 @@ public function setUp(): void $this->contextMock = $this->createMock(ContextInterface::class); $this->infoMock = $this->createMock(ResolveInfo::class); - $this->quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $this->quoteIdMaskMock->method('load')->willReturn($this->quoteIdMaskMock); - $this->quoteIdMaskMock->method('getQuoteId')->willReturn(1); - - $this->quoteIdMaskFactoryMock = $this->createGeneratedMock(QuoteIdMaskFactory::class, [ - 'create' - ]); - $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock); + $this->maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteIdInterface::class); + $this->maskedQuoteIdToQuoteIdMock->method('execute')->willReturn(1); $this->removeAdyenStateDataResolver = new RemoveAdyenStateData( $this->adyenStateDataHelperMock, - $this->quoteIdMaskFactoryMock + $this->maskedQuoteIdToQuoteIdMock ); } @@ -62,7 +54,7 @@ public function testResolve() $args = [ 'stateDataId' => $stateDataId, - 'cartId' => 1 + 'cartId' => '1' ]; $this->adyenStateDataHelperMock->expects($this->once())->method('remove')->willReturn(true); @@ -87,12 +79,12 @@ public function testResolveWithLocalizedException() $args = [ 'stateDataId' => $stateDataId, - 'cartId' => 1 + 'cartId' => '1' ]; $this->adyenStateDataHelperMock->expects($this->once())->method('remove')->willReturn(false); - $result = $this->removeAdyenStateDataResolver->resolve( + $this->removeAdyenStateDataResolver->resolve( $this->fieldMock, $this->contextMock, $this->infoMock, @@ -107,7 +99,7 @@ public function testResolveWithGraphQLAdyenException() $args = [ 'stateDataId' => 1, - 'cartId' => 1 + 'cartId' => '1' ]; $this->adyenStateDataHelperMock->expects($this->once()) @@ -154,7 +146,7 @@ private static function inputFailureDataProvider(): array return [ [ 'stateDataId' => '', - 'cartId' => 1 + 'cartId' => '1' ], [ 'stateDataId' => 1, @@ -166,7 +158,7 @@ private static function inputFailureDataProvider(): array ], [ 'stateDataId' => null, - 'cartId' => 1 + 'cartId' => '1' ] ]; } diff --git a/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php b/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php index 2ddd658938..70d826f6ba 100644 --- a/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php +++ b/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php @@ -18,18 +18,17 @@ use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Quote\Model\QuoteIdMask; -use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +use PHPUnit\Framework\MockObject\MockObject; class SaveAdyenStateDataTest extends AbstractAdyenTestCase { private SaveAdyenStateData $saveAdyenStateDataResolver; - private AdyenStateData $adyenStateDataHelperMock; - private QuoteIdMaskFactory $quoteIdMaskFactoryMock; - private QuoteIdMask $quoteIdMaskMock; - private Field $fieldMock; - private ContextInterface$contextMock; - private ResolveInfo $infoMock; + private AdyenStateData|MockObject $adyenStateDataHelperMock; + private Field|MockObject $fieldMock; + private ContextInterface|MockObject $contextMock; + private ResolveInfo|MockObject $infoMock; + private MaskedQuoteIdToQuoteIdInterface|MockObject $maskedQuoteIdToQuoteIdMock; public function setUp(): void { @@ -38,18 +37,12 @@ public function setUp(): void $this->contextMock = $this->createMock(ContextInterface::class); $this->infoMock = $this->createMock(ResolveInfo::class); - $this->quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']); - $this->quoteIdMaskMock->method('load')->willReturn($this->quoteIdMaskMock); - $this->quoteIdMaskMock->method('getQuoteId')->willReturn(1); - - $this->quoteIdMaskFactoryMock = $this->createGeneratedMock(QuoteIdMaskFactory::class, [ - 'create' - ]); - $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock); + $this->maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteIdInterface::class); + $this->maskedQuoteIdToQuoteIdMock->method('execute')->willReturn(1); $this->saveAdyenStateDataResolver = new SaveAdyenStateData( $this->adyenStateDataHelperMock, - $this->quoteIdMaskFactoryMock + $this->maskedQuoteIdToQuoteIdMock ); } @@ -60,7 +53,7 @@ public function testResolve() $args = [ 'stateData' => $stateData, - 'cartId' => 1 + 'cartId' => '1' ]; $this->adyenStateDataHelperMock->expects($this->once())->method('save')->willReturn($stateDataId); @@ -83,7 +76,7 @@ public function testResolveFailedWithException() $args = [ 'stateData' => "{}", - 'cartId' => 1 + 'cartId' => '1' ]; $this->adyenStateDataHelperMock->expects($this->once()) @@ -130,7 +123,7 @@ private static function inputFailureDataProvider(): array return [ [ 'stateData' => '', - 'cartId' => 1 + 'cartId' => '1' ], [ 'stateData' => "{}", @@ -142,7 +135,7 @@ private static function inputFailureDataProvider(): array ], [ 'stateData' => null, - 'cartId' => 1 + 'cartId' => '1' ] ]; } From 47d5ea483aa1f62073b2d89549990d510501b2ca Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 10:47:35 +0100 Subject: [PATCH 16/34] [ECP-9489] Fix PHPStan workflow --- .github/workflows/main.yml | 3 --- .github/workflows/phpstan.yml | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/phpstan.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 64010cf632..b8c34adba7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,9 +39,6 @@ jobs: - name: Code Sniffer run: vendor/bin/phpcs . - - name: PHPStan - run: vendor/bin/phpstan analyse . - - name: Run PHPUnit run: vendor/bin/phpunit --coverage-clover=build/clover.xml --log-junit=build/tests-log.xml -c Test/phpunit.xml Test/Unit diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000000..8ece52f825 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,46 @@ +name: PHPStan analysis + +on: + pull_request: + pull_request_target: + workflow_dispatch: + +jobs: + build: + if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) || (github.event_name == 'workflow_dispatch') + environment: ${{ (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) && 'external' || 'internal' }} + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: [8.2,8.3] + + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha || github.ref }} + fetch-depth: 0 + + - name: Use PHP ${{ matrix.php-version }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + tools: composer:v2 + + - name: Test plugin installation + run: | + echo "{\"http-basic\":{\"repo.magento.com\":{\"username\":\"${MAGENTO_USERNAME}\",\"password\":\"${MAGENTO_PASSWORD}\"}}}" > auth.json + composer install --prefer-dist + env: + CI: true + MAGENTO_USERNAME: ${{ secrets.MAGENTO_USERNAME }} + MAGENTO_PASSWORD: ${{ secrets.MAGENTO_PASSWORD }} + + - name: Install Magento PHPStan dependecies + run: | + composer require --dev bitexpert/phpstan-magento + composer config allow-plugins.phpstan/extension-installer true + composer require --dev phpstan/extension-installer + + - name: PHPStan + run: vendor/bin/phpstan analyse . From 3514bd81d32720adaf7fc0f7936de87abfdae7f7 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 10:53:42 +0100 Subject: [PATCH 17/34] [ECP-9489] Add PHPStan config file to exclude vendor dir --- .github/workflows/phpstan.yml | 2 +- phpstan.neon | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 phpstan.neon diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 8ece52f825..962f4e6d8f 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -43,4 +43,4 @@ jobs: composer require --dev phpstan/extension-installer - name: PHPStan - run: vendor/bin/phpstan analyse . + run: vendor/bin/phpstan analyse . -c phpstan.neon diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000000..a8c27c67a4 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,4 @@ +parameters: + level: 0 + excludePaths: + - vendor From fd4818ce3202fad2a8a83b45a58caa04ff766f5f Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 10:56:13 +0100 Subject: [PATCH 18/34] [ECP-9489] Fix formatting --- phpstan.neon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index a8c27c67a4..9f96b1cffc 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,4 @@ parameters: level: 0 - excludePaths: - - vendor + excludePaths: + - vendor From 0cc71ea8d85cb63e1337bb8edbf2a27a9ca8e74d Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 11:06:13 +0100 Subject: [PATCH 19/34] [ECP-9489] Adjust PHPStan configuration --- phpstan.neon | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/phpstan.neon b/phpstan.neon index 9f96b1cffc..a9c77ca4c6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,5 @@ parameters: level: 0 excludePaths: - - vendor + analyse: + - vendor From 3856f44d98ca89892e388eaa1a3907eda23f0470 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 11:15:14 +0100 Subject: [PATCH 20/34] [ECP-9489] Adjust PHPStan configuration --- phpstan.neon | 1 - 1 file changed, 1 deletion(-) diff --git a/phpstan.neon b/phpstan.neon index a9c77ca4c6..cdc4c86126 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,4 @@ parameters: - level: 0 excludePaths: analyse: - vendor From 064d6b842bb8fab8499db132e8c6ba5c79a932c3 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 11:18:09 +0100 Subject: [PATCH 21/34] [ECP-9489] Adjust PHPStan configuration --- phpstan.neon | 1 + 1 file changed, 1 insertion(+) diff --git a/phpstan.neon b/phpstan.neon index cdc4c86126..a9c77ca4c6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,5 @@ parameters: + level: 0 excludePaths: analyse: - vendor From 596afdcfd8320ac16f89128181fdd8aaa6fb9be2 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 11:27:50 +0100 Subject: [PATCH 22/34] [ECP-9489] Adjust PHPStan configuration --- phpstan.neon | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index a9c77ca4c6..3b865e156e 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,20 @@ parameters: level: 0 - excludePaths: - analyse: - - vendor + paths: + - AdminMessage + - Api + - Block + - Console + - Controller + - Cron + - Exception + - Gateway + - Helper + - Logger + - Model + - Observer + - Plugin + - Setup + - Test + - Ui + - view From f3fbfc57ee5dd43a1c0aedd9e1869b55419a739c Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 11:30:34 +0100 Subject: [PATCH 23/34] [ECP-9489] Adjust PHPStan workflow --- .github/workflows/phpstan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 962f4e6d8f..4842663803 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -43,4 +43,4 @@ jobs: composer require --dev phpstan/extension-installer - name: PHPStan - run: vendor/bin/phpstan analyse . -c phpstan.neon + run: vendor/bin/phpstan analyse -c phpstan.neon From 46b299a3d3f714ecf83c49fc806bb3800bbb96d0 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 14:57:39 +0100 Subject: [PATCH 24/34] [ECP-9489] Update PHPDocs for the interface --- Api/Repository/AdyenInvoiceRepositoryInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Api/Repository/AdyenInvoiceRepositoryInterface.php b/Api/Repository/AdyenInvoiceRepositoryInterface.php index 227926ca91..d27e08a62c 100644 --- a/Api/Repository/AdyenInvoiceRepositoryInterface.php +++ b/Api/Repository/AdyenInvoiceRepositoryInterface.php @@ -49,8 +49,8 @@ public function getByAdyenOrderPaymentId(int $adyenOrderPaymentId): ?array; /** * Performs persist operations for a specified adyen_invoice. * - * @param InvoiceInterface $entity The order ID. - * @return InvoiceInterface Order interface. + * @param InvoiceInterface $entity adyen_invoice entity + * @return InvoiceInterface */ public function save(InvoiceInterface $entity): InvoiceInterface; } From 4203483227ec970066bf838632cd1b8d404c477f Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 14:59:37 +0100 Subject: [PATCH 25/34] [ECP-9489] Implement AdyenCreditmemoRepository and deprecated old methods --- .../AdyenCreditmemoRepositoryInterface.php | 66 ++++++++ Helper/Creditmemo.php | 89 ++++------- Helper/Order.php | 148 ++++++------------ Model/AdyenCreditmemoRepository.php | 124 +++++++++++++++ Model/ResourceModel/Creditmemo/Creditmemo.php | 23 +++ 5 files changed, 294 insertions(+), 156 deletions(-) create mode 100644 Api/Repository/AdyenCreditmemoRepositoryInterface.php create mode 100644 Model/AdyenCreditmemoRepository.php diff --git a/Api/Repository/AdyenCreditmemoRepositoryInterface.php b/Api/Repository/AdyenCreditmemoRepositoryInterface.php new file mode 100644 index 0000000000..ce1b055663 --- /dev/null +++ b/Api/Repository/AdyenCreditmemoRepositoryInterface.php @@ -0,0 +1,66 @@ + + */ + +namespace Adyen\Payment\Api\Repository; + +use Adyen\Payment\Api\Data\CreditmemoInterface; +use Adyen\Payment\Api\Data\NotificationInterface; +use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\Api\SearchResultsInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; + +interface AdyenCreditmemoRepositoryInterface +{ + /** + * Retrieve adyen_creditmemo entity by the ID. + * + * @param int $entityId + * @return CreditmemoInterface Gift message. + * @throws NoSuchEntityException + */ + public function get(int $entityId): CreditmemoInterface; + + /** + * Retrieve adyen_creditmemo entities by `adyen_order_payment_id`. + * + * @param int $adyenOrderPaymentId + * @return CreditmemoInterface[]|null + */ + public function getByAdyenOrderPaymentId(int $adyenOrderPaymentId): ?array; + + /** + * Retrieve adyen_creditmemo entity by the given notification using the `pspreference` column. + * + * @param NotificationInterface $notification + * @return CreditmemoInterface|null + */ + public function getByRefundWebhook(NotificationInterface $notification): ?CreditmemoInterface; + + /** + * Retrieve adyen_creditmemo entities which match a specified criteria. + * + * @param SearchCriteriaInterface $searchCriteria + * @return SearchResultsInterface + * + * @throws LocalizedException + */ + public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface; + + /** + * Performs persist operations for a specified adyen_creditmemo. + * + * @param CreditmemoInterface $entity adyen_creditmemo entity. + * @return CreditmemoInterface + */ + public function save(CreditmemoInterface $entity): CreditmemoInterface; +} diff --git a/Helper/Creditmemo.php b/Helper/Creditmemo.php index 709ca30fe6..34a52c735f 100644 --- a/Helper/Creditmemo.php +++ b/Helper/Creditmemo.php @@ -11,20 +11,18 @@ namespace Adyen\Payment\Helper; -use Adyen\Payment\Api\Data\CreditmemoInterface; use Adyen\Payment\Api\Data\OrderPaymentInterface; +use Adyen\Payment\Api\Repository\AdyenCreditmemoRepositoryInterface; use Adyen\Payment\Model\Order\Payment; use Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo as CreditMemoResourceModel; use Adyen\Payment\Model\CreditmemoFactory; use Adyen\Payment\Model\Creditmemo as AdyenCreditmemoModel; use Adyen\Payment\Model\ResourceModel\Order\Payment as OrderPaymentResourceModel; -use Magento\Framework\Exception\AlreadyExistsException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Creditmemo as MagentoCreditMemoModel; use Magento\Framework\App\Helper\AbstractHelper; use Magento\Framework\App\Helper\Context; -use Magento\Sales\Model\Order\CreditmemoFactory as MagentoCreditMemoFactory; -use Magento\Sales\Model\ResourceModel\Order\Creditmemo as MagentoCreditMemoResourceModel; /** * Helper class for anything related to the creditmemo entity @@ -34,46 +32,22 @@ class Creditmemo extends AbstractHelper { /** - * @var Data - */ - protected $adyenDataHelper; - - /** - * @var OrderPaymentResourceModel - */ - protected $orderPaymentResourceModel; - - /** - * @var CreditmemoResourceModel - */ - private $adyenCreditmemoResourceModel; - - /** - * @var CreditmemoFactory - */ - private $adyenCreditmemoFactory; - - /** - * Creditmemo constructor. * @param Context $context * @param Data $adyenDataHelper * @param CreditmemoFactory $adyenCreditmemoFactory - * @param CreditmemoResourceModel $adyenCreditmemoResourceModel + * @param CreditMemoResourceModel $adyenCreditmemoResourceModel * @param OrderPaymentResourceModel $orderPaymentResourceModel + * @param AdyenCreditmemoRepositoryInterface $adyenCreditmemoRepository */ public function __construct( Context $context, - Data $adyenDataHelper, - CreditmemoFactory $adyenCreditmemoFactory, - CreditmemoResourceModel $adyenCreditmemoResourceModel, - OrderPaymentResourceModel $orderPaymentResourceModel - ) - { + protected Data $adyenDataHelper, + private readonly CreditmemoFactory $adyenCreditmemoFactory, + private readonly CreditmemoResourceModel $adyenCreditmemoResourceModel, + protected OrderPaymentResourceModel $orderPaymentResourceModel, + private readonly AdyenCreditmemoRepositoryInterface $adyenCreditmemoRepository + ) { parent::__construct($context); - $this->adyenDataHelper = $adyenDataHelper; - $this->adyenCreditmemoFactory = $adyenCreditmemoFactory; - $this->adyenCreditmemoResourceModel = $adyenCreditmemoResourceModel; - $this->orderPaymentResourceModel = $orderPaymentResourceModel; } /** @@ -84,7 +58,6 @@ public function __construct( * @param string $originalReference * @param float $refundAmount * @return AdyenCreditmemoModel - * @throws AlreadyExistsException */ public function createAdyenCreditMemo( Order\Payment $payment, @@ -110,52 +83,56 @@ public function createAdyenCreditMemo( $adyenCreditmemo->setAmount($refundAmount); $adyenCreditmemo->setStatus(AdyenCreditmemoModel::WAITING_FOR_WEBHOOK_STATUS); - $this->adyenCreditmemoResourceModel->save($adyenCreditmemo); + $this->adyenCreditmemoRepository->save($adyenCreditmemo); return $adyenCreditmemo; } /** * Link all the adyen_creditmemos related to the adyen_order_payment with the given magento entity of the creditmemo - * @throws AlreadyExistsException + * + * @param Payment $adyenOrderPayment + * @param MagentoCreditMemoModel $magentoCreditmemo + * @return void */ public function linkAndUpdateAdyenCreditmemos( Payment $adyenOrderPayment, MagentoCreditmemoModel $magentoCreditmemo ): void { - $adyenCreditmemoLoader = $this->adyenCreditmemoFactory->create(); - - $adyenCreditmemos = $this->adyenCreditmemoResourceModel->getAdyenCreditmemosByAdyenPaymentid( + $adyenCreditmemos = $this->adyenCreditmemoRepository->getByAdyenOrderPaymentId( $adyenOrderPayment->getEntityId() ); if (isset($adyenCreditmemos)) { foreach ($adyenCreditmemos as $adyenCreditmemo) { - /** @var AdyenCreditmemoModel $currAdyenCreditmemo */ - $currAdyenCreditmemo = $adyenCreditmemoLoader->load( - $adyenCreditmemo[CreditmemoInterface::ENTITY_ID], - CreditmemoInterface::ENTITY_ID - ); - - if ($currAdyenCreditmemo->getCreditmemoId() !== null) { - continue; - } + if ($adyenCreditmemo->getAmount() == $magentoCreditmemo->getGrandTotal()) { + $adyenCreditmemo->setCreditmemoId($magentoCreditmemo->getEntityId()); + $this->adyenCreditmemoRepository->save($adyenCreditmemo); - if ($currAdyenCreditmemo->getAmount() == $magentoCreditmemo->getGrandTotal()) { - $currAdyenCreditmemo->setCreditmemoId($magentoCreditmemo->getEntityId()); - $this->adyenCreditmemoResourceModel->save($currAdyenCreditmemo); break; } } } } + /** + * @param AdyenCreditmemoModel $adyenCreditmemo + * @param string $status + * @return void + */ public function updateAdyenCreditmemosStatus(AdyenCreditmemoModel $adyenCreditmemo, string $status) { $adyenCreditmemo->setStatus($status); - $this->adyenCreditmemoResourceModel->save($adyenCreditmemo); + $this->adyenCreditmemoRepository->save($adyenCreditmemo); } + /** + * @deprecated Use AdyenCreditmemoRepositoryInterface::getByRefundWebhook() instead. + * + * @param string $pspreference + * @return AdyenCreditmemoModel|null + * @throws NoSuchEntityException + */ public function getAdyenCreditmemoByPspreference(string $pspreference): ?AdyenCreditmemoModel { $results = $this->adyenCreditmemoResourceModel->getAdyenCreditmemoByPspreference($pspreference); @@ -163,6 +140,6 @@ public function getAdyenCreditmemoByPspreference(string $pspreference): ?AdyenCr return null; } - return $this->adyenCreditmemoFactory->create()->load($results['entity_id']); + return $this->adyenCreditmemoRepository->get($results['entity_id']); } } diff --git a/Helper/Order.php b/Helper/Order.php index 8ad0facfe2..ed5dff962b 100644 --- a/Helper/Order.php +++ b/Helper/Order.php @@ -11,13 +11,13 @@ namespace Adyen\Payment\Helper; +use Adyen\Payment\Api\Data\CreditmemoInterface; use Adyen\Payment\Api\Data\OrderPaymentInterface; +use Adyen\Payment\Api\Repository\AdyenCreditmemoRepositoryInterface; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\Notification; use Adyen\Payment\Model\ResourceModel\Order\Payment\CollectionFactory as OrderPaymentCollectionFactory; -use Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo as AdyenCreditMemoResourceModel; use Adyen\Payment\Helper\Creditmemo as AdyenCreditmemoHelper; -use Adyen\Payment\Model\Creditmemo as AdyenCreditmemoModel; use Exception; use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\App\Helper\AbstractHelper; @@ -30,106 +30,60 @@ use Magento\Sales\Model\Order as MagentoOrder; use Magento\Sales\Model\Order\Email\Sender\OrderSender; use Magento\Sales\Model\Order\Payment\Transaction\Builder; +use Magento\Sales\Model\Order\StatusResolver; use Magento\Sales\Model\OrderRepository; use Magento\Sales\Model\ResourceModel\Order\Status\CollectionFactory as OrderStatusCollectionFactory; class Order extends AbstractHelper { - /** @var Builder */ - private $transactionBuilder; - - /** @var Data */ - private $dataHelper; - - /** @var AdyenLogger */ - private $adyenLogger; - - /** @var OrderSender */ - private $orderSender; - - /** @var TransactionFactory */ - private $transactionFactory; - - /** @var ChargedCurrency */ - private $chargedCurrency; - - /** @var AdyenOrderPayment */ - private $adyenOrderPaymentHelper; - - /** @var Config */ - private $configHelper; - - /** @var OrderStatusCollectionFactory */ - private $orderStatusCollectionFactory; - - /** @var SearchCriteriaBuilder */ - private $searchCriteriaBuilder; - - /** @var OrderRepository */ - private $orderRepository; - - /** @var NotifierPool */ - private $notifierPool; - - /** @var OrderPaymentCollectionFactory */ - private $adyenOrderPaymentCollectionFactory; - - /** @var PaymentMethods */ - private $paymentMethodsHelper; - - /** @var AdyenCreditMemoResourceModel */ - private $adyenCreditmemoResourceModel; - - /** @var AdyenCreditmemoHelper */ - private $adyenCreditmemoHelper; - - private MagentoOrder\StatusResolver $statusResolver; - + /** + * @param Context $context + * @param Builder $transactionBuilder + * @param Data $dataHelper + * @param AdyenLogger $adyenLogger + * @param OrderSender $orderSender + * @param TransactionFactory $transactionFactory + * @param ChargedCurrency $chargedCurrency + * @param AdyenOrderPayment $adyenOrderPaymentHelper + * @param Config $configHelper + * @param OrderStatusCollectionFactory $orderStatusCollectionFactory + * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param OrderRepository $orderRepository + * @param NotifierPool $notifierPool + * @param OrderPaymentCollectionFactory $adyenOrderPaymentCollectionFactory + * @param PaymentMethods $paymentMethodsHelper + * @param Creditmemo $adyenCreditmemoHelper + * @param StatusResolver $statusResolver + * @param AdyenCreditmemoRepositoryInterface $adyenCreditmemoRepository + */ public function __construct( Context $context, - Builder $transactionBuilder, - Data $dataHelper, - AdyenLogger $adyenLogger, - OrderSender $orderSender, - TransactionFactory $transactionFactory, - ChargedCurrency $chargedCurrency, - AdyenOrderPayment $adyenOrderPaymentHelper, - Config $configHelper, - OrderStatusCollectionFactory $orderStatusCollectionFactory, - SearchCriteriaBuilder $searchCriteriaBuilder, - OrderRepository $orderRepository, - NotifierPool $notifierPool, - OrderPaymentCollectionFactory $adyenOrderPaymentCollectionFactory, - PaymentMethods $paymentMethodsHelper, - AdyenCreditMemoResourceModel $adyenCreditmemoResourceModel, - AdyenCreditmemoHelper $adyenCreditmemoHelper, - MagentoOrder\StatusResolver $statusResolver + private readonly Builder $transactionBuilder, + private readonly Data $dataHelper, + private readonly AdyenLogger $adyenLogger, + private readonly OrderSender $orderSender, + private readonly TransactionFactory $transactionFactory, + private readonly ChargedCurrency $chargedCurrency, + private readonly AdyenOrderPayment $adyenOrderPaymentHelper, + private readonly Config $configHelper, + private readonly OrderStatusCollectionFactory $orderStatusCollectionFactory, + private readonly SearchCriteriaBuilder $searchCriteriaBuilder, + private readonly OrderRepository $orderRepository, + private readonly NotifierPool $notifierPool, + private readonly OrderPaymentCollectionFactory $adyenOrderPaymentCollectionFactory, + private readonly PaymentMethods $paymentMethodsHelper, + private readonly AdyenCreditmemoHelper $adyenCreditmemoHelper, + private readonly MagentoOrder\StatusResolver $statusResolver, + private readonly AdyenCreditmemoRepositoryInterface $adyenCreditmemoRepository ) { parent::__construct($context); - $this->transactionBuilder = $transactionBuilder; - $this->dataHelper = $dataHelper; - $this->adyenLogger = $adyenLogger; - $this->orderSender = $orderSender; - $this->transactionFactory = $transactionFactory; - $this->chargedCurrency = $chargedCurrency; - $this->adyenOrderPaymentHelper = $adyenOrderPaymentHelper; - $this->configHelper = $configHelper; - $this->orderStatusCollectionFactory = $orderStatusCollectionFactory; - $this->searchCriteriaBuilder = $searchCriteriaBuilder; - $this->orderRepository = $orderRepository; - $this->notifierPool = $notifierPool; - $this->adyenOrderPaymentCollectionFactory = $adyenOrderPaymentCollectionFactory; - $this->paymentMethodsHelper = $paymentMethodsHelper; - $this->adyenCreditmemoResourceModel = $adyenCreditmemoResourceModel; - $this->adyenCreditmemoHelper = $adyenCreditmemoHelper; - $this->statusResolver = $statusResolver; } /** * @param MagentoOrder $order * @param Notification $notification * @return TransactionInterface|null - * @throws \Exception + * @throws Exception */ public function updatePaymentDetails(MagentoOrder $order, Notification $notification): ?TransactionInterface { @@ -487,14 +441,12 @@ public function addRefundFailedNotice(MagentoOrder $order, Notification $notific sprintf('Refund has failed. Unable to change back status of the order.
%s', $description) ), $order->getStatus()); - $linkedAdyenCreditmemo = $this->adyenCreditmemoHelper->getAdyenCreditmemoByPspreference( - $notification->getPspreference() - ); + $linkedAdyenCreditmemo = $this->adyenCreditmemoRepository->getByRefundWebhook($notification); - if ($linkedAdyenCreditmemo instanceof AdyenCreditmemoModel) { + if (isset($linkedAdyenCreditmemo)) { $this->adyenCreditmemoHelper->updateAdyenCreditmemosStatus( $linkedAdyenCreditmemo, - AdyenCreditmemoModel::FAILED_STATUS + CreditmemoInterface::FAILED_STATUS ); } @@ -598,9 +550,7 @@ public function refundOrder(MagentoOrder $order, Notification $notification): Ma * Check adyen_creditmemo table. * If credit memo doesn't exist for this notification, create it. */ - $linkedAdyenCreditmemo = $this->adyenCreditmemoHelper->getAdyenCreditmemoByPspreference( - $notification->getPspreference() - ); + $linkedAdyenCreditmemo = $this->adyenCreditmemoRepository->getByRefundWebhook($notification); if (is_null($linkedAdyenCreditmemo)) { if ($order->canCreditmemo()) { @@ -670,11 +620,9 @@ public function refundOrder(MagentoOrder $order, Notification $notification): Ma ); } - if ($linkedAdyenCreditmemo instanceof AdyenCreditmemoModel) { - $this->adyenCreditmemoHelper->updateAdyenCreditmemosStatus( - $linkedAdyenCreditmemo, AdyenCreditmemoModel::COMPLETED_STATUS - ); - } + $this->adyenCreditmemoHelper->updateAdyenCreditmemosStatus( + $linkedAdyenCreditmemo, CreditmemoInterface::COMPLETED_STATUS + ); $order->addStatusHistoryComment(__(sprintf( '%s Webhook successfully handled', diff --git a/Model/AdyenCreditmemoRepository.php b/Model/AdyenCreditmemoRepository.php new file mode 100644 index 0000000000..c924d593ab --- /dev/null +++ b/Model/AdyenCreditmemoRepository.php @@ -0,0 +1,124 @@ + + */ + +namespace Adyen\Payment\Model; + +use Adyen\AdyenException; +use Adyen\Payment\Api\Data\CreditmemoInterface; +use Adyen\Payment\Api\Data\NotificationInterface; +use Adyen\Payment\Api\Repository\AdyenCreditmemoRepositoryInterface; +use Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo as CreditmemoResourceModel; +use Adyen\Payment\Model\ResourceModel\Creditmemo\CollectionFactory; +use Adyen\Webhook\EventCodes; +use Magento\Framework\Api\Search\SearchResultFactory; +use Magento\Framework\Api\SearchCriteria\CollectionProcessor; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\Api\SearchResultsInterface; +use Magento\Framework\Exception\AlreadyExistsException; +use Magento\Framework\Exception\LocalizedException; + +class AdyenCreditmemoRepository implements AdyenCreditmemoRepositoryInterface +{ + /** + * @param CreditmemoFactory $adyenCreditmemoFactory + * @param CreditmemoResourceModel $resourceModel + * @param SearchResultFactory $searchResultsFactory + * @param CollectionFactory $collectionFactory + * @param CollectionProcessor $collectionProcessor + * @param SearchCriteriaBuilder $searchCriteriaBuilder + */ + public function __construct( + private readonly CreditmemoFactory $adyenCreditmemoFactory, + private readonly CreditmemoResourceModel $resourceModel, + private readonly SearchResultFactory $searchResultsFactory, + private readonly CollectionFactory $collectionFactory, + private readonly CollectionProcessor $collectionProcessor, + private readonly SearchCriteriaBuilder $searchCriteriaBuilder + ) { } + + /** + * @param int $entityId + * @return CreditmemoInterface + */ + public function get(int $entityId): CreditmemoInterface + { + $entity = $this->adyenCreditmemoFactory->create(); + $this->resourceModel->load($entity, $entity, 'entity_id'); + + return $entity; + } + + /** + * @param SearchCriteriaInterface $searchCriteria + * @return SearchResultsInterface + */ + public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface + { + $searchResult = $this->searchResultsFactory->create(); + $collection = $this->collectionFactory->create(); + $this->collectionProcessor->process($searchCriteria, $collection); + $searchResult->setItems($collection->getItems()); + $searchResult->setTotalCount($collection->getSize()); + + return $searchResult; + } + + /** + * @param int $adyenOrderPaymentId + * @return array|CreditmemoInterface[]|null + */ + public function getByAdyenOrderPaymentId(int $adyenOrderPaymentId): ?array + { + $searchCriteria = $this->searchCriteriaBuilder + ->addFilter(CreditmemoInterface::ADYEN_ORDER_PAYMENT_ID, $adyenOrderPaymentId) + ->create(); + + return $this->getList($searchCriteria)->getItems(); + } + + /** + * @throws AlreadyExistsException + */ + public function save(CreditmemoInterface $entity): CreditmemoInterface + { + $this->resourceModel->save($entity); + + return $entity; + } + + /** + * @param NotificationInterface $notification + * @return CreditmemoInterface|null + * @throws AdyenException + * @throws LocalizedException + */ + public function getByRefundWebhook(NotificationInterface $notification): ?CreditmemoInterface + { + if ($notification->getEventCode() !== EventCodes::REFUND) { + throw new AdyenException(sprintf( + 'Refund webhook is expected to get the adyen_creditmemo, %s notification given.', + $notification->getEventCode() + )); + } + + $entityId = $this->resourceModel->getIdByPspreference($notification->getPspreference()); + + if (empty($entityId)) { + return null; + } else { + $entity = $this->adyenCreditmemoFactory->create(); + $this->resourceModel->load($entity, $entityId, 'entity_id'); + + return $entity; + } + } +} diff --git a/Model/ResourceModel/Creditmemo/Creditmemo.php b/Model/ResourceModel/Creditmemo/Creditmemo.php index ef90fdb14b..2f91abae52 100644 --- a/Model/ResourceModel/Creditmemo/Creditmemo.php +++ b/Model/ResourceModel/Creditmemo/Creditmemo.php @@ -12,6 +12,7 @@ namespace Adyen\Payment\Model\ResourceModel\Creditmemo; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; class Creditmemo extends AbstractDb @@ -29,6 +30,8 @@ protected function _construct() /** * Get all the adyen_creditmemo entries linked to the adyen_order_payment * + * @deprecated Use AdyenCreditmemoRepositoryInterface::getByAdyenOrderPaymentId() instead. + * * @param int $adyenPaymentId * @return array|null */ @@ -44,6 +47,8 @@ public function getAdyenCreditmemosByAdyenPaymentid(int $adyenPaymentId): ?array } /** + * @deprecated Use AdyenCreditmemoRepositoryInterface::getByRefundWebhook() instead. + * * @param string $pspreference * @return array|null */ @@ -57,4 +62,22 @@ public function getAdyenCreditmemoByPspreference(string $pspreference): ?array return empty($result) ? null : $result; } + + /** + * @param string $pspreference + * @return string + * @throws LocalizedException + */ + public function getIdByPspreference(string $pspreference): string + { + $connection = $this->getConnection(); + + $select = $connection->select() + ->from($this->getMainTable(), 'entity_id') + ->where('pspreference = :pspreference'); + + $bind = [':pspreference' => $pspreference]; + + return $connection->fetchOne($select, $bind); + } } From a500de653b70735d53604622d5c18f0b953420c9 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Wed, 15 Jan 2025 15:08:35 +0100 Subject: [PATCH 26/34] [ECP-9489] Update PHPDocs --- Api/Repository/AdyenCreditmemoRepositoryInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Api/Repository/AdyenCreditmemoRepositoryInterface.php b/Api/Repository/AdyenCreditmemoRepositoryInterface.php index ce1b055663..28ed2bb091 100644 --- a/Api/Repository/AdyenCreditmemoRepositoryInterface.php +++ b/Api/Repository/AdyenCreditmemoRepositoryInterface.php @@ -25,7 +25,7 @@ interface AdyenCreditmemoRepositoryInterface * Retrieve adyen_creditmemo entity by the ID. * * @param int $entityId - * @return CreditmemoInterface Gift message. + * @return CreditmemoInterface Adyen creditmemo entity * @throws NoSuchEntityException */ public function get(int $entityId): CreditmemoInterface; From 1e0fe849ab02c7a91e113c072dabc9bc994c1d0a Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Thu, 16 Jan 2025 11:25:41 +0100 Subject: [PATCH 27/34] [ECP-9489] Skip class.notFound errors for pseudo test classes --- Test/api-functional/GraphQl/AdyenTest.php | 1 + Test/api-functional/Webapi/ChannelParameterTest.php | 1 + Test/api-functional/Webapi/DonationsTest.php | 1 + 3 files changed, 3 insertions(+) diff --git a/Test/api-functional/GraphQl/AdyenTest.php b/Test/api-functional/GraphQl/AdyenTest.php index 676a6b8344..fc614918cb 100644 --- a/Test/api-functional/GraphQl/AdyenTest.php +++ b/Test/api-functional/GraphQl/AdyenTest.php @@ -36,6 +36,7 @@ class AdyenTest extends GraphQlAbstract protected function setUp(): void { $objectManager = Bootstrap::getObjectManager(); + /** @phpstan-ignore class.notFound */ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); } diff --git a/Test/api-functional/Webapi/ChannelParameterTest.php b/Test/api-functional/Webapi/ChannelParameterTest.php index 654c9f9e13..3ffca4dd12 100644 --- a/Test/api-functional/Webapi/ChannelParameterTest.php +++ b/Test/api-functional/Webapi/ChannelParameterTest.php @@ -25,6 +25,7 @@ class ChannelParameterTest extends WebapiAbstract protected function setUp(): void { $objectManager = Bootstrap::getObjectManager(); + /** @phpstan-ignore class.notFound */ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); } diff --git a/Test/api-functional/Webapi/DonationsTest.php b/Test/api-functional/Webapi/DonationsTest.php index 4fc1160c7c..306f7efa0c 100644 --- a/Test/api-functional/Webapi/DonationsTest.php +++ b/Test/api-functional/Webapi/DonationsTest.php @@ -25,6 +25,7 @@ class DonationsTest extends WebapiAbstract protected function setUp(): void { $objectManager = Bootstrap::getObjectManager(); + /** @phpstan-ignore class.notFound */ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); } From 894b9e37226770a45c3f797a79ce8b11d3eeec33 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Thu, 16 Jan 2025 15:46:22 +0100 Subject: [PATCH 28/34] [ECP-9489] Fix DB initialization parameters --- Model/ResourceModel/Creditmemo/Collection.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Model/ResourceModel/Creditmemo/Collection.php b/Model/ResourceModel/Creditmemo/Collection.php index b8ce8814e3..5c97c356c7 100644 --- a/Model/ResourceModel/Creditmemo/Collection.php +++ b/Model/ResourceModel/Creditmemo/Collection.php @@ -12,15 +12,18 @@ namespace Adyen\Payment\Model\ResourceModel\Creditmemo; -use Adyen\Payment\Model\Creditmemo; +use Adyen\Payment\Model\Creditmemo as CreditmemoModel; +use Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo as CreditmemoResourceModel; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; class Collection extends AbstractCollection { - - public function _construct() + /** + * @return void + */ + public function _construct(): void { - $this->_init(\Adyen\Payment\Model\Creditmemo::class, Creditmemo::class); + $this->_init(CreditmemoModel::class, CreditmemoResourceModel::class); } /** From 9215392020b0a1f76d894409d8bf59cf24ce8343 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Fri, 17 Jan 2025 09:23:29 +0100 Subject: [PATCH 29/34] [ECP-9489] Implement AdyenOrderPaymentRepository --- .../AdyenOrderPaymentRepositoryInterface.php | 57 +++++++ Helper/Webhook/CaptureWebhookHandler.php | 20 ++- Model/AdyenOrderPaymentRepository.php | 140 ++++++++++++++++++ Model/Api/GuestAdyenOrderPaymentStatus.php | 2 +- Observer/CreditmemoObserver.php | 88 ++--------- Observer/InvoiceObserver.php | 78 +++------- Test/Unit/Helper/CreditmemoTest.php | 13 +- .../Webhook/CaptureWebhookHandlerTest.php | 14 +- etc/di.xml | 4 + 9 files changed, 264 insertions(+), 152 deletions(-) create mode 100644 Api/Repository/AdyenOrderPaymentRepositoryInterface.php create mode 100644 Model/AdyenOrderPaymentRepository.php diff --git a/Api/Repository/AdyenOrderPaymentRepositoryInterface.php b/Api/Repository/AdyenOrderPaymentRepositoryInterface.php new file mode 100644 index 0000000000..9696c34e7d --- /dev/null +++ b/Api/Repository/AdyenOrderPaymentRepositoryInterface.php @@ -0,0 +1,57 @@ + + */ + +namespace Adyen\Payment\Api\Repository; + +use Adyen\Payment\Api\Data\OrderPaymentInterface; +use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\Api\SearchResultsInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; + +interface AdyenOrderPaymentRepositoryInterface +{ + const AVAILABLE_CAPTURE_STATUSES = [ + OrderPaymentInterface::CAPTURE_STATUS_AUTO_CAPTURE, + OrderPaymentInterface::CAPTURE_STATUS_MANUAL_CAPTURE, + OrderPaymentInterface::CAPTURE_STATUS_PARTIAL_CAPTURE, + OrderPaymentInterface::CAPTURE_STATUS_NO_CAPTURE + ]; + + /** + * Retrieve adyen_order_payment entity by the ID. + * + * @param int $entityId + * @return OrderPaymentInterface Adyen order payment entity + * @throws NoSuchEntityException + */ + public function get(int $entityId): OrderPaymentInterface; + + /** + * Retrieve adyen_order_payment entities by `payment_id`. + * + * @param int $paymentId + * @param array $captureStatuses + * @return OrderPaymentInterface[]|null + */ + public function getByPaymentId(int $paymentId, array $captureStatuses = []): ?array; + + /** + * Retrieve adyen_order_payment entities which match a specified criteria. + * + * @param SearchCriteriaInterface $searchCriteria + * @return SearchResultsInterface + * + * @throws LocalizedException + */ + public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface; +} diff --git a/Helper/Webhook/CaptureWebhookHandler.php b/Helper/Webhook/CaptureWebhookHandler.php index 1455328397..7510c6a67e 100644 --- a/Helper/Webhook/CaptureWebhookHandler.php +++ b/Helper/Webhook/CaptureWebhookHandler.php @@ -12,29 +12,38 @@ namespace Adyen\Payment\Helper\Webhook; -use Adyen\Payment\Api\Data\OrderPaymentInterface; +use Adyen\Payment\Api\Repository\AdyenOrderPaymentRepositoryInterface; use Adyen\Payment\Helper\AdyenOrderPayment; use Adyen\Payment\Helper\Invoice; use Adyen\Payment\Helper\Order; use Adyen\Payment\Helper\PaymentMethods; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\Notification; -use Adyen\Payment\Model\Order\PaymentFactory; use Adyen\Webhook\PaymentStates; use Magento\Framework\Exception\AlreadyExistsException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Sales\Api\InvoiceRepositoryInterface; use Magento\Sales\Model\Order as MagentoOrder; class CaptureWebhookHandler implements WebhookHandlerInterface { + /** + * @param Invoice $invoiceHelper + * @param AdyenOrderPayment $adyenOrderPaymentHelper + * @param AdyenLogger $adyenLogger + * @param Order $orderHelper + * @param PaymentMethods $paymentMethodsHelper + * @param InvoiceRepositoryInterface $invoiceRepository + * @param AdyenOrderPaymentRepositoryInterface $adyenOrderPaymentRepository + */ public function __construct( private readonly Invoice $invoiceHelper, - private readonly PaymentFactory $adyenOrderPaymentFactory, private readonly AdyenOrderPayment $adyenOrderPaymentHelper, private readonly AdyenLogger $adyenLogger, private readonly Order $orderHelper, private readonly PaymentMethods $paymentMethodsHelper, - private readonly InvoiceRepositoryInterface $invoiceRepository + private readonly InvoiceRepositoryInterface $invoiceRepository, + private readonly AdyenOrderPaymentRepositoryInterface $adyenOrderPaymentRepository ) { } /** @@ -43,6 +52,7 @@ public function __construct( * @param string $transitionState * @return MagentoOrder * @throws AlreadyExistsException + * @throws NoSuchEntityException */ public function handleWebhook(MagentoOrder $order, Notification $notification, string $transitionState): MagentoOrder { @@ -67,7 +77,7 @@ public function handleWebhook(MagentoOrder $order, Notification $notification, s $adyenInvoice = $this->invoiceHelper->handleCaptureWebhook($order, $notification); // Refresh the order by fetching it from the db $order = $this->orderHelper->fetchOrderByIncrementId($notification); - $adyenOrderPayment = $this->adyenOrderPaymentFactory->create()->load($adyenInvoice->getAdyenPaymentOrderId(), OrderPaymentInterface::ENTITY_ID); + $adyenOrderPayment = $this->adyenOrderPaymentRepository->get($adyenInvoice->getAdyenPaymentOrderId()); $this->adyenOrderPaymentHelper->refreshPaymentCaptureStatus($adyenOrderPayment, $notification->getAmountCurrency()); $this->adyenLogger->addAdyenNotification( sprintf( diff --git a/Model/AdyenOrderPaymentRepository.php b/Model/AdyenOrderPaymentRepository.php new file mode 100644 index 0000000000..c626715076 --- /dev/null +++ b/Model/AdyenOrderPaymentRepository.php @@ -0,0 +1,140 @@ + + */ + +namespace Adyen\Payment\Model; + +use Adyen\AdyenException; +use Adyen\Payment\Api\Data\OrderPaymentInterface; +use Adyen\Payment\Api\Repository\AdyenOrderPaymentRepositoryInterface; +use Adyen\Payment\Logger\AdyenLogger; +use Adyen\Payment\Model\Order\PaymentFactory as AdyenOrderPaymentFactory; +use Adyen\Payment\Model\ResourceModel\Order\Payment\CollectionFactory; +use Adyen\Payment\Model\ResourceModel\Order\Payment as AdyenOrderPaymentResourceModel; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\Search\FilterGroupBuilder; +use Magento\Framework\Api\Search\SearchResultFactory; +use Magento\Framework\Api\SearchCriteria\CollectionProcessor; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\Api\SearchResultsInterface; + +class AdyenOrderPaymentRepository implements AdyenOrderPaymentRepositoryInterface +{ + /** + * @param AdyenOrderPaymentResourceModel $resourceModel + * @param AdyenOrderPaymentFactory $adyenOrderPaymentFactory + * @param SearchResultFactory $searchResultsFactory + * @param CollectionFactory $collectionFactory + * @param CollectionProcessor $collectionProcessor + * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param FilterBuilder $filterBuilder + * @param FilterGroupBuilder $filterGroupBuilder + * @param AdyenLogger $adyenLogger + */ + public function __construct( + private readonly AdyenOrderPaymentResourceModel $resourceModel, + private readonly AdyenOrderPaymentFactory $adyenOrderPaymentFactory, + private readonly SearchResultFactory $searchResultsFactory, + private readonly CollectionFactory $collectionFactory, + private readonly CollectionProcessor $collectionProcessor, + private readonly SearchCriteriaBuilder $searchCriteriaBuilder, + private readonly FilterBuilder $filterBuilder, + private readonly FilterGroupBuilder $filterGroupBuilder, + private readonly AdyenLogger $adyenLogger + ) { } + + /** + * @param SearchCriteriaInterface $searchCriteria + * @return SearchResultsInterface + */ + public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface + { + $searchResult = $this->searchResultsFactory->create(); + $collection = $this->collectionFactory->create(); + $this->collectionProcessor->process($searchCriteria, $collection); + $searchResult->setItems($collection->getItems()); + $searchResult->setTotalCount($collection->getSize()); + + return $searchResult; + } + + /** + * @param int $paymentId + * @param array $captureStatuses + * @return OrderPaymentInterface[]|null + * @throws AdyenException + */ + public function getByPaymentId(int $paymentId, array $captureStatuses = []): ?array + { + $paymentIdFilter = $this->filterBuilder->setField(OrderPaymentInterface::PAYMENT_ID) + ->setConditionType('eq') + ->setValue($paymentId) + ->create(); + + $captureStatusFilters = []; + + if (!empty($captureStatuses)) { + $this->validateCaptureStatuses($captureStatuses); + + foreach ($captureStatuses as $captureStatus) { + $captureStatusFilters[] = $this->filterBuilder->setField(OrderPaymentInterface::CAPTURE_STATUS) + ->setConditionType('eq') + ->setValue($captureStatus) + ->create(); + } + } + + /* + * Create two different filter groups for logical AND operation between `payment_id` and `capture_status` + * fields. Filter group `$captureStatusFilters` provides logical OR between `capture_status` values. + */ + $paymentIdFilterGroup = $this->filterGroupBuilder->setFilters([$paymentIdFilter])->create(); + $captureStatusFilterGroup = $this->filterGroupBuilder->setFilters($captureStatusFilters)->create(); + + $searchCriteria = $this->searchCriteriaBuilder + ->setFilterGroups([$paymentIdFilterGroup, $captureStatusFilterGroup]) + ->create(); + + return $this->getList($searchCriteria)->getItems(); + } + + /** + * @param int $entityId + * @return OrderPaymentInterface + */ + public function get(int $entityId): OrderPaymentInterface + { + $entity = $this->adyenOrderPaymentFactory->create(); + $this->resourceModel->load($entity, $entityId, 'entity_id'); + + return $entity; + } + + /** + * @param array $captureStatuses + * @return void + * @throws AdyenException + */ + private function validateCaptureStatuses(array $captureStatuses): void + { + foreach ($captureStatuses as $captureStatus) { + if (!array_contains($captureStatuses, $captureStatus)) { + $message = sprintf( + "Invalid capture status %s has been provided for adyen_order_payment repository!", + $captureStatus + ); + + $this->adyenLogger->error($message); + throw new AdyenException($message); + } + } + } +} diff --git a/Model/Api/GuestAdyenOrderPaymentStatus.php b/Model/Api/GuestAdyenOrderPaymentStatus.php index 27a0a6496e..bceab1ba09 100644 --- a/Model/Api/GuestAdyenOrderPaymentStatus.php +++ b/Model/Api/GuestAdyenOrderPaymentStatus.php @@ -43,7 +43,7 @@ public function getOrderPaymentStatus(string $orderId, string $cartId): string $order = $this->orderRepository->get($orderId); - if ($order->getQuoteId() !== $quoteId) { + if (intval($order->getQuoteId()) !== $quoteId) { $errorMessage = sprintf("Order for ID %s not found!", $orderId); $this->adyenLogger->error($errorMessage); diff --git a/Observer/CreditmemoObserver.php b/Observer/CreditmemoObserver.php index 88dbea6df6..0eb5e347fd 100644 --- a/Observer/CreditmemoObserver.php +++ b/Observer/CreditmemoObserver.php @@ -11,108 +11,40 @@ namespace Adyen\Payment\Observer; -use Adyen\Payment\Helper\AdyenOrderPayment; +use Adyen\Payment\Api\Repository\AdyenOrderPaymentRepositoryInterface; use Adyen\Payment\Helper\Creditmemo as CreditMemoHelper; -use Adyen\Payment\Api\Data\OrderPaymentInterface; -use Adyen\Payment\Helper\Config; -use Adyen\Payment\Helper\Invoice as InvoiceHelper; -use Adyen\Payment\Helper\Order as OrderHelper; -use Adyen\Payment\Logger\AdyenLogger; -use Adyen\Payment\Model\Order\PaymentFactory; -use Adyen\Payment\Model\ResourceModel\Order\Payment; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; -use Magento\Framework\Exception\AlreadyExistsException; -use Magento\Sales\Model\Order; -use Magento\Sales\Model\Order\Invoice; -use Magento\Sales\Model\Order\StatusResolver; use Magento\Sales\Model\Order\Creditmemo; -use Adyen\Payment\Helper\PaymentMethods; class CreditmemoObserver implements ObserverInterface { - /** @var Payment $adyenPaymentResourceModel */ - private $adyenPaymentResourceModel; - - /** @var PaymentFactory */ - private $adyenOrderPaymentFactory; - - /** @var InvoiceHelper $invoiceHelper*/ - private $invoiceHelper; - - /** @var StatusResolver $statusResolver */ - private $statusResolver; - - /** @var AdyenOrderPayment $adyenOrderPaymentHelper */ - private $adyenOrderPaymentHelper; - - /** @var CreditmemoHelper $creditmemoHelper */ - private $creditmemoHelper; - - /** @var Config $configHelper */ - private $configHelper; - - /** @var PaymentMethods $paymentMethodsHelper */ - private $paymentMethodsHelper; - - /** @var OrderHelper */ - private $orderHelper; - /** - * @var AdyenLogger + * @param CreditMemoHelper $creditmemoHelper + * @param AdyenOrderPaymentRepositoryInterface $adyenOrderPaymentRepository */ - private $logger; - public function __construct( - Payment $adyenPaymentResourceModel, - PaymentFactory $adyenOrderPaymentFactory, - InvoiceHelper $invoiceHelper, - StatusResolver $statusResolver, - AdyenOrderPayment $adyenOrderPaymentHelper, - CreditmemoHelper $creditmemoHelper, - Config $configHelper, - AdyenLogger $adyenLogger, - PaymentMethods $paymentMethodsHelper, - OrderHelper $orderHelper - ) { - $this->adyenPaymentResourceModel = $adyenPaymentResourceModel; - $this->adyenOrderPaymentFactory = $adyenOrderPaymentFactory; - $this->invoiceHelper = $invoiceHelper; - $this->statusResolver = $statusResolver; - $this->adyenOrderPaymentHelper = $adyenOrderPaymentHelper; - $this->creditmemoHelper = $creditmemoHelper; - $this->configHelper = $configHelper; - $this->logger = $adyenLogger; - $this->paymentMethodsHelper = $paymentMethodsHelper; - $this->orderHelper = $orderHelper; - } + private readonly CreditmemoHelper $creditmemoHelper, + private readonly AdyenOrderPaymentRepositoryInterface $adyenOrderPaymentRepository + ) { } /** * Link all adyen_creditmemos to the appropriate magento credit memo and set the order to PROCESSING to allow * further credit memos to be generated * * @param Observer $observer - * @throws AlreadyExistsException */ - public function execute(Observer $observer) + public function execute(Observer $observer): void { - $adyenOrderPaymentFactory = $this->adyenOrderPaymentFactory->create(); - /** @var Creditmemo $creditmemo */ $creditmemo = $observer->getData('creditmemo'); $order = $creditmemo->getOrder(); $payment = $order->getPayment(); - $adyenOrderPayments = $this->adyenPaymentResourceModel->getLinkedAdyenOrderPayments( - $payment->getEntityId() - ); + $adyenOrderPayments = $this->adyenOrderPaymentRepository->getByPaymentId($payment->getEntityId()); + foreach ($adyenOrderPayments as $adyenOrderPayment) { - /** @var \Adyen\Payment\Model\Order\Payment $adyenOrderPaymentObject */ - $adyenOrderPaymentObject = $adyenOrderPaymentFactory->load( - $adyenOrderPayment[OrderPaymentInterface::ENTITY_ID], - OrderPaymentInterface::ENTITY_ID - ); - $this->creditmemoHelper->linkAndUpdateAdyenCreditmemos($adyenOrderPaymentObject, $creditmemo); + $this->creditmemoHelper->linkAndUpdateAdyenCreditmemos($adyenOrderPayment, $creditmemo); } } } diff --git a/Observer/InvoiceObserver.php b/Observer/InvoiceObserver.php index a53ffd870d..73e1a719a8 100644 --- a/Observer/InvoiceObserver.php +++ b/Observer/InvoiceObserver.php @@ -11,14 +11,11 @@ namespace Adyen\Payment\Observer; +use Adyen\Payment\Api\Repository\AdyenOrderPaymentRepositoryInterface; use Adyen\Payment\Helper\AdyenOrderPayment; use Adyen\Payment\Api\Data\OrderPaymentInterface; -use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Invoice as InvoiceHelper; -use Adyen\Payment\Helper\Order as OrderHelper; use Adyen\Payment\Logger\AdyenLogger; -use Adyen\Payment\Model\Order\PaymentFactory; -use Adyen\Payment\Model\ResourceModel\Order\Payment; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Exception\AlreadyExistsException; @@ -29,56 +26,22 @@ class InvoiceObserver implements ObserverInterface { - /** @var Payment $adyenPaymentResourceModel */ - private $adyenPaymentResourceModel; - - /** @var PaymentFactory */ - private $adyenOrderPaymentFactory; - - /** @var InvoiceHelper $invoiceHelper*/ - private $invoiceHelper; - - /** @var StatusResolver $statusResolver */ - private $statusResolver; - - /** @var AdyenOrderPayment $adyenOrderPaymentHelper */ - private $adyenOrderPaymentHelper; - - /** @var Config $configHelper */ - private $configHelper; - - /** @var PaymentMethods $paymentMethodsHelper */ - private $paymentMethodsHelper; - - /** @var OrderHelper */ - private $orderHelper; - /** - * @var AdyenLogger + * @param InvoiceHelper $invoiceHelper + * @param StatusResolver $statusResolver + * @param AdyenOrderPayment $adyenOrderPaymentHelper + * @param AdyenLogger $logger + * @param PaymentMethods $paymentMethodsHelper + * @param AdyenOrderPaymentRepositoryInterface $adyenOrderPaymentRepository */ - private $logger; - public function __construct( - Payment $adyenPaymentResourceModel, - PaymentFactory $adyenOrderPaymentFactory, - InvoiceHelper $invoiceHelper, - StatusResolver $statusResolver, - AdyenOrderPayment $adyenOrderPaymentHelper, - Config $configHelper, - AdyenLogger $adyenLogger, - PaymentMethods $paymentMethodsHelper, - OrderHelper $orderHelper - ) { - $this->adyenPaymentResourceModel = $adyenPaymentResourceModel; - $this->adyenOrderPaymentFactory = $adyenOrderPaymentFactory; - $this->invoiceHelper = $invoiceHelper; - $this->statusResolver = $statusResolver; - $this->adyenOrderPaymentHelper = $adyenOrderPaymentHelper; - $this->configHelper = $configHelper; - $this->logger = $adyenLogger; - $this->paymentMethodsHelper = $paymentMethodsHelper; - $this->orderHelper = $orderHelper; - } + private readonly InvoiceHelper $invoiceHelper, + private readonly StatusResolver $statusResolver, + private readonly AdyenOrderPayment $adyenOrderPaymentHelper, + private readonly AdyenLogger $logger, + private readonly PaymentMethods $paymentMethodsHelper, + private readonly AdyenOrderPaymentRepositoryInterface $adyenOrderPaymentRepository + ) { } /** * Link all adyen_invoices to the appropriate magento invoice and set the order to PROCESSING to allow @@ -87,10 +50,8 @@ public function __construct( * @param Observer $observer * @throws AlreadyExistsException */ - public function execute(Observer $observer) + public function execute(Observer $observer): void { - $adyenOrderPaymentFactory = $this->adyenOrderPaymentFactory->create(); - /** @var Invoice $invoice */ $invoice = $observer->getData('invoice'); $order = $invoice->getOrder(); @@ -107,15 +68,14 @@ public function execute(Observer $observer) array_merge($this->logger->getInvoiceContext($invoice), $this->logger->getOrderContext($order)) ); - $adyenOrderPayments = $this->adyenPaymentResourceModel->getLinkedAdyenOrderPayments( + $adyenOrderPayments = $this->adyenOrderPaymentRepository->getByPaymentId( $payment->getEntityId(), [OrderPaymentInterface::CAPTURE_STATUS_NO_CAPTURE, OrderPaymentInterface::CAPTURE_STATUS_PARTIAL_CAPTURE] ); + foreach ($adyenOrderPayments as $adyenOrderPayment) { - /** @var \Adyen\Payment\Model\Order\Payment $adyenOrderPaymentObject */ - $adyenOrderPaymentObject = $adyenOrderPaymentFactory->load($adyenOrderPayment[OrderPaymentInterface::ENTITY_ID], OrderPaymentInterface::ENTITY_ID); - $linkedAmount = $this->invoiceHelper->linkAndUpdateAdyenInvoices($adyenOrderPaymentObject, $invoice); - $this->adyenOrderPaymentHelper->updatePaymentTotalCaptured($adyenOrderPaymentObject, $linkedAmount); + $linkedAmount = $this->invoiceHelper->linkAndUpdateAdyenInvoices($adyenOrderPayment, $invoice); + $this->adyenOrderPaymentHelper->updatePaymentTotalCaptured($adyenOrderPayment, $linkedAmount); } $status = $this->statusResolver->getOrderStatusByState($order, Order::STATE_PAYMENT_REVIEW); diff --git a/Test/Unit/Helper/CreditmemoTest.php b/Test/Unit/Helper/CreditmemoTest.php index 0d75f5acc0..acae388362 100644 --- a/Test/Unit/Helper/CreditmemoTest.php +++ b/Test/Unit/Helper/CreditmemoTest.php @@ -12,6 +12,7 @@ namespace Adyen\Payment\Test\Unit\Helper; use Adyen\Payment\Api\Data\OrderPaymentInterface; +use Adyen\Payment\Api\Repository\AdyenCreditmemoRepositoryInterface; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Creditmemo; use Adyen\Payment\Model\CreditmemoFactory; @@ -191,7 +192,8 @@ protected function createCreditmemoHelper( $adyenDataHelper = null, $adyenCreditmemoFactory = null, $adyenCreditmemoResourceModel = null, - $orderPaymentResourceModel = null + $orderPaymentResourceModel = null, + $adyenCreditmemoRepositoryMock = null ): Creditmemo { if (is_null($context)) { @@ -216,12 +218,19 @@ protected function createCreditmemoHelper( $orderPaymentResourceModel = $this->createMock(Payment::class); } + if (is_null($adyenCreditmemoRepositoryMock)) { + $adyenCreditmemoRepositoryMock = $this->createMock( + AdyenCreditmemoRepositoryInterface::class + ); + } + return new Creditmemo( $context, $adyenDataHelper, $adyenCreditmemoFactory, $adyenCreditmemoResourceModel, - $orderPaymentResourceModel + $orderPaymentResourceModel, + $adyenCreditmemoRepositoryMock ); } } diff --git a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php index b3b67ab28c..ac52b43715 100644 --- a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php @@ -73,13 +73,13 @@ private function createCaptureWebhookHandler( } return new CaptureWebhookHandler( - invoiceHelper: $invoiceHelper, - adyenOrderPaymentFactory: $adyenOrderPaymentFactory, - adyenOrderPaymentHelper: $adyenOrderPaymentHelper, - adyenLogger: $adyenLogger, - orderHelper: $orderHelper, - paymentMethodsHelper: $paymentMethodsHelper, - invoiceRepository: $invoiceRepository + $invoiceHelper, + $adyenOrderPaymentHelper, + $adyenLogger, + $orderHelper, + $paymentMethodsHelper, + $invoiceRepository, + $adyenOrderPaymentFactory ); } diff --git a/etc/di.xml b/etc/di.xml index 019e6db119..758f3421e8 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -1701,6 +1701,10 @@ + + From ab2c6ff6156a0b1369329f681e3f859fecb6b464 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 21 Jan 2025 09:31:45 +0100 Subject: [PATCH 30/34] [ECP-9489] Update unit tests --- Helper/Creditmemo.php | 18 +++--- Test/Unit/Helper/OrderTest.php | 110 ++++++++++++++++----------------- 2 files changed, 61 insertions(+), 67 deletions(-) diff --git a/Helper/Creditmemo.php b/Helper/Creditmemo.php index 34a52c735f..162cdfb425 100644 --- a/Helper/Creditmemo.php +++ b/Helper/Creditmemo.php @@ -16,7 +16,7 @@ use Adyen\Payment\Model\Order\Payment; use Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo as CreditMemoResourceModel; use Adyen\Payment\Model\CreditmemoFactory; -use Adyen\Payment\Model\Creditmemo as AdyenCreditmemoModel; +use Adyen\Payment\Api\Data\CreditmemoInterface as AdyenCreditmemoInterface; use Adyen\Payment\Model\ResourceModel\Order\Payment as OrderPaymentResourceModel; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Sales\Model\Order; @@ -57,14 +57,14 @@ public function __construct( * @param string $pspReference * @param string $originalReference * @param float $refundAmount - * @return AdyenCreditmemoModel + * @return AdyenCreditmemoInterface */ public function createAdyenCreditMemo( Order\Payment $payment, string $pspReference, string $originalReference, float $refundAmount - ): AdyenCreditmemoModel { + ): AdyenCreditmemoInterface { // get adyen_order_payment record /** @var OrderPaymentInterface $adyenOrderPayment */ $adyenOrderPayment = $this->orderPaymentResourceModel->getOrderPaymentDetails( @@ -73,7 +73,7 @@ public function createAdyenCreditMemo( ); // create adyen_credit_memo record - /** @var AdyenCreditmemoModel $adyenCreditmemo */ + /** @var AdyenCreditmemoInterface $adyenCreditmemo */ $adyenCreditmemo = $this->adyenCreditmemoFactory->create(); $adyenCreditmemo->setPspreference($pspReference); $adyenCreditmemo->setOriginalReference($originalReference); @@ -81,7 +81,7 @@ public function createAdyenCreditMemo( $adyenOrderPayment[OrderPaymentInterface::ENTITY_ID] ); $adyenCreditmemo->setAmount($refundAmount); - $adyenCreditmemo->setStatus(AdyenCreditmemoModel::WAITING_FOR_WEBHOOK_STATUS); + $adyenCreditmemo->setStatus(AdyenCreditmemoInterface::WAITING_FOR_WEBHOOK_STATUS); $this->adyenCreditmemoRepository->save($adyenCreditmemo); @@ -116,11 +116,11 @@ public function linkAndUpdateAdyenCreditmemos( } /** - * @param AdyenCreditmemoModel $adyenCreditmemo + * @param AdyenCreditmemoInterface $adyenCreditmemo * @param string $status * @return void */ - public function updateAdyenCreditmemosStatus(AdyenCreditmemoModel $adyenCreditmemo, string $status) + public function updateAdyenCreditmemosStatus(AdyenCreditmemoInterface $adyenCreditmemo, string $status) { $adyenCreditmemo->setStatus($status); $this->adyenCreditmemoRepository->save($adyenCreditmemo); @@ -130,10 +130,10 @@ public function updateAdyenCreditmemosStatus(AdyenCreditmemoModel $adyenCreditme * @deprecated Use AdyenCreditmemoRepositoryInterface::getByRefundWebhook() instead. * * @param string $pspreference - * @return AdyenCreditmemoModel|null + * @return AdyenCreditmemoInterface|null * @throws NoSuchEntityException */ - public function getAdyenCreditmemoByPspreference(string $pspreference): ?AdyenCreditmemoModel { + public function getAdyenCreditmemoByPspreference(string $pspreference): ?AdyenCreditmemoInterface { $results = $this->adyenCreditmemoResourceModel->getAdyenCreditmemoByPspreference($pspreference); if (is_null($results)) { diff --git a/Test/Unit/Helper/OrderTest.php b/Test/Unit/Helper/OrderTest.php index 35527dca30..54f0685f7d 100644 --- a/Test/Unit/Helper/OrderTest.php +++ b/Test/Unit/Helper/OrderTest.php @@ -11,6 +11,8 @@ namespace Adyen\Payment\Test\Unit\Helper; +use Adyen\Payment\Api\Data\NotificationInterface; +use Adyen\Payment\Api\Repository\AdyenCreditmemoRepositoryInterface; use Adyen\Payment\Helper\AdyenOrderPayment; use Adyen\Payment\Helper\ChargedCurrency; use Adyen\Payment\Helper\Config; @@ -19,10 +21,8 @@ use Adyen\Payment\Helper\Order; use Adyen\Payment\Helper\PaymentMethods; use Adyen\Payment\Model\AdyenAmountCurrency; -use Adyen\Payment\Model\Config\Source\Status\AdyenState; -use Adyen\Payment\Model\Creditmemo as AdyenCreditmemoModel; +use Adyen\Payment\Api\Data\CreditmemoInterface; use Adyen\Payment\Model\Notification; -use Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo as AdyenCreditMemoResourceModel; use Adyen\Payment\Model\ResourceModel\Order\Payment\CollectionFactory as OrderPaymentCollectionFactory; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; @@ -33,15 +33,16 @@ use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Model\Order as MagentoOrder; use Magento\Sales\Model\Order\Email\Sender\OrderSender; +use Magento\Sales\Model\Order\Payment; +use Magento\Sales\Model\Order\Payment\Transaction; use Magento\Sales\Model\Order\Payment\Transaction\Builder; +use Magento\Sales\Model\Order\Shipment; use Magento\Sales\Model\OrderRepository; use Magento\Sales\Model\ResourceModel\Order\Status\CollectionFactory as OrderStatusCollectionFactory; use Magento\Sales\Api\Data\TransactionInterface; class OrderTest extends AbstractAdyenTestCase { - protected $adyenCreditmemoHelperMock; - public function testFinalizeOrderFinalized() { $dataHelper = $this->createConfiguredMock(Data::class, ['formatAmount' => 'EUR123']); @@ -170,7 +171,7 @@ public function testHoldCancelOrderNotConfigurableToCancel() $this->arrayHasKey('pspReference') ); - $paymentMock = $this->createMock(\Magento\Sales\Model\Order\Payment::class); + $paymentMock = $this->createMock(Payment::class); $paymentMock->method('getData')->willReturnMap([ ['adyen_psp_reference', null, 'test_psp_reference'], ['entity_id', null, 'test_entity_id'] @@ -206,13 +207,13 @@ public function testRefundOrderSuccessful() $adyenOrderPaymentHelper->expects($this->once())->method('refundAdyenOrderPayment'); $adyenCreditmemoHelper = $this->createMock(AdyenCreditmemoHelper::class); - $adyenCreditMemo = $this->createMock(AdyenCreditmemoModel::class); + $adyenCreditMemo = $this->createMock(CreditmemoInterface::class); $adyenCreditmemoHelper->expects($this->once()) ->method('createAdyenCreditMemo') ->willReturn($adyenCreditMemo); $adyenCreditmemoHelper->expects($this->once()) ->method('updateAdyenCreditmemosStatus') - ->with($adyenCreditMemo, AdyenCreditmemoModel::COMPLETED_STATUS); + ->with($adyenCreditMemo, CreditmemoInterface::COMPLETED_STATUS); $orderHelper = $this->createOrderHelper( null, @@ -229,17 +230,16 @@ public function testRefundOrderSuccessful() null, null, null, - null, $adyenCreditmemoHelper ); - $orderPaymentReturnMock = $this->createConfiguredMock(MagentoOrder\Payment::class, [ + $orderPaymentReturnMock = $this->createConfiguredMock(Payment::class, [ 'getCreditmemo' => $this->createMock(MagentoOrder\Creditmemo::class) ]); - $orderPaymentMock = $this->createConfiguredMock(MagentoOrder\Payment::class, [ + $orderPaymentMock = $this->createConfiguredMock(Payment::class, [ 'registerRefundNotification' => $orderPaymentReturnMock ]); - $orderConfigMock = $this->createConfiguredMock(\Magento\Sales\Model\Order\Config::class, [ + $orderConfigMock = $this->createConfiguredMock(MagentoOrder\Config::class, [ 'getStateDefaultStatus' => MagentoOrder::STATE_CLOSED ]); $order = $this->createConfiguredMock(MagentoOrder::class, [ @@ -255,27 +255,25 @@ public function testRefundOrderSuccessful() public function testRefundFailedNotice() { $notification = $this->createMock(Notification::class); - $notification->method('getPspreference')->willReturn('123'); + $notification->expects($this->exactly(2)) + ->method('getPspreference') + ->willReturn('123'); + $adyenCreditmemoHelper = $this->createMock(AdyenCreditmemoHelper::class); - $adyenCreditMemo = $this->createMock(AdyenCreditmemoModel::class); + $adyenCreditMemo = $this->createMock(CreditmemoInterface::class); - $adyenCreditmemoHelper->expects($this->once()) - ->method('getAdyenCreditmemoByPspreference') + $adyenCreditmemoRepositoryMock = $this->createMock(AdyenCreditmemoRepositoryInterface::class); + $adyenCreditmemoRepositoryMock->expects($this->once()) + ->method('getByRefundWebhook') + ->with($notification) ->willReturn($adyenCreditMemo); $adyenCreditmemoHelper->expects($this->once()) ->method('updateAdyenCreditmemosStatus') - ->with($adyenCreditMemo, AdyenCreditmemoModel::FAILED_STATUS); + ->with($adyenCreditMemo, CreditmemoInterface::FAILED_STATUS); + + $orderMock = $this->createMock(MagentoOrder::class); - $orderPaymentReturnMock = $this->createConfiguredMock(MagentoOrder\Payment::class, [ - 'getCreditmemo' => $this->createMock(MagentoOrder\Creditmemo::class) - ]); - $orderPaymentMock = $this->createConfiguredMock(MagentoOrder\Payment::class, [ - 'registerRefundNotification' => $orderPaymentReturnMock - ]); - $orderConfigMock = $this->createConfiguredMock(\Magento\Sales\Model\Order\Config::class, [ - 'getStateDefaultStatus' => MagentoOrder::STATE_CLOSED - ]); $orderHelper = $this->createOrderHelper( null, null, @@ -291,16 +289,13 @@ public function testRefundFailedNotice() null, null, null, + $adyenCreditmemoHelper, null, - $adyenCreditmemoHelper + $adyenCreditmemoRepositoryMock ); - $order = $this->createConfiguredMock(MagentoOrder::class, [ - 'getPayment' => $orderPaymentMock, - 'getConfig' => $orderConfigMock, - 'canCreditmemo' => true - ]); - $orderHelper->addRefundFailedNotice($order, $notification); + $result = $orderHelper->addRefundFailedNotice($orderMock, $notification); + $this->assertInstanceOf(NotificationInterface::class, $result); } public function testUpdatePaymentDetailsWithOrderInitiallyInStatePaymentReview() @@ -309,18 +304,18 @@ public function testUpdatePaymentDetailsWithOrderInitiallyInStatePaymentReview() $notificationMock = $this->createMock(Notification::class); $notificationMock->method('getPspreference')->willReturn($pspReference); - $paymentMock = $this->createMock(MagentoOrder\Payment::class); + $paymentMock = $this->createMock(Payment::class); $paymentMock->expects($this->once())->method('setCcTransId')->with($pspReference); $paymentMock->expects($this->once())->method('setLastTransId')->with($pspReference); $paymentMock->expects($this->once())->method('setTransactionId')->with($pspReference); $orderMock = $this->createConfiguredMock(MagentoOrder::class, [ 'getPayment' => $paymentMock, - 'getState' => \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW, - 'setState' => \Magento\Sales\Model\Order::STATE_NEW + 'getState' => MagentoOrder::STATE_PAYMENT_REVIEW, + 'setState' => MagentoOrder::STATE_NEW ]); - $transactionMock = $this->createMock(\Magento\Sales\Model\Order\Payment\Transaction::class); + $transactionMock = $this->createMock(Transaction::class); $transactionMock->expects($this->once())->method('setIsClosed')->with(false); $transactionMock->expects($this->once())->method('save'); @@ -342,21 +337,21 @@ public function testUpdatePaymentDetailsWithOrderInitiallyInStatePaymentReview() $result = $orderHelper->updatePaymentDetails($orderMock, $notificationMock); - $this->assertInstanceOf(\Magento\Sales\Model\Order\Payment\Transaction::class, $result); + $this->assertInstanceOf(Transaction::class, $result); } public function testUpdatePaymentDetailsWithOrderNotInStatePaymentReview() { $pspReference = '123456789'; - $paymentMock = $this->createConfiguredMock(MagentoOrder\Payment::class, [ + $paymentMock = $this->createConfiguredMock(Payment::class, [ 'setCcTransId' => $pspReference, 'setLastTransId' => $pspReference, 'setTransactionId' => $pspReference ]); $orderMock = $this->createConfiguredMock(MagentoOrder::class, [ 'getPayment' => $paymentMock, - 'getState' => \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW, - 'setState' => \Magento\Sales\Model\Order::STATE_NEW + 'getState' => MagentoOrder::STATE_PAYMENT_REVIEW, + 'setState' => MagentoOrder::STATE_NEW ]); $notificationMock = $this->createConfiguredMock(Notification::class, [ @@ -364,7 +359,7 @@ public function testUpdatePaymentDetailsWithOrderNotInStatePaymentReview() ]); $transactionBuilderMock = $this->createMock(Builder::class); - $transactionMock = $this->createMock(\Magento\Sales\Model\Order\Payment\Transaction::class); + $transactionMock = $this->createMock(Transaction::class); $transactionBuilderMock->expects($this->once()) ->method('setPayment') ->with($paymentMock) @@ -446,7 +441,7 @@ public function testSendOrderMailSuccess() $orderMock = $this->createMock(MagentoOrder::class); $adyenLoggerMock = $this->createMock(AdyenLogger::class); $orderSenderMock = $this->createMock(OrderSender::class); - $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class) + $paymentMock = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() ->getMock(); @@ -491,7 +486,7 @@ public function testCreateShipmentSuccess() { $adyenLoggerMock = $this->createMock(AdyenLogger::class); $orderMock = $this->createMock(MagentoOrder::class); - $shipmentMock = $this->createPartialMock(\Magento\Sales\Model\Order\Shipment::class, ['register', 'getOrder', 'addComment']); + $shipmentMock = $this->createPartialMock(Shipment::class, ['register', 'getOrder', 'addComment']); $shipmentMock->method('getOrder')->willReturn($orderMock); $transactionBuilderMock = $this->createMock(Builder::class); @@ -519,7 +514,7 @@ public function testCreateShipmentCannotShip() $adyenLoggerMock = $this->createMock(AdyenLogger::class); $orderMock = $this->createMock(MagentoOrder::class); $transactionBuilderMock = $this->createMock(Builder::class); - $paymentMock = $this->createMock(\Magento\Sales\Model\Order\Payment::class); + $paymentMock = $this->createMock(Payment::class); $paymentMock->method('getData') ->willReturnMap([ ['adyen_psp_reference', null, 'test_psp_reference'], @@ -569,7 +564,7 @@ public function testSetPrePaymentAuthorized() [$this->stringContains('Order status is changed to Pre-authorised status')] ); - $paymentMock = $this->createMock(\Magento\Sales\Model\Order\Payment::class); + $paymentMock = $this->createMock(Payment::class); $paymentMock->method('getData')->willReturnMap([ ['adyen_psp_reference', null, 'test_psp_reference'], ['entity_id', null, 'test_entity_id'] @@ -615,7 +610,7 @@ public function testSetPrePaymentAuthorizedNoStatus() $this->arrayHasKey('pspReference') ); - $paymentMock = $this->createMock(\Magento\Sales\Model\Order\Payment::class); + $paymentMock = $this->createMock(Payment::class); $paymentMock->method('getData')->willReturnMap([ ['adyen_psp_reference', null, 'test_psp_reference'], ['entity_id', null, 'test_entity_id'] @@ -645,7 +640,7 @@ public function testSetStatusOrderCreation() $storeId = 1; $assignedStatusForStateNew = 'pending'; - $paymentMock = $this->createMock(MagentoOrder\Payment::class); + $paymentMock = $this->createMock(Payment::class); $paymentMock->method('getMethod')->willReturn($paymentMethodCode); $orderMock = $this->createMock(OrderInterface::class); @@ -654,7 +649,7 @@ public function testSetStatusOrderCreation() $configHelper = $this->createMock(Config::class); $configHelper->method('getConfigData')->with('order_status', $paymentMethodCode, $storeId) - ->willReturn(\Magento\Sales\Model\Order::STATE_NEW); + ->willReturn(MagentoOrder::STATE_NEW); $statusResolverMock = $this->createMock(MagentoOrder\StatusResolver::class); $statusResolverMock->method('getOrderStatusByState')->willReturn($assignedStatusForStateNew); @@ -675,7 +670,6 @@ public function testSetStatusOrderCreation() null, null, null, - null, $statusResolverMock ); @@ -699,9 +693,9 @@ protected function createOrderHelper( $orderRepository = null, $notifierPool = null, $paymentMethodsHelper = null, - $adyenCreditmemoResourceModel = null, $adyenCreditmemoHelper = null, - $statusResolver = null + $statusResolver = null, + $adyenCreditmemoRepositoryMock = null, ): Order { $context = $this->createMock(Context::class); @@ -762,10 +756,6 @@ protected function createOrderHelper( $paymentMethodsHelper = $this->createMock(PaymentMethods::class); } - if (is_null($adyenCreditmemoResourceModel)) { - $adyenCreditmemoResourceModel = $this->createMock(AdyenCreditMemoResourceModel::class); - } - if (is_null($adyenCreditmemoHelper)) { $adyenCreditmemoHelper = $this->createMock(AdyenCreditmemoHelper::class); } @@ -774,6 +764,10 @@ protected function createOrderHelper( $statusResolver = $this->createMock(MagentoOrder\StatusResolver::class); } + if (is_null($adyenCreditmemoRepositoryMock)) { + $adyenCreditmemoRepositoryMock = $this->createMock(AdyenCreditmemoRepositoryInterface::class); + } + return new Order( $context, $builder, @@ -790,9 +784,9 @@ protected function createOrderHelper( $notifierPool, $orderPaymentCollectionFactory, $paymentMethodsHelper, - $adyenCreditmemoResourceModel, $adyenCreditmemoHelper, - $statusResolver + $statusResolver, + $adyenCreditmemoRepositoryMock ); } } From 85b5b9a3c059e1cd07bb63c6b97b0825bd7cff3f Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 21 Jan 2025 11:14:34 +0100 Subject: [PATCH 31/34] [ECP-9489] Update unit tests --- Model/Api/AdyenDonations.php | 28 ++- Test/Unit/Model/Api/AdyenDonationsTest.php | 243 +++++++++++++++++++-- 2 files changed, 239 insertions(+), 32 deletions(-) diff --git a/Model/Api/AdyenDonations.php b/Model/Api/AdyenDonations.php index 8c21aa9144..99e0cdb9e8 100644 --- a/Model/Api/AdyenDonations.php +++ b/Model/Api/AdyenDonations.php @@ -12,6 +12,7 @@ namespace Adyen\Payment\Model\Api; +use Adyen\AdyenException; use Adyen\Payment\Api\AdyenDonationsInterface; use Adyen\Payment\Helper\ChargedCurrency; use Adyen\Payment\Helper\Config; @@ -70,12 +71,20 @@ public function donate(int $orderId, string $payload): void $this->makeDonation($payload, $order); } + /** + * @param string $payload + * @param OrderInterface $order + * @return void + * @throws AdyenException + * @throws LocalizedException + */ public function makeDonation(string $payload, OrderInterface $order): void { $payload = $this->jsonSerializer->unserialize($payload); - $paymentMethodInstance = $order->getPayment()->getMethodInstance(); - $donationToken = $order->getPayment()->getAdditionalInformation('donationToken'); + $payment = $order->getPayment(); + $paymentMethodInstance = $payment->getMethodInstance(); + $donationToken = $payment->getAdditionalInformation('donationToken'); if (!$donationToken) { throw new LocalizedException(__('Donation failed!')); @@ -99,10 +108,10 @@ function ($amount) use ($formatter, $currencyCode) { } $payload['donationToken'] = $donationToken; - $payload['donationOriginalPspReference'] = $order->getPayment()->getAdditionalInformation('pspReference'); + $payload['donationOriginalPspReference'] = $payment->getAdditionalInformation('pspReference'); // Override payment method object with payment method code - if ($order->getPayment()->getMethod() === AdyenCcConfigProvider::CODE) { + if ($payment->getMethod() === AdyenCcConfigProvider::CODE) { $payload['paymentMethod'] = 'scheme'; } elseif ($this->paymentMethodsHelper->isAlternativePaymentMethod($paymentMethodInstance)) { $payload['paymentMethod'] = $this->paymentMethodsHelper->getAlternativePaymentMethodTxVariant( @@ -128,7 +137,7 @@ function ($amount) use ($formatter, $currencyCode) { $this->removeDonationToken($order); } catch (LocalizedException $e) { - $this->donationTryCount = $order->getPayment()->getAdditionalInformation('donationTryCount'); + $this->donationTryCount = $payment->getAdditionalInformation('donationTryCount'); if ($this->donationTryCount >= 5) { // Remove donation token after 5 try and throw a exception. @@ -142,12 +151,14 @@ function ($amount) use ($formatter, $currencyCode) { private function incrementTryCount(Order $order): void { + $payment = $order->getPayment(); + if (!$this->donationTryCount) { - $order->getPayment()->setAdditionalInformation('donationTryCount', 1); + $payment->setAdditionalInformation('donationTryCount', 1); } else { $this->donationTryCount += 1; - $order->getPayment()->setAdditionalInformation('donationTryCount', $this->donationTryCount); + $payment->setAdditionalInformation('donationTryCount', $this->donationTryCount); } $this->orderRepository->save($order); @@ -155,7 +166,8 @@ private function incrementTryCount(Order $order): void private function removeDonationToken(Order $order): void { - $order->getPayment()->unsAdditionalInformation('donationToken'); + $payment = $order->getPayment(); + $payment->unsAdditionalInformation('donationToken'); $this->orderRepository->save($order); } } diff --git a/Test/Unit/Model/Api/AdyenDonationsTest.php b/Test/Unit/Model/Api/AdyenDonationsTest.php index a019fe3a40..b87d37b091 100644 --- a/Test/Unit/Model/Api/AdyenDonationsTest.php +++ b/Test/Unit/Model/Api/AdyenDonationsTest.php @@ -3,7 +3,7 @@ * * Adyen Payment module (https://www.adyen.com/) * - * Copyright (c) 2023 Adyen N.V. (https://www.adyen.com/) + * Copyright (c) 2025 Adyen N.V. (https://www.adyen.com/) * See LICENSE.txt for license details. * * Author: Adyen @@ -11,47 +11,242 @@ namespace Adyen\Payment\Test\Unit\Model\Api; +use Adyen\AdyenException; use Adyen\Payment\Helper\ChargedCurrency; use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\PaymentMethods; +use Adyen\Payment\Model\AdyenAmountCurrency; use Adyen\Payment\Model\Api\AdyenDonations; use Adyen\Payment\Model\Sales\OrderRepository; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Framework\Serialize\Serializer\Json; use Magento\Payment\Gateway\Command\CommandPoolInterface; -use Magento\Sales\Api\Data\OrderInterface; +use Magento\Payment\Gateway\CommandInterface; +use Magento\Payment\Model\MethodInterface; +use Magento\Sales\Model\Order; +use PHPUnit\Framework\MockObject\MockObject; +use Magento\Framework\Serialize\Serializer\Json; class AdyenDonationsTest extends AbstractAdyenTestCase { + private ?AdyenDonations $adyenDonations; + private CommandPoolInterface|MockObject $commandPoolMock; + private Json|MockObject $jsonMock; + private Data|MockObject $dataMock; + private Config|MockObject $configMock; + private ChargedCurrency|MockObject $chargedCurrencyMock; + private PaymentMethods|MockObject $paymentMethodsMock; + private OrderRepository|MockObject $orderRepositoryMock; + + protected function setUp(): void + { + $this->commandPoolMock = $this->createMock(CommandPoolInterface::class); + $this->jsonMock = $this->createPartialMock(Json::class, []); + $this->dataMock = $this->createPartialMock(Data::class, []); + $this->chargedCurrencyMock = $this->createMock(ChargedCurrency::class); + $this->configMock = $this->createMock(Config::class); + $this->paymentMethodsMock = $this->createPartialMock(PaymentMethods::class, []); + $this->orderRepositoryMock = $this->createMock(OrderRepository::class); + + $this->adyenDonations = new AdyenDonations( + $this->commandPoolMock, + $this->jsonMock, + $this->dataMock, + $this->chargedCurrencyMock, + $this->configMock, + $this->paymentMethodsMock, + $this->orderRepositoryMock + ); + } + + protected function tearDown(): void + { + $this->adyenDonations = null; + } + + private static function paymentMethodDataProvider(): array + { + return [ + [ + 'paymentMethod' => 'adyen_cc', + 'paymentMethodGroup' => 'adyen', + 'customerId' => 1, + 'executeSuccess' => true, + 'donationTryCount' => 0 + ], + [ + 'paymentMethod' => 'adyen_ideal', + 'paymentMethodGroup' => 'adyen-alternative-payment-method', + 'customerId' => null, + 'executeSuccess' => true, + 'donationTryCount' => 0 + ], + [ + 'paymentMethod' => 'adyen_cc', + 'paymentMethodGroup' => 'adyen', + 'customerId' => null, + 'executeSuccess' => false, + 'donationTryCount' => 0 + ], + [ + 'paymentMethod' => 'adyen_cc', + 'paymentMethodGroup' => 'adyen', + 'customerId' => null, + 'executeSuccess' => false, + 'donationTryCount' => 5 + ], + ]; + } + /** - * @throws NoSuchEntityException - * @throws LocalizedException + * @dataProvider paymentMethodDataProvider + * @param $paymentMethod + * @param $paymentMethodGroup + * @param $customerId + * @param $executeSuccess + * @param $donationTryCount + * @return void * @throws InputException + * @throws LocalizedException + * @throws NoSuchEntityException */ - public function testDonate() + public function testDonate($paymentMethod, $paymentMethodGroup, $customerId, $executeSuccess, $donationTryCount) { - $orderRepositoryMock = $this->createPartialMock(OrderRepository::class, ['get']); - $orderRepositoryMock->expects(self::atLeastOnce()) + $orderId = 1; + $payload = '{"amount":{"value":1000,"currency":"EUR"}}'; + $donationTokenMock = 'mock_token_abcde'; + $orderCurrency = 'EUR'; + $storeId = 1; + $donationAmounts = '1,5,10'; + $pspReference = 'xyz_12345'; + $orderIncrementId = '00000000001'; + + $paymentMethodInstanceMock = $this->createMock(MethodInterface::class); + $paymentMethodInstanceMock->method('getConfigData') + ->with('group') + ->willReturn($paymentMethodGroup); + + $paymentMock = $this->createMock(Order\Payment::class); + $paymentMock->expects($this->once()) + ->method('getMethodInstance') + ->willReturn($paymentMethodInstanceMock); + $paymentMock->expects($this->once()) + ->method('getMethod') + ->willReturn($paymentMethod); + $paymentMock->method('getAdditionalInformation') + ->willReturnMap([ + ['donationToken', $donationTokenMock], + ['pspReference', $pspReference], + ['donationTryCount', $donationTryCount] + ]); + + $orderMock = $this->createMock(Order::class); + $orderMock->method('getPayment')->willReturn($paymentMock); + $orderMock->method('getStoreId')->willReturn($storeId); + $orderMock->method('getCustomerId')->willReturn($customerId); + $orderMock->method('getIncrementId')->willReturn($orderIncrementId); + + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->with($orderId) + ->willReturn($orderMock); + $this->orderRepositoryMock->method('save')->with($orderMock); + + $orderAmountCurrencyMock = $this->createMock(AdyenAmountCurrency::class); + $orderAmountCurrencyMock->method('getCurrencyCode')->willReturn($orderCurrency); + + $this->chargedCurrencyMock->expects($this->once()) + ->method('getOrderAmountCurrency') + ->with($orderMock, false) + ->willReturn($orderAmountCurrencyMock); + + $this->configMock->expects($this->once()) + ->method('getAdyenGivingDonationAmounts') + ->with($storeId) + ->willReturn($donationAmounts); + + $donationCommand = $this->createMock(CommandInterface::class); + + if ($executeSuccess) { + $paymentMock->expects($this->once()) + ->method('unsAdditionalInformation') + ->with('donationToken'); + + $donationCommand->expects($this->once())->method('execute'); + } else { + $this->expectException(LocalizedException::class); + + $donationCommand->method('execute')->willThrowException( + new LocalizedException(__('exception')) + ); + } + + $this->commandPoolMock->expects($this->once()) ->method('get') - ->willReturn($this->createMock(OrderInterface::class)); - - $adyenDonationsMock = $this->getMockBuilder(AdyenDonations::class) - ->setMethods(['makeDonation']) - ->setConstructorArgs([ - $this->createMock(CommandPoolInterface::class), - $this->createMock(Json::class), - $this->createMock(Data::class), - $this->createMock(ChargedCurrency::class), - $this->createMock(Config::class), - $this->createMock(PaymentMethods::class), - $orderRepositoryMock - ]) - ->getMock(); - - $adyenDonationsMock->donate(1, ''); + ->with('capture') + ->willReturn($donationCommand); + + $this->adyenDonations->donate($orderId, $payload); + } + + /** + * @return void + * @throws LocalizedException + * @throws AdyenException + */ + public function testNullDonationToken() + { + $this->expectException(LocalizedException::class); + + $payload = '{"amount":{"value":1000,"currency":"EUR"}}'; + $donationTokenMock = null; + + $paymentMock = $this->createMock(Order\Payment::class); + $paymentMock->method('getAdditionalInformation') + ->willReturnMap([ + ['donationToken', $donationTokenMock] + ]); + + $orderMock = $this->createMock(Order::class); + $orderMock->expects($this->once())->method('getPayment')->willReturn($paymentMock); + + // Assert LocalizedException + $this->adyenDonations->makeDonation($payload, $orderMock); + } + + /** + * @return void + * @throws AdyenException + * @throws LocalizedException + */ + public function testCurrencyMismatch() + { + $this->expectException(LocalizedException::class); + + $payload = '{"amount":{"value":1000,"currency":"EUR"}}'; + $donationTokenMock = 'mock_token_abcde'; + $orderCurrency = 'TRY'; + + $paymentMock = $this->createMock(Order\Payment::class); + $paymentMock->method('getAdditionalInformation') + ->willReturnMap([ + ['donationToken', $donationTokenMock] + ]); + $orderMock = $this->createMock(Order::class); + $orderMock->expects($this->once())->method('getPayment')->willReturn($paymentMock); + + $orderAmountCurrencyMock = $this->createMock(AdyenAmountCurrency::class); + $orderAmountCurrencyMock->method('getCurrencyCode')->willReturn($orderCurrency); + + $this->chargedCurrencyMock->expects($this->once()) + ->method('getOrderAmountCurrency') + ->with($orderMock, false) + ->willReturn($orderAmountCurrencyMock); + + // Assert LocalizedException + $this->adyenDonations->makeDonation($payload, $orderMock); } } From 13aed2dfbebcee61de5a085e6930481e61ba50de Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 21 Jan 2025 11:49:51 +0100 Subject: [PATCH 32/34] [ECP-9489] Update unit tests --- Test/Unit/Helper/CreditmemoTest.php | 84 ++++++------------- .../Webhook/CaptureWebhookHandlerTest.php | 81 ++++++++---------- 2 files changed, 64 insertions(+), 101 deletions(-) diff --git a/Test/Unit/Helper/CreditmemoTest.php b/Test/Unit/Helper/CreditmemoTest.php index acae388362..950023efe1 100644 --- a/Test/Unit/Helper/CreditmemoTest.php +++ b/Test/Unit/Helper/CreditmemoTest.php @@ -11,6 +11,7 @@ namespace Adyen\Payment\Test\Unit\Helper; +use Adyen\Payment\Api\Data\CreditmemoInterface; use Adyen\Payment\Api\Data\OrderPaymentInterface; use Adyen\Payment\Api\Repository\AdyenCreditmemoRepositoryInterface; use Adyen\Payment\Helper\Data; @@ -46,23 +47,24 @@ public function testCreateAdyenCreditMemo() $adyenCreditmemoFactoryMock = $this->createGeneratedMock(CreditmemoFactory::class, ['create']); $adyenCreditmemoFactoryMock->method('create')->willReturn($adyenCreditmemoMock); - $adyenCreditmemoResourceModel = $this->createMock( - \Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo::class - ); + $adyenCreditmemoRepositoryMock = $this->createMock(AdyenCreditmemoRepositoryInterface::class); + $adyenCreditmemoRepositoryMock->expects($this->once()) + ->method('save') + ->with($adyenCreditmemoMock); $creditmemoHelper = $this->createCreditmemoHelper( null, null, $adyenCreditmemoFactoryMock, - $adyenCreditmemoResourceModel, - $orderPaymentResourceModel + null, + $orderPaymentResourceModel, + $adyenCreditmemoRepositoryMock ); $adyenCreditmemoMock->expects($this->once())->method('setPspreference')->with($pspReference); $adyenCreditmemoMock->expects($this->once())->method('setOriginalReference')->with($originalReference); $adyenCreditmemoMock->expects($this->once())->method('setAdyenPaymentOrderId')->with($adyenOrderPaymentId); $adyenCreditmemoMock->expects($this->once())->method('setAmount')->with($refundAmount); - $adyenCreditmemoResourceModel->expects($this->once())->method('save')->with($adyenCreditmemoMock); $result = $creditmemoHelper->createAdyenCreditMemo( $paymentMock, @@ -84,67 +86,35 @@ public function testLinkAndUpdateAdyenCreditmemos() ] ); - $adyenCreditmemos = [ - [ - 'entity_id' => 1, - 'creditmemo_id' => 00001, - 'adyen_payment_order_id' => 5 - ], - [ - 'entity_id' => 2, - 'creditmemo_id' => 00002, - 'adyen_payment_order_id' => 5 - ] - ]; - - $adyenCreditmemoResourceModelMock = $this->createConfiguredMock( - \Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo::class, - [ - 'getAdyenCreditmemosByAdyenPaymentid' => $adyenCreditmemos, - 'save' => $this->createPartialMock( - \Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo::class, - ['save'] - ) - ] - ); - - $adyenCreditmemoResourceModelMock->expects($this->atLeastOnce()) - ->method('save') - ->willReturn(true); - - $magentoCreditmemoMock = $this->createConfiguredMock(\Magento\Sales\Model\Order\Creditmemo::class, [ - 'getEntityId' => $magentoCreditmemoId + $adyenCreditmemoMock = $this->createConfiguredMock(CreditmemoInterface::class, [ + 'getAmount' => 10.00 ]); + $adyenCreditmemoMock->expects($this->once())->method('setCreditmemoId')->with($magentoCreditmemoId); + $adyenCreditmemoMock->expects($this->once())->method('setCreditmemoId')->with($magentoCreditmemoId); - $adyenCreditmemoMock = $this->createMock(\Adyen\Payment\Model\Creditmemo::class); + $adyenCreditmemos[] = $adyenCreditmemoMock; - $adyenCreditmemoLoaderMock = $this->getMockBuilder(\Adyen\Payment\Model\Creditmemo::class) - ->disableOriginalConstructor() - ->getMock(); - - $adyenCreditmemoLoaderMock->method('load')->willReturn($adyenCreditmemoMock); - - $adyenCreditmemoFactoryMock = $this->createGeneratedMock(CreditmemoFactory::class, ['create']); - $adyenCreditmemoFactoryMock->method('create')->willReturn($adyenCreditmemoLoaderMock); - - $adyenCreditmemoResourceModelMock->expects($this->once()) - ->method('getAdyenCreditmemosByAdyenPaymentid') + $adyenCreditmemoRepositoryMock = $this->createMock(AdyenCreditmemoRepositoryInterface::class); + $adyenCreditmemoRepositoryMock->expects($this->once()) + ->method('getByAdyenOrderPaymentId') ->with($adyenOrderPaymentId) ->willReturn($adyenCreditmemos); + $adyenCreditmemoRepositoryMock->expects($this->once()) + ->method('save') + ->with($adyenCreditmemoMock); - foreach ($adyenCreditmemos as $adyenCreditmemo) { - $currAdyenCreditmemoMock = $this->createPartialMock(AbstractModel::class, []); - $currAdyenCreditmemoMock->setData($adyenCreditmemo); - $currAdyenCreditmemoMock->setEntityId($magentoCreditmemoMock->getEntityId()); - $currAdyenCreditmemoMock->setCreditmemoId($magentoCreditmemoMock->getEntityId()); - $adyenCreditmemoResourceModelMock->save($currAdyenCreditmemoMock); - } + $magentoCreditmemoMock = $this->createConfiguredMock(\Magento\Sales\Model\Order\Creditmemo::class, [ + 'getEntityId' => $magentoCreditmemoId, + 'getGrandTotal' => 10.00 + ]); $creditmemoHelper = $this->createCreditmemoHelper( null, null, - $adyenCreditmemoFactoryMock, - $adyenCreditmemoResourceModelMock + null, + null, + null, + $adyenCreditmemoRepositoryMock ); $creditmemoHelper->linkAndUpdateAdyenCreditmemos($adyenOrderPaymentMock, $magentoCreditmemoMock); diff --git a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php index ac52b43715..675d3bd6e6 100644 --- a/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php +++ b/Test/Unit/Helper/Webhook/CaptureWebhookHandlerTest.php @@ -1,29 +1,27 @@ createMockWithMethods(Invoice::class, ['handleCaptureWebhook'], []); } - if($adyenOrderPaymentFactory == null) { - $adyenOrderPaymentFactory = $this->createGeneratedMock(PaymentFactory::class, ['create', 'load']); - } - if($adyenOrderPaymentHelper == null) { + if ($adyenOrderPaymentHelper == null) { $adyenOrderPaymentHelper = $this->createMockWithMethods(AdyenOrderPayment::class, ['refreshPaymentCaptureStatus'], []); } - if($adyenLogger == null) { + if ($adyenLogger == null) { $adyenLogger = $this->createGeneratedMock(AdyenLogger::class, ['addAdyenNotification', 'getInvoiceContext']); } - if($orderHelper == null) { + if ($orderHelper == null) { $orderHelper = $this->createGeneratedMock(Order::class, ['fetchOrderByIncrementId', 'finalizeOrder']); } - if($paymentMethodsHelper == null) { + if ($paymentMethodsHelper == null) { $paymentMethodsHelper = $this->createGeneratedMock(PaymentMethods::class); } - if($invoiceRepository == null) { + if ($invoiceRepository == null) { $invoiceRepository = $this->createGeneratedMock(InvoiceRepositoryInterface::class); } + if ($adyenOrderPaymentRepositoryMock == null) { + $adyenOrderPaymentRepositoryMock = $this->createGeneratedMock(AdyenOrderPaymentRepositoryInterface::class); + } return new CaptureWebhookHandler( $invoiceHelper, @@ -79,25 +77,23 @@ private function createCaptureWebhookHandler( $orderHelper, $paymentMethodsHelper, $invoiceRepository, - $adyenOrderPaymentFactory + $adyenOrderPaymentRepositoryMock ); } public function testHandleWebhookWithAutoCapture() { - // Set up a partial mock for the Invoice class to expect no calls to handleCaptureWebhook - $invoiceHelperMock = $this->createMockWithMethods(Invoice::class, ['handleCaptureWebhook'], []); - $invoiceHelperMock->expects($this->never())->method('handleCaptureWebhook'); - - // Mock the paymentMethodsHelper to return false for isAutoCapture - $paymentMethodsHelperMock = $this->createMockWithMethods(PaymentMethods::class, ['isAutoCapture'], []); + // Mock the paymentMethodsHelper to return true for isAutoCapture + $paymentMethodsHelperMock = $this->createMock(PaymentMethods::class); $paymentMethodsHelperMock->method('isAutoCapture')->willReturn(true); + $adyenLoggerMock = $this->createMock(AdyenLogger::class); + $adyenLoggerMock->expects($this->once())->method('addAdyenNotification'); + $this->captureWebhookHandler = $this->createCaptureWebhookHandler( null, null, - null, - null, + $adyenLoggerMock, null, $paymentMethodsHelperMock ); @@ -111,8 +107,14 @@ public function testHandleWebhookWithAutoCapture() public function testHandleWebhookWithoutAutoCapture() { + $adyenOrderPaymentId = 123; + $invoiceId = 456; + // Mock methods - $adyenInvoice = $this->createConfiguredMock(AdyenInvoice::class, ['getAdyenPaymentOrderId' => 123, 'getInvoiceId' => 456]); + $adyenInvoice = $this->createConfiguredMock( + AdyenInvoice::class, + ['getAdyenPaymentOrderId' => $adyenOrderPaymentId, 'getInvoiceId' => $invoiceId] + ); $magentoInvoice = $this->createMock(MagentoOrder\Invoice::class); $magentoInvoiceRepositoryMock = $this->createMock(InvoiceRepositoryInterface::class); @@ -134,22 +136,13 @@ public function testHandleWebhookWithoutAutoCapture() ->with($this->order, $this->notification) ->willReturn($this->order); - // Mock the adyenOrderPaymentFactory - $adyenOrderPaymentFactoryMock = $this->createGeneratedMock(PaymentFactory::class, ['create']); - - $adyenOrderPaymentMock = $this->getMockBuilder(Payment::class) - ->setMethods(['load']) // Define the method you want to mock - ->disableOriginalConstructor() - ->getMock(); - - $adyenOrderPaymentMock->expects($this->once()) - ->method('load') - ->with(123, OrderPaymentInterface::ENTITY_ID) - ->willReturnSelf(); // Return the mock itself + $adyenOrderPaymentMock = $this->createMock(Payment::class); - // Set up expectations for the create and load methods - $adyenOrderPaymentFactoryMock->expects($this->once()) - ->method('create') + $adyenOrderPaymentRepositoryMock = + $this->createMock(AdyenOrderPaymentRepositoryInterface::class); + $adyenOrderPaymentRepositoryMock->expects($this->once()) + ->method('get') + ->with($adyenOrderPaymentId) ->willReturn($adyenOrderPaymentMock); $adyenOrderPaymentHelperMock = $this->createMock(AdyenOrderPayment::class); @@ -160,12 +153,12 @@ public function testHandleWebhookWithoutAutoCapture() $this->captureWebhookHandler = $this->createCaptureWebhookHandler( $invoiceHelperMock, - $adyenOrderPaymentFactoryMock, $adyenOrderPaymentHelperMock, null, $orderHelperMock, $paymentMethodsHelperMock, - $magentoInvoiceRepositoryMock + $magentoInvoiceRepositoryMock, + $adyenOrderPaymentRepositoryMock ); // Test handleWebhook method From ad675add1929c8a5754fdcfe14242b3db7b5c4e2 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 21 Jan 2025 14:05:34 +0100 Subject: [PATCH 33/34] [ECP-9489] Update unit tests --- Model/AdyenCreditmemoRepository.php | 4 +- .../Model/AdyenCreditmemoRepositoryTest.php | 262 ++++++++++++++++++ 2 files changed, 264 insertions(+), 2 deletions(-) create mode 100644 Test/Unit/Model/AdyenCreditmemoRepositoryTest.php diff --git a/Model/AdyenCreditmemoRepository.php b/Model/AdyenCreditmemoRepository.php index c924d593ab..09d2ee4071 100644 --- a/Model/AdyenCreditmemoRepository.php +++ b/Model/AdyenCreditmemoRepository.php @@ -52,7 +52,7 @@ public function __construct( public function get(int $entityId): CreditmemoInterface { $entity = $this->adyenCreditmemoFactory->create(); - $this->resourceModel->load($entity, $entity, 'entity_id'); + $this->resourceModel->load($entity, $entityId, CreditmemoInterface::ENTITY_ID); return $entity; } @@ -116,7 +116,7 @@ public function getByRefundWebhook(NotificationInterface $notification): ?Credit return null; } else { $entity = $this->adyenCreditmemoFactory->create(); - $this->resourceModel->load($entity, $entityId, 'entity_id'); + $this->resourceModel->load($entity, $entityId, CreditmemoInterface::ENTITY_ID); return $entity; } diff --git a/Test/Unit/Model/AdyenCreditmemoRepositoryTest.php b/Test/Unit/Model/AdyenCreditmemoRepositoryTest.php new file mode 100644 index 0000000000..2c1ea60ace --- /dev/null +++ b/Test/Unit/Model/AdyenCreditmemoRepositoryTest.php @@ -0,0 +1,262 @@ + + */ + +use Adyen\AdyenException; +use Adyen\Payment\Api\Data\CreditmemoInterface; +use Adyen\Payment\Api\Data\NotificationInterface; +use Adyen\Payment\Model\AdyenCreditmemoRepository; +use Adyen\Payment\Model\Creditmemo; +use Adyen\Payment\Model\ResourceModel\Creditmemo\Collection as CreditmemoCollection; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Adyen\Payment\Model\CreditmemoFactory; +use Adyen\Payment\Model\ResourceModel\Creditmemo\CollectionFactory; +use Adyen\Payment\Model\ResourceModel\Creditmemo\Creditmemo as CreditmemoResourceModel; +use Magento\Framework\Api\Search\SearchResultFactory; +use Magento\Framework\Api\Search\SearchResultInterface; +use Magento\Framework\Api\SearchCriteria\CollectionProcessor; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\Api\SearchResultsInterface; +use Magento\Framework\Exception\AlreadyExistsException; +use Magento\Framework\Exception\LocalizedException; +use PHPUnit\Framework\MockObject\MockObject; + +class AdyenCreditmemoRepositoryTest extends AbstractAdyenTestCase +{ + private ?AdyenCreditmemoRepository $adyenCreditmemoRepository; + private CreditmemoFactory|MockObject $creditmemoFactoryMock; + private CreditmemoResourceModel|MockObject $creditmemoResourceModelMock; + private SearchResultFactory|MockObject $searchResultFactoryMock; + private CollectionFactory|MockObject $collectionFactoryMock; + private CollectionProcessor|MockObject $collectionProcessorMock; + private SearchCriteriaBuilder|MockObject $searchCriteriaBuilderMock; + + /** + * @return void + */ + protected function setUp(): void + { + $this->creditmemoFactoryMock = $this->createGeneratedMock(CreditmemoFactory::class, [ + 'create' + ]); + $this->creditmemoResourceModelMock = $this->createMock(CreditmemoResourceModel::class); + $this->searchResultFactoryMock = $this->createMock(SearchResultFactory::class); + $this->collectionFactoryMock = $this->createGeneratedMock(CollectionFactory::class, [ + 'create' + ]); + $this->collectionProcessorMock = $this->createMock(CollectionProcessor::class); + $this->searchCriteriaBuilderMock = $this->createMock(SearchCriteriaBuilder::class); + + $this->adyenCreditmemoRepository = new AdyenCreditmemoRepository( + $this->creditmemoFactoryMock, + $this->creditmemoResourceModelMock, + $this->searchResultFactoryMock, + $this->collectionFactoryMock, + $this->collectionProcessorMock, + $this->searchCriteriaBuilderMock + ); + } + + /** + * @return void + */ + protected function tearDown(): void + { + $this->adyenCreditmemoRepository = null; + } + + /** + * @return void + */ + public function testGet() + { + $entityId = 1; + $creditmemo = $this->createMock(Creditmemo::class); + + $this->creditmemoFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($creditmemo); + + $this->creditmemoResourceModelMock->expects($this->once()) + ->method('load') + ->with($creditmemo, $entityId, CreditmemoInterface::ENTITY_ID) + ->willReturnSelf(); + + $result = $this->adyenCreditmemoRepository->get($entityId); + $this->assertInstanceOf(CreditmemoInterface::class, $result); + } + + /** + * @return void + */ + public function testGetList() + { + $searchResultMock = $this->createPartialMock(SearchResultInterface::class, []); + $this->searchResultFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($searchResultMock); + + $collectionMock = $this->createMock(CreditmemoCollection::class); + $collectionResult[] = $this->createMock(Creditmemo::class); + $collectionMock->method('getItems')->willReturn($collectionResult); + $collectionMock->method('getSize')->willReturn(count($collectionResult)); + $this->collectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($collectionMock); + + $searchCriteriaMock = $this->createMock(SearchCriteriaInterface::class); + + $this->collectionProcessorMock->expects($this->once()) + ->method('process') + ->with($searchCriteriaMock, $collectionMock); + + $searchResultMock->expects($this->once()) + ->method('setItems') + ->with($collectionResult); + $searchResultMock->expects($this->once()) + ->method('setTotalCount') + ->with(count($collectionResult)); + + $result = $this->adyenCreditmemoRepository->getList($searchCriteriaMock); + + $this->assertInstanceOf(SearchResultsInterface::class, $result); + } + + /** + * @return void + */ + public function testGetByAdyenOrderPaymentId() + { + $adyenOrderPaymentId = 1; + + $searchCriteriaMock = $this->createMock(SearchCriteriaInterface::class); + $this->searchCriteriaBuilderMock->expects($this->once()) + ->method('addFilter') + ->with(CreditmemoInterface::ADYEN_ORDER_PAYMENT_ID, $adyenOrderPaymentId) + ->willReturnSelf(); + + $this->searchCriteriaBuilderMock->expects($this->once()) + ->method('create') + ->willReturn($searchCriteriaMock); + + $collectionResult[] = $this->createMock(Creditmemo::class); + + $searchResultMock = $this->createMock(SearchResultInterface::class); + $searchResultMock->expects($this->once()) + ->method('getItems') + ->willReturn($collectionResult); + + $this->searchResultFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($searchResultMock); + + $collectionMock = $this->createMock(CreditmemoCollection::class); + $this->collectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($collectionMock); + + $result = $this->adyenCreditmemoRepository->getByAdyenOrderPaymentId($adyenOrderPaymentId); + $this->assertIsArray($result); + } + + /** + * @return void + * @throws AlreadyExistsException + */ + public function testSave() + { + $creditmemo = $this->createMock(Creditmemo::class); + + $this->creditmemoResourceModelMock->expects($this->once()) + ->method('save') + ->with($creditmemo) + ->willReturnSelf(); + + $result = $this->adyenCreditmemoRepository->save($creditmemo); + $this->assertInstanceOf(CreditmemoInterface::class, $result); + } + + /** + * @return array[] + */ + private static function webhookTestDataProvider(): array + { + return [ + [ + 'eventCode' => 'REFUND', + 'isExpectedType' => true, + 'creditmemoId' => "1", + 'isResultValid' => true + ], + [ + 'eventCode' => 'CAPTURE', + 'isExpectedType' => false, + 'creditmemoId' => "1", + 'isResultValid' => true + ], + [ + 'eventCode' => 'REFUND', + 'isExpectedType' => true, + 'creditmemoId' => "", + 'isResultValid' => false + ] + ]; + } + + /** + * @dataProvider webhookTestDataProvider + * + * @param $eventCode + * @param $isExpectedType + * @param $creditmemoId + * @param $isResultValid + * @return void + * @throws AdyenException + * @throws LocalizedException + */ + public function testGetByRefundWebhook($eventCode, $isExpectedType, $creditmemoId, $isResultValid) + { + $notificationPspreference = 'xyz_12345'; + + $notification = $this->createMock(NotificationInterface::class); + $notification->method('getEventCode')->willReturn($eventCode); + $notification->method('getPspreference')->willReturn($notificationPspreference); + + if (!$isExpectedType) { + $this->expectException(AdyenException::class); + + // No result required, assert exception + $this->adyenCreditmemoRepository->getByRefundWebhook($notification); + } else { + $this->creditmemoResourceModelMock->expects($this->once()) + ->method('getIdByPspreference') + ->with($notificationPspreference) + ->willReturn($creditmemoId); + + if ($isResultValid) { + $creditmemo = $this->createMock(Creditmemo::class); + $this->creditmemoFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($creditmemo); + + $this->creditmemoResourceModelMock->expects($this->once()) + ->method('load') + ->with($creditmemo, $creditmemoId, CreditmemoInterface::ENTITY_ID) + ->willReturnSelf(); + + $result = $this->adyenCreditmemoRepository->getByRefundWebhook($notification); + $this->assertInstanceOf(CreditmemoInterface::class, $result); + } else { + $this->assertNull($this->adyenCreditmemoRepository->getByRefundWebhook($notification)); + } + } + } +} From dbfe65920f73b82c058f19fff3b0712e3a724342 Mon Sep 17 00:00:00 2001 From: Can Demiralp Date: Tue, 21 Jan 2025 14:08:45 +0100 Subject: [PATCH 34/34] [ECP-9489] Update unit tests --- Test/Unit/Model/AdyenCreditmemoRepositoryTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Test/Unit/Model/AdyenCreditmemoRepositoryTest.php b/Test/Unit/Model/AdyenCreditmemoRepositoryTest.php index 2c1ea60ace..376359c6eb 100644 --- a/Test/Unit/Model/AdyenCreditmemoRepositoryTest.php +++ b/Test/Unit/Model/AdyenCreditmemoRepositoryTest.php @@ -9,6 +9,8 @@ * Author: Adyen */ +namespace Adyen\Payment\Test\Helper\Unit\Model; + use Adyen\AdyenException; use Adyen\Payment\Api\Data\CreditmemoInterface; use Adyen\Payment\Api\Data\NotificationInterface;