From 8f096fa84a8d5d589c8908d95f09aeefc391c604 Mon Sep 17 00:00:00 2001 From: hossam-adyen <132500300+hossam-adyen@users.noreply.github.com> Date: Wed, 24 Jul 2024 14:50:32 +0200 Subject: [PATCH] [ECP-8715] Update to model based PHP Library (#2456) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [ECP-8715] Update to model based PHP Library * Update adyen/php-api-library to ^17.0.0 * fix: Notification model `getUpdatedAt` method uses `created_at` date instead of `updated_at` (#2417) Co-authored-by: Peter Ojo * Fix 301 Return value while running command console (#2396) * [FIX] Fix 301 Return value while running command console * Add Magento\Framework\Console\Cli constants since deprecated Symfony\Component\Console\Command\Command --------- Co-authored-by: Rok Popov Ledinski Co-authored-by: Can Demiralp Co-authored-by: hossam-adyen <132500300+hossam-adyen@users.noreply.github.com> * Update dependency squizlabs/php_codesniffer to ~3.8.0 (#2426) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: hossam-adyen <132500300+hossam-adyen@users.noreply.github.com> * [ECP-8893] Allow usage of storedPaymentMethodId on headless payment requests (#2431) * [ECP-8893] Allow usage of storedPaymentMethodId in the request * [ECP-8893] Write unit tests * [ECP-8825] Enable pipeline runs for external contributions (#2451) * Add e2e flow for external contributors * Add dispatch for debugging * Tweak workflow name * Tweak workflow * Debug * Remove draft pipeline * Update e2e test pipeline * Update GraphQL test pipeline * Update Main CI workflow * Update RestAPI test workflow * DEBUG - Add test pipeline * Add authorization step * DEBUG - Test auth step * Define an internal environment * DEBUG - Try removing auth step and switch to conditional * Remove trial pipeline * Add designated worklfow for debugging * Embed authorize step in build and add conditional * Remove debug pipeline * [ECP-8890] Update class references (#2441) * [ECP-8878] Add pspReference to additional_information (#2443) * [ECP-8787] Handle Pending resultCode on multishipping (#2448) * [ECP-8822] Update management webhook endpoint (#2440) * Support model based for gitcards payments and refactor * Support model based for TransactionCancel and refactor * Support model based for TransactionRefund and refactor * Support model based for TransactionCapture * Support model based for TransactionDonate * Support model based for TransactionPaymentLinks * Support model based for PaymentRequest * Update Return controller * Update OrdersApi * Update PaymentsDetails helper * Remove createAdyenCheckoutService and deprecated checkout service * Use UtilityApi * Use model based for diffrent places * Use Adyen\Service\Management APIs * Fix unit tests * Fix unit tests * Fix conflict getMerchantAccountsAndClientKey * Fix all unit tests * entirely parse models to array * Fix TypeError: Adyen\Service\Checkout\OrdersApi::getBalanceOfGiftCard(): Argument #1 ($balanceCheckRequest) must be of type Adyen\Model\Checkout\BalanceCheckRequest, array given * use query params to pass page size and pagenumber * Fix new unit tests * Add AdyenPaymentMethodsBalanceTest * update DataTest new tests * Sonarcloud check fixes * Add MerchantAccountsTest * Add more tests for ManagementHelperTest * update TransactionPaymentTest * Add TransactionCaptureTest * Add TransactionCancelTest * Update DataTest * Add WebhookTestTest && AutoConfigurationTest * Add more code coverage * Add more code coverage in DataTest.php * mark createAdyenRecurringService & createAdyenCheckoutService as deprecated * Update ManagementHelper.php * Small refactor * unit test fixes * CS * Update PaymentDetailsTest.php * [ECP-8715] Fix PaymentsDetails class after merge conflict * [ECP-8715] Fix unit tests after merge conflict * [ECP-8715] Fix unit tests after merge conflict * [ECP-8715] Fix redundant line * FixPaymentDetails * [ECP-8715] Add type declarations * [ECP-8715] Fix test webhook url builder * [ECP-8715] Add type declarations * [ECP-8715] Formatting * [ECP-8715] Format the response array * [ECP-8715] Format the response array and add type declarations * [ECP-8715] Fix amount issue on second partial payment and declare types * [ECP-8715] Add type declarations and use toArray() method * [ECP-8715] Add type declarations and use toArray() method * [ECP-8715] Formatting * [ECP-8715] Use toArray() method * [ECP-8715] Use toArray() method and add type declarations * [ECP-8715] Use toArray() method and add type declarations remove unused exception * [ECP-8715] Use toArray() method and add type declarations * [ECP-8715] Use toArray() method and add type declarations * [ECP-8715] Fx return value, use toArray() method and add type declarations * [ECP-8715] Use toArray() method and add type declarations * [ECP-8715] Use toArray() method and add type declarations * [ECP-8715] Add type declarations * [ECP-8715] Use toArray() method and add type declarations * [ECP-8715] Fix Capture unit tests * [ECP-8715] Fix mixed unit tests * [ECP-8715] Fix Data helper unit tests --------- Co-authored-by: Paweł Ledwig <48790035+pawel-ledwig@users.noreply.github.com> Co-authored-by: Peter Ojo Co-authored-by: Tuyen Nguyen Co-authored-by: Rok Popov Ledinski Co-authored-by: Can Demiralp Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Cenk Kucukiravul Co-authored-by: Can Demiralp --- .../Configuration/MerchantAccounts.php | 47 ++- .../Adminhtml/Configuration/WebhookTest.php | 26 +- Gateway/Http/Client/TransactionCancel.php | 51 +++- Gateway/Http/Client/TransactionCapture.php | 91 ++++-- Gateway/Http/Client/TransactionDonate.php | 31 +- Gateway/Http/Client/TransactionPayment.php | 125 ++++++-- .../Http/Client/TransactionPaymentLinks.php | 27 +- Gateway/Http/Client/TransactionRefund.php | 47 ++- Helper/Data.php | 56 +++- Helper/ManagementHelper.php | 174 +++++++----- Helper/OrdersApi.php | 27 +- Helper/PaymentMethods.php | 252 +++++++++++++++- Helper/PaymentsDetails.php | 32 ++- Model/Api/AdyenPaymentMethodsBalance.php | 43 ++- Model/Api/PaymentRequest.php | 41 ++- Model/Config/Adminhtml/WebhookTest.php | 2 +- Model/Config/Backend/AutoConfiguration.php | 60 +++- Model/Config/Backend/WebhookCredentials.php | 34 ++- Plugin/PaymentVaultDeleteToken.php | 38 ++- .../Configuration/MerchantAccountsTest.php | 64 +++++ .../Configuration/WebhookTestTest.php | 78 +++++ .../Http/Client/TransactionCancelTest.php | 137 +++++++++ .../Http/Client/TransactionCaptureTest.php | 61 ++-- .../Http/Client/TransactionPaymentTest.php | 95 ++++++- .../Http/Client/TransactionRefundTest.php | 21 +- Test/Unit/Helper/DataTest.php | 170 ++++++++++- Test/Unit/Helper/ManagementHelperTest.php | 268 +++++++++++++++--- Test/Unit/Helper/PaymentDetailsTest.php | 24 +- Test/Unit/Helper/PaymentMethodsTest.php | 60 +--- Test/Unit/Helper/PaymentRequestTest.php | 26 +- .../Api/AdyenPaymentMethodsBalanceTest.php | 100 +++++++ .../Config/Backend/AutoConfigurationTest.php | 64 +++++ .../Plugin/PaymentVaultDeleteTokenTest.php | 10 +- 33 files changed, 1950 insertions(+), 432 deletions(-) create mode 100644 Test/Unit/Controller/Adminhtml/Configuration/MerchantAccountsTest.php create mode 100644 Test/Unit/Controller/Adminhtml/Configuration/WebhookTestTest.php create mode 100644 Test/Unit/Gateway/Http/Client/TransactionCancelTest.php create mode 100644 Test/Unit/Model/Api/AdyenPaymentMethodsBalanceTest.php create mode 100644 Test/Unit/Model/Config/Backend/AutoConfigurationTest.php diff --git a/Controller/Adminhtml/Configuration/MerchantAccounts.php b/Controller/Adminhtml/Configuration/MerchantAccounts.php index 2fbad6021..3279f89ab 100644 --- a/Controller/Adminhtml/Configuration/MerchantAccounts.php +++ b/Controller/Adminhtml/Configuration/MerchantAccounts.php @@ -1,23 +1,10 @@ */ @@ -28,21 +15,28 @@ use Adyen\ConnectionException; use Adyen\Payment\Helper\ManagementHelper; use Magento\Backend\App\Action; +use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; use Magento\Backend\App\Action\Context; +use Magento\Framework\Exception\NoSuchEntityException; class MerchantAccounts extends Action { /** * @var ManagementHelper */ - protected $managementHelper; + protected ManagementHelper $managementHelper; /** * @var JsonFactory */ - protected $resultJsonFactory; + protected JsonFactory $resultJsonFactory; + /** + * @param Context $context + * @param ManagementHelper $managementHelper + * @param JsonFactory $resultJsonFactory + */ public function __construct( Context $context, ManagementHelper $managementHelper, @@ -54,21 +48,27 @@ public function __construct( } /** - * @return \Magento\Framework\Controller\Result\Json + * @return Json + * @throws NoSuchEntityException */ - public function execute() + public function execute(): Json { $resultJson = $this->resultJsonFactory->create(); try { $apiKey = $this->getRequest()->getParam('apiKey', ''); $demoMode = (int) $this->getRequest()->getParam('demoMode'); - //Use the stored xapi key if the return value is encrypted chars only or it is empty, + // Use the stored xapi key if the return value is encrypted chars only or it is empty, if (!empty($apiKey) && preg_match('/^\*+$/', (string) $apiKey)) { $apiKey = ''; } - $managementApiService = $this->managementHelper->getManagementApiService($apiKey, $demoMode); - $response = $this->managementHelper->getMerchantAccountsAndClientKey($managementApiService); + $client = $this->managementHelper->getAdyenApiClient($apiKey, $demoMode); + $accountMerchantLevelApi = $this->managementHelper->getAccountMerchantLevelApi($client); + $myAPICredentialApi = $this->managementHelper->getMyAPICredentialApi($client); + $response = $this->managementHelper->getMerchantAccountsAndClientKey( + $accountMerchantLevelApi, + $myAPICredentialApi + ); $resultJson->setData($response); return $resultJson; @@ -83,4 +83,3 @@ public function execute() return $resultJson; } } - diff --git a/Controller/Adminhtml/Configuration/WebhookTest.php b/Controller/Adminhtml/Configuration/WebhookTest.php index 65861d2ff..10cacd93e 100644 --- a/Controller/Adminhtml/Configuration/WebhookTest.php +++ b/Controller/Adminhtml/Configuration/WebhookTest.php @@ -16,10 +16,8 @@ use Adyen\Payment\Helper\ManagementHelper; use Magento\Backend\App\Action; use Magento\Backend\App\Action\Context; -use Magento\Framework\App\ResponseInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; -use Magento\Framework\Controller\ResultInterface; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Store\Model\StoreManager; @@ -28,27 +26,27 @@ class WebhookTest extends Action /** * @var ManagementHelper */ - private $managementApiHelper; + private ManagementHelper $managementApiHelper; /** * @var Config */ - protected $configHelper; + protected Config $configHelper; /** * @var JsonFactory */ - protected $resultJsonFactory; + protected JsonFactory $resultJsonFactory; /** * @var Context */ - protected $context; + protected Context $context; /** * @var StoreManager */ - protected $storeManager; + protected StoreManager $storeManager; /** * @param Context $context @@ -73,11 +71,11 @@ public function __construct( } /** - * @return ResponseInterface|Json|ResultInterface + * @return Json * @throws AdyenException * @throws NoSuchEntityException */ - public function execute() + public function execute(): Json { $storeId = $this->storeManager->getStore()->getId(); @@ -87,11 +85,11 @@ public function execute() $environment = $isDemoMode ? 'test' : 'live'; $apiKey = $this->configHelper->getApiKey($environment, $storeId); - $managementApiService = $this->managementApiHelper->getManagementApiService($apiKey, $isDemoMode); - $response = $this->managementApiHelper->webhookTest($merchantAccount, $webhookId, $managementApiService); - - $success = isset($response['data']) && - in_array('success', array_column($response['data'], 'status'), true); + $client = $this->managementApiHelper->getAdyenApiClient($apiKey, $isDemoMode); + $service =$this->managementApiHelper->getWebhooksMerchantLevelApi($client); + $response = $this->managementApiHelper->webhookTest($merchantAccount, $webhookId, $service); + $success = isset($response) && + in_array('success', array_column($response->getData(), 'status'), true); $resultJson = $this->resultJsonFactory->create(); $resultJson->setData([ diff --git a/Gateway/Http/Client/TransactionCancel.php b/Gateway/Http/Client/TransactionCancel.php index 49ae63440..7c14aa40f 100644 --- a/Gateway/Http/Client/TransactionCancel.php +++ b/Gateway/Http/Client/TransactionCancel.php @@ -13,16 +13,29 @@ use Adyen\AdyenException; use Adyen\Client; +use Adyen\Model\Checkout\PaymentCancelRequest; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Idempotency; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Payment\Gateway\Http\ClientInterface; use Magento\Payment\Gateway\Http\TransferInterface; class TransactionCancel implements ClientInterface { + /** + * @var Data + */ private Data $adyenHelper; + + /** + * @var Idempotency + */ private Idempotency $idempotencyHelper; + /** + * @param Data $adyenHelper + * @param Idempotency $idempotencyHelper + */ public function __construct( Data $adyenHelper, Idempotency $idempotencyHelper @@ -31,34 +44,46 @@ public function __construct( $this->idempotencyHelper = $idempotencyHelper; } + /** + * @param TransferInterface $transferObject + * @return array + * @throws AdyenException + * @throws NoSuchEntityException + */ public function placeRequest(TransferInterface $transferObject): array { - $request = $transferObject->getBody(); + $requests = $transferObject->getBody(); $headers = $transferObject->getHeaders(); $clientConfig = $transferObject->getClientConfig(); + $client = $this->adyenHelper->initializeAdyenClientWithClientConfig($clientConfig); - $service = $this->adyenHelper->createAdyenCheckoutService($client); - $response = []; + $service = $this->adyenHelper->initializeModificationsApi($client); + $responseData = []; - foreach ($request as $requests) { + foreach ($requests as $request) { $idempotencyKey = $this->idempotencyHelper->generateIdempotencyKey( - $requests, + $request, $headers['idempotencyExtraData'] ?? null ); $requestOptions['idempotencyKey'] = $idempotencyKey; $requestOptions['headers'] = $this->adyenHelper->buildRequestHeaders(); - $this->adyenHelper->logRequest($requests, Client::API_CHECKOUT_VERSION, '/cancels'); + $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, '/cancels'); + $paymentCancelRequest = new PaymentCancelRequest($request); + try { - $responses = $service->cancels($requests, $requestOptions); + $response = $service->cancelAuthorisedPaymentByPspReference( + $request['paymentPspReference'], + $paymentCancelRequest, + $requestOptions + ); + $responseData = $response->toArray(); + $this->adyenHelper->logResponse($responseData); } catch (AdyenException $e) { - $response['error'] = $e->getMessage(); + $responseData['error'] = $e->getMessage(); + $this->adyenHelper->logAdyenException($e); } - $this->adyenHelper->logResponse($responses); - - $response = $responses; } - return $response; + return $responseData; } - } diff --git a/Gateway/Http/Client/TransactionCapture.php b/Gateway/Http/Client/TransactionCapture.php index ea1f7c2b5..9b14bb200 100644 --- a/Gateway/Http/Client/TransactionCapture.php +++ b/Gateway/Http/Client/TransactionCapture.php @@ -13,11 +13,14 @@ use Adyen\AdyenException; use Adyen\Client; +use Adyen\Model\Checkout\PaymentCaptureRequest; use Adyen\Payment\Api\Data\OrderPaymentInterface; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Idempotency; use Adyen\Payment\Helper\Requests; use Adyen\Payment\Logger\AdyenLogger; +use Adyen\Service\Checkout\ModificationsApi; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Payment\Gateway\Http\ClientInterface; use Magento\Payment\Gateway\Http\TransferInterface; @@ -29,10 +32,26 @@ class TransactionCapture implements ClientInterface const ORIGINAL_REFERENCE = 'paymentPspReference'; const CAPTURE_RECEIVED = 'received'; + /** + * @var Data + */ private Data $adyenHelper; + + /** + * @var AdyenLogger + */ private AdyenLogger $adyenLogger; + + /** + * @var Idempotency + */ private Idempotency $idempotencyHelper; + /** + * @param Data $adyenHelper + * @param AdyenLogger $adyenLogger + * @param Idempotency $idempotencyHelper + */ public function __construct( Data $adyenHelper, AdyenLogger $adyenLogger, @@ -43,42 +62,66 @@ public function __construct( $this->idempotencyHelper = $idempotencyHelper; } + /** + * @param TransferInterface $transferObject + * @return array + * @throws AdyenException + * @throws NoSuchEntityException + */ public function placeRequest(TransferInterface $transferObject): array { $request = $transferObject->getBody(); $headers = $transferObject->getHeaders(); $clientConfig = $transferObject->getClientConfig(); + $client = $this->adyenHelper->initializeAdyenClientWithClientConfig($clientConfig); - $service = $this->adyenHelper->createAdyenCheckoutService($client); + $service = $this->adyenHelper->initializeModificationsApi($client); $requestOptions['headers'] = $this->adyenHelper->buildRequestHeaders(); if (array_key_exists(self::MULTIPLE_AUTHORIZATIONS, $request)) { return $this->placeMultipleCaptureRequests($service, $request, $requestOptions); } - else { - $idempotencyKey = $this->idempotencyHelper->generateIdempotencyKey( - $request, - $headers['idempotencyExtraData'] ?? null - ); - $requestOptions['idempotencyKey'] = $idempotencyKey; - } + + $idempotencyKey = $this->idempotencyHelper->generateIdempotencyKey( + $request, + $headers['idempotencyExtraData'] ?? null + ); + $requestOptions['idempotencyKey'] = $idempotencyKey; $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, '/captures'); + $paymentCaptureRequest = new PaymentCaptureRequest($request); + $responseData = []; try { - $response = $service->captures($request, $requestOptions); - $response = $this->copyParamsToResponse($response, $request); + $response = $service->captureAuthorisedPayment( + $request['paymentPspReference'], + $paymentCaptureRequest, + $requestOptions + ); + + $responseData = $response->toArray(); + $responseData = $this->copyParamsToResponse($responseData, $request); + $this->adyenHelper->logResponse($responseData); } catch (AdyenException $e) { - $response['error'] = $e->getMessage(); + $this->adyenHelper->logAdyenException($e); + $responseData['error'] = $e->getMessage(); } - $this->adyenHelper->logResponse($response); - return $response; + return $responseData; } - private function placeMultipleCaptureRequests($service, $requestContainer, $requestOptions): array - { + /** + * @param ModificationsApi $service + * @param array $requestContainer + * @param array $requestOptions + * @return array + */ + private function placeMultipleCaptureRequests( + ModificationsApi $service, + array $requestContainer, + array $requestOptions + ): array { $response = []; foreach ($requestContainer[self::MULTIPLE_AUTHORIZATIONS] as $request) { $idempotencyKeyExtraData = $request['idempotencyExtraData']; @@ -92,7 +135,14 @@ private function placeMultipleCaptureRequests($service, $requestContainer, $requ try { // Copy merchant account from parent array to every request array $request[Requests::MERCHANT_ACCOUNT] = $requestContainer[Requests::MERCHANT_ACCOUNT]; - $singleResponse = $service->captures($request, $requestOptions); + $paymentCaptureRequest = new PaymentCaptureRequest($request); + $singleResponseObj = $service->captureAuthorisedPayment( + $request['paymentPspReference'], + $paymentCaptureRequest, + $requestOptions + ); + + $singleResponse = $singleResponseObj->toArray(); $singleResponse[self::FORMATTED_CAPTURE_AMOUNT] = $request['amount']['currency'] . ' ' . $this->adyenHelper->originalAmount( $request['amount']['value'], @@ -101,9 +151,7 @@ private function placeMultipleCaptureRequests($service, $requestContainer, $requ $singleResponse = $this->copyParamsToResponse($singleResponse, $request); $response[self::MULTIPLE_AUTHORIZATIONS][] = $singleResponse; } catch (AdyenException $e) { - $pspReference = isset($request[OrderPaymentInterface::PSPREFRENCE]) ? - $request[OrderPaymentInterface::PSPREFRENCE] : - 'pspReference not set'; + $pspReference = $request[OrderPaymentInterface::PSPREFRENCE] ?? 'pspReference not set'; $message = sprintf( 'Exception occurred when attempting to capture multiple authorizations. @@ -120,6 +168,11 @@ private function placeMultipleCaptureRequests($service, $requestContainer, $requ return $response; } + /** + * @param array $response + * @param array $request + * @return array + */ private function copyParamsToResponse(array $response, array $request): array { $response[self::CAPTURE_AMOUNT] = $request['amount']['value']; diff --git a/Gateway/Http/Client/TransactionDonate.php b/Gateway/Http/Client/TransactionDonate.php index 7475993fc..ee63f10cf 100644 --- a/Gateway/Http/Client/TransactionDonate.php +++ b/Gateway/Http/Client/TransactionDonate.php @@ -14,18 +14,37 @@ use Adyen\AdyenException; use Adyen\Client; +use Adyen\Model\Checkout\DonationPaymentRequest; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Idempotency; -use Adyen\Service\Checkout; +use Adyen\Service\Checkout\DonationsApi; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Payment\Gateway\Http\ClientInterface; use Magento\Payment\Gateway\Http\TransferInterface; class TransactionDonate implements ClientInterface { + /** + * @var Client + */ private Client $client; + + /** + * @var Data + */ private Data $adyenHelper; + + /** + * @var Idempotency + */ private Idempotency $idempotencyHelper; + /** + * @param Data $adyenHelper + * @param Idempotency $idempotencyHelper + * @throws AdyenException + * @throws NoSuchEntityException + */ public function __construct( Data $adyenHelper, Idempotency $idempotencyHelper @@ -37,15 +56,16 @@ public function __construct( } /** - * @inheritDoc + * @param TransferInterface $transferObject + * @return array * @throws AdyenException */ - public function placeRequest(TransferInterface $transferObject) + public function placeRequest(TransferInterface $transferObject): array { $request = $transferObject->getBody(); $headers = $transferObject->getHeaders(); - $service = new Checkout($this->client); + $service = new DonationsApi($this->client); $idempotencyKey = $this->idempotencyHelper->generateIdempotencyKey( $request, @@ -57,7 +77,8 @@ public function placeRequest(TransferInterface $transferObject) $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, 'donations'); try { - $response = $service->donations($request, $requestOptions); + $responseObj = $service->donations(new DonationPaymentRequest($request), $requestOptions); + $response = $responseObj->toArray(); } catch (AdyenException $e) { $response = ['error' => $e->getMessage()]; } diff --git a/Gateway/Http/Client/TransactionPayment.php b/Gateway/Http/Client/TransactionPayment.php index d5aa8019b..07a4e135e 100644 --- a/Gateway/Http/Client/TransactionPayment.php +++ b/Gateway/Http/Client/TransactionPayment.php @@ -13,7 +13,9 @@ use Adyen\AdyenException; use Adyen\Client; -use Adyen\Payment\Gateway\Request\HeaderDataBuilder; +use Adyen\ConnectionException; +use Adyen\Model\Checkout\PaymentRequest; +use Adyen\Model\Checkout\PaymentResponse as CheckoutPaymentResponse; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\GiftcardPayment; use Adyen\Payment\Helper\Idempotency; @@ -21,23 +23,61 @@ use Adyen\Payment\Model\PaymentResponse; use Adyen\Payment\Model\PaymentResponseFactory; use Adyen\Payment\Model\ResourceModel\PaymentResponse as PaymentResponseResourceModel; -use Adyen\Service\Checkout; +use Adyen\Service\Checkout\PaymentsApi; +use Magento\Framework\Exception\AlreadyExistsException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Payment\Gateway\Http\ClientInterface; use Magento\Payment\Gateway\Http\TransferInterface; use Magento\Store\Model\StoreManagerInterface; class TransactionPayment implements ClientInterface { + /** + * @var Data + */ private Data $adyenHelper; + + /** + * @var PaymentResponseFactory + */ private PaymentResponseFactory $paymentResponseFactory; + + /** + * @var PaymentResponseResourceModel + */ private PaymentResponseResourceModel $paymentResponseResourceModel; + + /** + * @var Idempotency + */ private Idempotency $idempotencyHelper; + + /** + * @var OrdersApi + */ private OrdersApi $orderApiHelper; + + /** + * @var StoreManagerInterface + */ private StoreManagerInterface $storeManager; + + /** + * @var GiftcardPayment + */ private GiftcardPayment $giftcardPaymentHelper; private ?int $remainingOrderAmount; + /** + * @param Data $adyenHelper + * @param PaymentResponseFactory $paymentResponseFactory + * @param PaymentResponseResourceModel $paymentResponseResourceModel + * @param Idempotency $idempotencyHelper + * @param OrdersApi $orderApiHelper + * @param StoreManagerInterface $storeManager + * @param GiftcardPayment $giftcardPaymentHelper + */ public function __construct( Data $adyenHelper, PaymentResponseFactory $paymentResponseFactory, @@ -57,64 +97,83 @@ public function __construct( $this->remainingOrderAmount = null; } + /** + * @param TransferInterface $transferObject + * @return array + * @throws AdyenException + * @throws AlreadyExistsException + * @throws ConnectionException + * @throws NoSuchEntityException + */ public function placeRequest(TransferInterface $transferObject): array { - $request = $transferObject->getBody(); + $requestData = $transferObject->getBody(); $headers = $transferObject->getHeaders(); $clientConfig = $transferObject->getClientConfig(); - $this->remainingOrderAmount = $request['amount']['value']; + $this->remainingOrderAmount = $requestData['amount']['value']; // If the payments call is already done return the request - if (!empty($request['resultCode'])) { + if (!empty($requestData['resultCode'])) { //Initiate has already a response - return $request; + return $requestData; } $client = $this->adyenHelper->initializeAdyenClientWithClientConfig($clientConfig); - $service = $this->adyenHelper->createAdyenCheckoutService($client); + $service = $this->adyenHelper->initializePaymentsApi($client); + $responseData = []; try { - list($request, $giftcardResponse) = $this->processGiftcards($request, $service); + list($requestData, $giftcardResponse) = $this->processGiftcards($requestData, $service); + + /** @var PaymentResponse $giftcardResponse */ if (isset($giftcardResponse) && $this->remainingOrderAmount === 0) { - return $giftcardResponse; + return $giftcardResponse->toArray(); } + $paymentRequest = new PaymentRequest($requestData); + $idempotencyKey = $this->idempotencyHelper->generateIdempotencyKey( - $request, + $requestData, $headers['idempotencyExtraData'] ?? null ); $requestOptions['idempotencyKey'] = $idempotencyKey; $requestOptions['headers'] = $headers; - - $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, '/payments'); - $response = $service->payments($request, $requestOptions); + $this->adyenHelper->logRequest($requestData, Client::API_CHECKOUT_VERSION, '/payments'); + $response = $service->payments($paymentRequest, $requestOptions); // Store the /payments response in the database in case it is needed in order to finish the payment /** @var PaymentResponse $paymentResponse */ $paymentResponse = $this->paymentResponseFactory->create(); - $paymentResponse->setResponse(json_encode($response)); - $paymentResponse->setResultCode($response['resultCode']); - $paymentResponse->setMerchantReference($request["reference"]); - + $paymentResponse->setResponse((string)$response); + $paymentResponse->setResultCode($response->getResultCode()); + $paymentResponse->setMerchantReference($requestData["reference"]); $this->paymentResponseResourceModel->save($paymentResponse); + $responseData = $response->toArray(); + + $this->adyenHelper->logResponse($responseData); } catch (AdyenException $e) { - $response['error'] = $e->getMessage(); - $response['errorCode'] = $e->getAdyenErrorCode(); + $this->adyenHelper->logAdyenException($e); } - $this->adyenHelper->logResponse($response); - return $response; + return $responseData; } + /** + * @param array $request + * @param PaymentsApi $service + * @param array $redeemedGiftcards + * @param array $ordersResponse + * @return CheckoutPaymentResponse + * @throws AdyenException + * @throws AlreadyExistsException + */ private function handleGiftcardPayments( array $request, - Checkout $service, + PaymentsApi $service, array $redeemedGiftcards, array $ordersResponse - ): array { - $response = []; - + ): CheckoutPaymentResponse { foreach ($redeemedGiftcards as $giftcard) { $stateData = json_decode($giftcard['state_data'], true); @@ -141,9 +200,8 @@ private function handleGiftcardPayments( '/payments' ); - $response = $service->payments($giftcardPaymentRequest); - - $this->adyenHelper->logResponse($response); + $response = $service->payments(new PaymentRequest($giftcardPaymentRequest)); + $this->adyenHelper->logResponse($response->toArray()); /** @var PaymentResponse $paymentResponse */ $paymentResponse = $this->paymentResponseFactory->create(); @@ -159,7 +217,15 @@ private function handleGiftcardPayments( return $response; } - public function processGiftcards(array $request, Checkout $service): array + /** + * @param array $request + * @param PaymentsApi $service + * @return array + * @throws AdyenException + * @throws AlreadyExistsException + * @throws NoSuchEntityException + */ + public function processGiftcards(array $request, PaymentsApi $service): array { if (isset($request['giftcardRequestParameters'])) { $redeemedGiftcards = $request['giftcardRequestParameters']; @@ -182,6 +248,7 @@ public function processGiftcards(array $request, Checkout $service): array } else { $giftcardResponse = null; } + return array($request, $giftcardResponse); } } diff --git a/Gateway/Http/Client/TransactionPaymentLinks.php b/Gateway/Http/Client/TransactionPaymentLinks.php index e3e71d13a..bfe05a6c6 100644 --- a/Gateway/Http/Client/TransactionPaymentLinks.php +++ b/Gateway/Http/Client/TransactionPaymentLinks.php @@ -13,16 +13,30 @@ use Adyen\AdyenException; use Adyen\Client; +use Adyen\Model\Checkout\PaymentLinkRequest; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Idempotency; +use Adyen\Service\Checkout\PaymentLinksApi; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Payment\Gateway\Http\ClientInterface; use Magento\Payment\Gateway\Http\TransferInterface; class TransactionPaymentLinks implements ClientInterface { + /** + * @var Data + */ private Data $adyenHelper; + + /** + * @var Idempotency + */ private Idempotency $idempotencyHelper; + /** + * @param Data $adyenHelper + * @param Idempotency $idempotencyHelper + */ public function __construct( Data $adyenHelper, Idempotency $idempotencyHelper @@ -31,6 +45,12 @@ public function __construct( $this->idempotencyHelper = $idempotencyHelper; } + /** + * @param TransferInterface $transferObject + * @return array + * @throws AdyenException + * @throws NoSuchEntityException + */ public function placeRequest(TransferInterface $transferObject): array { $request = $transferObject->getBody(); @@ -38,11 +58,11 @@ public function placeRequest(TransferInterface $transferObject): array $clientConfig = $transferObject->getClientConfig(); $client = $this->adyenHelper->initializeAdyenClientWithClientConfig($clientConfig); - $service = $this->adyenHelper->createAdyenCheckoutService($client); + $service = new PaymentLinksApi($client); // If the payment links call is already done return the request if (!empty($request['resultCode'])) { - //Initiate has already a response + // Initiate has already a response return $request; } @@ -56,7 +76,8 @@ public function placeRequest(TransferInterface $transferObject): array $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, '/paymentLinks'); try { - $response = $service->paymentLinks($request, $requestOptions); + $responseObj = $service->paymentLinks(new PaymentLinkRequest($request), $requestOptions); + $response = $responseObj->toArray(); } catch (AdyenException $e) { $response['error'] = $e->getMessage(); } diff --git a/Gateway/Http/Client/TransactionRefund.php b/Gateway/Http/Client/TransactionRefund.php index c67b95503..09b4e7176 100644 --- a/Gateway/Http/Client/TransactionRefund.php +++ b/Gateway/Http/Client/TransactionRefund.php @@ -13,8 +13,10 @@ use Adyen\AdyenException; use Adyen\Client; +use Adyen\Model\Checkout\PaymentRefundRequest; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Idempotency; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Payment\Gateway\Http\TransferInterface; /** @@ -22,9 +24,20 @@ */ class TransactionRefund implements TransactionRefundInterface { + /** + * @var Data + */ private Data $adyenHelper; + + /** + * @var Idempotency + */ private Idempotency $idempotencyHelper; + /** + * @param Data $adyenHelper + * @param Idempotency $idempotencyHelper + */ public function __construct( Data $adyenHelper, Idempotency $idempotencyHelper @@ -33,37 +46,51 @@ public function __construct( $this->idempotencyHelper = $idempotencyHelper; } + /** + * @param TransferInterface $transferObject + * @return array + * @throws AdyenException + * @throws NoSuchEntityException + */ public function placeRequest(TransferInterface $transferObject): array { $requests = $transferObject->getBody(); $headers = $transferObject->getHeaders(); $clientConfig = $transferObject->getClientConfig(); + $client = $this->adyenHelper->initializeAdyenClientWithClientConfig($clientConfig); - $service = $this->adyenHelper->createAdyenCheckoutService($client); + $service = $this->adyenHelper->initializeModificationsApi($client); + $responses = []; foreach ($requests as $request) { + $responseData = []; $idempotencyKey = $this->idempotencyHelper->generateIdempotencyKey( $request, $headers['idempotencyExtraData'] ?? null ); $requestOptions['idempotencyKey'] = $idempotencyKey; $requestOptions['headers'] = $this->adyenHelper->buildRequestHeaders(); - $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, '/refunds'); + $paymentRefundRequest = new PaymentRefundRequest($request); + try { - $response = $service->refunds($request, $requestOptions); + $response = $service->refundCapturedPayment( + $request['paymentPspReference'], + $paymentRefundRequest, + $requestOptions + ); + $responseData = $response->toArray(); // Add amount original reference and amount information to response - $response[self::REFUND_AMOUNT] = $request['amount']['value']; - $response[self::REFUND_CURRENCY] = $request['amount']['currency']; - $response[self::ORIGINAL_REFERENCE] = $request['paymentPspReference']; + $responseData[self::REFUND_AMOUNT] = $request['amount']['value']; + $responseData[self::REFUND_CURRENCY] = $request['amount']['currency']; + $responseData[self::ORIGINAL_REFERENCE] = $request['paymentPspReference']; + $this->adyenHelper->logResponse($responseData); } catch (AdyenException $e) { - $response = ['error' => $e->getMessage()]; + $this->adyenHelper->logAdyenException($e); } + $responses[] = $responseData; } - $this->adyenHelper->logResponse($response); - $responses[] = $response; - return $responses; } } diff --git a/Helper/Data.php b/Helper/Data.php index 81a41e577..4ece06341 100755 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -14,25 +14,30 @@ use Adyen\AdyenException; use Adyen\Client; use Adyen\Environment; +use Adyen\Model\Checkout\UtilityRequest; +use Adyen\Payment\Helper\Config as ConfigHelper; use Adyen\Payment\Gateway\Request\HeaderDataBuilder; use Adyen\Service\Checkout; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\Config\Source\RenderMode; use Adyen\Payment\Model\RecurringType; use Adyen\Payment\Model\ResourceModel\Notification\CollectionFactory as NotificationCollectionFactory; -use Adyen\Payment\Helper\Config as ConfigHelper; use Adyen\Payment\Observer\AdyenPaymentMethodDataAssignObserver; -use Adyen\Service\CheckoutUtility; +use Adyen\Service\Checkout\ModificationsApi; +use Adyen\Service\Checkout\OrdersApi; +use Adyen\Service\Checkout\PaymentsApi; +use Adyen\Service\Checkout\UtilityApi; use Adyen\Service\PosPayment; use Adyen\Service\Recurring; +use Adyen\Service\RecurringApi; use DateTime; use Exception; use Magento\Backend\Helper\Data as BackendHelper; use Magento\Directory\Model\Config\Source\Country; use Magento\Framework\App\CacheInterface; +use Magento\Framework\App\Cache\Type\Config as ConfigCache; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Helper\AbstractHelper; -use Magento\Framework\App\Cache\Type\Config as ConfigCache; use Magento\Framework\App\Helper\Context; use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ProductMetadataInterface; @@ -1197,6 +1202,26 @@ public function initializeAdyenClientWithClientConfig(array $clientConfig): Clie return $this->initializeAdyenClient($storeId, null, $motoMerchantAccount); } + public function initializePaymentsApi(Client $client):PaymentsApi + { + return new PaymentsApi($client); + } + + public function initializeModificationsApi(Client $client):ModificationsApi + { + return new ModificationsApi($client); + } + + public function initializeRecurringApi(Client $client):RecurringApi + { + return new RecurringApi($client); + } + + public function initializeOrdersApi(Client $client): OrdersApi + { + return new OrdersApi($client); + } + /** * @param Client $client * @return PosPayment @@ -1281,8 +1306,9 @@ private function getOriginKeyForOrigin($origin, $storeId = null) $client = $this->initializeAdyenClient($storeId); try { - $service = $this->createAdyenCheckoutUtilityService($client); - $response = $service->originKeys($params); + $service = new UtilityApi($client); + $responseObj = $service->originKeys(new UtilityRequest($params)); + $response = json_decode(json_encode($responseObj->jsonSerialize()), true); } catch (Exception $e) { $this->adyenLogger->error($e->getMessage()); } @@ -1318,16 +1344,6 @@ public function getCheckoutEnvironment($storeId = null) } } - /** - * @param Client $client - * @return CheckoutUtility - * @throws AdyenException - */ - private function createAdyenCheckoutUtilityService($client) - { - return new CheckoutUtility($client); - } - /** * Method can be used by interceptors to provide the customer ID in a different way. * @@ -1376,6 +1392,7 @@ public function isHppVaultEnabled($storeId = null) * @return Checkout * @throws AdyenException * @throws NoSuchEntityException + * @deprecared use `initializePaymentsApi`, or `initializeModificationsApi` based on your case */ public function createAdyenCheckoutService(Client $client = null): Checkout { @@ -1390,6 +1407,7 @@ public function createAdyenCheckoutService(Client $client = null): Checkout * @param $client * @return Recurring * @throws AdyenException + * @deprecared use `initializeRecurringApi()` */ public function createAdyenRecurringService($client) { @@ -1516,6 +1534,14 @@ public function logResponse(array $response) $this->adyenLogger->info('Response from Adyen API', $context); } + public function logAdyenException(AdyenException $e) + { + $responseArray = []; + $responseArray['error'] = $e->getMessage(); + $responseArray['errorCode'] = $e->getAdyenErrorCode(); + $this->logResponse($responseArray); + } + private function filterReferences(array $data): array { return array_filter($data, function($value, $key) { diff --git a/Helper/ManagementHelper.php b/Helper/ManagementHelper.php index b745f1a48..2baa4059c 100644 --- a/Helper/ManagementHelper.php +++ b/Helper/ManagementHelper.php @@ -16,8 +16,15 @@ */ use Adyen\AdyenException; -use Adyen\ConnectionException; -use Adyen\Service\Management; +use Adyen\Client; +use Adyen\Model\Management\CreateAllowedOriginRequest; +use Adyen\Model\Management\CreateMerchantWebhookRequest; +use Adyen\Model\Management\TestWebhookRequest; +use Adyen\Model\Management\TestWebhookResponse; +use Adyen\Model\Management\UpdateMerchantWebhookRequest; +use Adyen\Service\Management\AccountMerchantLevelApi; +use Adyen\Service\Management\MyAPICredentialApi; +use Adyen\Service\Management\WebhooksMerchantLevelApi; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Message\ManagerInterface; use Magento\Store\Model\StoreManager; @@ -29,32 +36,30 @@ class ManagementHelper /** * @var Data */ - private $dataHelper; + private Data $dataHelper; /** * @var StoreManager */ - private $storeManager; + private StoreManager $storeManager; /** * @var Config */ - private $configHelper; + private Config $configHelper; /** * @var EncryptorInterface */ - private $encryptor; + private EncryptorInterface $encryptor; /** - * Logging instance - * * @var AdyenLogger */ - private $adyenLogger; + private AdyenLogger $adyenLogger; /** * @var ManagerInterface */ - protected $messageManager; + protected ManagerInterface $messageManager; /** * ManagementHelper constructor. @@ -66,12 +71,12 @@ class ManagementHelper * @param ManagerInterface $messageManager */ public function __construct( - StoreManager $storeManager, + StoreManager $storeManager, EncryptorInterface $encryptor, - Data $dataHelper, - Config $configHelper, - AdyenLogger $adyenLogger, - ManagerInterface $messageManager + Data $dataHelper, + Config $configHelper, + AdyenLogger $adyenLogger, + ManagerInterface $messageManager ) { $this->dataHelper = $dataHelper; $this->storeManager = $storeManager; @@ -82,18 +87,23 @@ public function __construct( } /** - * @param Management $managementApiService + * @param AccountMerchantLevelApi $accountMerchantLevelApi + * @param MyAPICredentialApi $myAPICredentialApi * @return array - * @throws AdyenException | ConnectionException + * @throws AdyenException * @throws NoSuchEntityException */ - public function getMerchantAccountsAndClientKey(Management $managementApiService): array - { + public function getMerchantAccountsAndClientKey( + AccountMerchantLevelApi $accountMerchantLevelApi, + MyAPICredentialApi $myAPICredentialApi + ): array { $merchantAccounts = []; $page = 1; $pageSize = 100; - //get the merchant accounts using get /merchants. - $responseMerchants = $managementApiService->merchantAccount->list(["pageSize" => $pageSize]); + $responseMerchantsObj = $accountMerchantLevelApi->listMerchantAccounts( + ['queryParams' => ['pageSize' => $pageSize]] + ); + $responseMerchants = $responseMerchantsObj->toArray(); while (count($merchantAccounts) < $responseMerchants['itemsTotal']) { foreach ($responseMerchants['data'] as $merchantAccount) { $defaultDC = array_filter($merchantAccount['dataCenters'], function ($dc) { @@ -107,12 +117,15 @@ public function getMerchantAccountsAndClientKey(Management $managementApiService } ++$page; if (isset($responseMerchants['_links']['next'])) { - $responseMerchants = $managementApiService->merchantAccount->list( - ["pageSize" => $pageSize, "pageNumber" => $page] + $responseMerchantsObj = $accountMerchantLevelApi->listMerchantAccounts( + ['queryParams' => ["pageSize" => $pageSize, "pageNumber" => $page]] ); + $responseMerchants = $responseMerchantsObj->toArray(); } } - $responseMe = $managementApiService->me->retrieve(); + + $responseMeObj = $myAPICredentialApi->getApiCredentialDetails(); + $responseMe = $responseMeObj->toArray(); $currentMerchantAccount = $this->configHelper->getMerchantAccount($this->storeManager->getStore()->getId()); @@ -129,18 +142,18 @@ public function getMerchantAccountsAndClientKey(Management $managementApiService * @param string $password * @param string $url * @param bool $demoMode - * @param Management $managementApiService + * @param WebhooksMerchantLevelApi $service * @return string|null * @throws AdyenException * @throws NoSuchEntityException */ public function setupWebhookCredentials( - string $merchantId, - string $username, - string $password, - string $url, - bool $demoMode, - Management $managementApiService + string $merchantId, + string $username, + string $password, + string $url, + bool $demoMode, + WebhooksMerchantLevelApi $service ): ?string { $params = [ 'url' => $url, @@ -176,8 +189,9 @@ public function setupWebhookCredentials( // Try to reuse saved webhookId if merchant account is the same. if (!empty($webhookId) && $merchantId === $savedMerchantAccount) { try { - $response = $managementApiService->merchantWebhooks->update($merchantId, $webhookId, $params); - } catch (AdyenException $exception){ + $updateRequest = new UpdateMerchantWebhookRequest($params); + $response = $service->updateWebhook($merchantId, $webhookId, $updateRequest); + } catch (AdyenException $exception) { $this->adyenLogger->error($exception->getMessage()); } } @@ -186,9 +200,9 @@ public function setupWebhookCredentials( if (!isset($response) || empty($webhookId)) { try { $params['type'] = 'standard'; - $response = $managementApiService->merchantWebhooks->create($merchantId, $params); + $response = $service->setUpWebhook($merchantId, new CreateMerchantWebhookRequest($params)); // save webhook_id to configuration - $webhookId = $response['id']; + $webhookId = $response->getId(); $this->configHelper->setConfigData($webhookId, 'webhook_id', Config::XML_ADYEN_ABSTRACT_PREFIX); } catch (\Exception $exception) { $this->adyenLogger->error($exception->getMessage()); @@ -198,8 +212,8 @@ public function setupWebhookCredentials( if (!empty($webhookId)) { try { // generate hmac key and save - $response = $managementApiService->merchantWebhooks->generateHmac($merchantId, $webhookId); - $hmacKey = $response['hmacKey']; + $response = $service->generateHmacKey($merchantId, $webhookId); + $hmacKey = $response->getHmacKey(); $hmac = $this->encryptor->encrypt($hmacKey); $mode = $demoMode ? 'test' : 'live'; $this->configHelper->setConfigData($hmac, 'notification_hmac_key_' . $mode, Config::XML_ADYEN_ABSTRACT_PREFIX); @@ -217,66 +231,60 @@ public function setupWebhookCredentials( } /** - * @param Management $managementApiService + * @param MyAPICredentialApi $service * @return array * @throws AdyenException */ - public function getAllowedOrigins(Management $managementApiService): array + public function getAllowedOrigins(MyAPICredentialApi $service): array { - $response = $managementApiService->allowedOrigins->list(); + $responseObj = $service->getAllowedOrigins(); + $response = $responseObj->toArray(); return !empty($response) ? array_column($response['data'], 'domain') : []; } /** - * @param Management $managementApiService + * @param MyAPICredentialApi $service * @param string $domain * @return void * @throws AdyenException */ - public function saveAllowedOrigin(Management $managementApiService, string $domain): void + public function saveAllowedOrigin(MyAPICredentialApi $service, string $domain): void { - $managementApiService->allowedOrigins->create(['domain' => $domain]); + $service->addAllowedOrigin(new CreateAllowedOriginRequest(['domain' => $domain])); } /** * @param string $merchantId * @param string $webhookId - * @param Management $managementApiService - * @return mixed|string + * @param WebhooksMerchantLevelApi $service + * @return TestWebhookResponse|null */ - public function webhookTest(string $merchantId, string $webhookId, Management $managementApiService) - { - $params = [ - 'types' => [ - 'AUTHORISATION' - ] - ]; - + public function webhookTest( + string $merchantId, + string $webhookId, + WebhooksMerchantLevelApi $service + ): ?TestWebhookResponse { + $testWebhookRequest = new TestWebhookRequest(['types' => ['AUTHORISATION']]); + $response = null; try { - $response = $managementApiService->merchantWebhooks->test($merchantId, $webhookId, $params); - - $this->adyenLogger->info( - sprintf( 'response from webhook test %s', - json_encode($response)) - ); - - return $response; + $response = $service->testWebhook($merchantId, $webhookId, $testWebhookRequest); + $this->adyenLogger->info(sprintf('response from webhook test %s', $response)); } catch (AdyenException $exception) { $this->adyenLogger->error($exception->getMessage()); - - return $exception->getMessage(); } + + return $response; } /** * @param string $apiKey * @param bool $demoMode - * @return Management + * @return Client * @throws AdyenException * @throws NoSuchEntityException */ - public function getManagementApiService(string $apiKey, bool $demoMode): Management + public function getAdyenApiClient(string $apiKey, bool $demoMode): Client { $environment = $demoMode ? 'test' : 'live'; $storeId = $this->storeManager->getStore()->getId(); @@ -286,8 +294,40 @@ public function getManagementApiService(string $apiKey, bool $demoMode): Managem $apiKey = $this->configHelper->getApiKey($environment); } - $client = $this->dataHelper->initializeAdyenClient($storeId, $apiKey, null, $environment === 'test'); + return $this->dataHelper->initializeAdyenClient( + $storeId, $apiKey, + null, + $environment === 'test' + ); + } + + /** + * @param Client $client + * @return AccountMerchantLevelApi + * @throws AdyenException + */ + public function getAccountMerchantLevelApi(Client $client): AccountMerchantLevelApi + { + return new AccountMerchantLevelApi($client); + } + + /** + * @param Client $client + * @return MyAPICredentialApi + * @throws AdyenException + */ + public function getMyAPICredentialApi(Client $client): MyAPICredentialApi + { + return new MyAPICredentialApi($client); + } - return new Management($client); + /** + * @param Client $client + * @return WebhooksMerchantLevelApi + * @throws AdyenException + */ + public function getWebhooksMerchantLevelApi(Client $client): WebhooksMerchantLevelApi + { + return new WebhooksMerchantLevelApi($client); } } diff --git a/Helper/OrdersApi.php b/Helper/OrdersApi.php index ee438a47c..f17346826 100644 --- a/Helper/OrdersApi.php +++ b/Helper/OrdersApi.php @@ -12,17 +12,34 @@ namespace Adyen\Payment\Helper; use Adyen\AdyenException; +use Adyen\Model\Checkout\CreateOrderRequest; use Adyen\Client; -use Adyen\ConnectionException; use Adyen\Payment\Logger\AdyenLogger; +use Adyen\Service\Checkout\OrdersApi as CheckoutOrdersApi; use Magento\Framework\Exception\NoSuchEntityException; class OrdersApi { + /** + * @var Config + */ private Config $configHelper; + + /** + * @var Data + */ private Data $adyenHelper; + + /** + * @var AdyenLogger + */ private AdyenLogger $adyenLogger; + /** + * @param Config $configHelper + * @param Data $adyenHelper + * @param AdyenLogger $adyenLogger + */ public function __construct( Config $configHelper, Data $adyenHelper, @@ -40,7 +57,6 @@ public function __construct( * @param string $merchantReference * @return array * @throws AdyenException - * @throws ConnectionException * @throws NoSuchEntityException */ public function createOrder(string $merchantReference, int $amount, string $currency, string $storeId): array @@ -48,12 +64,13 @@ public function createOrder(string $merchantReference, int $amount, string $curr $request = $this->buildOrdersRequest($amount, $currency, $merchantReference, $storeId); $client = $this->adyenHelper->initializeAdyenClient($storeId); - $checkoutService = $this->adyenHelper->createAdyenCheckoutService($client); + $checkoutService = new CheckoutOrdersApi($client); try { $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, '/orders'); - $response = $checkoutService->orders($request); - } catch (ConnectionException $e) { + $responseObj = $checkoutService->orders(new CreateOrderRequest($request)); + $response = $responseObj->toArray(); + } catch (AdyenException $e) { $this->adyenLogger->error( "Connection to the endpoint failed. Check the Adyen Live endpoint prefix configuration." ); diff --git a/Helper/PaymentMethods.php b/Helper/PaymentMethods.php index ed0638a72..8e5d42387 100644 --- a/Helper/PaymentMethods.php +++ b/Helper/PaymentMethods.php @@ -15,6 +15,7 @@ use Adyen\Client; use Adyen\ConnectionException; use Adyen\Payment\Helper\Util\PaymentMethodUtil; +use Adyen\Model\Checkout\PaymentMethodsRequest; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\Notification; use Adyen\Payment\Model\Ui\Adminhtml\AdyenMotoConfigProvider; @@ -26,6 +27,7 @@ use Magento\Framework\App\Helper\Context; use Magento\Framework\App\RequestInterface; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\View\Asset\Repository; @@ -35,8 +37,11 @@ use Magento\Payment\Helper\Data as MagentoDataHelper; use Magento\Payment\Model\MethodInterface; use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\CartInterface; +use Magento\Quote\Model\Quote; use Magento\Sales\Model\Order; use Adyen\Payment\Helper\Data as AdyenDataHelper; +use Magento\Sales\Model\Order\Payment; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\Store; use Magento\Vault\Api\PaymentTokenRepositoryInterface; @@ -70,25 +75,116 @@ class PaymentMethods extends AbstractHelper AdyenMotoConfigProvider::CODE ]; + /** + * @var CartRepositoryInterface + */ protected CartRepositoryInterface $quoteRepository; + + /** + * @var ScopeConfigInterface + */ protected ScopeConfigInterface $config; + + /** + * @var Data + */ protected Data $adyenHelper; + + /** + * @var MagentoDataHelper + */ private MagentoDataHelper $dataHelper; + + /** + * @var ResolverInterface + */ protected ResolverInterface $localeResolver; + + /** + * @var AdyenLogger + */ protected AdyenLogger $adyenLogger; + + /** + * @var Data + */ protected Data $adyenDataHelper; + + /** + * @var Repository + */ protected Repository $assetRepo; + + /** + * @var RequestInterface + */ protected RequestInterface $request; + + /** + * @var Source + */ protected Source $assetSource; + + /** + * @var DesignInterface + */ protected DesignInterface $design; + + /** + * @var ThemeProviderInterface + */ protected ThemeProviderInterface $themeProvider; - protected \Magento\Quote\Model\Quote $quote; + + /** + * @var CartInterface + */ + protected CartInterface $quote; + + /** + * @var ChargedCurrency + */ private ChargedCurrency $chargedCurrency; + + /** + * @var Config + */ private Config $configHelper; + + /** + * @var SerializerInterface + */ private SerializerInterface $serializer; + + /** + * @var PaymentTokenRepositoryInterface + */ private PaymentTokenRepositoryInterface $paymentTokenRepository; + + /** + * @var SearchCriteriaBuilder + */ private SearchCriteriaBuilder $searchCriteriaBuilder; + /** + * @param Context $context + * @param CartRepositoryInterface $quoteRepository + * @param ScopeConfigInterface $config + * @param Data $adyenHelper + * @param ResolverInterface $localeResolver + * @param AdyenLogger $adyenLogger + * @param Repository $assetRepo + * @param RequestInterface $request + * @param Source $assetSource + * @param DesignInterface $design + * @param ThemeProviderInterface $themeProvider + * @param ChargedCurrency $chargedCurrency + * @param Config $configHelper + * @param MagentoDataHelper $dataHelper + * @param SerializerInterface $serializer + * @param Data $adyenDataHelper + * @param PaymentTokenRepositoryInterface $paymentTokenRepository + * @param SearchCriteriaBuilder $searchCriteriaBuilder + */ public function __construct( Context $context, CartRepositoryInterface $quoteRepository, @@ -129,6 +225,15 @@ public function __construct( $this->searchCriteriaBuilder = $searchCriteriaBuilder; } + /** + * @param int $quoteId + * @param string|null $country + * @param string|null $shopperLocale + * @return string + * @throws AdyenException + * @throws LocalizedException + * @throws NoSuchEntityException + */ public function getPaymentMethods(int $quoteId, ?string $country = null, ?string $shopperLocale = null): string { // get quote from quoteId @@ -143,11 +248,18 @@ public function getPaymentMethods(int $quoteId, ?string $country = null, ?string return $this->fetchPaymentMethods($country, $shopperLocale); } + /** + * @param string $methodCode + * @return bool + */ public function isAdyenPayment(string $methodCode): bool { return in_array($methodCode, $this->getAdyenPaymentMethods(), true); } + /** + * @return array + */ public function getAdyenPaymentMethods() : array { $paymentMethods = $this->dataHelper->getPaymentMethodList(); @@ -163,8 +275,17 @@ function ($key) { return array_keys($filtered); } - public function togglePaymentMethodsActivation(?bool $isActive =null, string $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, int $scopeId = 0): array - { + /** + * @param bool|null $isActive + * @param string $scope + * @param int $scopeId + * @return array + */ + public function togglePaymentMethodsActivation( + ?bool $isActive = null, + string $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + int $scopeId = 0 + ): array { $enabledPaymentMethods = []; if (is_null($isActive)) { @@ -191,7 +312,7 @@ public function togglePaymentMethodsActivation(?bool $isActive =null, string $sc * @param int $scopeId * @return void */ - public function removePaymentMethodsActivation(string $scope, int $scopeId) : void + public function removePaymentMethodsActivation(string $scope, int $scopeId): void { foreach ($this->getAdyenPaymentMethods() as $paymentMethod) { @@ -203,6 +324,14 @@ public function removePaymentMethodsActivation(string $scope, int $scopeId) : vo } } + /** + * @param string|null $country + * @param string|null $shopperLocale + * @return string + * @throws AdyenException + * @throws LocalizedException + * @throws NoSuchEntityException + */ protected function fetchPaymentMethods(?string $country = null, ?string $shopperLocale = null): string { $quote = $this->getQuote(); @@ -240,7 +369,13 @@ protected function fetchPaymentMethods(?string $country = null, ?string $shopper return json_encode($response); } - protected function filterStoredPaymentMethods($allowMultistoreTokens, $responseData, $customerId) + /** + * @param $allowMultistoreTokens + * @param $responseData + * @param $customerId + * @return mixed + */ + protected function filterStoredPaymentMethods($allowMultistoreTokens, $responseData, $customerId): mixed { if (!$allowMultistoreTokens && isset($responseData['storedPaymentMethods'])) { $searchCriteria = $this->searchCriteriaBuilder @@ -264,6 +399,10 @@ function ($method) use ($gatewayTokens) { return $responseData; } + /** + * @return float + * @throws AdyenException + */ protected function getCurrentPaymentAmount(): float { $total = $this->chargedCurrency->getQuoteAmountCurrency($this->getQuote())->getAmount(); @@ -291,6 +430,10 @@ protected function getCurrentPaymentAmount(): float throw new AdyenException($exceptionMessage); } + /** + * @param Store $store + * @return string + */ protected function getCurrentCountryCode(Store $store): string { $quote = $this->getQuote(); @@ -314,17 +457,25 @@ protected function getCurrentCountryCode(Store $store): string return ""; } + /** + * @param array $requestParams + * @param Store $store + * @return array + * @throws AdyenException + * @throws NoSuchEntityException + */ protected function getPaymentMethodsResponse(array $requestParams, Store $store): array { // initialize the adyen client $client = $this->adyenHelper->initializeAdyenClient($store->getId()); // initialize service - $service = $this->adyenHelper->createAdyenCheckoutService($client); + $service =$this->adyenHelper->initializePaymentsApi($client); try { $this->adyenHelper->logRequest($requestParams, Client::API_CHECKOUT_VERSION, '/paymentMethods'); - $responseData = $service->paymentMethods($requestParams); + $response = $service->paymentMethods(new PaymentMethodsRequest($requestParams)); + $responseData = $response->toArray(); } catch (AdyenException $e) { $this->adyenLogger->error( "The Payment methods response is empty check your Adyen configuration in Magento." @@ -343,26 +494,45 @@ protected function getPaymentMethodsResponse(array $requestParams, Store $store) return $responseData; } - protected function getQuote(): \Magento\Quote\Model\Quote + /** + * @return CartInterface + */ + protected function getQuote(): CartInterface { return $this->quote; } - protected function setQuote(\Magento\Quote\Model\Quote $quote): void + /** + * @param CartInterface $quote + * @return void + */ + protected function setQuote(CartInterface $quote): void { $this->quote = $quote; } + /** + * @return string|null + */ protected function getCurrentShopperReference(): ?string { $customerId = $this->getQuote()->getCustomerId(); return $customerId ? (string)$customerId : null; } + /** + * @param $merchantAccount + * @param Store $store + * @param Quote $quote + * @param string|null $shopperLocale + * @param string|null $country + * @return array + * @throws AdyenException + */ protected function getPaymentMethodsRequest( $merchantAccount, Store $store, - \Magento\Quote\Model\Quote $quote, + Quote $quote, ?string $shopperLocale = null, ?string $country = null ): array { @@ -398,6 +568,12 @@ protected function getPaymentMethodsRequest( return $paymentMethodRequest; } + /** + * @param array $paymentMethods + * @param array $paymentMethodsExtraDetails + * @return array + * @throws LocalizedException + */ protected function showLogosPaymentMethods(array $paymentMethods, array $paymentMethodsExtraDetails): array { if (!$this->adyenHelper->showLogos()) { @@ -445,6 +621,12 @@ protected function showLogosPaymentMethods(array $paymentMethods, array $payment return $paymentMethodsExtraDetails; } + /** + * @param array $paymentMethods + * @param array $paymentMethodsExtraDetails + * @return array + * @throws AdyenException + */ protected function addExtraConfigurationToPaymentMethods( array $paymentMethods, array $paymentMethodsExtraDetails @@ -468,16 +650,29 @@ protected function addExtraConfigurationToPaymentMethods( return $paymentMethodsExtraDetails; } + /** + * @param MethodInterface $paymentMethodInstance + * @return bool + */ public function isWalletPaymentMethod(MethodInterface $paymentMethodInstance): bool { return boolval($paymentMethodInstance->getConfigData('is_wallet')); } + /** + * @param MethodInterface $paymentMethodInstance + * @return bool + */ public function isAlternativePaymentMethod(MethodInterface $paymentMethodInstance): bool { return $paymentMethodInstance->getConfigData('group') === self::ADYEN_GROUP_ALTERNATIVE_PAYMENT_METHODS; } + /** + * @param MethodInterface $paymentMethodInstance + * @return string + * @throws AdyenException + */ public function getAlternativePaymentMethodTxVariant(MethodInterface $paymentMethodInstance): string { if (!$this->isAlternativePaymentMethod($paymentMethodInstance)) { @@ -487,16 +682,28 @@ public function getAlternativePaymentMethodTxVariant(MethodInterface $paymentMet return str_replace('adyen_', '', $paymentMethodInstance->getCode()); } + /** + * @param MethodInterface $paymentMethodInstance + * @return bool + */ public function paymentMethodSupportsRecurring(MethodInterface $paymentMethodInstance): bool { return boolval($paymentMethodInstance->getConfigData('supports_recurring')); } + /** + * @param Payment $payment + * @param string $method + * @return bool + */ public function checkPaymentMethod(Order\Payment $payment, string $method): bool { return $payment->getMethod() === $method; } + /** + * @return array + */ public function getCcAvailableTypes(): array { $types = []; @@ -514,6 +721,9 @@ public function getCcAvailableTypes(): array return $types; } + /** + * @return array + */ public function getCcAvailableTypesByAlt(): array { $types = []; @@ -531,6 +741,11 @@ public function getCcAvailableTypesByAlt(): array return $types; } + /** + * @param Order $order + * @param string $notificationPaymentMethod + * @return bool + */ public function isAutoCapture(Order $order, string $notificationPaymentMethod): bool { // validate if payment methods allows manual capture @@ -698,6 +913,13 @@ public function isAutoCapture(Order $order, string $notificationPaymentMethod): } } + /** + * @param Order $order + * @param Notification $notification + * @return bool + * @throws AdyenException + * @throws LocalizedException + */ public function compareOrderAndWebhookPaymentMethods(Order $order, Notification $notification): bool { $paymentMethodInstance = $order->getPayment()->getMethodInstance(); @@ -722,6 +944,10 @@ public function compareOrderAndWebhookPaymentMethods(Order $order, Notification return false; } + /** + * @param string $paymentMethod + * @return bool + */ public function isBankTransfer(string $paymentMethod): bool { if (strlen($paymentMethod) >= 12 && substr($paymentMethod, 0, 12) == "bankTransfer") { @@ -732,6 +958,12 @@ public function isBankTransfer(string $paymentMethod): bool return $isBankTransfer; } + /** + * @param Order $order + * @param Notification $notification + * @param string $status + * @return string|null + */ public function getBoletoStatus(Order $order, Notification $notification, string $status): ?string { $additionalData = !empty($notification->getAdditionalData()) ? $this->serializer->unserialize( diff --git a/Helper/PaymentsDetails.php b/Helper/PaymentsDetails.php index 279708403..db54ba2ef 100644 --- a/Helper/PaymentsDetails.php +++ b/Helper/PaymentsDetails.php @@ -12,6 +12,7 @@ namespace Adyen\Payment\Helper; use Adyen\AdyenException; +use Adyen\Model\Checkout\PaymentDetailsRequest; use Adyen\Payment\Helper\Util\DataArrayValidator; use Adyen\Payment\Logger\AdyenLogger; use Magento\Checkout\Model\Session; @@ -33,11 +34,32 @@ class PaymentsDetails 'merchantReference' ]; + /** + * @var Session + */ private Session $checkoutSession; + + /** + * @var Data + */ private Data $adyenHelper; + + /** + * @var AdyenLogger + */ private AdyenLogger $adyenLogger; + + /** + * @var Idempotency + */ private Idempotency $idempotencyHelper; + /** + * @param Session $checkoutSession + * @param Data $adyenHelper + * @param AdyenLogger $adyenLogger + * @param Idempotency $idempotencyHelper + */ public function __construct( Session $checkoutSession, Data $adyenHelper, @@ -58,15 +80,15 @@ public function __construct( public function initiatePaymentDetails(OrderInterface $order, array $payload): array { $request = $this->cleanUpPaymentDetailsPayload($payload); - try { $client = $this->adyenHelper->initializeAdyenClient($order->getStoreId()); - $service = $this->adyenHelper->createAdyenCheckoutService($client); + $service = $this->adyenHelper->initializePaymentsApi($client); $requestOptions['idempotencyKey'] = $this->idempotencyHelper->generateIdempotencyKey($request); $requestOptions['headers'] = $this->adyenHelper->buildRequestHeaders(); - $response = $service->paymentsDetails($request, $requestOptions); + $paymentDetailsObj = $service->paymentsDetails(new PaymentDetailsRequest($request), $requestOptions); + $response = $paymentDetailsObj->toArray(); } catch (AdyenException $e) { $this->adyenLogger->error("Payment details call failed: " . $e->getMessage()); $this->checkoutSession->restoreQuote(); @@ -77,6 +99,10 @@ public function initiatePaymentDetails(OrderInterface $order, array $payload): a return $response; } + /** + * @param array $payload + * @return array + */ private function cleanUpPaymentDetailsPayload(array $payload): array { $payload = DataArrayValidator::getArrayOnlyWithApprovedKeys( diff --git a/Model/Api/AdyenPaymentMethodsBalance.php b/Model/Api/AdyenPaymentMethodsBalance.php index 71ec7af5c..fc60a820e 100644 --- a/Model/Api/AdyenPaymentMethodsBalance.php +++ b/Model/Api/AdyenPaymentMethodsBalance.php @@ -13,10 +13,12 @@ namespace Adyen\Payment\Model\Api; use Adyen\AdyenException; +use Adyen\Model\Checkout\BalanceCheckRequest; use Adyen\Payment\Api\AdyenPaymentMethodsBalanceInterface; use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Data; use Adyen\Payment\Logger\AdyenLogger; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Serialize\Serializer\Json; use Magento\Store\Model\StoreManager; @@ -24,12 +26,38 @@ class AdyenPaymentMethodsBalance implements AdyenPaymentMethodsBalanceInterface { const FAILED_RESULT_CODE = 'Failed'; + /** + * @var Json + */ private Json $jsonSerializer; + + /** + * @var StoreManager + */ private StoreManager $storeManager; + + /** + * @var Config + */ private Config $config; + + /** + * @var Data + */ private Data $adyenHelper; + + /** + * @var AdyenLogger + */ private AdyenLogger $adyenLogger; + /** + * @param Json $jsonSerializer + * @param StoreManager $storeManager + * @param Config $config + * @param Data $adyenHelper + * @param AdyenLogger $adyenLogger + */ public function __construct( Json $jsonSerializer, StoreManager $storeManager, @@ -44,6 +72,12 @@ public function __construct( $this->adyenLogger = $adyenLogger; } + /** + * @param string $payload + * @return string + * @throws AdyenException + * @throws NoSuchEntityException + */ public function getBalance(string $payload): string { $payload = $this->jsonSerializer->unserialize($payload); @@ -53,17 +87,16 @@ public function getBalance(string $payload): string try { $client = $this->adyenHelper->initializeAdyenClient($storeId); - $service = $this->adyenHelper->createAdyenCheckoutService($client); - - $response = $service->paymentMethodsBalance($payload); + $service = $this->adyenHelper->initializeOrdersApi($client); + $response = $service->getBalanceOfGiftCard(new BalanceCheckRequest($payload)); - if ($response['resultCode'] === self::FAILED_RESULT_CODE) { + if ($response->getResultCode() === self::FAILED_RESULT_CODE) { // Balance endpoint doesn't send HTTP status 422 for invalid PIN, manual handling required. $errorMessage = $response['additionalData']['acquirerResponseCode'] ?? 'Unknown error!'; throw new AdyenException($errorMessage); } - return json_encode($response); + return json_encode($response->jsonSerialize()); } catch (AdyenException $e) { $this->adyenLogger->error( sprintf("An error occurred during balance check! %s", $e->getMessage()) diff --git a/Model/Api/PaymentRequest.php b/Model/Api/PaymentRequest.php index 63c27f2df..4978f894a 100755 --- a/Model/Api/PaymentRequest.php +++ b/Model/Api/PaymentRequest.php @@ -12,6 +12,9 @@ namespace Adyen\Payment\Model\Api; use Adyen\AdyenException; +use Adyen\Model\Checkout\PaymentDetailsRequest; +use Adyen\Model\Recurring\DisableRequest; +use Adyen\Model\Recurring\RecurringDetailsRequest; use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Data; use Adyen\Payment\Logger\AdyenLogger; @@ -27,16 +30,34 @@ class PaymentRequest extends DataObject { + /** + * @var EncryptorInterface + */ protected EncryptorInterface $encryptor; + /** + * @var Data + */ protected Data $adyenHelper; + /** + * @var AdyenLogger + */ protected AdyenLogger $adyenLogger; + /** + * @var Config + */ protected Config $configHelper; + /** + * @var RecurringType + */ protected RecurringType $recurringType; + /** + * @var State + */ protected State $appState; /** @@ -44,6 +65,7 @@ class PaymentRequest extends DataObject * @param EncryptorInterface $encryptor * @param Data $adyenHelper * @param AdyenLogger $adyenLogger + * @param Config $configHelper * @param RecurringType $recurringType * @param array $data */ @@ -70,7 +92,7 @@ public function __construct( * @throws LocalizedException * @throws NoSuchEntityException */ - public function authorise3d(Payment $payment): mixed + public function authorise3d(Payment $payment): array { $order = $payment->getOrder(); $storeId = $order->getStoreId(); @@ -102,13 +124,13 @@ public function authorise3d(Payment $payment): mixed try { $client = $this->adyenHelper->initializeAdyenClient($storeId); - $service = $this->adyenHelper->createAdyenCheckoutService($client); - $result = $service->paymentsDetails($request); + $service = $this->adyenHelper->initializePaymentsApi($client); + $response = $service->paymentsDetails(new PaymentDetailsRequest($request)); } catch (AdyenException $e) { throw new LocalizedException(__('3D secure failed')); } - return $result; + return $response->toArray(); } /** @@ -179,10 +201,10 @@ public function listRecurringContractByType(string $shopperReference, int $store // call lib $client = $this->adyenHelper->initializeAdyenClient($storeId); - $service = $this->adyenHelper->createAdyenRecurringService($client); - $result = $service->listRecurringDetails($request); + $service = $this->adyenHelper->initializeRecurringApi($client); + $response = $service->listRecurringDetails(new RecurringDetailsRequest($request)); - return $result; + return (array)$response->jsonSerialize(); } /** @@ -209,10 +231,11 @@ public function disableRecurringContract( // call lib $client = $this->adyenHelper->initializeAdyenClient($storeId); - $service = $this->adyenHelper->createAdyenRecurringService($client); + $service = $this->adyenHelper->initializeRecurringApi($client); try { - $result = $service->disable($request); + $response = $service->disable(new DisableRequest($request)); + $result = (array) $response->jsonSerialize(); } catch (Exception $e) { $this->adyenLogger->info($e->getMessage()); } diff --git a/Model/Config/Adminhtml/WebhookTest.php b/Model/Config/Adminhtml/WebhookTest.php index e21a3e750..1a26b30ea 100644 --- a/Model/Config/Adminhtml/WebhookTest.php +++ b/Model/Config/Adminhtml/WebhookTest.php @@ -55,7 +55,7 @@ protected function _getElementHtml(AbstractElement $element) public function getAjaxUrl() { - return $this->getUrl('adyen/configuration/webhooktest'); + return $this->getUrl('adyen/configuration/webhookTest'); } public function getButtonHtml() diff --git a/Model/Config/Backend/AutoConfiguration.php b/Model/Config/Backend/AutoConfiguration.php index 9aeff8919..19794788f 100644 --- a/Model/Config/Backend/AutoConfiguration.php +++ b/Model/Config/Backend/AutoConfiguration.php @@ -11,12 +11,14 @@ namespace Adyen\Payment\Model\Config\Backend; +use Adyen\AdyenException; use Adyen\Payment\Helper\BaseUrlHelper; use Adyen\Payment\Helper\ManagementHelper; use Magento\Framework\App\Cache\TypeListInterface; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Config\Value; use Magento\Framework\Data\Collection\AbstractDb; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Model\Context; use Magento\Framework\Model\ResourceModel\AbstractResource; use Magento\Framework\Registry; @@ -27,16 +29,30 @@ class AutoConfiguration extends Value /** * @var ManagementHelper */ - private $managementApiHelper; + private ManagementHelper $managementApiHelper; + /** * @var UrlInterface */ - private $url; + private UrlInterface $url; + /** * @var BaseUrlHelper */ - private $baseUrlHelper; + private BaseUrlHelper $baseUrlHelper; + /** + * @param Context $context + * @param Registry $registry + * @param ScopeConfigInterface $config + * @param TypeListInterface $cacheTypeList + * @param ManagementHelper $managementApiHelper + * @param UrlInterface $url + * @param BaseUrlHelper $baseUrlHelper + * @param AbstractResource|null $resource + * @param AbstractDb|null $resourceCollection + * @param array $data + */ public function __construct( Context $context, Registry $registry, @@ -55,23 +71,37 @@ public function __construct( $this->baseUrlHelper = $baseUrlHelper; } - public function beforeSave() + /** + * @return AutoConfiguration + * @throws AdyenException + * @throws NoSuchEntityException + */ + public function beforeSave(): AutoConfiguration { if ('auto' === $this->getValue()) { - $demoMode = (int)$this->getFieldsetDataValue('demo_mode'); - $environment = $demoMode ? 'test' : 'live'; + $this->saveAllowedOrigins(); + } + return parent::beforeSave(); + } - $apiKey = $this->getFieldsetDataValue('api_key_' . $environment); + /** + * @return void + * @throws AdyenException + * @throws NoSuchEntityException + */ + private function saveAllowedOrigins(): void + { + $demoMode = (int)$this->getFieldsetDataValue('demo_mode'); + $environment = $demoMode ? 'test' : 'live'; - $managementApiService = $this->managementApiHelper->getManagementApiService($apiKey, $demoMode); - $configuredOrigins = $this->managementApiHelper->getAllowedOrigins($managementApiService); + $apiKey = $this->getFieldsetDataValue('api_key_' . $environment); + $client = $this->managementApiHelper->getAdyenApiClient($apiKey, $demoMode); + $service = $this->managementApiHelper->getMyAPICredentialApi($client); + $configuredOrigins = $this->managementApiHelper->getAllowedOrigins($service); - $domain = $this->baseUrlHelper->getDomainFromUrl($this->url->getBaseUrl()); - if (!in_array($domain, $configuredOrigins)) { - $managementApiService = $this->managementApiHelper->getManagementApiService($apiKey, $demoMode); - $this->managementApiHelper->saveAllowedOrigin($managementApiService, $domain); - } + $domain = $this->baseUrlHelper->getDomainFromUrl($this->url->getBaseUrl()); + if (!in_array($domain, $configuredOrigins)) { + $this->managementApiHelper->saveAllowedOrigin($service, $domain); } - return parent::beforeSave(); } } diff --git a/Model/Config/Backend/WebhookCredentials.php b/Model/Config/Backend/WebhookCredentials.php index 77f0d9e95..8a3ca5b51 100644 --- a/Model/Config/Backend/WebhookCredentials.php +++ b/Model/Config/Backend/WebhookCredentials.php @@ -10,12 +10,15 @@ namespace Adyen\Payment\Model\Config\Backend; +use Adyen\AdyenException; use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\ManagementHelper; +use Adyen\Service\Management\WebhooksMerchantLevelApi; use Magento\Framework\App\Cache\TypeListInterface; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Config\Value; use Magento\Framework\Data\Collection\AbstractDb; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Model\Context; use Magento\Framework\Model\ResourceModel\AbstractResource; use Magento\Framework\Registry; @@ -26,17 +29,30 @@ class WebhookCredentials extends Value /** * @var ManagementHelper */ - private $managementApiHelper; + private ManagementHelper $managementApiHelper; + /** * @var Config */ - private $configHelper; + private Config $configHelper; /** * @var UrlInterface */ - private $url; + private UrlInterface $url; + /** + * @param Context $context + * @param Registry $registry + * @param ScopeConfigInterface $config + * @param TypeListInterface $cacheTypeList + * @param ManagementHelper $managementApiHelper + * @param Config $configHelper + * @param UrlInterface $url + * @param AbstractResource|null $resource + * @param AbstractDb|null $resourceCollection + * @param array $data + */ public function __construct( Context $context, Registry $registry, @@ -55,7 +71,12 @@ public function __construct( parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); } - public function beforeSave() + /** + * @return WebhookCredentials + * @throws AdyenException + * @throws NoSuchEntityException + */ + public function beforeSave(): WebhookCredentials { if ($this->getFieldsetDataValue('configuration_mode') === 'auto' && $this->getFieldsetDataValue('create_new_webhook') === '1') { @@ -72,15 +93,16 @@ public function beforeSave() $apiKey = $this->configHelper->getApiKey($environment); } $merchantAccount = $this->getFieldsetDataValue('merchant_account_auto'); + $client = $this->managementApiHelper->getAdyenApiClient($apiKey, $isDemoMode); + $service = new WebhooksMerchantLevelApi($client); - $managementApiService = $this->managementApiHelper->getManagementApiService($apiKey, $isDemoMode); $this->managementApiHelper->setupWebhookCredentials( $merchantAccount, $username, $password, $webhookUrl, $isDemoMode, - $managementApiService + $service ); } diff --git a/Plugin/PaymentVaultDeleteToken.php b/Plugin/PaymentVaultDeleteToken.php index 1712b1e02..2daeac50d 100644 --- a/Plugin/PaymentVaultDeleteToken.php +++ b/Plugin/PaymentVaultDeleteToken.php @@ -3,7 +3,7 @@ * * Adyen Payment module (https://www.adyen.com/) * - * Copyright (c) 2023 Adyen N.V. (https://www.adyen.com/) + * Copyright (c) 2024 Adyen N.V. (https://www.adyen.com/) * See LICENSE.txt for license details. * * Author: Adyen @@ -12,6 +12,7 @@ namespace Adyen\Payment\Plugin; use Adyen\AdyenException; +use Adyen\Model\Recurring\DisableRequest; use Adyen\Client; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Requests; @@ -24,12 +25,38 @@ class PaymentVaultDeleteToken { + /** + * @var StoreManagerInterface + */ protected StoreManagerInterface $storeManager; + + /** + * @var Data + */ protected Data $dataHelper; + + /** + * @var AdyenLogger + */ protected AdyenLogger $adyenLogger; + + /** + * @var Requests + */ protected Requests $requestsHelper; + + /** + * @var Vault + */ protected Vault $vaultHelper; + /** + * @param StoreManagerInterface $storeManager + * @param Data $dataHelper + * @param AdyenLogger $adyenLogger + * @param Requests $requestsHelper + * @param Vault $vaultHelper + */ public function __construct( StoreManagerInterface $storeManager, Data $dataHelper, @@ -60,15 +87,18 @@ public function beforeDelete(PaymentTokenRepositoryInterface $subject, PaymentTo try { $client = $this->dataHelper->initializeAdyenClient($storeId); - $recurringService = $this->dataHelper->createAdyenRecurringService($client); + $recurringService = $this->dataHelper->initializeRecurringApi($client); $this->dataHelper->logRequest( $request, Client::API_RECURRING_VERSION, sprintf("/pal/servlet/Recurring/%s/disable", Client::API_RECURRING_VERSION) ); - $response = $recurringService->disable($request); - $this->dataHelper->logResponse($response); + + $response = $recurringService->disable(new DisableRequest($request)); + + $responseData = $response->toArray(); + $this->dataHelper->logResponse($responseData); } catch (AdyenException $e) { $this->adyenLogger->error(sprintf( 'Error while attempting to disable token with id %s: %s', diff --git a/Test/Unit/Controller/Adminhtml/Configuration/MerchantAccountsTest.php b/Test/Unit/Controller/Adminhtml/Configuration/MerchantAccountsTest.php new file mode 100644 index 000000000..37b7a8379 --- /dev/null +++ b/Test/Unit/Controller/Adminhtml/Configuration/MerchantAccountsTest.php @@ -0,0 +1,64 @@ +createMock(RequestInterface::class); + $requestMock->expects($this->exactly(2)) + ->method('getParam') + ->withConsecutive(['apiKey', ''], ['demoMode']) + ->willReturnOnConsecutiveCalls($apiKey, $demoMode); + + $contextMock = $this->createConfiguredMock(Context::class, + [ + 'getRequest' => $requestMock + ] + ); + + $accountMerchantLevelApiMock = $this->createMock(AccountMerchantLevelApi::class); + $myAPICredentialApiMock = $this->createMock(MyAPICredentialApi::class); + $managementHelperMock = $this->createConfiguredMock(ManagementHelper::class,[ + 'getAccountMerchantLevelApi' => $accountMerchantLevelApiMock, + 'getMyAPICredentialApi' => $myAPICredentialApiMock, + 'getMerchantAccountsAndClientKey' => [ + 'merchantAccounts' => [], + 'clientKey' => '123', + 'currentMerchantAccount' => 'MerchantAccount1' + ] + ]); + + $result = $this->createConfiguredMock(Json::class, []); + $resultJsonFactoryMock = $this->createConfiguredMock(JsonFactory::class, [ + 'create' => $result + ]); + + $result->expects($this->once())->method('setData')->with([ + 'merchantAccounts' => [], + 'clientKey' => '123', + 'currentMerchantAccount' => 'MerchantAccount1' + ]); + + $merchantAccountsController = new MerchantAccounts( + $contextMock, + $managementHelperMock, + $resultJsonFactoryMock + ); + + $merchantAccountsController->execute(); + } +} diff --git a/Test/Unit/Controller/Adminhtml/Configuration/WebhookTestTest.php b/Test/Unit/Controller/Adminhtml/Configuration/WebhookTestTest.php new file mode 100644 index 000000000..ec9b7ec47 --- /dev/null +++ b/Test/Unit/Controller/Adminhtml/Configuration/WebhookTestTest.php @@ -0,0 +1,78 @@ +contextMock = $this->createMock(Context::class); + $this->managementHelper = $this->createMock(ManagementHelper::class); + $this->resultJsonFactoryMock = $this->createMock(JsonFactory::class); + $this->storeManagerMock = $this->createMock(StoreManager::class); + $this->configHelperMock = $this->createMock(Config::class); + + $objectManager = new ObjectManager($this); + $this->webhookTestController = $objectManager->getObject( + WebhookTest::class, + [ + 'context' => $this->contextMock, + 'managementApiHelper' => $this->managementHelper, + 'resultJsonFactory' => $this->resultJsonFactoryMock, + 'storeManager' => $this->storeManagerMock, + 'configHelper' => $this->configHelperMock + ] + ); + } + + public function testExecuteSuccess() + { + // Arrange + $storeId = 1; + $merchantAccount = 'TestMerchantAccount'; + $webhookId = 'TestWebhookId'; + $isDemoMode = true; + $apiKey = 'TestApiKey'; + $response = ['success' => true]; + + $store = $this->createMock(Store::class); + $this->storeManagerMock->method('getStore')->willReturn($store); + $this->configHelperMock->method('getMerchantAccount')->willReturn($merchantAccount); + $this->configHelperMock->method('getWebhookId')->willReturn($webhookId); + $this->configHelperMock->method('isDemoMode')->willReturn($isDemoMode); + $this->configHelperMock->method('getApiKey')->willReturn($apiKey); + $client = $this->createMock(Client::class); + $service = $this->createConfiguredMock(WebhooksMerchantLevelApi::class, [ + 'testWebhook' => new TestWebhookResponse(['status'=>'success']) + ]); + $this->managementHelper->method('getAdyenApiClient')->willReturn($client); + $this->managementHelper->method('getWebhooksMerchantLevelApi')->willReturn($service); + $resultJsonMock = $this->createMock(\Magento\Framework\Controller\Result\Json::class); + $resultJsonMock->expects($this->once())->method('setData')->willReturn($resultJsonMock); + $this->resultJsonFactoryMock->method('create')->willReturn($resultJsonMock); + // Act + $result = $this->webhookTestController->execute(); + // Assert + $this->assertSame($resultJsonMock, $result); + } +} diff --git a/Test/Unit/Gateway/Http/Client/TransactionCancelTest.php b/Test/Unit/Gateway/Http/Client/TransactionCancelTest.php new file mode 100644 index 000000000..f0fcbd35f --- /dev/null +++ b/Test/Unit/Gateway/Http/Client/TransactionCancelTest.php @@ -0,0 +1,137 @@ +adyenHelperMock = $this->createMock(Data::class); + + $this->idempotencyHelperMock = $this->createMock(Idempotency::class); + $this->transferObjectMock = $this->createMock(TransferInterface::class); + $this->clientMock = $this->createMock(Client::class); + $this->checkoutServiceMock = $this->createMock(Checkout\ModificationsApi::class); + $this->transferObjectMock->method('getClientConfig')->willReturn([]); + $this->checkoutServiceMock + ->method('cancelAuthorisedPaymentByPspReference') + ->willReturn(new PaymentCancelResponse(['status' => 'received'])); + $this->transactionCancel = new TransactionCancel( + $this->adyenHelperMock, + $this->idempotencyHelperMock + ); + } + + public function testSuccessfulCancellation() + { + // Arrange + $requestBody = [ + [ + 'merchantAccount' => 'TestMerchantAccount', + 'originalReference' => 'TestOriginalReference', + 'paymentPspReference' => 'paymentPspReference' + ] + ]; + $this->transferObjectMock->method('getBody')->willReturn($requestBody); + $this->transferObjectMock->method('getHeaders')->willReturn([]); + $this->transferObjectMock->method('getClientConfig')->willReturn([]); + $this->adyenHelperMock->method('initializeAdyenClientWithClientConfig')->willReturn($this->clientMock); + $this->adyenHelperMock->method('initializeModificationsApi')->willReturn($this->checkoutServiceMock); + $this->adyenHelperMock->method('buildRequestHeaders')->willReturn(['x-api-key' => 'test_key']); + + $expectedResult = ['status' => 'received']; + + // Act + $result = $this->transactionCancel->placeRequest($this->transferObjectMock); + + // Assert + $this->assertEquals($expectedResult, $result); + } + + public function testCancellationWithAdyenApiException() + { + // Arrange + $requestBody = [ + [ + 'merchantAccount' => 'TestMerchantAccount', + 'originalReference' => 'TestOriginalReference', + 'paymentPspReference' => 'paymentPspReference' + ] + ]; + $this->transferObjectMock->method('getBody')->willReturn($requestBody); + + $this->adyenHelperMock->method('initializeAdyenClientWithClientConfig')->willReturn($this->clientMock); + $this->adyenHelperMock->method('initializeModificationsApi')->willReturn($this->checkoutServiceMock); + $this->adyenHelperMock->method('buildRequestHeaders')->willReturn(['x-api-key' => 'test_key']); + + // Simulate Adyen API exception + $this->checkoutServiceMock->method('cancelAuthorisedPaymentByPspReference')->willThrowException(new AdyenException('API exception')); + + // Act + $result = $this->transactionCancel->placeRequest($this->transferObjectMock); + + // Assert + $this->assertSame($result, ['error' => 'API exception']); + } + + public function testCancellationWithMultipleRequests() + { + // Arrange + $requestBody = [ + [ + 'merchantAccount' => 'TestMerchantAccount1', + 'originalReference' => 'TestOriginalReference1', + 'paymentPspReference' => 'paymentPspReference1' + ], + [ + 'merchantAccount' => 'TestMerchantAccount2', + 'originalReference' => 'TestOriginalReference2', + 'paymentPspReference' => 'paymentPspReference2' + ] + ]; + $this->transferObjectMock->method('getBody')->willReturn($requestBody); + $this->transferObjectMock->method('getHeaders')->willReturn([]); + $this->transferObjectMock->method('getClientConfig')->willReturn([]); + + $this->adyenHelperMock->method('initializeAdyenClientWithClientConfig')->willReturn($this->clientMock); + $this->adyenHelperMock->method('initializeModificationsApi')->willReturn($this->checkoutServiceMock); + $this->adyenHelperMock->method('buildRequestHeaders')->willReturn(['x-api-key' => 'test_key']); + + $expectedResults = ['status' => 'received']; + + // Act + $results = $this->transactionCancel->placeRequest($this->transferObjectMock); + + // Assert + $this->assertEquals($expectedResults, $results); + } + + public function testCancellationWithEmptyRequestArray() + { + // Arrange + $requestBody = []; + $this->transferObjectMock->method('getBody')->willReturn($requestBody); + + // Act + $result = $this->transactionCancel->placeRequest($this->transferObjectMock); + + // Assert + $this->assertEmpty($result); + } +} \ No newline at end of file diff --git a/Test/Unit/Gateway/Http/Client/TransactionCaptureTest.php b/Test/Unit/Gateway/Http/Client/TransactionCaptureTest.php index 4c161dda7..a8bf1750c 100644 --- a/Test/Unit/Gateway/Http/Client/TransactionCaptureTest.php +++ b/Test/Unit/Gateway/Http/Client/TransactionCaptureTest.php @@ -2,7 +2,11 @@ namespace Adyen\Payment\Test\Unit\Gateway\Http\Client; +use Adyen\Client; +use Adyen\Model\Checkout\PaymentCaptureRequest; +use Adyen\Model\Checkout\PaymentCaptureResponse; use Adyen\Payment\Gateway\Http\Client\TransactionCapture; +use Adyen\Payment\Model\Order\Payment; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Adyen\Service\Checkout; use Magento\Payment\Gateway\Http\TransferInterface; @@ -10,15 +14,14 @@ use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Helper\Data; use Adyen\AdyenException; -use PHPUnit\Framework\MockObject\MockObject; class TransactionCaptureTest extends AbstractAdyenTestCase { - private TransactionCapture $transactionCapture; - private TransferInterface|MockObject $transferObject; - private array $request; - private Data|MockObject $adyenHelper; - private Idempotency|MockObject $idempotencyHelper; + private $transactionCapture; + private $transferObject; + private $request; + private $adyenHelper; + private $idempotencyHelper; protected function setUp(): void { @@ -44,17 +47,16 @@ protected function setUp(): void ]); } - private function configureAdyenMocks(array $response = null, \Exception $exception = null) + private function configureAdyenMocks(array $response = null, \Exception $exception = null): void { - $adyenClient = $this->createMock(\Adyen\Client::class); - $adyenService = $this->createMock(Checkout::class); + $adyenClient = $this->createMock(Client::class); + $checkoutModificationsService = $this->createMock(Checkout\ModificationsApi::class); $expectedIdempotencyKey = 'generated_idempotency_key'; $this->adyenHelper->method('initializeAdyenClientWithClientConfig')->willReturn($adyenClient); - $this->adyenHelper->method('createAdyenCheckoutService')->willReturn($adyenService); + $this->adyenHelper->method('initializeModificationsApi')->willReturn($checkoutModificationsService); $this->adyenHelper->method('buildRequestHeaders')->willReturn([]); $this->adyenHelper->expects($this->once())->method('logRequest'); - $this->adyenHelper->expects($this->once())->method('logResponse'); $this->idempotencyHelper->expects($this->once()) ->method('generateIdempotencyKey') @@ -65,32 +67,31 @@ private function configureAdyenMocks(array $response = null, \Exception $excepti ->willReturn($expectedIdempotencyKey); if ($response) { - $adyenService->expects($this->once()) - ->method('captures') + $this->adyenHelper->expects($this->once())->method('logResponse'); + + $request = new PaymentCaptureRequest($this->request); + + $responseMock = $this->createMock(PaymentCaptureResponse::class); + $responseMock->method('toArray')->willReturn($response); + + $requestOptions['idempotencyKey'] = $expectedIdempotencyKey; + $requestOptions['headers'] = []; + + $checkoutModificationsService->expects($this->once()) + ->method('captureAuthorisedPayment') ->with( - $this->equalTo($this->request), - $this->callback(function ($requestOptions) use ($expectedIdempotencyKey) { - return isset($requestOptions['idempotencyKey']) && - $requestOptions['idempotencyKey'] === $expectedIdempotencyKey; - }) + $this->request['paymentPspReference'], + $request, + $requestOptions ) - ->willReturn($response); + ->willReturn($responseMock); } if ($exception) { - $adyenService->expects($this->once()) - ->method('captures') - ->with( - $this->equalTo($this->request), - $this->callback(function ($requestOptions) use ($expectedIdempotencyKey) { - return isset($requestOptions['idempotencyKey']) && - $requestOptions['idempotencyKey'] === $expectedIdempotencyKey; - }) - ) + $checkoutModificationsService->expects($this->once()) + ->method('captureAuthorisedPayment') ->willThrowException($exception); } - - return $adyenService; } public function testPlaceRequest() diff --git a/Test/Unit/Gateway/Http/Client/TransactionPaymentTest.php b/Test/Unit/Gateway/Http/Client/TransactionPaymentTest.php index 5e97e1b38..56ddcde0d 100644 --- a/Test/Unit/Gateway/Http/Client/TransactionPaymentTest.php +++ b/Test/Unit/Gateway/Http/Client/TransactionPaymentTest.php @@ -11,10 +11,11 @@ namespace Adyen\Payment\Test\Unit\Gateway\Http\Client; +use Adyen\Model\Checkout\PaymentRequest; use Adyen\Payment\Api\Data\PaymentResponseInterface; use Adyen\Payment\Model\PaymentResponse; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; -use Adyen\Service\Checkout; +use Adyen\Service\Checkout\PaymentsApi; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Adyen\Payment\Helper\Data; use Adyen\Payment\Model\PaymentResponseFactory; @@ -22,6 +23,7 @@ use Adyen\Payment\Helper\Idempotency; use Adyen\Payment\Helper\OrdersApi; use Adyen\Payment\Gateway\Http\Client\TransactionPayment; +use Magento\Store\Api\Data\StoreInterface; use Magento\Store\Model\StoreManagerInterface; use Adyen\Payment\Helper\GiftcardPayment; use Magento\Payment\Gateway\Http\TransferInterface; @@ -98,12 +100,12 @@ public function testPlaceRequestGeneratesIdempotencyKey() ) ->willReturn($expectedIdempotencyKey); - $mockedPaymentResponse = [ + $paymentResponse = new \Adyen\Model\Checkout\PaymentResponse([ 'reference' => 'ABC12345', 'amount' => ['value' => 100], 'resultCode' => 'Authorised' - ]; - $serviceMock = $this->createMock(Checkout::class); + ]); + $serviceMock = $this->createMock(PaymentsApi::class); $serviceMock->expects($this->once()) ->method('payments') ->with( @@ -113,9 +115,9 @@ public function testPlaceRequestGeneratesIdempotencyKey() $requestOptions['idempotencyKey'] === $expectedIdempotencyKey; }) ) - ->willReturn($mockedPaymentResponse); + ->willReturn($paymentResponse); - $this->adyenHelperMock->method('createAdyenCheckoutService')->willReturn($serviceMock); + $this->adyenHelperMock->method('initializePaymentsApi')->willReturn($serviceMock); $response = $this->transactionPayment->placeRequest($transferObjectMock); @@ -125,7 +127,7 @@ public function testPlaceRequestGeneratesIdempotencyKey() public function testRequestHeadersAreAddedToPaymentsCall() { - $requestBody = ['reference' => 'ABC12345', 'amount' => ['value' => 1000]]; + $requestBody = new PaymentRequest(['reference' => 'ABC12345', 'amount' => ['value' => 1000]]); $expectedHeaders = ['header1' => 'value1', 'header2' => 'value2']; $transferObjectMock = $this->createConfiguredMock(TransferInterface::class, [ @@ -140,14 +142,13 @@ public function testRequestHeadersAreAddedToPaymentsCall() $actualHeaders = $this->adyenHelperMock->buildRequestHeaders(); - - $mockedPaymentResponse = [ + $paymentResponse = new \Adyen\Model\Checkout\PaymentResponse([ 'reference' => 'ABC12345', 'amount' => ['value' => 100], 'resultCode' => 'Authorised' - ]; + ]); - $serviceMock = $this->createMock(Checkout::class); + $serviceMock = $this->createMock(PaymentsApi::class); $serviceMock->expects($this->once()) ->method('payments') ->with( @@ -156,9 +157,9 @@ public function testRequestHeadersAreAddedToPaymentsCall() return isset($requestOptions['headers']) && $requestOptions['headers'] === $expectedHeaders; }) ) - ->willReturn($mockedPaymentResponse); + ->willReturn($paymentResponse); - $this->adyenHelperMock->method('createAdyenCheckoutService')->willReturn($serviceMock); + $this->adyenHelperMock->method('initializePaymentsApi')->willReturn($serviceMock); $response = $this->transactionPayment->placeRequest($transferObjectMock); @@ -166,4 +167,72 @@ public function testRequestHeadersAreAddedToPaymentsCall() $this->assertEquals('Authorised', $response['resultCode']); $this->assertEquals($expectedHeaders, $actualHeaders); } + + public function testProcessGiftCardsWithNoGiftCards() + { + $originalRequest = ['amount' => ['value' => 150, 'currency' => 'EUR']]; + $service = $this->createMock(PaymentsApi::class); + list($request, $giftcardResponse) = $this->transactionPayment->processGiftcards($originalRequest, $service); + + $this->assertEquals($request, $originalRequest); + $this->assertNull($giftcardResponse); + } + + public function testProcessGiftCardsWithGiftCards() + { + $amount = 250; + $store = $this->createConfiguredMock(StoreInterface::class, [ + 'getId' => 12 + ]); + $this->storeManagerMock->method('getStore')->willReturn($store); + $originalRequest = [ + 'reference' => '0000020', + 'giftcardRequestParameters' => [ + [ + 'state_data' => '{"paymentMethod":{"type": "giftcard"}, "giftcard": {"balance": {"value": 100}, "currency": "EUR"}}'], + [ + 'state_data' => '{"paymentMethod":{"type": "giftcard"}, "giftcard": {"balance": {"value": 50}, "currency": "EUR"}}' + ] + ], + 'amount' => [ + 'value' => $amount, + 'currency' => 'EUR' + ] + ]; + $response = new \Adyen\Model\Checkout\PaymentResponse(); + $response->setResultCode('Authorised'); + $response->setMerchantReference('PSPDMDM2222'); + $serviceMock = $this->createMock(PaymentsApi::class); + $serviceMock->expects($this->exactly(2)) + ->method('payments') + ->with( + $this->callback(function (PaymentRequest $detailsRequest) { + return true; + }), + )->willReturn($response); + $reflector = new \ReflectionProperty(TransactionPayment::class, 'remainingOrderAmount'); + $reflector->setAccessible(true); + $reflector->setValue($this->transactionPayment, $amount); + $orderData = [ + 'pspReference' => 'pspReference!23', + 'orderData' => 'orderData....' + ]; + $this->orderApiHelperMock + ->expects($this->once()) + ->method('createOrder') + ->willReturn($orderData); + + list($request, $giftCardResponse) = $this->transactionPayment->processGiftcards($originalRequest, $serviceMock); + $this->assertEquals( + $request, + [ + 'reference' => '0000020', + 'amount' => [ + 'value' => 100, + 'currency' => 'EUR' + ], + 'order' => $orderData + ] + ); + } } diff --git a/Test/Unit/Gateway/Http/Client/TransactionRefundTest.php b/Test/Unit/Gateway/Http/Client/TransactionRefundTest.php index d5499766c..3d9882599 100644 --- a/Test/Unit/Gateway/Http/Client/TransactionRefundTest.php +++ b/Test/Unit/Gateway/Http/Client/TransactionRefundTest.php @@ -12,11 +12,13 @@ namespace Adyen\Payment\Test\Unit\Gateway\Http\Client; use Adyen\Client; +use Adyen\Model\Checkout\PaymentRefundRequest; +use Adyen\Model\Checkout\PaymentRefundResponse; use Adyen\Payment\Gateway\Http\Client\TransactionRefund; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Idempotency; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; -use Adyen\Service\Checkout; +use Adyen\Service\Checkout\ModificationsApi; use Magento\Payment\Gateway\Http\TransferInterface; use PHPUnit\Framework\MockObject\MockObject; @@ -63,11 +65,11 @@ public function testPlaceRequestIncludesHeadersInRequest() 'getClientConfig' => [] ]); - $checkoutServiceMock = $this->createMock(Checkout::class); + $serviceMock = $this->createMock(ModificationsApi::class); $adyenClientMock = $this->createMock(Client::class); $this->adyenHelperMock->method('initializeAdyenClientWithClientConfig')->willReturn($adyenClientMock); - $this->adyenHelperMock->method('createAdyenCheckoutService')->willReturn($checkoutServiceMock); + $this->adyenHelperMock->method('initializeModificationsApi')->willReturn($serviceMock); $this->adyenHelperMock->method('buildRequestHeaders')->willReturn(['custom-header' => 'value']); $this->idempotencyHelperMock->expects($this->once()) @@ -75,10 +77,15 @@ public function testPlaceRequestIncludesHeadersInRequest() ->with($requestBody, $headers['idempotencyExtraData']) ->willReturn('generated_idempotency_key'); - $checkoutServiceMock->expects($this->once()) - ->method('refunds') + $serviceMock->expects($this->once()) + ->method('refundCapturedPayment') ->with( - $this->equalTo($requestBody), + $this->equalTo($requestBody['paymentPspReference']), + $this->callback(function (PaymentRefundRequest $paymentRefundRequest) { + $amount = $paymentRefundRequest->getAmount(); + $this->assertEquals($amount,['value' => 1000, 'currency' => 'EUR']); + return true; + }), $this->callback(function ($requestOptions) { $this->assertArrayHasKey('idempotencyKey', $requestOptions); $this->assertArrayHasKey('headers', $requestOptions); @@ -87,7 +94,7 @@ public function testPlaceRequestIncludesHeadersInRequest() return true; }) ) - ->willReturn(['pspReference' => 'refund_psp_reference']); + ->willReturn(new PaymentRefundResponse(['pspReference' => 'refund_psp_reference'])); $responses = $this->transactionRefund->placeRequest($transferObjectMock); diff --git a/Test/Unit/Helper/DataTest.php b/Test/Unit/Helper/DataTest.php index cb7a21137..81e1836ef 100755 --- a/Test/Unit/Helper/DataTest.php +++ b/Test/Unit/Helper/DataTest.php @@ -10,7 +10,9 @@ namespace Adyen\Payment\Test\Unit\Helper; +use Adyen\AdyenException; use Adyen\Client; +use Adyen\Config as AdyenConfig; use Adyen\Payment\Gateway\Request\HeaderDataBuilder; use Adyen\Payment\Helper\Config as ConfigHelper; use Adyen\Payment\Helper\Data; @@ -21,6 +23,10 @@ use Adyen\Payment\Model\ResourceModel\Notification\CollectionFactory as NotificationCollectionFactory; use Adyen\Payment\Observer\AdyenPaymentMethodDataAssignObserver; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Adyen\Service\Checkout\ModificationsApi; +use Adyen\Service\Checkout\OrdersApi; +use Adyen\Service\Checkout\PaymentsApi; +use Adyen\Service\RecurringApi; use Magento\Backend\Helper\Data as BackendHelper; use Magento\Customer\Helper\Address; use Magento\Directory\Model\Config\Source\Country; @@ -41,16 +47,14 @@ use Magento\Sales\Api\OrderManagementInterface; use Magento\Sales\Model\Order\Payment; use Magento\Sales\Model\Order\Status\HistoryFactory; +use Magento\Store\Model\Store; use Magento\Store\Model\StoreManager; use Magento\Tax\Model\Calculation; use Magento\Tax\Model\Config; use Magento\Sales\Model\Order; -use Magento\Framework\View\Asset\File; use ReflectionClass; -use Adyen\Service\Recurring; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; - class DataTest extends AbstractAdyenTestCase { /** @@ -58,8 +62,35 @@ class DataTest extends AbstractAdyenTestCase */ private $dataHelper; + private $clientMock; + private $adyenLogger; + private $ccTypesAltData; + private $configHelper; + private $objectManager; + private $store; + private $encryptor; + private $dataStorage; + private $assetRepo; + private $assetSource; + private $taxConfig; + private $taxCalculation; + private $backendHelper; + private $storeManager; + private $cache; + private $localeResolver; + private $config; + private $componentRegistrar; + private $localeHelper; + private $orderManagement; + private $orderStatusHistoryFactory; + public function setUp(): void { + $this->clientMock = $this->createConfiguredMock(Client::class, [ + 'getConfig' => new AdyenConfig(['environment' => 'test']) + ] + ); + // Prepare mock data for ccTypesAltData $this->ccTypesAltData = [ 'VI' => ['code_alt' => 'VI', 'code' => 'VI'], @@ -71,9 +102,10 @@ public function setUp(): void 'demo_mode' => '1' ] ]); + $this->objectManager = new ObjectManager($this); $context = $this->createMock(Context::class); - $this->store = $this->createMock(\Magento\Store\Model\Store::class); + $this->store = $this->createMock(Store::class); $this->encryptor = $this->createMock(EncryptorInterface::class); $this->dataStorage = $this->createMock(DataInterface::class); $country = $this->createMock(Country::class); @@ -91,6 +123,7 @@ public function setUp(): void ]); $this->adyenLogger = $this->createMock(AdyenLogger::class); $this->storeManager = $this->createMock(StoreManager::class); + $this->storeManager->method('getStore')->willReturn($this->store); $this->cache = $this->createMock(CacheInterface::class); $this->localeResolver = $this->createMock(ResolverInterface::class); $this->config = $this->createMock(ScopeConfigInterface::class); @@ -1365,8 +1398,9 @@ public function testGetOrigin() { $storeId = 1; $expectedBaseUrl = 'https://example.com/'; + $stateMock = $this->createMock(State::class); - $storeMock = $this->createMock(\Magento\Store\Model\Store::class); + $objectManagerStub = $this->createMock(\Magento\Framework\App\ObjectManager::class); $objectManagerStub->method('get')->willReturnMap([ [State::class, $stateMock] @@ -1379,13 +1413,8 @@ public function testGetOrigin() ->with('payment_origin_url', $storeId) ->willReturn(''); - // Mock the store manager to return the store mock - $this->storeManager->expects($this->once()) - ->method('getStore') - ->willReturn($storeMock); - // Mock the store to return the expected base URL - $storeMock->expects($this->once()) + $this->store->expects($this->once()) ->method('getBaseUrl') ->with(UrlInterface::URL_TYPE_WEB) ->willReturn($expectedBaseUrl); @@ -1446,7 +1475,7 @@ public function testGetAdyenMerchantAccountForAdyenPaymentMethod() $merchantAccount = 'mock_merchant_account'; // Mock the store manager and config helper - $storeMock = $this->createMock(\Magento\Store\Model\Store::class); + $storeMock = $this->createMock(Store::class); $storeMock->expects($this->any()) ->method('getId') ->willReturn($storeId); @@ -1476,7 +1505,7 @@ public function testGetAdyenMerchantAccountForAdyenPosCloudPaymentMethod() $merchantAccountPos = 'mock_pos_merchant_account'; // Mock the store manager and config helper - $storeMock = $this->createMock(\Magento\Store\Model\Store::class); + $storeMock = $this->createMock(Store::class); $storeMock->expects($this->any()) ->method('getId') ->willReturn($storeId); @@ -1715,4 +1744,119 @@ public function testCreateOpenInvoiceLineShipping() $this->assertArrayHasKey('openinvoicedata.line1.itemId', $result); $this->assertEquals("shippingCost", $result['openinvoicedata.line1.itemId']); } + + /** + * @test + */ + public function getRecurringTypesShouldReturnAnArrayOfRecurringTypes() + { + $this->assertEquals([ + RecurringType::ONECLICK => 'ONECLICK', + RecurringType::ONECLICK_RECURRING => 'ONECLICK,RECURRING', + RecurringType::RECURRING => 'RECURRING' + ], $this->dataHelper->getRecurringTypes()); + } + + public function getCheckoutFrontendRegionsShouldReturnAnArray() + { + $this->assertEquals([ + 'eu' => 'Default (EU - Europe)', + 'au' => 'AU - Australasia', + 'us' => 'US - United States', + 'in' => 'IN - India' + ], $this->dataHelper->getRecurringTypes()); + } + + public function testGetClientKey() + { + $expectedValue = 'client_key_test_value'; + $storeId = 1; + + $this->configHelper->method('isDemoMode') + ->with($storeId) + ->willReturn(true); + + $this->configHelper->method('getAdyenAbstractConfigData') + ->with('client_key_test', $storeId) + ->willReturn($expectedValue); + + $key = $this->dataHelper->getClientKey(1); + $this->assertEquals($expectedValue, $key); + } + + public function testGetApiKey() + { + $apiKey = 'api_key_test_value'; + $expectedValue = 'api_key_test_decryted_value'; + $storeId = 1; + + $this->configHelper->method('isDemoMode') + ->with($storeId) + ->willReturn(true); + + $this->configHelper->method('getAdyenAbstractConfigData') + ->with('api_key_test', $storeId) + ->willReturn($apiKey); + + $this->encryptor->method('decrypt') + ->with($apiKey) + ->willReturn($expectedValue); + + $key = $this->dataHelper->getAPIKey(1); + $this->assertEquals($expectedValue, $key); + } + + public function testIsDemoMode() + { + $storeId = 1; + $this->configHelper->method('getAdyenAbstractConfigDataFlag') + ->with('demo_mode', $storeId) + ->willReturn(true); + + $value = $this->dataHelper->isDemoMode($storeId); + + $this->assertEquals(true, $value); + } + + public function testCaptureModes() + { + $this->assertSame( + [ + 'auto' => 'Immediate', + 'manual' => 'Manual' + ], + $this->dataHelper->getCaptureModes() + ); + } + + public function testInitializePaymentsApi() + { + $service = $this->dataHelper->initializePaymentsApi($this->clientMock); + $this->assertInstanceOf(PaymentsApi::class, $service); + } + + public function testInitializeModificationsApi() + { + $service = $this->dataHelper->initializeModificationsApi($this->clientMock); + $this->assertInstanceOf(ModificationsApi::class, $service); + } + + public function testInitializeRecurringApi() + { + $service = $this->dataHelper->initializeRecurringApi($this->clientMock); + $this->assertInstanceOf(RecurringApi::class, $service); + } + + public function testInitializeOrdersApi() + { + $service = $this->dataHelper->initializeOrdersApi($this->clientMock); + $this->assertInstanceOf(OrdersApi::class, $service); + } + + public function testLogAdyenException() + { + $this->store->method('getId')->willReturn(1); + $this->adyenLogger->expects($this->once())->method('info'); + $this->dataHelper->logAdyenException(new AdyenException('error message', 123)); + } } diff --git a/Test/Unit/Helper/ManagementHelperTest.php b/Test/Unit/Helper/ManagementHelperTest.php index 028d3a577..9095f5f9d 100644 --- a/Test/Unit/Helper/ManagementHelperTest.php +++ b/Test/Unit/Helper/ManagementHelperTest.php @@ -11,18 +11,25 @@ namespace Adyen\Payment\Test\Unit\Helper; +use Adyen\AdyenException; use Adyen\Client; use Adyen\Config as HttpClientConfig; use Adyen\Environment; +use Adyen\Model\Management\AllowedOrigin; +use Adyen\Model\Management\AllowedOriginsResponse; +use Adyen\Model\Management\GenerateHmacKeyResponse; +use Adyen\Model\Management\ListMerchantResponse; +use Adyen\Model\Management\MeApiCredential; +use Adyen\Model\Management\TestWebhookResponse; +use Adyen\Model\Management\Webhook; use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\ManagementHelper; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; -use Adyen\Service\ResourceModel\Management\AllowedOrigins; -use Adyen\Service\ResourceModel\Management\Me; -use Adyen\Service\ResourceModel\Management\MerchantAccount; -use Adyen\Service\ResourceModel\Management\MerchantWebhooks; +use Adyen\Service\Management\AccountMerchantLevelApi; +use Adyen\Service\Management\MyAPICredentialApi; +use Adyen\Service\Management\WebhooksMerchantLevelApi; use Magento\Framework\Encryption\EncryptorInterface; use Magento\Framework\Message\ManagerInterface; use Magento\Store\Api\Data\StoreInterface; @@ -30,6 +37,16 @@ class ManagementHelperTest extends AbstractAdyenTestCase { + private Client $clientMock; + + public function setUp(): void + { + $this->clientMock = $this->createMock(Client::class); + $this->clientMock->expects($this->any()) + ->method('getConfig') + ->willReturn(new \Adyen\Config(['environment' => 'test'])); + } + public function testGetMerchantAccountsAndClientKey() { $merchantAccountListResponseJson = <<createConfiguredMock(StoreManager::class, [ 'getStore' => $this->createConfiguredMock(StoreInterface::class, [ @@ -169,17 +189,15 @@ public function testGetMerchantAccountsAndClientKey() ]); $managementHelper = $this->createManagementHelper($storeManagerMock, null, $dataHelperMock); - $managementApiService = $managementHelper->getManagementApiService("APIKEY", true); - - $managementApiService->merchantAccount = $this->createConfiguredMock(MerchantAccount::class, [ - 'list' => $merchantAccountListResponse + $accountMerchantLevelApi = $this->createConfiguredMock(AccountMerchantLevelApi::class, [ + 'listMerchantAccounts' => $merchantAccountListResponse ]); - $managementApiService->me = $this->createConfiguredMock(Me::class, [ - 'retrieve' => $meResponse + $myAPICredentialApi = $this->createConfiguredMock(MyAPICredentialApi::class, [ + 'getApiCredentialDetails' => $meResponse ]); - $result = $managementHelper->getMerchantAccountsAndClientKey($managementApiService); + $result = $managementHelper->getMerchantAccountsAndClientKey($accountMerchantLevelApi, $myAPICredentialApi); $this->assertArrayHasKey('currentMerchantAccount', $result); $this->assertEquals('test_abcdefg', $result['clientKey']); @@ -225,14 +243,10 @@ public function testSetupWebhookCredentialsSuccess() $configHelperMock ); - $managementApiService = $managementHelper->getManagementApiService("APIKEY", true); - $managementApiService->merchantWebhooks = $this->createConfiguredMock(MerchantWebhooks::class, [ - 'generateHmac' => [ - 'hmacKey' => "MOCK_HMAC_KEY" - ], - 'create' => [ - 'id' => 'WH-0123456789' - ] + + $service = $this->createConfiguredMock(WebhooksMerchantLevelApi::class, [ + 'setUpWebhook' => new Webhook(['id' => 'WH-0123456789']), + 'generateHmacKey' => new GenerateHmacKeyResponse(['hmacKey' => 'MOCK_HMAC_KEY']) ]); $result = $managementHelper->setupWebhookCredentials( @@ -241,12 +255,132 @@ public function testSetupWebhookCredentialsSuccess() $password, $url, $isDemoMode, - $managementApiService + $service ); $this->assertEquals('WH-0123456789', $result); } + public function testSetupWebhookCredentialsWithStoredWebhookSuccess() + { + $merchantId = 'MERCHANT_ID'; + $username = 'USERNAME'; + $password = 'PASSWORD'; + $url = 'https://www.test.store/webhook'; + $isDemoMode = true; + $webhookId = 'WH-000000000'; + + $storeManagerMock = $this->createConfiguredMock(StoreManager::class, [ + 'getStore' => $this->createConfiguredMock(StoreInterface::class, [ + 'getId' => 1 + ]) + ]); + + $encyptorMock = $this->createConfiguredMock(EncryptorInterface::class, [ + 'encrypt' => 'ENCRYPTED_VALUE' + ]); + + $dataHelperMock = $this->createConfiguredMock(Data::class, [ + 'initializeAdyenClient' => $this->createConfiguredMock(Client::class, [ + 'getConfig' => $this->createConfiguredMock(HttpClientConfig::class, [ + 'get' => Environment::TEST + ]) + ]) + ]); + + $configHelperMock = $this->createConfiguredMock(Config::class, [ + 'getWebhookId' => $webhookId, + 'getMerchantAccount' => $merchantId + ]); + + $adyenLogger = $this->createMock(AdyenLogger::class); + $adyenLogger->expects($this->never())->method('error'); + $managementHelper = $this->createManagementHelper( + $storeManagerMock, + $encyptorMock, + $dataHelperMock, + $configHelperMock, + $adyenLogger + ); + + $service = $this->createConfiguredMock(WebhooksMerchantLevelApi::class, [ + 'updateWebhook' => new Webhook(['id' => 'WH-0123456789']), + 'generateHmacKey' => new GenerateHmacKeyResponse(['hmacKey' => 'MOCK_HMAC_KEY']) + ]); + + $result = $managementHelper->setupWebhookCredentials( + $merchantId, + $username, + $password, + $url, + $isDemoMode, + $service + ); + + $this->assertEquals('WH-000000000', $result); + } + + + + public function testSetupWebhookCredentialsWithFaildGenerateHmacKey() + { + $merchantId = 'MERCHANT_ID'; + $username = 'USERNAME'; + $password = 'PASSWORD'; + $url = 'https://www.test.store/webhook'; + $isDemoMode = false; + $webhookId = 'WH-000000000'; + + $storeManagerMock = $this->createConfiguredMock(StoreManager::class, [ + 'getStore' => $this->createConfiguredMock(StoreInterface::class, [ + 'getId' => 1 + ]) + ]); + + $encyptorMock = $this->createConfiguredMock(EncryptorInterface::class, [ + 'encrypt' => 'ENCRYPTED_VALUE' + ]); + + $dataHelperMock = $this->createConfiguredMock(Data::class, [ + 'initializeAdyenClient' => $this->createConfiguredMock(Client::class, [ + 'getConfig' => $this->createConfiguredMock(HttpClientConfig::class, [ + 'get' => Environment::TEST + ]) + ]) + ]); + + $configHelperMock = $this->createConfiguredMock(Config::class, [ + 'getWebhookId' => $webhookId, + 'getMerchantAccount' => $merchantId + ]); + + $adyenLogger = $this->createMock(AdyenLogger::class); + $managementHelper = $this->createManagementHelper( + $storeManagerMock, + $encyptorMock, + $dataHelperMock, + $configHelperMock, + $adyenLogger + ); + + $service = $this->createConfiguredMock(WebhooksMerchantLevelApi::class, [ + 'updateWebhook' => new Webhook(['id' => 'WH-0123456789']) + ]); + $service->expects($this->once()) + ->method('generateHmacKey') + ->willThrowException(new \Exception('Some exception')); + + $this->expectException(\Exception::class); + $result = $managementHelper->setupWebhookCredentials( + $merchantId, + $username, + $password, + $url, + $isDemoMode, + $service + ); + } + public function testSetupWebhookCredentialsFailLive(): void { $merchantId = 'TestMerchantAccount'; @@ -286,21 +420,15 @@ public function testSetupWebhookCredentialsFailLive(): void $configHelperMock ); - $managementApiService = $managementHelper->getManagementApiService("APIKEY", true); - $managementApiService->merchantWebhooks = $this->createConfiguredMock(MerchantWebhooks::class, [ - 'generateHmac' => [ - 'hmacKey' => "MOCK_HMAC_KEY" - ], - 'create' => $this->throwException(new \Exception('Mock Service Exception')) - ]); - + $service = $this->createConfiguredMock(WebhooksMerchantLevelApi::class, []); + $service->expects($this->any())->method('setUpWebhook')->willThrowException(new \Exception('Mock Service Exception')); $resultWebhookId = $managementHelper->setupWebhookCredentials( $merchantId, $username, $password, $url, $isDemoMode, - $managementApiService + $service ); $this->assertEquals($webhookId, $resultWebhookId); @@ -352,10 +480,9 @@ public function testGetAllowedOrigins() null, $dataHelperMock ); - $managementApiService = $managementHelper->getManagementApiService("APIKEY", true); - $managementApiService->allowedOrigins = $this->createConfiguredMock(AllowedOrigins::class, [ - 'list' => json_decode($mockJsonResponse, true) + $myAPICredentialApi = $this->createConfiguredMock(MyAPICredentialApi::class, [ + 'getAllowedOrigins' => new AllowedOriginsResponse(json_decode($mockJsonResponse, true)) ]); $expectedArray = [ @@ -363,7 +490,7 @@ public function testGetAllowedOrigins() 'http://192.168.58.20' ]; - $result = $managementHelper->getAllowedOrigins($managementApiService); + $result = $managementHelper->getAllowedOrigins($myAPICredentialApi); $this->assertEquals($expectedArray, $result); } @@ -414,12 +541,12 @@ public function testWebhookTest() $configHelperMock ); - $managementApiService = $managementHelper->getManagementApiService("APIKEY", true); - $managementApiService->merchantWebhooks = $this->createConfiguredMock(MerchantWebhooks::class, [ - 'test' => json_decode($rawJsonResponse, true) + + $service = $this->createConfiguredMock(WebhooksMerchantLevelApi::class, [ + 'testWebhook' => new TestWebhookResponse(json_decode($rawJsonResponse, true)) ]); - $result = $managementHelper->webhookTest($merchantId, $webhookId, $managementApiService); + $result = $managementHelper->webhookTest($merchantId, $webhookId, $service); $success = isset($result['data']) && in_array('success', array_column($result['data'], 'status'), true); @@ -478,4 +605,67 @@ private function createManagementHelper( $messageManager ); } + + public function testSaveAllowedOrigin() + { + $helper = $this->createManagementHelper(); + $service = $this->createMock(MyAPICredentialApi::class); + $domian = 'DOMAIN'; + $service->expects($this->once())->method('addAllowedOrigin')->willReturn(new AllowedOrigin()); + $helper->saveAllowedOrigin($service, $domian); + } + + public function testWebhookTestFailure() + { + $webhookId = 'WH-000000000'; + $merchantId = 'MERCHANT_ID'; + $adyenLogger = $this->createMock(AdyenLogger::class); + $helper = $this->createManagementHelper(null,null,null,null,$adyenLogger); + $service = $this->createMock(WebhooksMerchantLevelApi::class); + $service->expects($this->once())->method('testWebhook')->willThrowException(new AdyenException()); + $adyenLogger->expects($this->never())->method('info'); + $adyenLogger->expects($this->once())->method('error'); + $helper->webhookTest($webhookId, $merchantId, $service); + } + + public function testGetAdyenApiClient() + { + $storeId = 1; + $apiKey = 'API_KEY'; + $storeManagerMock = $this->createConfiguredMock(StoreManager::class, [ + 'getStore' => $this->createConfiguredMock(StoreInterface::class, [ + 'getId' => $storeId + ]) + ]); + $configHelperMock = $this->createConfiguredMock(Config::class, [ + 'getApiKey' => $apiKey + ]); + $dataHelperMock = $this->createConfiguredMock(Data::class, [ + 'initializeAdyenClient' => $this->createConfiguredMock(Client::class,[]) + ]); + $helper = $this->createManagementHelper($storeManagerMock,null,$dataHelperMock, $configHelperMock); + $dataHelperMock + ->expects($this->once()) + ->method('initializeAdyenClient') + ->with($storeId, $apiKey); + $helper->getAdyenApiClient($apiKey, false); + } + + public function testGetAccountMerchantLevelApi() + { + $service = $this->createManagementHelper()->getAccountMerchantLevelApi($this->clientMock); + $this->assertInstanceOf(AccountMerchantLevelApi::class, $service); + } + + public function testGetMyAPICredentialApi() + { + $service = $this->createManagementHelper()->getMyAPICredentialApi($this->clientMock); + $this->assertInstanceOf(MyAPICredentialApi::class, $service); + } + + public function testWebhooksMerchantLevelApi() + { + $service = $this->createManagementHelper()->getWebhooksMerchantLevelApi($this->clientMock); + $this->assertInstanceOf(WebhooksMerchantLevelApi::class, $service); + } } diff --git a/Test/Unit/Helper/PaymentDetailsTest.php b/Test/Unit/Helper/PaymentDetailsTest.php index 7406661b4..f9ad6fd3e 100644 --- a/Test/Unit/Helper/PaymentDetailsTest.php +++ b/Test/Unit/Helper/PaymentDetailsTest.php @@ -11,6 +11,8 @@ namespace Adyen\Payment\Test\Unit\Helper; use Adyen\AdyenException; +use Adyen\Model\Checkout\PaymentDetailsRequest; +use Adyen\Model\Checkout\PaymentDetailsResponse; use Adyen\Payment\Helper\PaymentsDetails; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\Exception\ValidatorException; @@ -20,7 +22,7 @@ use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Helper\Idempotency; use Magento\Checkout\Model\Session; -use Adyen\Service\Checkout; +use Adyen\Service\Checkout\PaymentsApi; use Adyen\Client; class PaymentDetailsTest extends AbstractAdyenTestCase @@ -33,7 +35,7 @@ class PaymentDetailsTest extends AbstractAdyenTestCase private $orderMock; private $paymentMock; - private $checkoutServiceMock; + private $paymentsApiMock; private $adyenClientMock; protected function setUp(): void @@ -45,7 +47,7 @@ protected function setUp(): void $this->orderMock = $this->createMock(OrderInterface::class); $this->paymentMock = $this->createMock(Payment::class); - $this->checkoutServiceMock = $this->createMock(Checkout::class); + $this->paymentsApiMock = $this->createMock(PaymentsApi::class); $this->adyenClientMock = $this->createMock(Client::class); $this->orderMock->method('getPayment')->willReturn($this->paymentMock); @@ -53,7 +55,7 @@ protected function setUp(): void $this->paymentMock->method('getOrder')->willReturn($this->orderMock); $this->adyenHelperMock->method('initializeAdyenClient')->willReturn($this->adyenClientMock); - $this->adyenHelperMock->method('createAdyenCheckoutService')->willReturn($this->checkoutServiceMock); + $this->adyenHelperMock->method('initializePaymentsApi')->willReturn($this->paymentsApiMock); $this->paymentDetails = new PaymentsDetails( $this->checkoutSessionMock, @@ -65,9 +67,11 @@ protected function setUp(): void public function testInitiatePaymentDetailsSuccessfully() { + $serviceMock = $this->createMock(PaymentsApi::class); + $adyenClientMock = $this->createMock(Client::class); $payload = [ 'details' => [ - 'detail_key1' => 'some-details', + 'some_value' => 'some_details', 'merchantReference' => '00000000001' ], 'paymentData' => 'some_payment_data', @@ -79,7 +83,7 @@ public function testInitiatePaymentDetailsSuccessfully() 'headers' => ['headerKey' => 'headerValue'] ]; - $paymentDetailsResult = ['resultCode' => 'Authorised', 'action' => null, 'additionalData' => null]; + $paymentDetailsResult = ['resultCode' => 'Authorised']; $this->adyenHelperMock->method('buildRequestHeaders')->willReturn($requestOptions['headers']); $this->idempotencyHelperMock->method('generateIdempotencyKey')->willReturn($requestOptions['idempotencyKey']); @@ -88,10 +92,10 @@ public function testInitiatePaymentDetailsSuccessfully() $apiPayload = $payload; unset($apiPayload['details']['merchantReference']); - $this->checkoutServiceMock->expects($this->once()) + $this->paymentsApiMock->expects($this->once()) ->method('paymentsDetails') - ->with($apiPayload, $requestOptions) - ->willReturn($paymentDetailsResult); + ->with(new PaymentDetailsRequest($apiPayload), $requestOptions) + ->willReturn(new PaymentDetailsResponse($paymentDetailsResult)); $result = $this->paymentDetails->initiatePaymentDetails($this->orderMock, $payload); @@ -112,7 +116,7 @@ public function testInitiatePaymentDetailsFailure() 'threeDSAuthenticationOnly' => true, ]; - $this->checkoutServiceMock->method('paymentsDetails')->willThrowException(new AdyenException()); + $this->paymentsApiMock->method('paymentsDetails')->willThrowException(new AdyenException()); $this->adyenLoggerMock->expects($this->atLeastOnce())->method('error'); $this->checkoutSessionMock->expects($this->atLeastOnce())->method('restoreQuote'); diff --git a/Test/Unit/Helper/PaymentMethodsTest.php b/Test/Unit/Helper/PaymentMethodsTest.php index 1de373c4f..3aa38586d 100644 --- a/Test/Unit/Helper/PaymentMethodsTest.php +++ b/Test/Unit/Helper/PaymentMethodsTest.php @@ -13,6 +13,7 @@ use Adyen\Client; use Adyen\ConnectionException; +use Adyen\Model\Checkout\PaymentMethodsResponse; use Adyen\Payment\Helper\ChargedCurrency; use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Data as AdyenDataHelper; @@ -413,52 +414,13 @@ private function getPrivateMethod(string $className, string $methodName): Reflec return $method; } - public function testFetchPaymentMethodsWhenMerchantAccountEmpty() - { - $country = 'US'; - $shopperLocale = 'en_US'; - - // Invoke the private method - $fetchPaymentMethodsMethod = $this->getPrivateMethod( - PaymentMethods::class, - 'fetchPaymentMethods' - ); - - $storeId = 1; - - $this->storeMock->expects($this->any()) - ->method('getId') - ->willReturn($storeId); - - // Mock the getId method of the quote to return the quoteId - $this->quoteMock->expects($this->any()) - ->method('getStore') - ->willReturn($this->storeMock); - - $paymentMethodsHelper = $this->objectManager->getObject( - PaymentMethods::class, - [ - 'quote' => $this->quoteMock, - 'configHelper' => $this->configHelperMock, - ] - ); - - // Call the protected method with the necessary parameters - $result = $fetchPaymentMethodsMethod->invoke($paymentMethodsHelper, $country, $shopperLocale); - - // Assert the result - $this->assertIsString($result); // Ensure the result is a string - - $this->assertEquals(json_encode([]), $result); - } - public function testFetchPaymentMethodsWithEmptyResponseFromAdyenApi() { $quoteId = 1; $storeId = 1; $amountValue = 100; $adyenClientMock = $this->createMock(Client::class); - $checkoutServiceMock = $this->createMock(Checkout::class); + $checkoutServiceMock = $this->createMock(Checkout\PaymentsApi::class); // Setup test scenario $this->storeMock->expects($this->any()) ->method('getId') @@ -473,7 +435,7 @@ public function testFetchPaymentMethodsWithEmptyResponseFromAdyenApi() ->with('merchant_account', $storeId) // Ensure it's called with the expected parameters ->willReturn('mocked_merchant_account'); // Define the return value for the mocked method $this->adyenHelperMock->method('initializeAdyenClient')->willReturn($adyenClientMock); - $this->adyenHelperMock->method('createAdyenCheckoutService')->willReturn($checkoutServiceMock); + $this->adyenHelperMock->method('initializePaymentsApi')->willReturn($checkoutServiceMock); $this->amountCurrencyMock->method('getCurrencyCode')->willReturn('EUR'); $this->amountCurrencyMock->method('getAmount')->willReturn($amountValue); $this->chargedCurrencyMock->method('getQuoteAmountCurrency')->willReturn($this->amountCurrencyMock); @@ -524,7 +486,7 @@ public function testSuccessfulRetrievalOfPaymentMethods() ]; $adyenClientMock = $this->createMock(Client::class); - $checkoutServiceMock = $this->createMock(Checkout::class); + $checkoutServiceMock = $this->createMock(Checkout\PaymentsApi::class); $quoteId = 1; $storeId = 1; $amountValue = '100'; @@ -565,13 +527,15 @@ public function testSuccessfulRetrievalOfPaymentMethods() ->willReturn($paymentMethodsExtraDetails); $this->adyenHelperMock->method('initializeAdyenClient')->willReturn($adyenClientMock); + $this->adyenHelperMock->method('initializePaymentsApi')->willReturn($checkoutServiceMock); - $this->adyenHelperMock->method('createAdyenCheckoutService')->willReturn($checkoutServiceMock); + $responseMock = $this->createMock(PaymentMethodsResponse::class); + $responseMock->method('toArray')->willReturn($expectedResult); // Simulate successful API call $checkoutServiceMock->expects($this->once()) ->method('paymentMethods') - ->willReturn($expectedResult); + ->willReturn($responseMock); $this->storeMock->expects($this->any()) ->method('getId') @@ -587,14 +551,12 @@ public function testSuccessfulRetrievalOfPaymentMethods() ->with('merchant_account', $storeId) // Ensure it's called with the expected parameters ->willReturn('mocked_merchant_account'); // Define the return value for the mocked method - $this->amountCurrencyMock->method('getCurrencyCode')->willReturn('EUR'); $this->amountCurrencyMock->method('getAmount')->willReturn($amountValue); $this->chargedCurrencyMock->method('getQuoteAmountCurrency')->willReturn($this->amountCurrencyMock); $this->adyenHelperMock->expects($this->once()) - ->method('logResponse') - ->with($expectedResult); + ->method('logResponse'); $paymentMethods = $this->objectManager->getObject( PaymentMethods::class, @@ -1166,7 +1128,7 @@ public function testConnectionExceptionHandling(): void $this->storeMock->method('getId')->willReturn($storeId); $clientMock = $this->createMock(Client::class); - $checkoutServiceMock = $this->createMock(Checkout::class); + $checkoutServiceMock = $this->createMock(Checkout\PaymentsApi::class); $this->adyenHelperMock->expects($this->once()) ->method('initializeAdyenClient') @@ -1174,7 +1136,7 @@ public function testConnectionExceptionHandling(): void ->willReturn($clientMock); $this->adyenHelperMock - ->method('createAdyenCheckoutService') + ->method('initializePaymentsApi') ->with($clientMock) ->willReturn($checkoutServiceMock); diff --git a/Test/Unit/Helper/PaymentRequestTest.php b/Test/Unit/Helper/PaymentRequestTest.php index dbc965fdc..cef3fa582 100644 --- a/Test/Unit/Helper/PaymentRequestTest.php +++ b/Test/Unit/Helper/PaymentRequestTest.php @@ -12,12 +12,18 @@ namespace Adyen\Payment\Test\Unit\Helper; use Adyen\Client; +use Adyen\Model\Checkout\PaymentDetailsResponse; +use Adyen\Model\Recurring\DisableResult; +use Adyen\Model\Recurring\RecurringDetailsRequest; +use Adyen\Model\Recurring\RecurringDetailsResult; use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Data; use Adyen\Payment\Model\Api\PaymentRequest; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Adyen\Service\Checkout; +use Adyen\Service\Checkout\PaymentsApi; use Adyen\Service\Recurring; +use Adyen\Service\RecurringApi; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Sales\Model\Order; @@ -55,14 +61,14 @@ public function testAuthorise3d() $paymentMock = $this->createMock(Payment::class); $paymentMock->method('getOrder')->willReturn($orderMock); - $checkoutServiceMock = $this->createMock(Checkout::class); - $checkoutServiceMock->method('paymentsDetails')->willReturn([]); + $paymentsApiMock = $this->createMock(PaymentsApi::class); + $paymentsApiMock->method('paymentsDetails')->willReturn(new PaymentDetailsResponse([])); $this->adyenHelper ->method('initializeAdyenClient') ->willReturn($this->createMock(Client::class)); - $this->adyenHelper->method('createAdyenCheckoutService')->willReturn($checkoutServiceMock); + $this->adyenHelper->method('initializePaymentsApi')->willReturn($paymentsApiMock); $result = $this->paymentRequest->authorise3d($paymentMock); $this->assertIsArray($result); @@ -70,13 +76,13 @@ public function testAuthorise3d() public function testListRecurringContractByType() { - $recurringServiceMock = $this->createMock(Recurring::class); - $recurringServiceMock->method('listRecurringDetails')->willReturn([]); + $recurringServiceMock = $this->createMock(RecurringApi::class); + $recurringServiceMock->method('listRecurringDetails')->willReturn(new RecurringDetailsResult([])); $this->adyenHelper ->method('initializeAdyenClient') ->willReturn($this->createMock(Client::class)); - $this->adyenHelper->method('createAdyenRecurringService')->willReturn($recurringServiceMock); + $this->adyenHelper->method('initializeRecurringApi')->willReturn($recurringServiceMock); $this->assertIsArray($this->paymentRequest->listRecurringContractByType('001', 1, 'CardOnFile')); } @@ -90,17 +96,15 @@ public function testDisableRecurringContract($response, $assert) $this->expectException(LocalizedException::class); } - $result = [ - 'response' => $response - ]; + $result = new DisableResult(['response' => $response]); - $recurringServiceMock = $this->createMock(Recurring::class); + $recurringServiceMock = $this->createMock(RecurringApi::class); $recurringServiceMock->method('disable')->willReturn($result); $this->adyenHelper ->method('initializeAdyenClient') ->willReturn($this->createMock(Client::class)); - $this->adyenHelper->method('createAdyenRecurringService')->willReturn($recurringServiceMock); + $this->adyenHelper->method('initializeRecurringApi')->willReturn($recurringServiceMock); $apiResponse = $this->paymentRequest->disableRecurringContract('TOKEN_PLACEHOLDER', '001', 1); diff --git a/Test/Unit/Model/Api/AdyenPaymentMethodsBalanceTest.php b/Test/Unit/Model/Api/AdyenPaymentMethodsBalanceTest.php new file mode 100644 index 000000000..3f818965f --- /dev/null +++ b/Test/Unit/Model/Api/AdyenPaymentMethodsBalanceTest.php @@ -0,0 +1,100 @@ +jsonSerializer = new Json(); + $this->storeManager = $this->createConfiguredMock( + StoreManager::class, + [ + 'getStore' => $this->createConfiguredMock( + Store::class, [ + 'getId' => 'StoreId' + ] + ), + ] + ); + $this->config = $this->createConfiguredMock(Config::class, [ + 'getMerchantAccount' => 'merchantAccount' + ]); + $this->response = new BalanceCheckResponse(); + $this->response->setResultCode('Success'); + $this->response->setBalance(new Amount(['currency'=> 'EUR', 'value'=> 400])); + $this->ordersApi = $this->createConfiguredMock(OrdersApi::class, [ + 'getBalanceOfGiftCard' => $this->response + ]); + $this->adyenHelper = $this->createConfiguredMock(Data::class, [ + 'initializeAdyenClient' => $this->createConfiguredMock(Client::class, []), + 'initializeOrdersApi' => $this->ordersApi + ]); + $this->adyenLogger = $this->createMock(AdyenLogger::class); + $this->merchantAccount = 'my-merchant-account'; + } + + public function testSuccessfulGetBalance() + { + $payload = '{"paymentMethod":{"type":"giftcard","brand":"genericgiftcard","encryptedCardNumber":"eyJhbGciOi......"},"amount":{"currency":"EUR","value":8361}}'; + $adyenPaymentMethodsBalance = new AdyenPaymentMethodsBalance( + $this->jsonSerializer, + $this->storeManager, + $this->config, + $this->adyenHelper, + $this->adyenLogger + ); + + $balance = $adyenPaymentMethodsBalance->getBalance($payload); + $this->assertEquals(json_encode($this->response->jsonSerialize()), $balance); + } + + public function testFailedGetBalance() + { + + $response = new BalanceCheckResponse(); + $response->setResultCode(AdyenPaymentMethodsBalance::FAILED_RESULT_CODE); + $ordersApi = $this->createConfiguredMock(OrdersApi::class, [ + 'getBalanceOfGiftCard' => $response + ]); + + $adyenHelper = $this->createConfiguredMock(Data::class, [ + 'initializeAdyenClient' => $this->createConfiguredMock(Client::class, []), + 'initializeOrdersApi' => $ordersApi + ]); + + $payload = '{"paymentMethod":{"type":"giftcard","brand":"genericgiftcard","encryptedCardNumber":"eyJhbGciOi......"},"amount":{"currency":"EUR","value":8361}}'; + $adyenPaymentMethodsBalance = new AdyenPaymentMethodsBalance( + $this->jsonSerializer, + $this->storeManager, + $this->config, + $adyenHelper, + $this->adyenLogger + ); + + $this->expectException(AdyenException::class); + $adyenPaymentMethodsBalance->getBalance($payload); + } +} diff --git a/Test/Unit/Model/Config/Backend/AutoConfigurationTest.php b/Test/Unit/Model/Config/Backend/AutoConfigurationTest.php new file mode 100644 index 000000000..10af9c697 --- /dev/null +++ b/Test/Unit/Model/Config/Backend/AutoConfigurationTest.php @@ -0,0 +1,64 @@ +contextMock = $this->createMock(Context::class); + $this->registryMock = $this->createMock(Registry::class); + $this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class); + $this->typeListtMock = $this->createMock(TypeListInterface::class); + $this->managementHelperMock = $this->createMock(ManagementHelper::class); + + $this->urlMock = $this->createConfiguredMock(UrlInterface::class, [ + 'getBaseUrl' => 'my base url' + ]); + $this->baseUrlHelperMock = $this->createConfiguredMock(BaseUrlHelper::class, [ + 'getDomainFromUrl' => 'mydomain' + ]); + + $this->autoConfiguration = new AutoConfiguration( + $this->contextMock, + $this->registryMock, + $this->scopeConfigMock, + $this->typeListtMock, + $this->managementHelperMock, + $this->urlMock, + $this->baseUrlHelperMock, + null, + null, + [ + 'fieldset_data' => [ + 'demo_mode' => 1, + 'api_key_live' => '2', + 'api_key_test' => '2' + ] + ] + ); + } + + public function testSaveAllowedOrigins() + { + $this->managementHelperMock->expects($this->once())->method('saveAllowedOrigin'); + $this->invokeMethod($this->autoConfiguration, 'saveAllowedOrigins'); + } +} diff --git a/Test/Unit/Plugin/PaymentVaultDeleteTokenTest.php b/Test/Unit/Plugin/PaymentVaultDeleteTokenTest.php index 83180d078..212052b79 100644 --- a/Test/Unit/Plugin/PaymentVaultDeleteTokenTest.php +++ b/Test/Unit/Plugin/PaymentVaultDeleteTokenTest.php @@ -11,11 +11,13 @@ namespace Adyen\Payment\Test\Plugin; +use Adyen\Model\Recurring\DisableResult; use Adyen\Payment\Helper\Data; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Plugin\PaymentVaultDeleteToken; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Adyen\Payment\Helper\Requests; +use Adyen\Service\RecurringApi; use Magento\Vault\Api\Data\PaymentTokenInterface; use Magento\Vault\Api\PaymentTokenRepositoryInterface; use Magento\Store\Model\StoreManagerInterface; @@ -64,11 +66,13 @@ public function testSuccessfullyDisableValidAdyenPaymentTokenBeforeDeletion() $this->vaultHelperMock->method('isAdyenPaymentCode')->willReturn(true); $clientMock = $this->createMock(Client::class); - $recurringServiceMock = $this->createMock(Recurring::class); + $recurringServiceMock = $this->createMock(RecurringApi::class); $this->dataHelperMock->method('initializeAdyenClient')->willReturn($clientMock); - $this->dataHelperMock->method('createAdyenRecurringService')->willReturn($recurringServiceMock); + $this->dataHelperMock->method('initializeRecurringApi')->willReturn($recurringServiceMock); - $recurringServiceMock->expects($this->once())->method('disable')->willReturn(['response' => 'success']); + $recurringServiceMock->expects($this->once()) + ->method('disable') + ->willReturn(new DisableResult(['response' => 'success'])); $this->paymentVaultDeleteToken = new PaymentVaultDeleteToken( $storeManagerMock,