diff --git a/.github/Makefile b/.github/Makefile index 729a6871f2..e0b1d2c469 100644 --- a/.github/Makefile +++ b/.github/Makefile @@ -41,7 +41,7 @@ configure: n98-magerun2.phar bin/magento config:set payment/adyen_abstract/merchant_account "${ADYEN_MERCHANT}" bin/magento config:set payment/adyen_abstract/notifications_ip_check 0 bin/magento config:set payment/adyen_abstract/payment_authorized 'processing' - bin/magento config:set payment/adyen_abstract/payment_pre_authorized 'pending_payment' + bin/magento config:set payment/adyen_abstract/payment_pre_authorized 'adyen_authorized' bin/magento config:set payment/adyen_abstract/capture_mode 'manual' bin/magento config:set payment/adyen_abstract/paypal_capture_mode 0 bin/magento config:set payment/adyen_abstract/recurring_configuration '{"adyen_cc":{"name":"Cards","enabled":"1","recurringProcessingModel":"CardOnFile"},"adyen_sepadirectdebit":{"name":"SEPA Direct Debit","enabled":"1","recurringProcessingModel":"CardOnFile"}}' diff --git a/Api/InstantPurchase/PaymentMethodIntegration/AdyenAvailabilityCheckerInterface.php b/Api/InstantPurchase/PaymentMethodIntegration/AdyenAvailabilityCheckerInterface.php new file mode 100644 index 0000000000..ecaefc56d0 --- /dev/null +++ b/Api/InstantPurchase/PaymentMethodIntegration/AdyenAvailabilityCheckerInterface.php @@ -0,0 +1,31 @@ + + */ + +namespace Adyen\Payment\Api\InstantPurchase\PaymentMethodIntegration; + +use Magento\InstantPurchase\PaymentMethodIntegration\AvailabilityCheckerInterface; + +interface AdyenAvailabilityCheckerInterface extends AvailabilityCheckerInterface +{ + /** + * Checks if Adyen alternative payment method may be used for instant purchase. + * + * This interface extends the default `AvailabilityCheckerInterface` and implements + * a new method with payment method argument. This interface is used in `InstantPurchaseIntegrations` + * plugin to override the `AvailabilityCheckerInterface` which doesn't have payment method argument. + * + * @param string $paymentMethodCode + * + * @return bool + */ + public function isAvailableAdyenMethod(string $paymentMethodCode): bool; +} diff --git a/Gateway/Http/Client/TransactionCancel.php b/Gateway/Http/Client/TransactionCancel.php index 707412d06d..f7d1406469 100644 --- a/Gateway/Http/Client/TransactionCancel.php +++ b/Gateway/Http/Client/TransactionCancel.php @@ -66,7 +66,7 @@ public function placeRequest(TransferInterface $transferObject): array $headers['idempotencyExtraData'] ?? null ); $requestOptions['idempotencyKey'] = $idempotencyKey; - $requestOptions['headers'] = $this->adyenHelper->buildRequestHeaders(); + $requestOptions['headers'] = $headers; $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, '/cancels'); $request['applicationInfo'] = $this->adyenHelper->buildApplicationInfo($client); $paymentCancelRequest = new PaymentCancelRequest($request); diff --git a/Gateway/Http/Client/TransactionCapture.php b/Gateway/Http/Client/TransactionCapture.php index ad699a9ba6..05a71cbd73 100644 --- a/Gateway/Http/Client/TransactionCapture.php +++ b/Gateway/Http/Client/TransactionCapture.php @@ -77,16 +77,19 @@ public function placeRequest(TransferInterface $transferObject): array $client = $this->adyenHelper->initializeAdyenClientWithClientConfig($clientConfig); $service = $this->adyenHelper->initializeModificationsApi($client); - $requestOptions['headers'] = $this->adyenHelper->buildRequestHeaders(); + $requestOptions['headers'] = $headers; $request['applicationInfo'] = $this->adyenHelper->buildApplicationInfo($client); if (array_key_exists(self::MULTIPLE_AUTHORIZATIONS, $request)) { return $this->placeMultipleCaptureRequests($service, $request, $requestOptions); } + $idempotencyKeyExtraData = $request['idempotencyExtraData']; + unset($request['idempotencyExtraData']); + $idempotencyKey = $this->idempotencyHelper->generateIdempotencyKey( $request, - $headers['idempotencyExtraData'] ?? null + $idempotencyKeyExtraData ?? null ); $requestOptions['idempotencyKey'] = $idempotencyKey; diff --git a/Gateway/Http/Client/TransactionPaymentLinks.php b/Gateway/Http/Client/TransactionPaymentLinks.php index c43d5d81bf..71e0f8237a 100644 --- a/Gateway/Http/Client/TransactionPaymentLinks.php +++ b/Gateway/Http/Client/TransactionPaymentLinks.php @@ -55,10 +55,12 @@ public function placeRequest(TransferInterface $transferObject): array { $request = $transferObject->getBody(); $headers = $transferObject->getHeaders(); + $idempotencyKeyExtraData = $headers['idempotencyExtraData'] ?? null; + unset($headers['idempotencyExtraData']); $clientConfig = $transferObject->getClientConfig(); $client = $this->adyenHelper->initializeAdyenClientWithClientConfig($clientConfig); - $service = new PaymentLinksApi($client); + $service = $this->adyenHelper->initializePaymentLinksApi($client); // If the payment links call is already done return the request if (!empty($request['resultCode'])) { @@ -68,11 +70,11 @@ public function placeRequest(TransferInterface $transferObject): array $idempotencyKey = $this->idempotencyHelper->generateIdempotencyKey( $request, - $headers['idempotencyExtraData'] ?? null + $idempotencyKeyExtraData ); $requestOptions['idempotencyKey'] = $idempotencyKey; - $requestOptions['headers'] = $this->adyenHelper->buildRequestHeaders(); + $requestOptions['headers'] = $headers; $request['applicationInfo'] = $this->adyenHelper->buildApplicationInfo($client); $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, '/paymentLinks'); diff --git a/Gateway/Http/Client/TransactionRefund.php b/Gateway/Http/Client/TransactionRefund.php index 238f18fb79..6474c300de 100644 --- a/Gateway/Http/Client/TransactionRefund.php +++ b/Gateway/Http/Client/TransactionRefund.php @@ -56,6 +56,8 @@ public function placeRequest(TransferInterface $transferObject): array { $requests = $transferObject->getBody(); $headers = $transferObject->getHeaders(); + $idempotencyKeyExtraData = $headers['idempotencyExtraData']; + unset($headers['idempotencyExtraData']); $clientConfig = $transferObject->getClientConfig(); $client = $this->adyenHelper->initializeAdyenClientWithClientConfig($clientConfig); @@ -66,10 +68,11 @@ public function placeRequest(TransferInterface $transferObject): array $responseData = []; $idempotencyKey = $this->idempotencyHelper->generateIdempotencyKey( $request, - $headers['idempotencyExtraData'] ?? null + $idempotencyKeyExtraData ?? null ); $requestOptions['idempotencyKey'] = $idempotencyKey; - $requestOptions['headers'] = $this->adyenHelper->buildRequestHeaders(); + $requestOptions['headers'] = $headers; + $this->adyenHelper->logRequest($request, Client::API_CHECKOUT_VERSION, '/refunds'); $request['applicationInfo'] = $this->adyenHelper->buildApplicationInfo($client); $paymentRefundRequest = new PaymentRefundRequest($request); diff --git a/Gateway/Request/CaptureDataBuilder.php b/Gateway/Request/CaptureDataBuilder.php index 99b3d23545..ff8ce9557a 100644 --- a/Gateway/Request/CaptureDataBuilder.php +++ b/Gateway/Request/CaptureDataBuilder.php @@ -109,7 +109,10 @@ public function build(array $buildSubject): array $requestBody = [ "amount" => $modificationAmount, "reference" => $payment->getOrder()->getIncrementId(), - "paymentPspReference" => $pspReference + "paymentPspReference" => $pspReference, + "idempotencyExtraData" => [ + 'totalInvoiced' => $payment->getOrder()->getTotalInvoiced() ?? 0 + ] ]; //Check additionaldata @@ -119,11 +122,6 @@ public function build(array $buildSubject): array } $request['body'] = $requestBody; $request['clientConfig'] = ["storeId" => $payment->getOrder()->getStoreId()]; - $request['headers'] = [ - 'idempotencyExtraData' => [ - 'totalInvoiced' => $payment->getOrder()->getTotalInvoiced() ?? 0 - ] - ]; return $request; } diff --git a/Gateway/Request/HeaderDataBuilder.php b/Gateway/Request/Header/HeaderDataBuilder.php similarity index 84% rename from Gateway/Request/HeaderDataBuilder.php rename to Gateway/Request/Header/HeaderDataBuilder.php index 66cd1aa703..d2c772f1e6 100644 --- a/Gateway/Request/HeaderDataBuilder.php +++ b/Gateway/Request/Header/HeaderDataBuilder.php @@ -9,18 +9,15 @@ * Author: Adyen */ -namespace Adyen\Payment\Gateway\Request; +namespace Adyen\Payment\Gateway\Request\Header; use Adyen\Payment\Helper\Data; use Magento\Payment\Gateway\Data\PaymentDataObject; use Magento\Payment\Gateway\Helper\SubjectReader; use Magento\Payment\Gateway\Request\BuilderInterface; -class HeaderDataBuilder implements BuilderInterface +class HeaderDataBuilder implements BuilderInterface, HeaderDataBuilderInterface { - const FRONTENDTYPE = 'external-platform-frontendtype'; - const FRONTENDTYPE_HEADLESS = 'headless'; - /** * @var Data */ diff --git a/Gateway/Request/Header/HeaderDataBuilderInterface.php b/Gateway/Request/Header/HeaderDataBuilderInterface.php new file mode 100644 index 0000000000..ac10244854 --- /dev/null +++ b/Gateway/Request/Header/HeaderDataBuilderInterface.php @@ -0,0 +1,15 @@ + @@ -15,75 +15,87 @@ use Adyen\Payment\Helper\StateData; use Adyen\Payment\Helper\Vault; use Adyen\Payment\Model\Config\Source\ThreeDSFlow; -use Adyen\Payment\Model\Ui\AdyenCcConfigProvider; +use Magento\Framework\Exception\LocalizedException; use Magento\Payment\Gateway\Data\PaymentDataObject; use Magento\Payment\Gateway\Helper\SubjectReader; use Magento\Payment\Gateway\Request\BuilderInterface; +use Magento\Vault\Api\Data\PaymentTokenFactoryInterface; class RecurringVaultDataBuilder implements BuilderInterface { - private StateData $stateData; - private Vault $vaultHelper; - private Config $configHelper; - + /** + * @param StateData $stateData + * @param Vault $vaultHelper + * @param Config $configHelper + */ public function __construct( - StateData $stateData, - Vault $vaultHelper, - Config $configHelper - ) { - $this->stateData = $stateData; - $this->vaultHelper = $vaultHelper; - $this->configHelper = $configHelper; - } + private readonly StateData $stateData, + private readonly Vault $vaultHelper, + private readonly Config $configHelper + ) { } + /** + * @throws LocalizedException + */ public function build(array $buildSubject): array { /** @var PaymentDataObject $paymentDataObject */ $paymentDataObject = SubjectReader::readPayment($buildSubject); + $payment = $paymentDataObject->getPayment(); $paymentMethod = $payment->getMethodInstance(); + $order = $payment->getOrder(); $extensionAttributes = $payment->getExtensionAttributes(); + $paymentToken = $extensionAttributes->getVaultPaymentToken(); $details = json_decode((string) ($paymentToken->getTokenDetails() ?: '{}'), true); - // Initialize the request body with the current state data - $requestBody = $this->stateData->getStateData($order->getQuoteId()); + if ($paymentToken->getType() === PaymentTokenFactoryInterface::TOKEN_TYPE_CREDIT_CARD) { + // Build base request for card token payments (including card wallets) - // For now this will only be used by tokens created trough adyen_hpp payment methods - if (array_key_exists(Vault::TOKEN_TYPE, $details)) { - $requestBody['recurringProcessingModel'] = $details[Vault::TOKEN_TYPE]; - } else { - // If recurringProcessingModel doesn't exist in the token details, use the default value from config. - $requestBody['recurringProcessingModel'] = $this->vaultHelper->getPaymentMethodRecurringProcessingModel( - $paymentMethod->getProviderCode(), - $order->getStoreId() - ); - } + $isInstantPurchase = (bool) $payment->getAdditionalInformation('instant-purchase'); + + if ($isInstantPurchase) { + // `Instant Purchase` doesn't have the component and state data. Build the `paymentMethod` object. + $requestBody['paymentMethod']['type'] = 'scheme'; + $requestBody['paymentMethod']['storedPaymentMethodId'] = $paymentToken->getGatewayToken(); + } else { + // Initialize the request body with the current state data if it's not `Instant Purchase`. + $requestBody = $this->stateData->getStateData($order->getQuoteId()); + } - /* - * allow3DS flag is required to trigger the native 3DS challenge. - * Otherwise, shopper will be redirected to the issuer for challenge. - * Due to new VISA compliance requirements, holderName is added to the payments call - */ - if ($paymentMethod->getCode() === AdyenCcConfigProvider::CC_VAULT_CODE) { + /* + * `allow3DS: true` flag is required to trigger the native 3DS challenge. + * Otherwise, shopper will be redirected to the issuer for challenge. + */ $requestBody['additionalData']['allow3DS2'] = $this->configHelper->getThreeDSFlow($order->getStoreId()) === ThreeDSFlow::THREEDS_NATIVE; + + // Due to new VISA compliance requirements, holderName is added to the payments call $requestBody['paymentMethod']['holderName'] = $details['cardHolderName'] ?? null; - } + } else { + // Build base request for alternative payment methods for regular checkout and Instant Purchase - /** - * Build paymentMethod object for alternative payment methods - */ - if ($paymentMethod->getCode() !== AdyenCcConfigProvider::CC_VAULT_CODE) { $requestBody['paymentMethod'] = [ 'type' => $details['type'], 'storedPaymentMethodId' => $paymentToken->getGatewayToken() ]; } - $request['body'] = $requestBody; + // Check the `stateData` if `recurringProcessingModel` is added through a headless request. + if (array_key_exists(Vault::TOKEN_TYPE, $details)) { + $requestBody['recurringProcessingModel'] = $details[Vault::TOKEN_TYPE]; + } else { + // If recurringProcessingModel doesn't exist in the token details, use the default value from config. + $requestBody['recurringProcessingModel'] = $this->vaultHelper->getPaymentMethodRecurringProcessingModel( + $paymentMethod->getProviderCode(), + $order->getStoreId() + ); + } - return $request; + return [ + 'body' => $requestBody + ]; } } diff --git a/Helper/Config.php b/Helper/Config.php index 8657bfe26a..9bbebe10af 100644 --- a/Helper/Config.php +++ b/Helper/Config.php @@ -592,6 +592,16 @@ public function getThreeDSFlow(int $storeId = null): string ); } + public function getIsCvcRequiredForRecurringCardPayments(int $storeId = null): bool + { + return (bool) $this->getConfigData( + 'require_cvc', + Config::XML_ADYEN_CC_VAULT, + $storeId, + true + ); + } + public function getConfigData(string $field, string $xmlPrefix, ?int $storeId, bool $flag = false): mixed { $path = implode("/", [self::XML_PAYMENT_PREFIX, $xmlPrefix, $field]); diff --git a/Helper/Data.php b/Helper/Data.php index 3b82731973..c628eb2514 100755 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -17,8 +17,8 @@ use Adyen\Model\Checkout\ApplicationInfo; use Adyen\Model\Checkout\CommonField; use Adyen\Model\Checkout\UtilityRequest; +use Adyen\Payment\Gateway\Request\Header\HeaderDataBuilderInterface; 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; @@ -27,6 +27,7 @@ use Adyen\Payment\Observer\AdyenPaymentMethodDataAssignObserver; use Adyen\Service\Checkout\ModificationsApi; use Adyen\Service\Checkout\OrdersApi; +use Adyen\Service\Checkout\PaymentLinksApi; use Adyen\Service\Checkout\PaymentsApi; use Adyen\Service\Checkout\UtilityApi; use Adyen\Service\PosPayment; @@ -1173,16 +1174,16 @@ public function buildRequestHeaders($payment = null) { $magentoDetails = $this->getMagentoDetails(); $headers = [ - 'external-platform-name' => $magentoDetails['name'], - 'external-platform-version' => $magentoDetails['version'], - 'external-platform-edition' => $magentoDetails['edition'], - 'merchant-application-name' => $this->getModuleName(), - 'merchant-application-version' => $this->getModuleVersion() + HeaderDataBuilderInterface::EXTERNAL_PLATFORM_NAME => $magentoDetails['name'], + HeaderDataBuilderInterface::EXTERNAL_PLATFORM_VERSION => $magentoDetails['version'], + HeaderDataBuilderInterface::EXTERNAL_PLATFORM_EDITION => $magentoDetails['edition'], + HeaderDataBuilderInterface::MERCHANT_APPLICATION_NAME => $this->getModuleName(), + HeaderDataBuilderInterface::MERCHANT_APPLICATION_VERSION => $this->getModuleVersion() ]; - if(isset($payment) && !is_null($payment->getAdditionalInformation(HeaderDataBuilder::FRONTENDTYPE))) { - $headers[HeaderDataBuilder::FRONTENDTYPE] = - $payment->getAdditionalInformation(HeaderDataBuilder::FRONTENDTYPE); + if(isset($payment) && !is_null($payment->getAdditionalInformation(HeaderDataBuilderInterface::ADDITIONAL_DATA_FRONTEND_TYPE_KEY))) { + $headers[HeaderDataBuilderInterface::EXTERNAL_PLATFORM_FRONTEND_TYPE] = + $payment->getAdditionalInformation(HeaderDataBuilderInterface::ADDITIONAL_DATA_FRONTEND_TYPE_KEY); } return $headers; @@ -1248,6 +1249,11 @@ public function initializeOrdersApi(Client $client): OrdersApi return new OrdersApi($client); } + public function initializePaymentLinksApi(Client $client):PaymentLinksApi + { + return new PaymentLinksApi($client); + } + /** * @param Client $client * @return PosPayment diff --git a/Model/InstantPurchase/Card/AvailabilityChecker.php b/Model/InstantPurchase/Card/AvailabilityChecker.php new file mode 100644 index 0000000000..eedc0b0a8d --- /dev/null +++ b/Model/InstantPurchase/Card/AvailabilityChecker.php @@ -0,0 +1,59 @@ + + */ + +namespace Adyen\Payment\Model\InstantPurchase\Card; + +use Adyen\Payment\Helper\Config; +use Adyen\Payment\Helper\Vault; +use Adyen\Payment\Model\Ui\AdyenCcConfigProvider; +use Magento\InstantPurchase\PaymentMethodIntegration\AvailabilityCheckerInterface; +use Magento\Store\Model\StoreManagerInterface; + +class AvailabilityChecker implements AvailabilityCheckerInterface +{ + /** + * @param Config $configHelper + * @param Vault $vaultHelper + * @param StoreManagerInterface $storeManager + */ + public function __construct( + private readonly Config $configHelper, + private readonly Vault $vaultHelper, + private readonly StoreManagerInterface $storeManager + ) { } + + /** + * Instant Purchase is available if card recurring is enabled, recurring processing model is set to `CardOnFile` + * and CVC is not required to complete the payment. + */ + public function isAvailable(): bool + { + $storeId = $this->storeManager->getStore()->getId(); + + $isCardRecurringEnabled = $this->vaultHelper->getPaymentMethodRecurringActive( + AdyenCcConfigProvider::CODE, + $storeId + ); + + $recurringProcessingModel = $this->vaultHelper->getPaymentMethodRecurringProcessingModel( + AdyenCcConfigProvider::CODE, + $storeId + ); + + $isCvcRequiredForCardRecurringPayments = + $this->configHelper->getIsCvcRequiredForRecurringCardPayments($storeId); + + return $isCardRecurringEnabled && + !$isCvcRequiredForCardRecurringPayments && + $recurringProcessingModel === Vault::CARD_ON_FILE; + } +} diff --git a/Model/InstantPurchase/Card/TokenFormatter.php b/Model/InstantPurchase/Card/TokenFormatter.php new file mode 100644 index 0000000000..d90ddd1bfb --- /dev/null +++ b/Model/InstantPurchase/Card/TokenFormatter.php @@ -0,0 +1,56 @@ + + */ + +namespace Adyen\Payment\Model\InstantPurchase\Card; + +use Adyen\Payment\Helper\Data; +use InvalidArgumentException; +use Magento\InstantPurchase\PaymentMethodIntegration\PaymentTokenFormatterInterface; +use Magento\Vault\Api\Data\PaymentTokenInterface; + +/** + * Adyen stored card formatter. + */ +class TokenFormatter implements PaymentTokenFormatterInterface +{ + public function __construct( + protected readonly Data $adyenHelper + ) { } + + public function formatPaymentToken(PaymentTokenInterface $paymentToken): string + { + $details = json_decode($paymentToken->getTokenDetails() ?: '{}', true); + + if (!isset($details['type'], $details['maskedCC'], $details['expirationDate'])) { + throw new InvalidArgumentException('Invalid Adyen card token details.'); + } + + $ccTypes = $this->adyenHelper->getAdyenCcTypes(); + $typeArrayIndex = array_search($details['type'], array_column($ccTypes, 'code_alt')); + + if (is_int($typeArrayIndex)) { + $ccType = $ccTypes[array_keys($ccTypes)[$typeArrayIndex]]['name']; + } else { + $ccType = $details['type']; + } + + return sprintf( + '%s: %s, %s: %s (%s: %s)', + __('Card'), + $ccType, + __('ending'), + $details['maskedCC'], + __('expires'), + $details['expirationDate'] + ); + } +} diff --git a/Model/InstantPurchase/PaymentMethods/AvailabilityChecker.php b/Model/InstantPurchase/PaymentMethods/AvailabilityChecker.php new file mode 100644 index 0000000000..c192159181 --- /dev/null +++ b/Model/InstantPurchase/PaymentMethods/AvailabilityChecker.php @@ -0,0 +1,62 @@ + + */ + +namespace Adyen\Payment\Model\InstantPurchase\PaymentMethods; + +use Adyen\Payment\Api\InstantPurchase\PaymentMethodIntegration\AdyenAvailabilityCheckerInterface; +use Adyen\Payment\Helper\Vault; +use Magento\Framework\Exception\NotFoundException; +use Magento\Store\Model\StoreManagerInterface; + +class AvailabilityChecker implements AdyenAvailabilityCheckerInterface +{ + /** + * @param Vault $vaultHelper + * @param StoreManagerInterface $storeManager + */ + public function __construct( + private readonly Vault $vaultHelper, + private readonly StoreManagerInterface $storeManager + ) { } + + /** + * Instant Purchase is available if payment method recurring is enabled and + * recurring processing model is set to `CardOnFile`. + */ + public function isAvailableAdyenMethod(string $paymentMethodCode): bool + { + $storeId = $this->storeManager->getStore()->getId(); + + $isMethodRecurringEnabled = $this->vaultHelper->getPaymentMethodRecurringActive( + $paymentMethodCode, + $storeId + ); + $recurringProcessingModel = $this->vaultHelper->getPaymentMethodRecurringProcessingModel( + $paymentMethodCode, + $storeId + ); + + return $isMethodRecurringEnabled && $recurringProcessingModel === Vault::CARD_ON_FILE; + } + + /** + * @throws NotFoundException + */ + public function isAvailable(): bool + { + /* + * This is the pseudo implementation of the interface. Actual logic has been written + * in `isAvailableAdyenMethod() and implemented via plugin `InstantPurchaseIntegrationTest`. + */ + throw new NotFoundException(__('This method has not been implemented!')); + } +} diff --git a/Model/InstantPurchase/PaymentMethods/TokenFormatter.php b/Model/InstantPurchase/PaymentMethods/TokenFormatter.php new file mode 100644 index 0000000000..e5f27501f3 --- /dev/null +++ b/Model/InstantPurchase/PaymentMethods/TokenFormatter.php @@ -0,0 +1,28 @@ + + */ + +namespace Adyen\Payment\Model\InstantPurchase\PaymentMethods; + +use Magento\InstantPurchase\PaymentMethodIntegration\PaymentTokenFormatterInterface; +use Magento\Vault\Api\Data\PaymentTokenInterface; + +/** + * Adyen stored payment method formatter. + */ +class TokenFormatter implements PaymentTokenFormatterInterface +{ + public function formatPaymentToken(PaymentTokenInterface $paymentToken): string + { + $details = json_decode($paymentToken->getTokenDetails(), true); + return $details['tokenLabel']; + } +} diff --git a/Model/Ui/AdyenCcConfigProvider.php b/Model/Ui/AdyenCcConfigProvider.php index ece2d81eeb..f8722f0e9a 100755 --- a/Model/Ui/AdyenCcConfigProvider.php +++ b/Model/Ui/AdyenCcConfigProvider.php @@ -127,12 +127,8 @@ public function getConfig(): array } // check if cvc is required - $config['payment']['adyenCc']['requireCvc'] = $this->configHelper->getConfigData( - 'require_cvc', - Config::XML_ADYEN_CC_VAULT, - $storeId, - true - ); + $config['payment']['adyenCc']['requireCvc'] = + $this->configHelper->getIsCvcRequiredForRecurringCardPayments($storeId); return $config; } diff --git a/Observer/AdyenCcDataAssignObserver.php b/Observer/AdyenCcDataAssignObserver.php index 6168deebb3..79ed087eab 100644 --- a/Observer/AdyenCcDataAssignObserver.php +++ b/Observer/AdyenCcDataAssignObserver.php @@ -19,7 +19,7 @@ use Magento\Framework\Event\Observer; use Magento\Payment\Observer\AbstractDataAssignObserver; use Magento\Quote\Api\Data\PaymentInterface; -use Adyen\Payment\Gateway\Request\HeaderDataBuilder; +use Adyen\Payment\Gateway\Request\Header\HeaderDataBuilderInterface; class AdyenCcDataAssignObserver extends AbstractDataAssignObserver { @@ -46,7 +46,7 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver self::CC_TYPE, self::RETURN_URL, self::RECURRING_PROCESSING_MODEL, - HeaderDataBuilder::FRONTENDTYPE + HeaderDataBuilderInterface::ADDITIONAL_DATA_FRONTEND_TYPE_KEY ]; /** diff --git a/Observer/AdyenPaymentMethodDataAssignObserver.php b/Observer/AdyenPaymentMethodDataAssignObserver.php index e90ce7b0a0..efe803a0fc 100644 --- a/Observer/AdyenPaymentMethodDataAssignObserver.php +++ b/Observer/AdyenPaymentMethodDataAssignObserver.php @@ -11,7 +11,7 @@ namespace Adyen\Payment\Observer; -use Adyen\Payment\Gateway\Request\HeaderDataBuilder; +use Adyen\Payment\Gateway\Request\Header\HeaderDataBuilderInterface; use Adyen\Payment\Helper\StateData; use Adyen\Payment\Helper\Util\CheckoutStateDataValidator; use Adyen\Payment\Helper\Util\DataArrayValidator; @@ -39,7 +39,7 @@ class AdyenPaymentMethodDataAssignObserver extends AbstractDataAssignObserver self::RETURN_URL, self::RECURRING_PROCESSING_MODEL, self::CC_NUMBER, - HeaderDataBuilder::FRONTENDTYPE + HeaderDataBuilderInterface::ADDITIONAL_DATA_FRONTEND_TYPE_KEY ]; protected CheckoutStateDataValidator $checkoutStateDataValidator; diff --git a/Plugin/InstantPurchaseIntegration.php b/Plugin/InstantPurchaseIntegration.php new file mode 100644 index 0000000000..62ef42985e --- /dev/null +++ b/Plugin/InstantPurchaseIntegration.php @@ -0,0 +1,65 @@ + + */ + +namespace Adyen\Payment\Plugin; + +use Adyen\Payment\Helper\PaymentMethods; +use Adyen\Payment\Api\InstantPurchase\PaymentMethodIntegration\AdyenAvailabilityCheckerInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\InstantPurchase\PaymentMethodIntegration\Integration; +use Magento\Payment\Helper\Data; + +class InstantPurchaseIntegration +{ + /** + * @param AdyenAvailabilityCheckerInterface $adyenAvailabilityChecker + * @param PaymentMethods $paymentMethodsHelper + * @param Data $paymentDataHelper + */ + public function __construct( + protected readonly AdyenAvailabilityCheckerInterface $adyenAvailabilityChecker, + protected readonly PaymentMethods $paymentMethodsHelper, + protected readonly Data $paymentDataHelper + ) { } + + /** + * @param Integration $subject + * @param callable $proceed + * @return bool + * @throws LocalizedException + */ + public function aroundIsAvailable(Integration $subject, callable $proceed): bool + { + $vaultPaymentMethodInstance = $subject->getPaymentMethod(); + $providerMethodCode = $vaultPaymentMethodInstance->getProviderCode(); + + $providerMethodInstance = $this->paymentDataHelper->getMethodInstance( + $providerMethodCode + ); + $isAdyenAlternativePaymentMethod = $this->paymentMethodsHelper->isAlternativePaymentMethod( + $providerMethodInstance + ); + $isAdyenWalletPaymentMethod = $this->paymentMethodsHelper->isWalletPaymentMethod( + $providerMethodInstance + ); + + if ($isAdyenAlternativePaymentMethod && !$isAdyenWalletPaymentMethod) { + /* + * As the same `AvailabilityChecker` is used for all alternative payment methods, + * we need to identify the payment method. This plugin overrides the `AvailabilityCheckerInterface` + * and implements a custom method to check the availability based on the payment method code. + */ + return $this->adyenAvailabilityChecker->isAvailableAdyenMethod($providerMethodCode); + } else { + return $proceed(); + } + } +} diff --git a/Test/Unit/Gateway/Http/Client/TransactionCaptureTest.php b/Test/Unit/Gateway/Http/Client/TransactionCaptureTest.php index 19348bed58..801c94f776 100644 --- a/Test/Unit/Gateway/Http/Client/TransactionCaptureTest.php +++ b/Test/Unit/Gateway/Http/Client/TransactionCaptureTest.php @@ -43,11 +43,12 @@ protected function setUp(): void 'amount' => ['value' => 100, 'currency' => 'USD'], 'paymentPspReference' => 'testPspReference', 'applicationInfo' => $applicationInfo, + 'idempotencyExtraData' => ['someData'] ]; $this->transferObject = $this->createConfiguredMock(TransferInterface::class, [ 'getBody' => $this->request, - 'getHeaders' => ['idempotencyExtraData' => ['someData']], + 'getHeaders' => [], 'getClientConfig' => [] ]); } @@ -63,10 +64,13 @@ private function configureAdyenMocks(array $response = null, \Exception $excepti $this->adyenHelper->method('buildRequestHeaders')->willReturn([]); $this->adyenHelper->expects($this->once())->method('logRequest'); + $trimmedRequest = $this->request; + unset($trimmedRequest['idempotencyExtraData']); + $this->idempotencyHelper->expects($this->once()) ->method('generateIdempotencyKey') ->with( - $this->request, + $trimmedRequest, $this->equalTo(['someData']) ) ->willReturn($expectedIdempotencyKey); diff --git a/Test/Unit/Gateway/Http/Client/TransactionPaymentLinksTest.php b/Test/Unit/Gateway/Http/Client/TransactionPaymentLinksTest.php new file mode 100644 index 0000000000..c52733c959 --- /dev/null +++ b/Test/Unit/Gateway/Http/Client/TransactionPaymentLinksTest.php @@ -0,0 +1,120 @@ +adyenHelperMock = $this->createMock(Data::class); + $this->idempotencyHelperMock = $this->createMock(Idempotency::class); + $this->transferObjectMock = $this->createMock(TransferInterface::class); + $this->applicationInfoMock = $this->createMock(ApplicationInfo::class); + $this->adyenHelperMock->method('buildApplicationInfo')->willReturn($this->applicationInfoMock); + $this->transferObjectMock->method('getClientConfig')->willReturn([]); + $this->clientMock = $this->createMock(Client::class); + $this->adyenHelperMock->method('initializeAdyenClientWithClientConfig')->willReturn($this->clientMock); + $this->paymentLinksApiMock = $this->createMock(PaymentLinksApi::class); + $this->adyenHelperMock + ->method('initializePaymentLinksApi') + ->with($this->clientMock) + ->willReturn($this->paymentLinksApiMock); + + $this->transactionPaymentLinks = new TransactionPaymentLinks( + $this->adyenHelperMock, + $this->idempotencyHelperMock + ); + } + + public function testSuccessfulPlaceRequest() + { + $requestBody = [ + 'allowedPaymentMethods' => ['ideal','giropay'], + 'amount' => ['value' => 1000, 'currency' => 'EUR'], + 'applicationInfo' => $this->applicationInfoMock + ]; + + $headers = [ 'idempotencyExtraData' => [], 'header' => 'some-data']; + $idempotencyKey = 'generated_idempotency_key'; + + $this->transferObjectMock->method('getBody')->willReturn($requestBody); + $this->transferObjectMock->method('getHeaders')->willReturn($headers); + + $this->idempotencyHelperMock->expects($this->once()) + ->method('generateIdempotencyKey') + ->with($requestBody, $headers['idempotencyExtraData']) + ->willReturn('generated_idempotency_key'); + + $this->paymentLinksApiMock->expects($this->once()) + ->method('paymentLinks') + ->with( + $this->callback(function (PaymentLinkRequest $paymentLinkRequest) use ($requestBody) { + $amount = $paymentLinkRequest->getAmount(); + $this->assertEquals($amount, ['value' => 1000, 'currency' => 'EUR']); + $allowedPaymentMethods = $paymentLinkRequest->getAllowedPaymentMethods(); + $this->assertEquals($allowedPaymentMethods, ['ideal', 'giropay']); + return true; + }), + $this->callback(function ($requestOptions) use ($idempotencyKey, $headers) { + $this->assertArrayHasKey('idempotencyKey', $requestOptions); + $this->assertArrayHasKey('headers', $requestOptions); + $this->assertEquals($idempotencyKey, $requestOptions['idempotencyKey']); + $this->assertEquals(['header' => 'some-data'], $requestOptions['headers']); + return true; + }) + )->willReturn(new PaymentLinkResponse(['url' => 'https://paymentlink.com'])); + + $response = $this->transactionPaymentLinks->placeRequest($this->transferObjectMock); + $this->assertIsArray($response); + $this->assertArrayHasKey('url', $response); + } + + public function testRequestWithAdyenException() + { + $requestBody = [ + 'amount' => ['currency' => 'EUR', 'value' => 1000], + 'merchantAccount' => 'TestMerchant', + 'reference' => 'TestReference', + ]; + $this->transferObjectMock->method('getBody')->willReturn($requestBody); + $this->transferObjectMock->method('getHeaders')->willReturn([]); + $this->transferObjectMock->method('getClientConfig')->willReturn([]); + + $this->paymentLinksApiMock + ->method('paymentLinks') + ->willThrowException(new AdyenException()); + + $response = $this->transactionPaymentLinks->placeRequest($this->transferObjectMock); + + $this->assertArrayHasKey('error', $response); + } + + public function testRequestWithResultCodePresent() + { + $requestBody = ['resultCode' => 'Authorised']; + $this->transferObjectMock->method('getBody')->willReturn($requestBody); + + $response = $this->transactionPaymentLinks->placeRequest($this->transferObjectMock); + $this->assertEquals($requestBody, $response); + } + +} diff --git a/Test/Unit/Gateway/Http/Client/TransactionRefundTest.php b/Test/Unit/Gateway/Http/Client/TransactionRefundTest.php index 21b2730451..3ba9370ac4 100644 --- a/Test/Unit/Gateway/Http/Client/TransactionRefundTest.php +++ b/Test/Unit/Gateway/Http/Client/TransactionRefundTest.php @@ -71,7 +71,6 @@ public function testPlaceRequestIncludesHeadersInRequest() $this->adyenHelperMock->method('initializeAdyenClientWithClientConfig')->willReturn($adyenClientMock); $this->adyenHelperMock->method('initializeModificationsApi')->willReturn($serviceMock); - $this->adyenHelperMock->method('buildRequestHeaders')->willReturn(['custom-header' => 'value']); $this->idempotencyHelperMock->expects($this->once()) ->method('generateIdempotencyKey') @@ -91,7 +90,6 @@ public function testPlaceRequestIncludesHeadersInRequest() $this->assertArrayHasKey('idempotencyKey', $requestOptions); $this->assertArrayHasKey('headers', $requestOptions); $this->assertEquals('generated_idempotency_key', $requestOptions['idempotencyKey']); - $this->assertArrayHasKey('custom-header', $requestOptions['headers']); return true; }) ) diff --git a/Test/Unit/Gateway/Request/HeaderDataBuilderTest.php b/Test/Unit/Gateway/Request/Header/HeaderDataBuilderTest.php similarity index 97% rename from Test/Unit/Gateway/Request/HeaderDataBuilderTest.php rename to Test/Unit/Gateway/Request/Header/HeaderDataBuilderTest.php index 7c15e659a1..b270347fb1 100644 --- a/Test/Unit/Gateway/Request/HeaderDataBuilderTest.php +++ b/Test/Unit/Gateway/Request/Header/HeaderDataBuilderTest.php @@ -2,7 +2,7 @@ namespace Adyen\Payment\Test\Unit\Gateway\Request; -use Adyen\Payment\Gateway\Request\HeaderDataBuilder; +use Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Adyen\Payment\Helper\Data; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; diff --git a/Test/Unit/Gateway/Request/RecurringVaultDataBuilderTest.php b/Test/Unit/Gateway/Request/RecurringVaultDataBuilderTest.php index 55960af346..35a83eb3e5 100644 --- a/Test/Unit/Gateway/Request/RecurringVaultDataBuilderTest.php +++ b/Test/Unit/Gateway/Request/RecurringVaultDataBuilderTest.php @@ -12,47 +12,72 @@ namespace Adyen\Payment\Test\Gateway\Request; use Adyen\Payment\Gateway\Request\RecurringVaultDataBuilder; +use Adyen\Payment\Helper\Config; +use Adyen\Payment\Helper\StateData; +use Adyen\Payment\Helper\Vault as AdyenVaultHelper; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\Api\ExtensionAttributesInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Exception\LocalizedException; use Magento\Payment\Gateway\Data\PaymentDataObject; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Payment; +use Magento\Vault\Api\Data\PaymentTokenFactoryInterface; use Magento\Vault\Api\Data\PaymentTokenInterface; use Magento\Vault\Model\Method\Vault; +use PHPUnit\Framework\MockObject\MockObject; class RecurringVaultDataBuilderTest extends AbstractAdyenTestCase { - private object $recurringVaultDataBuilder; - private $vaultHelperMock; + protected ?RecurringVaultDataBuilder $recurringVaultDataBuilder; + protected AdyenVaultHelper|MockObject $vaultHelperMock; + protected StateData|MockObject $stateDataHelperMock; + protected Config|MockObject $configHelperMock; /** * @return void */ protected function setUp(): void { - $this->vaultHelperMock = $this->createMock(\Adyen\Payment\Helper\Vault::class); + $this->vaultHelperMock = $this->createMock(AdyenVaultHelper::class); + $this->stateDataHelperMock = $this->createMock(StateData::class); + $this->configHelperMock = $this->createMock(Config::class); + + $this->recurringVaultDataBuilder = new RecurringVaultDataBuilder( + $this->stateDataHelperMock, + $this->vaultHelperMock, + $this->configHelperMock + ); + } - $objectManager = new ObjectManager($this); - $this->recurringVaultDataBuilder = $objectManager->getObject(RecurringVaultDataBuilder::class, [ - 'vaultHelper' => $this->vaultHelperMock - ]); + /** + * @return void + */ + protected function tearDown(): void + { + $this->recurringVaultDataBuilder = null; } /** * @param $paymentMethodCode * @param $tokenDetails - * @param $expect3dsFlag - * @dataProvider dataProvider + * @param $tokenType + * @param $isInstantPurchase + * * @return void + * @throws LocalizedException + * + * @dataProvider dataProvider */ - public function testBuild($paymentMethodCode, $tokenDetails, $expect3dsFlag) + public function testBuild($paymentMethodCode, $tokenDetails, $tokenType, $isInstantPurchase) { + $quoteId = 1; + $storeId = 1; + $paymentMethodProviderCode = str_replace('_vault', '', $paymentMethodCode); $orderMock = $this->createMock(Order::class); - $orderMock->method('getQuoteId')->willReturn(1); - $orderMock->method('getStoreId')->willReturn(1); + $orderMock->method('getQuoteId')->willReturn($quoteId); + $orderMock->method('getStoreId')->willReturn($storeId); $paymentMethodInstanceMock = $this->createMock(Vault::class); $paymentMethodInstanceMock->method('getProviderCode')->willReturn($paymentMethodProviderCode); @@ -61,6 +86,7 @@ public function testBuild($paymentMethodCode, $tokenDetails, $expect3dsFlag) $paymentTokenMock = $this->createMock(PaymentTokenInterface::class); $paymentTokenMock->method('getTokenDetails')->willReturn($tokenDetails); $paymentTokenMock->method('getGatewayToken')->willReturn("ABC1234567"); + $paymentTokenMock->method('getType')->willReturn($tokenType); $extensionAttributesMock = $this->createGeneratedMock(ExtensionAttributesInterface::class, [ 'getVaultPaymentToken' @@ -71,6 +97,9 @@ public function testBuild($paymentMethodCode, $tokenDetails, $expect3dsFlag) $paymentMock->method('getOrder')->willReturn($orderMock); $paymentMock->method('getMethodInstance')->willReturn($paymentMethodInstanceMock); $paymentMock->method('getExtensionAttributes')->willReturn($extensionAttributesMock); + $paymentMock->method('getAdditionalInformation') + ->with('instant-purchase') + ->willReturn($isInstantPurchase); $buildSubject = [ 'payment' => $this->createConfiguredMock(PaymentDataObject::class, [ @@ -81,12 +110,22 @@ public function testBuild($paymentMethodCode, $tokenDetails, $expect3dsFlag) $this->vaultHelperMock->method('getPaymentMethodRecurringProcessingModel') ->willReturn('CardOnFile'); + if ($tokenType === PaymentTokenFactoryInterface::TOKEN_TYPE_CREDIT_CARD && !$isInstantPurchase) { + $this->stateDataHelperMock->expects($this->once()) + ->method('getStateData') + ->with($quoteId); + } + $request = $this->recurringVaultDataBuilder->build($buildSubject); $this->assertIsArray($request); $this->assertArrayHasKey('recurringProcessingModel', $request['body']); - if ($expect3dsFlag) { + + if ($tokenType === PaymentTokenFactoryInterface::TOKEN_TYPE_CREDIT_CARD) { $this->assertArrayHasKey('allow3DS2', $request['body']['additionalData']); + $this->assertArrayHasKey('holderName', $request['body']['paymentMethod']); + } else { + $this->assertArrayNotHasKey('additionalData', $request['body']); } } @@ -96,23 +135,39 @@ public static function dataProvider(): array [ 'paymentMethodCode' => 'adyen_cc_vault', 'tokenDetails' => '{"type":"visa","maskedCC":"1111","expirationDate":"3\/2030", "tokenType": "CardOnFile"}', - 'expect3dsFlag' => true + 'tokenType' => 'card', + 'isInstantPurchase' => false ], [ 'paymentMethodCode' => 'adyen_cc_vault', 'tokenDetails' => '{"type":"visa","maskedCC":"1111","expirationDate":"3\/2030"}', - 'expect3dsFlag' => true + 'tokenType' => 'card', + 'isInstantPurchase' => false + ], + [ + 'paymentMethodCode' => 'adyen_cc_vault', + 'tokenDetails' => '{"type":"visa","maskedCC":"1111","expirationDate":"3\/2030"}', + 'tokenType' => 'card', + 'isInstantPurchase' => true ], [ 'paymentMethodCode' => 'adyen_klarna_vault', 'tokenDetails' => '{"type":"klarna", "tokenType": "CardOnFile"}', - 'expect3dsFlag' => false + 'tokenType' => 'account', + 'isInstantPurchase' => false ], [ 'paymentMethodCode' => 'adyen_klarna_vault', 'tokenDetails' => '{"type":"klarna"}', - 'expect3dsFlag' => false + 'tokenType' => 'account', + 'isInstantPurchase' => false ], + [ + 'paymentMethodCode' => 'adyen_klarna_vault', + 'tokenDetails' => '{"type":"klarna"}', + 'tokenType' => 'account', + 'isInstantPurchase' => true + ] ]; } } diff --git a/Test/Unit/Helper/ConfigTest.php b/Test/Unit/Helper/ConfigTest.php index bf70dd4f49..c67a06cbce 100644 --- a/Test/Unit/Helper/ConfigTest.php +++ b/Test/Unit/Helper/ConfigTest.php @@ -148,4 +148,25 @@ public function testGetThreeDSModes() $result = $this->configHelper->getThreeDSFlow($storeId); $this->assertEquals($expectedResult, $result); } + + public function testGetIsCvcRequiredForRecurringCardPayments() + { + $storeId = PHP_INT_MAX; + $expectedResult = true; + + $path = sprintf( + "%s/%s/%s", + Config::XML_PAYMENT_PREFIX, + Config::XML_ADYEN_CC_VAULT, + 'require_cvc' + ); + + $this->scopeConfigMock->expects($this->once()) + ->method('isSetFlag') + ->with($this->equalTo($path), $this->equalTo(ScopeInterface::SCOPE_STORE), $this->equalTo($storeId)) + ->willReturn($expectedResult); + + $result = $this->configHelper->getIsCvcRequiredForRecurringCardPayments($storeId); + $this->assertEquals($expectedResult, $result); + } } diff --git a/Test/Unit/Helper/DataTest.php b/Test/Unit/Helper/DataTest.php index ffb82e21cc..ffc52261e3 100755 --- a/Test/Unit/Helper/DataTest.php +++ b/Test/Unit/Helper/DataTest.php @@ -15,7 +15,7 @@ use Adyen\Config as AdyenConfig; use Adyen\Model\Checkout\ApplicationInfo; use Adyen\Model\Checkout\CommonField; -use Adyen\Payment\Gateway\Request\HeaderDataBuilder; +use Adyen\Payment\Gateway\Request\Header\HeaderDataBuilderInterface; use Adyen\Payment\Helper\Config as ConfigHelper; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Locale; @@ -27,6 +27,7 @@ use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Adyen\Service\Checkout\ModificationsApi; use Adyen\Service\Checkout\OrdersApi; +use Adyen\Service\Checkout\PaymentLinksApi; use Adyen\Service\Checkout\PaymentsApi; use Adyen\Service\RecurringApi; use Magento\Backend\Helper\Data as BackendHelper; @@ -1090,15 +1091,15 @@ public function testBuildRequestHeadersWithNonNullFrontendType() // Set up expectations for the getAdditionalInformation method $payment->method('getAdditionalInformation') - ->with(HeaderDataBuilder::FRONTENDTYPE) + ->with(HeaderDataBuilderInterface::ADDITIONAL_DATA_FRONTEND_TYPE_KEY) ->willReturn('some_frontend_type'); // Call the method under test $result = $this->dataHelper->buildRequestHeaders($payment); // Assert that the 'frontend-type' header is correctly set - $this->assertArrayHasKey(HeaderDataBuilder::FRONTENDTYPE, $result); - $this->assertEquals('some_frontend_type', $result[HeaderDataBuilder::FRONTENDTYPE]); + $this->assertArrayHasKey(HeaderDataBuilderInterface::EXTERNAL_PLATFORM_FRONTEND_TYPE, $result); + $this->assertEquals('some_frontend_type', $result[HeaderDataBuilderInterface::EXTERNAL_PLATFORM_FRONTEND_TYPE]); // Assert other headers as needed } @@ -1110,7 +1111,7 @@ public function testBuildRequestHeadersWithoutPayment() $result = $this->dataHelper->buildRequestHeaders(); // Assert that the 'frontend-type' header is not set - $this->assertArrayNotHasKey(HeaderDataBuilder::FRONTENDTYPE, $result); + $this->assertArrayNotHasKey(HeaderDataBuilderInterface::EXTERNAL_PLATFORM_FRONTEND_TYPE, $result); } public function testLogResponse() @@ -1892,6 +1893,12 @@ public function testInitializeOrdersApi() $this->assertInstanceOf(OrdersApi::class, $service); } + public function testInitializePaymentLinksApi() + { + $service = $this->dataHelper->initializePaymentLinksApi($this->clientMock); + $this->assertInstanceOf(PaymentLinksApi::class, $service); + } + public function testLogAdyenException() { $this->store->method('getId')->willReturn(1); diff --git a/Test/Unit/Model/InstantPurchase/Card/AvailabilityCheckerTest.php b/Test/Unit/Model/InstantPurchase/Card/AvailabilityCheckerTest.php new file mode 100644 index 0000000000..b0d1cb4f6e --- /dev/null +++ b/Test/Unit/Model/InstantPurchase/Card/AvailabilityCheckerTest.php @@ -0,0 +1,126 @@ + + */ + +namespace Adyen\Payment\Test\Helper\Unit\Model\InstantPurchase\Card; + +use Adyen\Payment\Helper\Config; +use Adyen\Payment\Helper\Vault; +use Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker; +use Adyen\Payment\Model\Ui\AdyenCcConfigProvider; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreManagerInterface; +use PHPUnit\Framework\MockObject\MockObject; + +class AvailabilityCheckerTest extends AbstractAdyenTestCase +{ + const STORE_ID = PHP_INT_MAX; + + protected ?AvailabilityChecker $availabilityChecker; + protected Config|MockObject $configHelperMock; + protected Vault|MockObject $vaultHelperMock; + protected StoreManagerInterface|MockObject $storeManagerMock; + + /** + * @return void + */ + public function setUp(): void + { + $this->configHelperMock = $this->createMock(Config::class); + $this->vaultHelperMock = $this->createMock(Vault::class); + $this->storeManagerMock = $this->createMock(StoreManagerInterface::class); + + $store = $this->createMock(StoreInterface::class); + $store->method('getId')->willReturn(self::STORE_ID); + $this->storeManagerMock->method('getStore')->willReturn($store); + + $this->availabilityChecker = new AvailabilityChecker( + $this->configHelperMock, + $this->vaultHelperMock, + $this->storeManagerMock + ); + } + + /** + * @return void + */ + public function tearDown(): void + { + $this->availabilityChecker = null; + } + + /** + * @param $isCardRecurringEnabled + * @param $recurringProcessingModel + * @param $isCvcRequiredForCardRecurringPayments + * @param $expectedResult + * + * @dataProvider availabilityTestDataProvider + * + * @return void + */ + public function testIsAvailable( + $isCardRecurringEnabled, + $recurringProcessingModel, + $isCvcRequiredForCardRecurringPayments, + $expectedResult + ) { + $this->vaultHelperMock->expects($this->once()) + ->method('getPaymentMethodRecurringActive') + ->with(AdyenCcConfigProvider::CODE, self::STORE_ID) + ->willReturn($isCardRecurringEnabled); + + $this->vaultHelperMock->expects($this->once()) + ->method('getPaymentMethodRecurringProcessingModel') + ->with(AdyenCcConfigProvider::CODE, self::STORE_ID) + ->willReturn($recurringProcessingModel); + + $this->configHelperMock->expects($this->once()) + ->method('getIsCvcRequiredForRecurringCardPayments') + ->with(self::STORE_ID) + ->willReturn($isCvcRequiredForCardRecurringPayments); + + $this->assertEquals($expectedResult, $this->availabilityChecker->isAvailable()); + } + + /** + * @return array[] + */ + protected static function availabilityTestDataProvider(): array + { + return [ + [ + 'isCardRecurringEnabled' => true, + 'recurringProcessingModel' => Vault::CARD_ON_FILE, + 'isCvcRequiredForCardRecurringPayments' => false, + 'expectedResult' => true + ], + [ + 'isCardRecurringEnabled' => true, + 'recurringProcessingModel' => Vault::SUBSCRIPTION, + 'isCvcRequiredForCardRecurringPayments' => false, + 'expectedResult' => false + ], + [ + 'isCardRecurringEnabled' => false, + 'recurringProcessingModel' => Vault::CARD_ON_FILE, + 'isCvcRequiredForCardRecurringPayments' => false, + 'expectedResult' => false + ], + [ + 'isCardRecurringEnabled' => true, + 'recurringProcessingModel' => Vault::CARD_ON_FILE, + 'isCvcRequiredForCardRecurringPayments' => true, + 'expectedResult' => false + ] + ]; + } +} diff --git a/Test/Unit/Model/InstantPurchase/Card/TokenFormatterTest.php b/Test/Unit/Model/InstantPurchase/Card/TokenFormatterTest.php new file mode 100644 index 0000000000..0874bee0f4 --- /dev/null +++ b/Test/Unit/Model/InstantPurchase/Card/TokenFormatterTest.php @@ -0,0 +1,99 @@ + + */ + +namespace Adyen\Payment\Test\Helper\Unit\Model\InstantPurchase\Card; + +use Adyen\Payment\Helper\Data; +use Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use InvalidArgumentException; +use Magento\Vault\Api\Data\PaymentTokenInterface; +use PHPUnit\Framework\MockObject\MockObject; + +class TokenFormatterTest extends AbstractAdyenTestCase +{ + const VALID_TOKEN_DETAILS_VISA = '{"type":"visa","maskedCC":"1111","expirationDate":"3/2030","cardHolderName":"Veronica Costello","tokenType":"CardOnFile"}'; + const VALID_TOKEN_DETAILS_EXOTIC = '{"type":"exoticScheme","maskedCC":"4444","expirationDate":"3/2030","cardHolderName":"Veronica Costello","tokenType":"CardOnFile"}'; + + const INVALID_TOKEN_DETAILS = '{"type":"visa","maskedCC":"1111"}'; + const CC_TYPES_MOCK = [ + 'VI' => [ + 'code_alt' => 'visa', + 'name' => 'Visa' + ], + 'MC' => [ + 'code_alt' => 'mc', + 'name' => 'MasterCard' + ] + ]; + + protected TokenFormatter $tokenFormatter; + protected Data|MockObject $adyenHelperMock; + protected PaymentTokenInterface|MockObject $paymentTokenMock; + + public function setUp(): void + { + $this->paymentTokenMock = $this->createMock(PaymentTokenInterface::class); + $this->adyenHelperMock = $this->createMock(Data::class); + + $this->adyenHelperMock->method('getAdyenCcTypes')->willReturn(self::CC_TYPES_MOCK); + + $this->tokenFormatter = new TokenFormatter($this->adyenHelperMock); + } + + /** + * @param $tokenDetails + * @param $expected + * + * @dataProvider validTokenFormatterTestDataProvider + * + * @return void + */ + public function testFormatPaymentTokenValid($tokenDetails, $expected) + { + $this->paymentTokenMock->expects($this->once()) + ->method('getTokenDetails') + ->willReturn($tokenDetails); + + $this->assertEquals( + $expected, + $this->tokenFormatter->formatPaymentToken($this->paymentTokenMock) + ); + } + + protected static function validTokenFormatterTestDataProvider(): array + { + return [ + [ + 'tokenDetails' => self::VALID_TOKEN_DETAILS_VISA, + 'expected' => 'Card: Visa, ending: 1111 (expires: 3/2030)' + ], + [ + 'tokenDetails' => self::VALID_TOKEN_DETAILS_EXOTIC, + 'expected' => 'Card: exoticScheme, ending: 4444 (expires: 3/2030)' + ], + ]; + } + + /** + * @return void + */ + public function testFormatPaymentTokenInvalid() + { + $this->expectException(InvalidArgumentException::class); + + $this->paymentTokenMock->expects($this->once()) + ->method('getTokenDetails') + ->willReturn(self::INVALID_TOKEN_DETAILS); + + $this->tokenFormatter->formatPaymentToken($this->paymentTokenMock); + } +} diff --git a/Test/Unit/Model/InstantPurchase/PaymentMethods/AvailabilityCheckerTest.php b/Test/Unit/Model/InstantPurchase/PaymentMethods/AvailabilityCheckerTest.php new file mode 100644 index 0000000000..0ac040e133 --- /dev/null +++ b/Test/Unit/Model/InstantPurchase/PaymentMethods/AvailabilityCheckerTest.php @@ -0,0 +1,121 @@ + + */ + +namespace Adyen\Payment\Test\Helper\Unit\Model\InstantPurchase\PaymentMethods; + +use Adyen\Payment\Helper\Vault; +use Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Magento\Framework\Exception\NotFoundException; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreManagerInterface; +use PHPUnit\Framework\MockObject\MockObject; + +class AvailabilityCheckerTest extends AbstractAdyenTestCase +{ + const STORE_ID = PHP_INT_MAX; + + protected ?AvailabilityChecker $availabilityChecker; + protected Vault|MockObject $vaultHelperMock; + protected StoreManagerInterface|MockObject $storeManagerMock; + + /** + * @return void + */ + public function setUp(): void + { + $this->vaultHelperMock = $this->createMock(Vault::class); + $this->storeManagerMock = $this->createMock(StoreManagerInterface::class); + + $store = $this->createMock(StoreInterface::class); + $store->method('getId')->willReturn(self::STORE_ID); + $this->storeManagerMock->method('getStore')->willReturn($store); + + $this->availabilityChecker = new AvailabilityChecker( + $this->vaultHelperMock, + $this->storeManagerMock + ); + } + + /** + * @return void + */ + public function tearDown(): void + { + $this->availabilityChecker = null; + } + + /** + * @param $paymentMethod + * @param $isMethodRecurringEnabled + * @param $recurringProcessingModel + * @param $expectedResult + * + * @return void + * @dataProvider availabilityTestDataProvider + */ + public function testIsAvailableAdyenMethod( + $paymentMethod, + $isMethodRecurringEnabled, + $recurringProcessingModel, + $expectedResult + ) { + $this->vaultHelperMock->expects($this->once()) + ->method('getPaymentMethodRecurringActive') + ->with($paymentMethod, self::STORE_ID) + ->willReturn($isMethodRecurringEnabled); + + $this->vaultHelperMock->expects($this->once()) + ->method('getPaymentMethodRecurringProcessingModel') + ->with($paymentMethod, self::STORE_ID) + ->willReturn($recurringProcessingModel); + + $this->assertEquals($expectedResult, $this->availabilityChecker->isAvailableAdyenMethod($paymentMethod)); + } + + /** + * @return array[] + */ + protected static function availabilityTestDataProvider(): array + { + return [ + [ + 'paymentMethod' => 'sepa_direct_debit', + 'isMethodRecurringEnabled' => true, + 'recurringProcessingModel' => Vault::CARD_ON_FILE, + 'expectedResult' => true + ], + [ + 'paymentMethod' => 'sepa_direct_debit', + 'isMethodRecurringEnabled' => false, + 'recurringProcessingModel' => Vault::CARD_ON_FILE, + 'expectedResult' => false + ], + [ + 'paymentMethod' => 'sepa_direct_debit', + 'isMethodRecurringEnabled' => true, + 'recurringProcessingModel' => Vault::SUBSCRIPTION, + 'expectedResult' => false + ] + ]; + } + + /** + * Ensure `isAvailable` is not implemented. + * + * @return void + */ + public function testIsAvailable() + { + $this->expectException(NotFoundException::class); + $this->availabilityChecker->isAvailable(); + } +} diff --git a/Test/Unit/Model/InstantPurchase/PaymentMethods/TokenFormatterTest.php b/Test/Unit/Model/InstantPurchase/PaymentMethods/TokenFormatterTest.php new file mode 100644 index 0000000000..f6fce59ff2 --- /dev/null +++ b/Test/Unit/Model/InstantPurchase/PaymentMethods/TokenFormatterTest.php @@ -0,0 +1,36 @@ + + */ + +namespace Adyen\Payment\Test\Helper\Unit\Model\InstantPurchase\PaymentMethods; + +use Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Magento\Vault\Api\Data\PaymentTokenInterface; + +class TokenFormatterTest extends AbstractAdyenTestCase +{ + public function testFormatPaymentToken() + { + $tokenFormatter = new TokenFormatter(); + $paymentTokenMock = $this->createMock(PaymentTokenInterface::class); + + $tokenDetails = '{"type":"sepadirectdebit","tokenLabel":"SEPA Direct Debit token created on 2024-12-11"}'; + + $paymentTokenMock->expects($this->once()) + ->method('getTokenDetails') + ->willReturn($tokenDetails); + + $this->assertEquals( + 'SEPA Direct Debit token created on 2024-12-11', + $tokenFormatter->formatPaymentToken($paymentTokenMock) + ); + } +} diff --git a/Test/Unit/Model/Ui/AdyenCcConfigProviderTest.php b/Test/Unit/Model/Ui/AdyenCcConfigProviderTest.php new file mode 100644 index 0000000000..96c9bfb9e6 --- /dev/null +++ b/Test/Unit/Model/Ui/AdyenCcConfigProviderTest.php @@ -0,0 +1,160 @@ + + */ + +namespace Adyen\Payment\Model\Ui; + +use Adyen\Payment\Helper\Config; +use Adyen\Payment\Helper\Data; +use Adyen\Payment\Helper\PaymentMethods; +use Adyen\Payment\Helper\Vault; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Framework\UrlInterface; +use Magento\Framework\View\Asset\File; +use Magento\Framework\View\Asset\Source; +use Magento\Payment\Model\CcConfig; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreManagerInterface; +use PHPUnit\Framework\MockObject\MockObject; + +class AdyenCcConfigProviderTest extends AbstractAdyenTestCase +{ + protected ?AdyenCcConfigProvider $adyenCcConfigProvider; + protected Data|MockObject $adyenHelperMock; + protected RequestInterface|MockObject $requestMock; + protected UrlInterface|MockObject $urlBuilderMock; + protected Source|MockObject $assetSourceMock; + protected StoreManagerInterface|MockObject $storeManagerMock; + protected CcConfig|MockObject $ccConfigMock; + protected SerializerInterface|MockObject $serializerMock; + protected Config|MockObject $configHelperMock; + protected PaymentMethods|MockObject $paymentMethodsHelperMock; + protected Vault|MockObject $vaultHelperMock; + + /** + * @return void + */ + protected function setUp(): void + { + $this->adyenHelperMock = $this->createMock(Data::class); + $this->requestMock = $this->createMock(RequestInterface::class); + $this->urlBuilderMock = $this->createMock(UrlInterface::class); + $this->assetSourceMock = $this->createMock(Source::class); + $this->storeManagerMock = $this->createMock(StoreManagerInterface::class); + $this->ccConfigMock = $this->createMock(CcConfig::class); + $this->serializerMock = $this->createMock(SerializerInterface::class); + $this->configHelperMock = $this->createMock(Config::class); + $this->paymentMethodsHelperMock = $this->createMock(PaymentMethods::class); + $this->vaultHelperMock = $this->createMock(Vault::class); + + $this->adyenCcConfigProvider = new AdyenCcConfigProvider( + $this->adyenHelperMock, + $this->requestMock, + $this->urlBuilderMock, + $this->assetSourceMock, + $this->storeManagerMock, + $this->ccConfigMock, + $this->serializerMock, + $this->configHelperMock, + $this->paymentMethodsHelperMock, + $this->vaultHelperMock + ); + } + + /** + * @return void + */ + protected function tearDown(): void + { + $this->adyenCcConfigProvider = null; + } + + /** + * @param $enableInstallments + * @return void + * + * @dataProvider getConfigTestDataProvider + */ + public function testGetConfig($enableInstallments) + { + $storeId = PHP_INT_MAX; + $store = $this->createMock(StoreInterface::class); + $store->method('getId')->willReturn($storeId); + $this->storeManagerMock->method('getStore')->willReturn($store); + + $this->configHelperMock->method('getAdyenCcConfigData') + ->willReturnMap([ + ['enable_installments', null, $enableInstallments], + ['installments', null, 'mock_serialized_installments'], + ['useccv', null, true] + ]); + + $this->adyenHelperMock->method('getAdyenCcTypes') + ->willReturn(['MC' => ['name' => 'MasterCard', 'code_alt' => 'mc']]); + + $assetMockMasterCard = $this->createMock(File::class); + $assetMockMasterCard->method('getSourceFile')->willReturn( + __DIR__ . '/../../../../view/base/web/images/adyen/adyen-hq.svg' + ); + + $this->ccConfigMock->method('createAsset')->willReturn($assetMockMasterCard); + + $this->assetSourceMock->method('findSource') + ->with($assetMockMasterCard) + ->willReturn('mock_relative_icon_path'); + + $this->ccConfigMock->expects($this->once()) + ->method('getCcMonths'); + + $this->ccConfigMock->expects($this->once()) + ->method('getCcYears'); + + $this->ccConfigMock->expects($this->once()) + ->method('getCvvImageUrl'); + + $configObject = $this->adyenCcConfigProvider->getConfig(); + + $this->assertArrayHasKey('installments', $configObject['payment']['adyenCc']); + $this->assertArrayHasKey('isClickToPayEnabled', $configObject['payment']['adyenCc']); + $this->assertArrayHasKey('icons', $configObject['payment']['adyenCc']); + $this->assertArrayHasKey('isCardRecurringEnabled', $configObject['payment']['adyenCc']); + $this->assertArrayHasKey('locale', $configObject['payment']['adyenCc']); + $this->assertArrayHasKey('title', $configObject['payment']['adyenCc']); + $this->assertArrayHasKey('methodCode', $configObject['payment']['adyenCc']); + $this->assertArrayHasKey('availableTypes', $configObject['payment']['ccform']); + $this->assertArrayHasKey('availableTypesByAlt', $configObject['payment']['ccform']); + $this->assertArrayHasKey('months', $configObject['payment']['ccform']); + $this->assertArrayHasKey('years', $configObject['payment']['ccform']); + $this->assertArrayHasKey('hasVerification', $configObject['payment']['ccform']); + $this->assertArrayHasKey('cvvImageUrl', $configObject['payment']['ccform']); + } + + /** + * @return array + */ + protected function getConfigTestDataProvider(): array + { + return [ + ['enableInstallments' => true], + ['enableInstallments' => false] + ]; + } + + /** + * @return void + */ + public function testConstants() + { + $this->assertEquals('adyen_cc', AdyenCcConfigProvider::CODE); + $this->assertEquals('adyen_cc_vault', AdyenCcConfigProvider::CC_VAULT_CODE); + } +} diff --git a/Test/Unit/Plugin/InstantPurchaseIntegrationTest.php b/Test/Unit/Plugin/InstantPurchaseIntegrationTest.php new file mode 100644 index 0000000000..f8fc8e3aea --- /dev/null +++ b/Test/Unit/Plugin/InstantPurchaseIntegrationTest.php @@ -0,0 +1,153 @@ + + */ + +namespace Adyen\Payment\Test\Plugin; + +use Adyen\Payment\Api\InstantPurchase\PaymentMethodIntegration\AdyenAvailabilityCheckerInterface; +use Adyen\Payment\Helper\PaymentMethods; +use Adyen\Payment\Model\Method\PaymentMethodVault; +use Adyen\Payment\Plugin\InstantPurchaseIntegration; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Magento\Framework\Exception\LocalizedException; +use Magento\InstantPurchase\PaymentMethodIntegration\Integration; +use Magento\Payment\Helper\Data; +use Magento\Payment\Model\MethodInterface; +use PHPUnit\Framework\MockObject\MockObject; + +class InstantPurchaseIntegrationTest extends AbstractAdyenTestCase +{ + protected ?InstantPurchaseIntegration $instantPurchaseIntegrationPlugin; + protected Integration|MockObject $subjectMock; + protected AdyenAvailabilityCheckerInterface|MockObject $adyenAvailabilityCheckerMock; + protected PaymentMethods|MockObject $paymentMethodsMock; + protected Data $magentoDataHelperMock; + + public function setUp(): void + { + $this->adyenAvailabilityCheckerMock = $this->createMock( + AdyenAvailabilityCheckerInterface::class + ); + $this->paymentMethodsMock = $this->createMock(PaymentMethods::class); + $this->magentoDataHelperMock = $this->createMock(Data::class); + $this->subjectMock = $this->createMock(Integration::class); + + $this->instantPurchaseIntegrationPlugin = new InstantPurchaseIntegration( + $this->adyenAvailabilityCheckerMock, + $this->paymentMethodsMock, + $this->magentoDataHelperMock + ); + } + + public function tearDown(): void + { + $this->instantPurchaseIntegrationPlugin = null; + } + + /** + * @param $providerCode + * @param $isAdyenAlternativePaymentMethod + * @param $isWallet + * @param $shouldIntercept + * + * @return void + * @throws LocalizedException + * + * @dataProvider dataProviderForNotApplicableCases + * + */ + public function testAroundIsAvailable( + $providerCode, + $isAdyenAlternativePaymentMethod, + $isWallet, + $shouldIntercept + ) { + $vaultMethodInstanceMock = $this->createMock(PaymentMethodVault::class); + $vaultMethodInstanceMock->method('getProviderCode') + ->willReturn($providerCode); + + $this->subjectMock->expects($this->once()) + ->method('getPaymentMethod') + ->willReturn($vaultMethodInstanceMock); + + $providerMethodInstanceMock = $this->createMock(MethodInterface::class); + + $this->magentoDataHelperMock->expects($this->once()) + ->method('getMethodInstance') + ->with($providerCode) + ->willReturn($providerMethodInstanceMock); + + $this->paymentMethodsMock->expects($this->once()) + ->method('isAlternativePaymentMethod') + ->with($providerMethodInstanceMock) + ->willReturn($isAdyenAlternativePaymentMethod); + + $this->paymentMethodsMock->expects($this->once()) + ->method('isWalletPaymentMethod') + ->with($providerMethodInstanceMock) + ->willReturn($isWallet); + + $this->subjectMock->method('isAvailable')->willReturn(true); + + if ($shouldIntercept) { + $this->adyenAvailabilityCheckerMock + ->expects($this->once()) + ->method('isAvailableAdyenMethod') + ->with($providerCode) + ->willReturn(true); + } else { + $this->adyenAvailabilityCheckerMock->expects($this->never())->method('isAvailableAdyenMethod'); + } + + $result = $this->instantPurchaseIntegrationPlugin->aroundIsAvailable( + $this->subjectMock, + [$this, 'callableMockFunction'] + ); + + $this->assertTrue($result); + } + + /** + * Mock the callable argument of `aroundIsAvailable` method. + * + * @return bool + */ + public function callableMockFunction(): bool + { + return true; + } + + /** + * @return array[] + */ + public static function dataProviderForNotApplicableCases(): array + { + return [ + [ + 'providerCode' => 'adyen_cc', + 'isAdyenAlternativePaymentMethod' => false, + 'isWallet' => false, + 'shouldIntercept' => false, + ], + [ + 'providerCode' => 'adyen_googlepay', + 'isAdyenAlternativePaymentMethod' => true, + 'isWallet' => true, + 'shouldIntercept' => false, + ], + [ + 'providerCode' => 'adyen_sepa_direct_debit', + 'isAdyenAlternativePaymentMethod' => true, + 'isWallet' => false, + 'shouldIntercept' => true, + ] + ]; + } +} diff --git a/composer.json b/composer.json index 6c775c9348..d9be60eaa9 100755 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "magento/module-vault": ">=101.2.4", "magento/module-multishipping": ">=100.4.4", "magento/module-graph-ql": ">=100.4.4", + "magento/module-instant-purchase": ">=100.4.4", "ext-json": "*" }, "require-dev": { diff --git a/etc/config.xml b/etc/config.xml index b432bd83ff..f47e7dfb23 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -68,6 +68,10 @@ Stored Cards (Adyen) AdyenPaymentCardVaultFacade 1 + + Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter + 0 @@ -171,6 +175,10 @@ Stored Klarna AdyenPaymentKlarnaVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -200,6 +208,10 @@ Stored PayPal AdyenPaymentPaypalVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -276,6 +288,10 @@ Stored Amazon Pay AdyenPaymentAmazonpayVaultFacade + + Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter + 0 @@ -305,6 +321,10 @@ Stored GooglePay AdyenPaymentGooglepayVaultFacade + + Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter + 0 @@ -383,6 +403,10 @@ Stored SEPA Direct Debit AdyenPaymentSepadirectdebitVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -498,6 +522,10 @@ Stored Apple Pay AdyenPaymentApplePayVaultFacade + + Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter + 0 @@ -896,6 +924,10 @@ Stored Klarna Debit Risk AdyenPaymentDirectEbankingVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -1054,6 +1086,10 @@ Stored EPS AdyenPaymentEpsVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -1168,6 +1204,10 @@ Stored Giropay AdyenPaymentGiropayVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -1286,6 +1326,10 @@ Stored Klarna Pay over Time AdyenPaymentKlarnaAccountVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -1312,6 +1356,10 @@ Stored Klarna Pay Now AdyenPaymentKlarnaPaynowVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -1514,6 +1562,10 @@ Stored Open banking AdyenPaymentPaybybankVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -1651,6 +1703,10 @@ Stored TWINT AdyenPaymentTwintVaultFacade + + Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter + 0 @@ -1743,6 +1799,10 @@ Stored Zip AdyenPaymentZipVaultFacade + + Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter + 0 @@ -1769,6 +1829,10 @@ Stored GCash AdyenPaymentGcashVaultFacade + + Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter + 0 @@ -1839,6 +1903,10 @@ Stored Carnet AdyenPaymentCarnetVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -1909,6 +1977,10 @@ Stored MoMo Wallet AdyenPaymentMomoWalletVaultFacade + + Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter + 0 @@ -1957,6 +2029,10 @@ Stored Bancontact AdyenPaymentBcmcVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -1983,6 +2059,10 @@ Stored Cash App Pay AdyenPaymentCashappVaultFacade + + Adyen\Payment\Model\InstantPurchase\PaymentMethods\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\PaymentMethods\TokenFormatter + 0 @@ -2207,6 +2287,10 @@ Stored DANA AdyenPaymentDanaVaultFacade + + Adyen\Payment\Model\InstantPurchase\Card\AvailabilityChecker + Adyen\Payment\Model\InstantPurchase\Card\TokenFormatter + 0 diff --git a/etc/di.xml b/etc/di.xml index aefb9b552a..e7fc019f4f 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -1079,7 +1079,7 @@ Adyen\Payment\Gateway\Request\ReturnUrlDataBuilder Adyen\Payment\Gateway\Request\ChannelDataBuilder Adyen\Payment\Gateway\Request\OriginDataBuilder - Adyen\Payment\Gateway\Request\HeaderDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder Adyen\Payment\Gateway\Request\GiftcardDataBuilder @@ -1113,6 +1113,7 @@ Adyen\Payment\Gateway\Request\PaymentDataBuilder Adyen\Payment\Gateway\Request\DescriptionDataBuilder Adyen\Payment\Gateway\Request\CheckoutDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder @@ -1132,7 +1133,7 @@ Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder Adyen\Payment\Gateway\Request\RecurringVaultDataBuilder Adyen\Payment\Gateway\Request\ShopperInteractionDataBuilder - Adyen\Payment\Gateway\Request\HeaderDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder Adyen\Payment\Gateway\Request\GiftcardDataBuilder @@ -1152,7 +1153,7 @@ Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder Adyen\Payment\Gateway\Request\RecurringVaultDataBuilder Adyen\Payment\Gateway\Request\ShopperInteractionDataBuilder - Adyen\Payment\Gateway\Request\HeaderDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder Adyen\Payment\Gateway\Request\GiftcardDataBuilder @@ -1200,7 +1201,7 @@ Adyen\Payment\Gateway\Request\RecurringDataBuilder Adyen\Payment\Gateway\Request\ShopperInteractionDataBuilder Adyen\Payment\Gateway\Request\CheckoutDataBuilder - Adyen\Payment\Gateway\Request\HeaderDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder Adyen\Payment\Gateway\Request\ReturnUrlDataBuilder Adyen\Payment\Gateway\Request\ChannelDataBuilder Adyen\Payment\Gateway\Request\OriginDataBuilder @@ -1220,7 +1221,7 @@ Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder Adyen\Payment\Gateway\Request\ShopperInteractionDataBuilder Adyen\Payment\Gateway\Request\CheckoutDataBuilder - Adyen\Payment\Gateway\Request\HeaderDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder Adyen\Payment\Gateway\Request\ReturnUrlDataBuilder Adyen\Payment\Gateway\Request\ChannelDataBuilder Adyen\Payment\Gateway\Request\OriginDataBuilder @@ -1248,7 +1249,7 @@ Adyen\Payment\Gateway\Request\RecurringDataBuilder Adyen\Payment\Gateway\Request\ShopperInteractionDataBuilder Adyen\Payment\Gateway\Request\CheckoutDataBuilder - Adyen\Payment\Gateway\Request\HeaderDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder Adyen\Payment\Gateway\Request\ReturnUrlDataBuilder Adyen\Payment\Gateway\Request\ChannelDataBuilder Adyen\Payment\Gateway\Request\OriginDataBuilder @@ -1269,6 +1270,7 @@ Adyen\Payment\Gateway\Request\MerchantAccountDataBuilder Adyen\Payment\Gateway\Request\CaptureDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder @@ -1286,6 +1288,7 @@ Adyen\Payment\Gateway\Request\RefundDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder @@ -1302,6 +1305,7 @@ Adyen\Payment\Gateway\Request\CancelDataBuilder + Adyen\Payment\Gateway\Request\Header\HeaderDataBuilder @@ -1461,6 +1465,8 @@ + Magento\Framework\Filesystem\Driver\File @@ -1717,6 +1723,9 @@ + + + @@ -4559,4 +4568,4 @@ adyen_doku_mandiri_va - \ No newline at end of file + diff --git a/view/frontend/web/js/view/payment/method-renderer/adyen-cc-vault-method.js b/view/frontend/web/js/view/payment/method-renderer/adyen-cc-vault-method.js index dbad6e1d5a..45a44078e1 100644 --- a/view/frontend/web/js/view/payment/method-renderer/adyen-cc-vault-method.js +++ b/view/frontend/web/js/view/payment/method-renderer/adyen-cc-vault-method.js @@ -260,7 +260,7 @@ define([ stateData: stateData, public_hash: this.publicHash, numberOfInstallments: this.installment(), - frontendType: 'luma' + frontendType: 'default' }, }; }, diff --git a/view/frontend/web/js/view/payment/method-renderer/adyen-pm-method.js b/view/frontend/web/js/view/payment/method-renderer/adyen-pm-method.js index f6bf2dffc9..c3918236f7 100755 --- a/view/frontend/web/js/view/payment/method-renderer/adyen-pm-method.js +++ b/view/frontend/web/js/view/payment/method-renderer/adyen-pm-method.js @@ -155,7 +155,7 @@ define( fullScreenLoader.stopLoader(); errorProcessor.process(error, this.currentMessageContainer); }, - + renderCheckoutComponent: function() { let methodCode = this.getMethodCode(); let configuration = this.buildComponentConfiguration(this.paymentMethod(), this.paymentMethodsExtraInfo()); @@ -294,7 +294,7 @@ define( let additionalData = {}; additionalData.brand_code = this.paymentMethod().type; - additionalData.frontendType = 'luma'; + additionalData.frontendType = 'default'; let stateData; if (this.paymentComponent) { diff --git a/view/frontend/web/js/view/payment/method-renderer/adyen-pm-vault-method.js b/view/frontend/web/js/view/payment/method-renderer/adyen-pm-vault-method.js index 5452313181..3f56674671 100644 --- a/view/frontend/web/js/view/payment/method-renderer/adyen-pm-vault-method.js +++ b/view/frontend/web/js/view/payment/method-renderer/adyen-pm-vault-method.js @@ -54,6 +54,15 @@ define([ */ getIcons: function (type) { return this.details.icon; + }, + getData: function () { + return { + method: this.code, + additional_data: { + public_hash: this.publicHash, + frontendType: 'default' + }, + }; } }); });