We will be off from 27/1 (Monday) to 31/1 (Friday) (GMT +7) for our Tet Holiday (Lunar New Year) in our country

Commit 10062ad9 authored by Alexandros Moraitis's avatar Alexandros Moraitis Committed by GitHub

[PW-3431] Merge generic component to 7.0.0-rc.1 (#888)

* Add bundle.js with checkout component version 3.12.1 (#828)

Add the AdyenComponent var in the requireJS paramas

* [PW-3133] Refactor threeds2 to paymentDetails (#829)

* Refactor threeds2 to paymentDetails

* paymentDetails.paymentDetails -> paymentDetails.process

* [PW-3136]Processing generic payment details requests (#835)

* Processing generic payment details requests
Co-authored-by: default avatarmarcoss <marcos.silvagarcia@adyen.com>

* [PW-3137] Refactor Payment Status endpoint (#839)

* [PW-3127] Validate payment methods (#838)

* payment methods response validation

* Remove getConnectedTerminals

* Refactor

* Fix suggestions

* Refactor paymentmethods

* Refactor method names

* Refactor payment method request

* [PW-3174] Use the generic component for card payments (#840)

* Use bundle instead of the component

* Store action and additionalData from /payments response

* [WIP] handle paymentDetails for card payments

* Remove custom redirect page

The checkout redirect component does the redirect for both 3DS1(now) and
alternative payment(WIP)

* Store and return details

Store action, resultCode, additionalData, pspReference, nad paymentData

* Show challenge in a popup for 3DS2

* [PW-3180] Remove generalResponseValidator (#841)

* Use bundle instead of the component

* Store action and additionalData from /payments response

* [WIP] handle paymentDetails for card payments

* Remove custom redirect page

The checkout redirect component does the redirect for both 3DS1(now) and
alternative payment(WIP)

* Store and return details

Store action, resultCode, additionalData, pspReference, nad paymentData

* Show challenge in a popup for 3DS2

* Remove GeneralResponseValidator.php

Change wrong phpdocs as well

* Use Generic Components for Google Pay (#845)
Co-authored-by: default avatarmarcoss <marcos.silvagarcia@adyen.com>

* [PW-3131] Use generic component for alternative payment methods (#843)

* Remove methodlist

* Remove payment-details.js and move request into the service.js

* Rename retrieveAvailablePaymentMethods to getPaymentMethods

and return a promise instead of setting the methods when done

* Remove threeds2-js-utils.js and usage

* Add adyen-configuration.js

* Initialize checkout component and store it

* Use the new paymentMethods response from the component

* Move logic from CcAuthorizationDataBuilder to CheckoutDataBuilder

Remove CcAuthorizationDataBuilder.php

* require php api library version 8

Use checkout API v64 instead of 52
Use the new services from the library since v7

* Move logic from ThreeDS2DataBuilder to CheckoutDataBuilder

Remove ThreeDS2DataBuilder.php

* Simplify adyen-cc-method.js

Send the whole state.data in 1 request field instead of manually mapping

* Adjust adyen-payment-service to multi payment method structure

the onAdditionalData callback can be handled only from the main
adyenCheckout component therefore it cannot be created in one central
place but in each payment method renderer

* Adjust the AdyenCcDataAssignObserver to handle the full state data

* Update generic component to the latest bundle

* Fix 3DS1 response in CheckoutResponseValidator.php

We don't need to map fields and store each field individually

* Standardise cc and alternative payment methods observers

Validate the top level keys in state.data from the checkout component
Store additionalData fields in additionalInformation

* Use state.data validated array for the /payments request

Do not map each field in the request from additionalInformation but use
the validated state.data array as a base request

* Standardise alternative payment methods frontend

Do not create checkout components one by one but while iterating through
the paymentMethods list
Build state.data for payment methods which has no component created
Prefill component input fields with data the plugin already know
Remove unused code

* Remove line item itemId from checkout requests

Version 64 does not support it anymore

* Adjust personal details request structure to checkout version 64

Open invoice payment methods required a different request structure
before, in version 64 it has been standardised and enforced

* Make paymentMethods array observable

Update payment methods list when shipping address country is changed
Rerender payment methods list on the frontend when paymentMethods array
changes

* Update view/frontend/web/js/model/adyen-configuration.js
Co-authored-by: default avatarÁngel Campos <angel.campos@adyen.com>

* Fix code smells

* Fix removed dependency
Co-authored-by: default avatarÁngel Campos <angel.campos@adyen.com>

* Fix bug sonar after sonarcloud check

* Add legend field

* Add legend field in the correct place

* Update Helper/Requests.php
Co-authored-by: default avatarAttila Kiss <42297201+cyattilakiss@users.noreply.github.com>
Co-authored-by: default avatarAttila Kiss <42297201+cyattilakiss@users.noreply.github.com>
Co-authored-by: default avatarÁngel Campos <angel.campos@adyen.com>
Co-authored-by: default avatarmarcoss <marcos.silvagarcia@adyen.com>
Co-authored-by: default avatarMarcos Garcia <marcos.asgarcia@gmail.com>
Co-authored-by: default avatarattilak <attila.kiss@adyen.com>
parent 43fb5b0c
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
namespace Adyen\Payment\Api; namespace Adyen\Payment\Api;
interface AdyenThreeDS2ProcessInterface interface AdyenPaymentDetailsInterface
{ {
/** /**
* @param string $payload * @param string $payload
......
This diff is collapsed.
...@@ -148,7 +148,6 @@ class Redirect extends \Magento\Framework\App\Action\Action ...@@ -148,7 +148,6 @@ class Redirect extends \Magento\Framework\App\Action\Action
if ($order->getPayment()) { if ($order->getPayment()) {
$active = $order->getPayment()->getAdditionalInformation('3dActive'); $active = $order->getPayment()->getAdditionalInformation('3dActive');
$success = $order->getPayment()->getAdditionalInformation('3dSuccess'); $success = $order->getPayment()->getAdditionalInformation('3dSuccess');
$checkoutAPM = $order->getPayment()->getAdditionalInformation('checkoutAPM');
} }
// check if 3D secure is active. If not just go to success page // check if 3D secure is active. If not just go to success page
...@@ -257,10 +256,6 @@ class Redirect extends \Magento\Framework\App\Action\Action ...@@ -257,10 +256,6 @@ class Redirect extends \Magento\Framework\App\Action\Action
$this->_view->getLayout()->initMessages(); $this->_view->getLayout()->initMessages();
$this->_view->renderLayout(); $this->_view->renderLayout();
} }
} elseif (!empty($checkoutAPM)) {
$this->_view->loadLayout();
$this->_view->getLayout()->initMessages();
$this->_view->renderLayout();
} else { } else {
$this->_redirect('checkout/onepage/success', ['_query' => ['utm_nooverride' => '1']]); $this->_redirect('checkout/onepage/success', ['_query' => ['utm_nooverride' => '1']]);
} }
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2019 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
class CcAuthorizationDataBuilder implements BuilderInterface
{
/**
* @param array $buildSubject
* @return mixed
*/
public function build(array $buildSubject)
{
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$requestBody = [];
// If ccType is set use this. For bcmc you need bcmc otherwise it will fail
$requestBody['paymentMethod']['type'] = "scheme";
if ($cardNumber = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER)) {
$requestBody['paymentMethod']['encryptedCardNumber'] = $cardNumber;
}
if ($expiryMonth = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH)) {
$requestBody['paymentMethod']['encryptedExpiryMonth'] = $expiryMonth;
}
if ($expiryYear = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR)) {
$requestBody['paymentMethod']['encryptedExpiryYear'] = $expiryYear;
}
if ($holderName = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME)) {
$requestBody['paymentMethod']['holderName'] = $holderName;
}
if ($securityCode = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE)) {
$requestBody['paymentMethod']['encryptedSecurityCode'] = $securityCode;
}
// Remove from additional data
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME);
// if installments is set and card type is credit card add it into the request
$numberOfInstallments = $payment->getAdditionalInformation(
AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS
) ?: 0;
$comboCardType = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::COMBO_CARD_TYPE) ?: 'credit';
if ($numberOfInstallments > 0) {
$requestBody['installments']['value'] = $numberOfInstallments;
}
// if card type is debit then change the issuer type and unset the installments field
if ($comboCardType == 'debit') {
if ($selectedDebitBrand = $this->getSelectedDebitBrand($payment->getAdditionalInformation('cc_type'))) {
$requestBody['additionalData']['overwriteBrand'] = true;
$requestBody['selectedBrand'] = $selectedDebitBrand;
$requestBody['paymentMethod']['type'] = $selectedDebitBrand;
}
unset($requestBody['installments']);
}
$request['body'] = $requestBody;
return $request;
}
/**
* @param string $brand
* @return string
*/
private function getSelectedDebitBrand($brand)
{
if ($brand == 'VI') {
return 'electron';
}
if ($brand == 'MC') {
return 'maestro';
}
return null;
}
}
...@@ -23,7 +23,9 @@ ...@@ -23,7 +23,9 @@
namespace Adyen\Payment\Gateway\Request; namespace Adyen\Payment\Gateway\Request;
use Adyen\Payment\Helper\ChargedCurrency; use Adyen\Payment\Helper\ChargedCurrency;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
use Magento\Payment\Gateway\Request\BuilderInterface; use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenHppDataAssignObserver; use Adyen\Payment\Observer\AdyenHppDataAssignObserver;
...@@ -85,22 +87,13 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -85,22 +87,13 @@ class CheckoutDataBuilder implements BuilderInterface
$payment = $paymentDataObject->getPayment(); $payment = $paymentDataObject->getPayment();
$order = $payment->getOrder(); $order = $payment->getOrder();
$storeId = $order->getStoreId(); $storeId = $order->getStoreId();
$requestBody = [];
// Initialize the request body with the validated state data
$requestBody = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::STATE_DATA);
// do not send email // do not send email
$order->setCanSendNewEmailFlag(false); $order->setCanSendNewEmailFlag(false);
$requestBodyPaymentMethod['type'] = $payment->getAdditionalInformation(
AdyenHppDataAssignObserver::BRAND_CODE
);
// Additional data for payment methods with issuer list
if ($payment->getAdditionalInformation(AdyenHppDataAssignObserver::ISSUER_ID)) {
$requestBodyPaymentMethod['issuer'] = $payment->getAdditionalInformation(
AdyenHppDataAssignObserver::ISSUER_ID
);
}
$requestBody['returnUrl'] = $this->storeManager->getStore()->getBaseUrl( $requestBody['returnUrl'] = $this->storeManager->getStore()->getBaseUrl(
\Magento\Framework\UrlInterface::URL_TYPE_LINK \Magento\Framework\UrlInterface::URL_TYPE_LINK
) . 'adyen/process/result'; ) . 'adyen/process/result';
...@@ -118,46 +111,6 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -118,46 +111,6 @@ class CheckoutDataBuilder implements BuilderInterface
$requestBody['bankAccount']['ownerName'] = $payment->getAdditionalInformation("bankAccountOwnerName"); $requestBody['bankAccount']['ownerName'] = $payment->getAdditionalInformation("bankAccountOwnerName");
} }
// Additional data for open invoice payment
if ($payment->getAdditionalInformation("gender")) {
$order->setCustomerGender(
$this->gender->getMagentoGenderFromAdyenGender(
$payment->getAdditionalInformation("gender")
)
);
$requestBodyPaymentMethod['personalDetails']['gender'] = $payment->getAdditionalInformation("gender");
}
if ($payment->getAdditionalInformation("dob")) {
$order->setCustomerDob($payment->getAdditionalInformation("dob"));
$requestBodyPaymentMethod['personalDetails']['dateOfBirth'] = $this->adyenHelper->formatDate(
$payment->getAdditionalInformation("dob"),
'Y-m-d'
);
}
if ($payment->getAdditionalInformation("telephone")) {
$order->getBillingAddress()->setTelephone($payment->getAdditionalInformation("telephone"));
$requestBodyPaymentMethod['personalDetails']['telephoneNumber'] = $payment->getAdditionalInformation(
"telephone"
);
}
if ($payment->getAdditionalInformation("ssn")) {
$requestBodyPaymentMethod['personalDetails']['socialSecurityNumber'] =
$payment->getAdditionalInformation("ssn");
}
// Additional data for sepa direct debit
if ($payment->getAdditionalInformation("ownerName")) {
$requestBodyPaymentMethod['sepa.ownerName'] = $payment->getAdditionalInformation("ownerName");
}
if ($payment->getAdditionalInformation("ibanNumber")) {
$requestBodyPaymentMethod['sepa.ibanNumber'] = $payment->getAdditionalInformation("ibanNumber");
}
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod( if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod(
$payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE) $payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE)
) || $this->adyenHelper->isPaymentMethodAfterpayTouchMethod( ) || $this->adyenHelper->isPaymentMethodAfterpayTouchMethod(
...@@ -221,12 +174,55 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -221,12 +174,55 @@ class CheckoutDataBuilder implements BuilderInterface
$order->setCanSendNewEmailFlag(true); $order->setCanSendNewEmailFlag(true);
} }
// if installments is set and card type is credit card add it into the request
$numberOfInstallments = $payment->getAdditionalInformation(
AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS
) ?: 0;
$comboCardType = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::COMBO_CARD_TYPE) ?: 'credit';
if ($numberOfInstallments > 0) {
$requestBody['installments']['value'] = $numberOfInstallments;
}
// if card type is debit then change the issuer type and unset the installments field
if ($comboCardType == 'debit') {
if ($selectedDebitBrand = $this->getSelectedDebitBrand($payment->getAdditionalInformation('cc_type'))) {
$requestBody['additionalData']['overwriteBrand'] = true;
$requestBody['selectedBrand'] = $selectedDebitBrand;
$requestBody['paymentMethod']['type'] = $selectedDebitBrand;
}
unset($requestBody['installments']);
}
if ($this->adyenHelper->isCreditCardThreeDS2Enabled($storeId)) {
$requestBody['additionalData']['allow3DS2'] = true;
}
$requestBody['origin'] = $this->adyenHelper->getOrigin($storeId);
$requestBody['channel'] = 'web';
if (isset($requestBodyPaymentMethod)) {
$requestBody['paymentMethod'] = $requestBodyPaymentMethod; $requestBody['paymentMethod'] = $requestBodyPaymentMethod;
}
$request['body'] = $requestBody; $request['body'] = $requestBody;
return $request; return $request;
} }
/**
* @param string $brand
* @return string
*/
private function getSelectedDebitBrand($brand)
{
if ($brand == 'VI') {
return 'electron';
}
if ($brand == 'MC') {
return 'maestro';
}
return null;
}
/** /**
* @param \Magento\Sales\Model\Order $order * @param \Magento\Sales\Model\Order $order
* *
...@@ -267,7 +263,6 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -267,7 +263,6 @@ class CheckoutDataBuilder implements BuilderInterface
$formFields['lineItems'][] = [ $formFields['lineItems'][] = [
'id' => $item->getId(), 'id' => $item->getId(),
'itemId' => $item->getId(),
'amountExcludingTax' => $formattedPriceExcludingTax, 'amountExcludingTax' => $formattedPriceExcludingTax,
'taxAmount' => $formattedTaxAmount, 'taxAmount' => $formattedTaxAmount,
'description' => $item->getName(), 'description' => $item->getName(),
...@@ -318,7 +313,7 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -318,7 +313,7 @@ class CheckoutDataBuilder implements BuilderInterface
} }
$formFields['lineItems'][] = [ $formFields['lineItems'][] = [
'itemId' => 'shippingCost', 'id' => 'shippingCost',
'amountExcludingTax' => $formattedPriceExcludingTax, 'amountExcludingTax' => $formattedPriceExcludingTax,
'taxAmount' => $formattedTaxAmount, 'taxAmount' => $formattedTaxAmount,
'description' => $order->getShippingDescription(), 'description' => $order->getShippingDescription(),
......
...@@ -33,7 +33,7 @@ class CancelResponseValidator extends AbstractValidator ...@@ -33,7 +33,7 @@ class CancelResponseValidator extends AbstractValidator
private $adyenLogger; private $adyenLogger;
/** /**
* GeneralResponseValidator constructor. * CancelResponseValidator constructor.
* *
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory * @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger * @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
......
...@@ -33,7 +33,7 @@ class CaptureResponseValidator extends AbstractValidator ...@@ -33,7 +33,7 @@ class CaptureResponseValidator extends AbstractValidator
private $adyenLogger; private $adyenLogger;
/** /**
* GeneralResponseValidator constructor. * CaptureResponseValidator constructor.
* *
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory * @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger * @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
......
...@@ -38,10 +38,11 @@ class CheckoutResponseValidator extends AbstractValidator ...@@ -38,10 +38,11 @@ class CheckoutResponseValidator extends AbstractValidator
private $adyenHelper; private $adyenHelper;
/** /**
* GeneralResponseValidator constructor. * CheckoutResponseValidator constructor.
* *
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory * @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger * @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param \Adyen\Payment\Helper\Data $adyenHelper
*/ */
public function __construct( public function __construct(
\Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory, \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory,
...@@ -66,29 +67,32 @@ class CheckoutResponseValidator extends AbstractValidator ...@@ -66,29 +67,32 @@ class CheckoutResponseValidator extends AbstractValidator
$payment->setAdditionalInformation('3dActive', false); $payment->setAdditionalInformation('3dActive', false);
$isValid = true; $isValid = true;
$errorMessages = []; $errorMessages = [];
$resultCode = $response['resultCode'];
// validate result // validate result
if (!empty($resultCode)) { if (!empty($response['resultCode'])) {
$resultCode = $response['resultCode'];
$payment->setAdditionalInformation('resultCode', $resultCode); $payment->setAdditionalInformation('resultCode', $resultCode);
switch ($resultCode) {
case "IdentifyShopper": if (!empty($response['action'])) {
$payment->setAdditionalInformation('threeDSType', $resultCode); $payment->setAdditionalInformation('action', $response['action']);
$payment->setAdditionalInformation( }
'threeDS2Token',
$response['authentication']['threeds2.fingerprintToken'] if (!empty($response['additionalData'])) {
); $payment->setAdditionalInformation('additionalData', $response['additionalData']);
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']); }
break;
case "ChallengeShopper": if (!empty($response['pspReference'])) {
$payment->setAdditionalInformation('threeDSType', $resultCode); $payment->setAdditionalInformation('pspReference', $response['pspReference']);
$payment->setAdditionalInformation( }
'threeDS2Token',
$response['authentication']['threeds2.challengeToken'] if (!empty($response['paymentData'])) {
);
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']); $payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']);
break; }
switch ($resultCode) {
case "Authorised": case "Authorised":
case "Received": case "Received":
// TODO refactor since the full additionalData is stored in additionalInformation already
// For banktransfers store all bankTransfer details // For banktransfers store all bankTransfer details
if (!empty($response['additionalData']['bankTransfer.owner'])) { if (!empty($response['additionalData']['bankTransfer.owner'])) {
foreach ($response['additionalData'] as $key => $value) { foreach ($response['additionalData'] as $key => $value) {
...@@ -106,6 +110,31 @@ class CheckoutResponseValidator extends AbstractValidator ...@@ -106,6 +110,31 @@ class CheckoutResponseValidator extends AbstractValidator
} }
} }
// TODO doudle check this
if (isset($response['additionalData']) && is_array($response['additionalData'])) {
$additionalData = $response['additionalData'];
if (isset($additionalData['boletobancario.dueDate'])) {
$payment->setAdditionalInformation(
'dueDate',
$additionalData['boletobancario.dueDate']
);
}
if (isset($additionalData['boletobancario.expirationDate'])) {
$payment->setAdditionalInformation(
'expirationDate',
$additionalData['boletobancario.expirationDate']
);
}
if (isset($additionalData['boletobancario.url'])) {
$payment->setAdditionalInformation(
'url',
$additionalData['boletobancario.url']
);
}
}
// Save cc_type if available in the response // Save cc_type if available in the response
if (!empty($response['additionalData']['paymentMethod'])) { if (!empty($response['additionalData']['paymentMethod'])) {
$ccType = $this->adyenHelper->getMagentoCreditCartType( $ccType = $this->adyenHelper->getMagentoCreditCartType(
...@@ -114,90 +143,15 @@ class CheckoutResponseValidator extends AbstractValidator ...@@ -114,90 +143,15 @@ class CheckoutResponseValidator extends AbstractValidator
$payment->setAdditionalInformation('cc_type', $ccType); $payment->setAdditionalInformation('cc_type', $ccType);
$payment->setCcType($ccType); $payment->setCcType($ccType);
} }
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
break; break;
case "IdentifyShopper":
case "ChallengeShopper":
case "PresentToShopper": case "PresentToShopper":
if (!empty($response['action'])) {
$payment->setAdditionalInformation('action', $response['action']);
}
if (!empty($response['pspReference'])) {
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
}
break;
case 'Pending': case 'Pending':
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']);
if (!empty($response['action'])) {
$payment->setAdditionalInformation('action', $response['action']);
}
break;
case "RedirectShopper": case "RedirectShopper":
$payment->setAdditionalInformation('threeDSType', $resultCode); // nothing extra
$redirectUrl = null;
$paymentData = null;
if (!empty($response['redirect']['url'])) {
$redirectUrl = $response['redirect']['url'];
}
if (!empty($response['redirect']['method'])) {
$redirectMethod = $response['redirect']['method'];
}
if (!empty($response['paymentData'])) {
$paymentData = $response['paymentData'];
}
// If the redirect data is there then the payment is a card payment with 3d secure
if (
isset($response['redirect']['data']['PaReq']) &&
isset($response['redirect']['data']['MD'])
) {
$paReq = null;
$md = null;
$payment->setAdditionalInformation('3dActive', true);
if (!empty($response['redirect']['data']['PaReq'])) {
$paReq = $response['redirect']['data']['PaReq'];
}
if (!empty($response['redirect']['data']['MD'])) {
$md = $response['redirect']['data']['MD'];
}
if ($paReq && $md && $redirectUrl && $paymentData && $redirectMethod) {
$payment->setAdditionalInformation('redirectUrl', $redirectUrl);
$payment->setAdditionalInformation('redirectMethod', $redirectMethod);
$payment->setAdditionalInformation('paRequest', $paReq);
$payment->setAdditionalInformation('md', $md);
$payment->setAdditionalInformation('paymentData', $paymentData);
} else {
$isValid = false;
$errorMsg = __('3D secure is not valid.');
$this->adyenLogger->error($errorMsg);
$errorMessages[] = $errorMsg;
}
// otherwise it is an alternative payment method which only requires the
// redirect url to be present
} else {
// Flag to show we are in the checkoutAPM flow
$payment->setAdditionalInformation('checkoutAPM', true);
if (!empty($response['details'])) {
$payment->setAdditionalInformation('details', $response['details']);
}
if ($redirectUrl && $paymentData && $redirectMethod) {
$payment->setAdditionalInformation('redirectUrl', $redirectUrl);
$payment->setAdditionalInformation('redirectMethod', $redirectMethod);
$payment->setAdditionalInformation('paymentData', $paymentData);
} else {
$isValid = false;
$errorMsg = __('Payment method is not valid.');
$this->adyenLogger->error($errorMsg);
$errorMessages[] = $errorMsg;
}
}
break; break;
case "Refused": case "Refused":
$errorMsg = __('The payment is REFUSED.'); $errorMsg = __('The payment is REFUSED.');
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Gateway\Validator;
use Magento\Payment\Gateway\Validator\AbstractValidator;
class GeneralResponseValidator extends AbstractValidator
{
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
private $adyenLogger;
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* GeneralResponseValidator constructor.
*
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
*/
public function __construct(
\Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Adyen\Payment\Helper\Data $adyenHelper
) {
$this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
parent::__construct($resultFactory);
}
/**
* @param array $validationSubject
* @return \Magento\Payment\Gateway\Validator\ResultInterface
*/
public function validate(array $validationSubject)
{
$response = \Magento\Payment\Gateway\Helper\SubjectReader::readResponse($validationSubject);
$paymentDataObjectInterface = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($validationSubject);
$payment = $paymentDataObjectInterface->getPayment();
$payment->setAdditionalInformation('3dActive', false);
$isValid = true;
$errorMessages = [];
// validate result
if (!empty($response['resultCode'])) {
switch ($response['resultCode']) {
case "Authorised":
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
// Save cc_type if available in the response
if (!empty($response['additionalData']['paymentMethod'])) {
$ccType = $this->adyenHelper->getMagentoCreditCartType(
$response['additionalData']['paymentMethod']
);
$payment->setAdditionalInformation('cc_type', $ccType);
$payment->setCcType($ccType);
}
break;
case "Received":
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
// set additionalData
if (isset($response['additionalData']) && is_array($response['additionalData'])) {
$additionalData = $response['additionalData'];
if (isset($additionalData['boletobancario.dueDate'])) {
$payment->setAdditionalInformation(
'dueDate',
$additionalData['boletobancario.dueDate']
);
}
if (isset($additionalData['boletobancario.expirationDate'])) {
$payment->setAdditionalInformation(
'expirationDate',
$additionalData['boletobancario.expirationDate']
);
}
if (isset($additionalData['boletobancario.url'])) {
$payment->setAdditionalInformation(
'url',
$additionalData['boletobancario.url']
);
}
}
break;
case "RedirectShopper":
$payment->setAdditionalInformation('3dActive', true);
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
$redirectUrl = $response['issuerUrl'];
$paReq = $response['paRequest'];
$md = $response['md'];
if (!empty($paReq) && !empty($md) && !empty($redirectUrl)) {
$payment->setAdditionalInformation('redirectUrl', $redirectUrl);
$payment->setAdditionalInformation('paRequest', $response['paRequest']);
$payment->setAdditionalInformation('md', $response['md']);
} else {
$isValid = false;
$errorMsg = __('3D secure is not valid.');
$this->adyenLogger->error($errorMsg);
$errorMessages[] = $errorMsg;
}
break;
case "Refused":
$errorMsg = __('The payment is REFUSED.');
// this will result the specific error
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
break;
default:
$errorMsg = __('Error with payment method please select different payment method.');
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
break;
}
} else {
$errorMsg = __('Error with payment method please select different payment method.');
if (!empty($response['error'])) {
$this->adyenLogger->error($response['error']);
}
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
}
return $this->createResult($isValid, $errorMessages);
}
}
...@@ -33,7 +33,7 @@ class RefundResponseValidator extends AbstractValidator ...@@ -33,7 +33,7 @@ class RefundResponseValidator extends AbstractValidator
private $adyenLogger; private $adyenLogger;
/** /**
* GeneralResponseValidator constructor. * RefundResponseValidator constructor.
* *
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory * @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger * @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
......
...@@ -15,59 +15,69 @@ ...@@ -15,59 +15,69 @@
* *
* Adyen Payment module (https://www.adyen.com/) * Adyen Payment module (https://www.adyen.com/)
* *
* Copyright (c) 2019 Adyen BV (https://www.adyen.com/) * Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details. * See LICENSE.txt for license details.
* *
* Author: Adyen <magento@adyen.com> * Author: Adyen <magento@adyen.com>
*/ */
namespace Adyen\Payment\Gateway\Request; namespace Adyen\Payment\Helper;
use Magento\Payment\Gateway\Request\BuilderInterface; class ConnectedTerminals
class ThreeDS2DataBuilder implements BuilderInterface
{ {
/** /**
* @var \Magento\Framework\App\State * @var \Magento\Checkout\Model\Session
*/ */
private $appState; protected $session;
/** /**
* @var \Adyen\Payment\Helper\Requests * @var \Adyen\Payment\Helper\Data
*/ */
private $adyenRequestsHelper; protected $adyenHelper;
/**
* ThreeDS2DataBuilder constructor.
*
* @param \Magento\Framework\Model\Context $context
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/
public function __construct( public function __construct(
\Magento\Framework\Model\Context $context, \Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Helper\Requests $adyenRequestsHelper \Magento\Checkout\Model\Session $session
) { ) {
$this->appState = $context->getAppState(); $this->adyenHelper = $adyenHelper;
$this->adyenRequestsHelper = $adyenRequestsHelper; $this->session = $session;
} }
/** /**
* @param array $buildSubject * @return array|mixed
* @return array * @throws \Adyen\AdyenException
* @throws \Magento\Framework\Exception\LocalizedException * @throws \Magento\Framework\Exception\LocalizedException
* @throws \Magento\Framework\Exception\NoSuchEntityException
*/ */
public function build(array $buildSubject) public function getConnectedTerminals()
{ {
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */ $storeId = $this->session->getQuote()->getStoreId();
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment(); // initialize the adyen client
$order = $paymentDataObject->getOrder(); $client = $this->adyenHelper->initializeAdyenClient($storeId, $this->adyenHelper->getPosApiKey($storeId));
$additionalInformation = $payment->getAdditionalInformation();
$request['body'] = $this->adyenRequestsHelper->buildThreeDS2Data( // initialize service
$additionalInformation, $service = $this->adyenHelper->createAdyenPosPaymentService($client);
$order->getStoreId(),
[] $requestParams = [
"merchantAccount" => $this->adyenHelper->getAdyenMerchantAccount('adyen_pos_cloud', $storeId),
];
// In case the POS store id is set, provide in the request
if (!empty($this->adyenHelper->getPosStoreId($storeId))) {
$requestParams['store'] = $this->adyenHelper->getPosStoreId($storeId);
}
try {
$responseData = $service->getConnectedTerminals($requestParams);
} catch (\Adyen\AdyenException $e) {
$this->adyenLogger->error(
"The getConnectedTerminals response is empty check your Adyen configuration in Magento."
); );
return $request; // return empty result
return [];
}
return $responseData;
} }
} }
This diff is collapsed.
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Helper;
use Adyen\Payment\Logger\AdyenLogger;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\Data\OrderPaymentInterface;
use Magento\Sales\Model\Order;
class PaymentResponseHandler
{
const AUTHORISED = 'Authorised';
const REFUSED = 'Refused';
const REDIRECT_SHOPPER = 'RedirectShopper';
const IDENTIFY_SHOPPER = 'IdentifyShopper';
const CHALLENGE_SHOPPER = 'ChallengeShopper';
const RECEIVED = 'Received';
const PENDING = 'Pending';
const PRESENT_TO_SHOPPER = 'PresentToShopper';
const ERROR = 'Error';
const CANCELLED = 'Cancelled';
private $adyenLogger;
public function __construct(
AdyenLogger $adyenLogger
) {
$this->adyenLogger = $adyenLogger;
}
public function formatPaymentResponse($resultCode, $action = null, $additionalData = null)
{
switch ($resultCode) {
case self::AUTHORISED:
case self::REFUSED:
case self::ERROR:
return [
"isFinal" => true,
"resultCode" => $resultCode,
];
case self::REDIRECT_SHOPPER:
case self::IDENTIFY_SHOPPER:
case self::CHALLENGE_SHOPPER:
case self::PENDING:
return [
"isFinal" => false,
"resultCode" => $resultCode,
"action" => $action
];
case self::PRESENT_TO_SHOPPER:
return [
"isFinal" => true,
"resultCode" => $resultCode,
"action" => $action
];
case self::RECEIVED:
return [
"isFinal" => true,
"resultCode" => $resultCode,
"additionalData" => $additionalData
];
default:
return [
"isFinal" => true,
"resultCode" => self::ERROR,
];
}
}
/**
* @param $paymentsResponse
* @param OrderPaymentInterface $payment
* @param OrderInterface|null $order
* @return bool
*/
public function handlePaymentResponse($paymentsResponse, $payment, $order = null)
{
if (empty($paymentsResponse)) {
$this->adyenLogger->error("Payment details call failed, paymentsResponse is empty");
return false;
}
if (!empty($paymentsResponse['resultCode']))
$payment->setAdditionalInformation('resultCode', $paymentsResponse['resultCode']);
if (!empty($paymentsResponse['action'])) {
$payment->setAdditionalInformation('action', $paymentsResponse['action']);
}
if (!empty($paymentsResponse['additionalData'])) {
$payment->setAdditionalInformation('additionalData', $paymentsResponse['additionalData']);
}
if (!empty($paymentsResponse['pspReference'])) {
$payment->setAdditionalInformation('pspReference', $paymentsResponse['pspReference']);
}
if (!empty($paymentsResponse['paymentData'])) {
$payment->setAdditionalInformation('adyenPaymentData', $paymentsResponse['paymentData']);
}
switch ($paymentsResponse['resultCode']) {
case self::PRESENT_TO_SHOPPER:
case self::PENDING:
case self::RECEIVED:
break;
//We don't need to handle these resultCodes
case self::REDIRECT_SHOPPER:
$this->adyenLogger->addAdyenResult("Customer was redirected.");
if ($order) {
$order->addStatusHistoryComment(
__(
'Customer was redirected to an external payment page. (In case of card payments the shopper is redirected to the bank for 3D-secure validation.) Once the shopper is authenticated,
the order status will be updated accordingly.
<br />Make sure that your notifications are being processed!
<br />If the order is stuck on this status, the shopper abandoned the session.
The payment can be seen as unsuccessful.
<br />The order can be automatically cancelled based on the OFFER_CLOSED notification.
Please contact Adyen Support to enable this.'
)
)->save();
}
break;
case self::AUTHORISED:
case self::IDENTIFY_SHOPPER:
case self::CHALLENGE_SHOPPER:
break;
//These resultCodes cancel the order and log an error
case self::REFUSED:
case self::ERROR:
default:
if (!$order->canCancel()) {
$order->setState(Order::STATE_NEW);
}
//TODO check if order gets cancelled
$order->cancel();
$this->adyenLogger->error(
sprintf("Payment details call failed for action, resultCode is %s Raw API responds: %s",
$paymentsResponse['resultCode'],
print_r($paymentsResponse, true)
));
return false;
}
return true;
}
}
...@@ -116,36 +116,10 @@ class Requests extends AbstractHelper ...@@ -116,36 +116,10 @@ class Requests extends AbstractHelper
// In case of virtual product and guest checkout there is a workaround to get the guest's email address // In case of virtual product and guest checkout there is a workaround to get the guest's email address
if (!empty($additionalData['guestEmail'])) { if (!empty($additionalData['guestEmail'])) {
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod($paymentMethod) &&
!$this->adyenHelper->isPaymentMethodAfterpayTouchMethod($paymentMethod)
) {
$request['paymentMethod']['personalDetails']['shopperEmail'] = $additionalData['guestEmail'];
} else {
$request['shopperEmail'] = $additionalData['guestEmail']; $request['shopperEmail'] = $additionalData['guestEmail'];
} }
}
if (!empty($billingAddress)) { if (!empty($billingAddress)) {
// Openinvoice (klarna and afterpay BUT not afterpay touch) methods requires different request format
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod($paymentMethod) &&
!$this->adyenHelper->isPaymentMethodAfterpayTouchMethod($paymentMethod)
) {
if ($customerEmail = $billingAddress->getEmail()) {
$request['paymentMethod']['personalDetails']['shopperEmail'] = $customerEmail;
}
if ($customerTelephone = trim($billingAddress->getTelephone())) {
$request['paymentMethod']['personalDetails']['telephoneNumber'] = $customerTelephone;
}
if ($firstName = $billingAddress->getFirstname()) {
$request['paymentMethod']['personalDetails']['firstName'] = $firstName;
}
if ($lastName = $billingAddress->getLastname()) {
$request['paymentMethod']['personalDetails']['lastName'] = $lastName;
}
} else {
if ($customerEmail = $billingAddress->getEmail()) { if ($customerEmail = $billingAddress->getEmail()) {
$request['shopperEmail'] = $customerEmail; $request['shopperEmail'] = $customerEmail;
} }
...@@ -161,7 +135,6 @@ class Requests extends AbstractHelper ...@@ -161,7 +135,6 @@ class Requests extends AbstractHelper
if ($lastName = $billingAddress->getLastname()) { if ($lastName = $billingAddress->getLastname()) {
$request['shopperName']['lastName'] = $lastName; $request['shopperName']['lastName'] = $lastName;
} }
}
if ($countryId = $billingAddress->getCountryId()) { if ($countryId = $billingAddress->getCountryId()) {
$request['countryCode'] = $countryId; $request['countryCode'] = $countryId;
...@@ -353,8 +326,6 @@ class Requests extends AbstractHelper ...@@ -353,8 +326,6 @@ class Requests extends AbstractHelper
$request['origin'] = $this->adyenHelper->getOrigin($storeId); $request['origin'] = $this->adyenHelper->getOrigin($storeId);
$request['channel'] = 'web'; $request['channel'] = 'web';
} }
return $request;
} }
/** /**
......
...@@ -24,43 +24,54 @@ ...@@ -24,43 +24,54 @@
namespace Adyen\Payment\Model; namespace Adyen\Payment\Model;
use Adyen\Payment\Model\Ui\AdyenCcConfigProvider; use Adyen\Payment\Api\AdyenOrderPaymentStatusInterface;
use Adyen\Payment\Helper\Data;
use Adyen\Payment\Helper\PaymentResponseHandler;
use Adyen\Payment\Logger\AdyenLogger;
use Magento\Sales\Api\OrderRepositoryInterface;
use Adyen\Payment\Model\Ui\AdyenGooglePayConfigProvider; use Adyen\Payment\Model\Ui\AdyenGooglePayConfigProvider;
use Adyen\Payment\Model\Ui\AdyenHppConfigProvider; use \Magento\Framework\Exception\NoSuchEntityException;
use Adyen\Payment\Model\Ui\AdyenOneclickConfigProvider;
class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentStatusInterface class AdyenOrderPaymentStatus implements AdyenOrderPaymentStatusInterface
{ {
/** /**
* @var \Magento\Sales\Api\OrderRepositoryInterface * @var OrderRepositoryInterface
*/ */
protected $orderRepository; protected $orderRepository;
/** /**
* @var \Adyen\Payment\Logger\AdyenLogger * @var AdyenLogger
*/ */
protected $adyenLogger; protected $adyenLogger;
/** /**
* @var \Adyen\Payment\Helper\Data * @var Data
*/ */
protected $adyenHelper; protected $adyenHelper;
/**
* @var PaymentResponseHandler
*/
private $paymentResponseHandler;
/** /**
* AdyenOrderPaymentStatus constructor. * AdyenOrderPaymentStatus constructor.
* *
* @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository * @param OrderRepositoryInterface $orderRepository
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger * @param AdyenLogger $adyenLogger
* @param \Adyen\Payment\Helper\Data $adyenHelper * @param Data $adyenHelper
* @param PaymentResponseHandler $paymentResponseHandler
*/ */
public function __construct( public function __construct(
\Magento\Sales\Api\OrderRepositoryInterface $orderRepository, OrderRepositoryInterface $orderRepository,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger, AdyenLogger $adyenLogger,
\Adyen\Payment\Helper\Data $adyenHelper Data $adyenHelper,
PaymentResponseHandler $paymentResponseHandler
) { ) {
$this->orderRepository = $orderRepository; $this->orderRepository = $orderRepository;
$this->adyenLogger = $adyenLogger; $this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper; $this->adyenHelper = $adyenHelper;
$this->paymentResponseHandler = $paymentResponseHandler;
} }
/** /**
...@@ -69,39 +80,23 @@ class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentSta ...@@ -69,39 +80,23 @@ class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentSta
*/ */
public function getOrderPaymentStatus($orderId) public function getOrderPaymentStatus($orderId)
{ {
try {
$order = $this->orderRepository->get($orderId); $order = $this->orderRepository->get($orderId);
$payment = $order->getPayment(); } catch (NoSuchEntityException $exception) {
$this->adyenLogger->addError('Order not found.');
if ($payment->getMethod() === AdyenCcConfigProvider::CODE || return json_encode(
$payment->getMethod() === AdyenOneclickConfigProvider::CODE $this->paymentResponseHandler->formatPaymentResponse(PaymentResponseHandler::ERROR)
) { );
$additionalInformation = $payment->getAdditionalInformation();
$type = null;
if (!empty($additionalInformation['threeDSType'])) {
$type = $additionalInformation['threeDSType'];
}
$token = null;
if (!empty($additionalInformation['threeDS2Token'])) {
$token = $additionalInformation['threeDS2Token'];
}
return $this->adyenHelper->buildThreeDS2ProcessResponseJson($type, $token);
} }
$payment = $order->getPayment();
/**
* If payment method result is Pending and action is provided provide component action back to checkout
*/
if ($payment->getMethod() === AdyenHppConfigProvider::CODE) {
$additionalInformation = $payment->getAdditionalInformation(); $additionalInformation = $payment->getAdditionalInformation();
if (
!empty($additionalInformation['action']) && if (empty($additionalInformation['resultCode'])) {
$additionalInformation['resultCode'] == 'Pending' $this->adyenLogger->addInfo('resultCode is empty in the payment\'s additional information');
) { return json_encode(
return json_encode(['action' => $additionalInformation['action']]); $this->paymentResponseHandler->formatPaymentResponse(PaymentResponseHandler::ERROR)
} );
} }
/** /**
* If payment method is google pay * If payment method is google pay
...@@ -113,6 +108,10 @@ class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentSta ...@@ -113,6 +108,10 @@ class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentSta
} }
} }
return true; return json_encode($this->paymentResponseHandler->formatPaymentResponse(
$additionalInformation['resultCode'],
!empty($additionalInformation['action']) ? $additionalInformation['action'] : null,
!empty($additionalInformation['additionalData']) ? $additionalInformation['additionalData'] : null
));
} }
} }
...@@ -23,14 +23,17 @@ ...@@ -23,14 +23,17 @@
namespace Adyen\Payment\Model; namespace Adyen\Payment\Model;
use Adyen\Payment\Api\AdyenThreeDS2ProcessInterface; use Adyen\AdyenException;
use Adyen\Payment\Api\AdyenPaymentDetailsInterface;
use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Data;
use Adyen\Payment\Helper\PaymentResponseHandler;
use Adyen\Payment\Helper\Vault; use Adyen\Payment\Helper\Vault;
use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Logger\AdyenLogger;
use Magento\Checkout\Model\Session; use Magento\Checkout\Model\Session;
use Magento\Sales\Model\OrderFactory; use Magento\Framework\Exception\LocalizedException;
use Magento\Sales\Api\OrderRepositoryInterface;
class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface class AdyenPaymentDetails implements AdyenPaymentDetailsInterface
{ {
/** /**
* @var Session * @var Session
...@@ -42,11 +45,6 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface ...@@ -42,11 +45,6 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
*/ */
private $adyenHelper; private $adyenHelper;
/**
* @var OrderFactory
*/
private $orderFactory;
/** /**
* @var AdyenLogger * @var AdyenLogger
*/ */
...@@ -58,26 +56,39 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface ...@@ -58,26 +56,39 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
private $vaultHelper; private $vaultHelper;
/** /**
* AdyenThreeDS2Process constructor. * @var OrderRepositoryInterface
*/
private $orderRepository;
/**
* @var PaymentResponseHandler
*/
private $paymentResponseHandler;
/**
* AdyenPaymentDetails constructor.
* *
* @param Session $checkoutSession * @param Session $checkoutSession
* @param Data $adyenHelper * @param Data $adyenHelper
* @param OrderFactory $orderFactory
* @param AdyenLogger $adyenLogger * @param AdyenLogger $adyenLogger
* @param Vault $vaultHelper * @param Vault $vaultHelper
* @param OrderRepositoryInterface $orderRepository
* @param PaymentResponseHandler $paymentResponseHandler
*/ */
public function __construct( public function __construct(
Session $checkoutSession, Session $checkoutSession,
Data $adyenHelper, Data $adyenHelper,
OrderFactory $orderFactory,
AdyenLogger $adyenLogger, AdyenLogger $adyenLogger,
Vault $vaultHelper Vault $vaultHelper,
OrderRepositoryInterface $orderRepository,
PaymentResponseHandler $paymentResponseHandler
) { ) {
$this->checkoutSession = $checkoutSession; $this->checkoutSession = $checkoutSession;
$this->adyenHelper = $adyenHelper; $this->adyenHelper = $adyenHelper;
$this->orderFactory = $orderFactory;
$this->adyenLogger = $adyenLogger; $this->adyenLogger = $adyenLogger;
$this->vaultHelper = $vaultHelper; $this->vaultHelper = $vaultHelper;
$this->orderRepository = $orderRepository;
$this->paymentResponseHandler = $paymentResponseHandler;
} }
/** /**
...@@ -92,130 +103,65 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface ...@@ -92,130 +103,65 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
// Validate JSON that has just been parsed if it was in a valid format // Validate JSON that has just been parsed if it was in a valid format
if (json_last_error() !== JSON_ERROR_NONE) { if (json_last_error() !== JSON_ERROR_NONE) {
throw new \Magento\Framework\Exception\LocalizedException( throw new LocalizedException(__('Payment details call failed because the request was not a valid JSON'));
__('3D secure 2.0 failed because the request was not a valid JSON')
);
} }
//Get order from payload and remove orderId from the array
if (empty($payload['orderId'])) { if (empty($payload['orderId'])) {
$order = $this->getOrder(); throw new LocalizedException
// In the next major release remove support for retrieving order from session and throw exception instead (__('Payment details call failed because of a missing order ID'));
//throw new \Magento\Framework\Exception\LocalizedException
//(__('3D secure 2.0 failed because of a missing order id'));
} else { } else {
// Create order by order id $order = $this->orderRepository->get($payload['orderId']);
$order = $this->orderFactory->create()->load($payload['orderId']); //TODO send state.data from frontend so no unsetting is necessary
// don't send orderId to adyen. Improve that orderId and state.data are separated in payload
unset($payload['orderId']); unset($payload['orderId']);
} }
$payment = $order->getPayment(); $payment = $order->getPayment();
// Init payments/details request
$result = [];
if ($paymentData = $payment->getAdditionalInformation("adyenPaymentData")) { if ($paymentData = $payment->getAdditionalInformation("adyenPaymentData")) {
// Add payment data into the request object // Add payment data into the request object
$request = [ $payload["paymentData"] = $paymentData;
"paymentData" => $paymentData
];
// unset payment data from additional information // unset payment data from additional information
$payment->unsAdditionalInformation("adyenPaymentData"); $payment->unsAdditionalInformation("adyenPaymentData");
} else { } else {
$this->adyenLogger->error("3D secure 2.0 failed, payment data not found"); $message = "Payment details call failed, payment data not found";
throw new \Magento\Framework\Exception\LocalizedException( $this->adyenLogger->error($message);
__('3D secure 2.0 failed, payment data not found') throw new LocalizedException(__($message));
);
}
// Depends on the component's response we send a fingerprint or the challenge result
if (!empty($payload['details']['threeds2.fingerprint'])) {
$request['details']['threeds2.fingerprint'] = $payload['details']['threeds2.fingerprint'];
} elseif (!empty($payload['details']['threeds2.challengeResult'])) {
$request['details']['threeds2.challengeResult'] = $payload['details']['threeds2.challengeResult'];
} elseif (!empty($payload)) {
$request = $payload;
} }
// Send the request // Send the request
try { try {
$client = $this->adyenHelper->initializeAdyenClient($order->getStoreId()); $client = $this->adyenHelper->initializeAdyenClient($order->getStoreId());
$service = $this->adyenHelper->createAdyenCheckoutService($client); $service = $this->adyenHelper->createAdyenCheckoutService($client);
$paymentDetails = $service->paymentsDetails($payload);
$result = $service->paymentsDetails($request); } catch (AdyenException $e) {
} catch (\Adyen\AdyenException $e) { $this->adyenLogger->error("Payment details call failed: " . $e->getMessage());
$this->adyenLogger->error("3D secure 2.0 failed" . $e->getMessage()); throw new LocalizedException(__('Payment details call failed'));
throw new \Magento\Framework\Exception\LocalizedException(__('3D secure 2.0 failed'));
} }
// Check if result is challenge shopper, if yes return the token //TODO test this with payments that return additionalData
if (!empty($result['resultCode']) && //TODO check for Authorized result code and move to the handler
$result['resultCode'] === 'ChallengeShopper' && if (!empty($paymentDetails['additionalData'])) {
!empty($result['authentication']['threeds2.challengeToken']) $this->vaultHelper->saveRecurringDetails($payment, $paymentDetails['additionalData']);
) {
return $this->adyenHelper->buildThreeDS2ProcessResponseJson(
$result['resultCode'],
$result['authentication']['threeds2.challengeToken']
);
} }
//Fallback for 3DS in case of redirect
if (!empty($result['resultCode']) &&
$result['resultCode'] === 'RedirectShopper'
) {
$response['type'] = $result['resultCode'];
$response['action']= $result['action'];
return json_encode($response);
}
// Save the payments response because we are going to need it during the place order flow
$payment->setAdditionalInformation("paymentsResponse", $result);
if (!empty($result['additionalData'])) { //TODO check if order save is necessary to save additionalData
$this->vaultHelper->saveRecurringDetails($payment, $result['additionalData']);
}
// To actually save the additional info changes into the quote
$order->save();
$response = []; if (!$this->paymentResponseHandler->handlePaymentResponse($paymentDetails, $payment, $order)) {
if ($result['resultCode'] != 'Authorised') {
$this->checkoutSession->restoreQuote(); $this->checkoutSession->restoreQuote();
throw new LocalizedException(__('The payment is REFUSED.'));
// Always cancel the order if the paymenth has failed
if (!$order->canCancel()) {
$order->setState(\Magento\Sales\Model\Order::STATE_NEW);
} }
$order->cancel()->save(); $action = null;
if (!empty($paymentDetails['action'])) {
$this->adyenLogger->error( $action = $paymentDetails['action'];
sprintf("Payment details call failed for action or 3ds2 payment method, resultcode is %s Raw API responds: %s",
$result['resultCode'],
print_r($result, true)
));
throw new \Magento\Framework\Exception\LocalizedException(__('The payment is REFUSED.'));
} }
$response['result'] = $result['resultCode']; $additionalData = null;
return json_encode($response); if (!empty($paymentDetails['additionalData'])) {
$additionalData = $paymentDetails['additionalData'];
} }
/** return json_encode($this->paymentResponseHandler->formatPaymentResponse($paymentDetails['resultCode'], $action, $additionalData));
* Get order object
*
* @return \Magento\Sales\Model\Order
* @deprecated Will be removed in 7.0.0
*/
protected function getOrder()
{
$incrementId = $this->checkoutSession->getLastRealOrderId();
$order = $this->orderFactory->create()->loadByIncrementId($incrementId);
return $order;
} }
} }
...@@ -73,6 +73,9 @@ class AdyenGenericConfigProvider implements ConfigProviderInterface ...@@ -73,6 +73,9 @@ class AdyenGenericConfigProvider implements ConfigProviderInterface
$config['payment']['adyen']['checkoutEnvironment'] = $this->adyenHelper->getCheckoutEnvironment( $config['payment']['adyen']['checkoutEnvironment'] = $this->adyenHelper->getCheckoutEnvironment(
$this->storeManager->getStore()->getId() $this->storeManager->getStore()->getId()
); );
$config['payment']['adyen']['locale'] = $this->adyenHelper->getStoreLocale(
$this->storeManager->getStore()->getId()
);
return $config; return $config;
} }
......
...@@ -43,9 +43,9 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface ...@@ -43,9 +43,9 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface
protected $urlBuilder; protected $urlBuilder;
/** /**
* @var \Adyen\Payment\Helper\PaymentMethods * @var \Adyen\Payment\Helper\ConnectedTerminals
*/ */
protected $paymentMethodsHelper; protected $connectedTerminalsHelper;
/** /**
* @var \Adyen\Payment\Helper\Data * @var \Adyen\Payment\Helper\Data
...@@ -62,20 +62,20 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface ...@@ -62,20 +62,20 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface
* *
* @param \Magento\Framework\App\RequestInterface $request * @param \Magento\Framework\App\RequestInterface $request
* @param \Magento\Framework\UrlInterface $urlBuilder * @param \Magento\Framework\UrlInterface $urlBuilder
* @param \Adyen\Payment\Helper\PaymentMethods $paymentMethodsHelper * @param \Adyen\Payment\Helper\ConnectedTerminals $connectedTerminalsHelper
* @param \Adyen\Payment\Helper\Data $adyenHelper * @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\Serialize\SerializerInterface $serializer * @param \Magento\Framework\Serialize\SerializerInterface $serializer
*/ */
public function __construct( public function __construct(
\Magento\Framework\App\RequestInterface $request, \Magento\Framework\App\RequestInterface $request,
\Magento\Framework\UrlInterface $urlBuilder, \Magento\Framework\UrlInterface $urlBuilder,
\Adyen\Payment\Helper\PaymentMethods $paymentMethodsHelper, \Adyen\Payment\Helper\ConnectedTerminals $connectedTerminalsHelper,
\Adyen\Payment\Helper\Data $adyenHelper, \Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Serialize\SerializerInterface $serializer \Magento\Framework\Serialize\SerializerInterface $serializer
) { ) {
$this->request = $request; $this->request = $request;
$this->urlBuilder = $urlBuilder; $this->urlBuilder = $urlBuilder;
$this->paymentMethodsHelper = $paymentMethodsHelper; $this->connectedTerminalsHelper = $connectedTerminalsHelper;
$this->adyenHelper = $adyenHelper; $this->adyenHelper = $adyenHelper;
$this->serializer = $serializer; $this->serializer = $serializer;
} }
...@@ -137,7 +137,7 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface ...@@ -137,7 +137,7 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface
*/ */
protected function getConnectedTerminals() protected function getConnectedTerminals()
{ {
$connectedTerminals = $this->paymentMethodsHelper->getConnectedTerminals(); $connectedTerminals = $this->connectedTerminalsHelper->getConnectedTerminals();
if (!empty($connectedTerminals['uniqueTerminalIds'])) { if (!empty($connectedTerminals['uniqueTerminalIds'])) {
return $connectedTerminals['uniqueTerminalIds']; return $connectedTerminals['uniqueTerminalIds'];
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* Adyen Payment module (https://www.adyen.com/) * Adyen Payment module (https://www.adyen.com/)
* *
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/) * Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details. * See LICENSE.txt for license details.
* *
* Author: Adyen <magento@adyen.com> * Author: Adyen <magento@adyen.com>
...@@ -26,77 +26,92 @@ namespace Adyen\Payment\Observer; ...@@ -26,77 +26,92 @@ namespace Adyen\Payment\Observer;
use Magento\Framework\Event\Observer; use Magento\Framework\Event\Observer;
use Magento\Payment\Observer\AbstractDataAssignObserver; use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Api\Data\PaymentInterface;
use \Adyen\Service\Validator\CheckoutStateDataValidator;
use \Adyen\Service\Validator\DataArrayValidator;
class AdyenCcDataAssignObserver extends AbstractDataAssignObserver class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
{ {
const CC_TYPE = 'cc_type'; const CC_TYPE = 'cc_type';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments'; const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
const STORE_CC = 'store_cc'; const STORE_CC = 'store_cc';
const ENCRYPTED_CREDIT_CARD_NUMBER = 'number';
const ENCRYPTED_SECURITY_CODE = 'cvc';
const ENCRYPTED_EXPIRY_MONTH = 'expiryMonth';
const ENCRYPTED_EXPIRY_YEAR = 'expiryYear';
const HOLDER_NAME = 'holderName';
const VARIANT = 'variant';
const JAVA_ENABLED = 'java_enabled';
const SCREEN_COLOR_DEPTH = 'screen_color_depth';
const SCREEN_WIDTH = 'screen_width';
const SCREEN_HEIGHT = 'screen_height';
const TIMEZONE_OFFSET = 'timezone_offset';
const LANGUAGE = 'language';
const GUEST_EMAIL = 'guestEmail'; const GUEST_EMAIL = 'guestEmail';
const COMBO_CARD_TYPE = 'combo_card_type'; const COMBO_CARD_TYPE = 'combo_card_type';
const STATE_DATA = 'stateData';
/** /**
* Approved root level keys from additional data array
*
* @var array * @var array
*/ */
protected $additionalInformationList = [ private static $approvedAdditionalDataKeys = [
self::CC_TYPE, self::STATE_DATA,
self::NUMBER_OF_INSTALLMENTS,
self::STORE_CC,
self::ENCRYPTED_CREDIT_CARD_NUMBER,
self::ENCRYPTED_SECURITY_CODE,
self::ENCRYPTED_EXPIRY_MONTH,
self::ENCRYPTED_EXPIRY_YEAR,
self::HOLDER_NAME,
self::VARIANT,
self::JAVA_ENABLED,
self::SCREEN_COLOR_DEPTH,
self::SCREEN_WIDTH,
self::SCREEN_HEIGHT,
self::TIMEZONE_OFFSET,
self::LANGUAGE,
self::GUEST_EMAIL, self::GUEST_EMAIL,
self::COMBO_CARD_TYPE self::COMBO_CARD_TYPE,
self::NUMBER_OF_INSTALLMENTS
]; ];
/**
* @var CheckoutStateDataValidator
*/
protected $checkoutStateDataValidator;
/**
* AdyenCcDataAssignObserver constructor.
*
* @param CheckoutStateDataValidator $checkoutStateDataValidator
*/
public function __construct(
CheckoutStateDataValidator $checkoutStateDataValidator
) {
$this->checkoutStateDataValidator = $checkoutStateDataValidator;
}
/** /**
* @param Observer $observer * @param Observer $observer
* @return void * @return void
*/ */
public function execute(Observer $observer) public function execute(Observer $observer)
{ {
// Get request fields
$data = $this->readDataArgument($observer); $data = $this->readDataArgument($observer);
// Get additional data array
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA); $additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
if (!is_array($additionalData)) { if (!is_array($additionalData)) {
return; return;
} }
$paymentInfo = $this->readPaymentModelArgument($observer); // Get a validated additional data array
$additionalData = DataArrayValidator::getArrayOnlyWithApprovedKeys(
$additionalData,
self::$approvedAdditionalDataKeys
);
// set ccType // json decode state data
if (!empty($additionalData['cc_type'])) { $stateData = [];
$paymentInfo->setCcType($additionalData['cc_type']); if (!empty($additionalData[self::STATE_DATA])) {
$stateData = json_decode($additionalData[self::STATE_DATA], true);
} }
foreach ($this->additionalInformationList as $additionalInformationKey) { // Get validated state data array
if (isset($additionalData[$additionalInformationKey])) { if (!empty($stateData)) {
$paymentInfo->setAdditionalInformation( $stateData = $this->checkoutStateDataValidator->getValidatedAdditionalData(
$additionalInformationKey, $stateData
$additionalData[$additionalInformationKey]
); );
} }
// Replace state data with the decoded and validated state data
$additionalData[self::STATE_DATA] = $stateData;
// Set additional data in the payment
$paymentInfo = $this->readPaymentModelArgument($observer);
foreach ($additionalData as $key => $data) {
$paymentInfo->setAdditionalInformation($key, $data);
}
// set ccType
if (!empty($additionalData[self::CC_TYPE])) {
$paymentInfo->setCcType($additionalData[self::CC_TYPE]);
} }
} }
} }
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* Adyen Payment module (https://www.adyen.com/) * Adyen Payment module (https://www.adyen.com/)
* *
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/) * Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details. * See LICENSE.txt for license details.
* *
* Author: Adyen <magento@adyen.com> * Author: Adyen <magento@adyen.com>
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
namespace Adyen\Payment\Observer; namespace Adyen\Payment\Observer;
use Adyen\Service\Validator\CheckoutStateDataValidator;
use Adyen\Service\Validator\DataArrayValidator;
use Magento\Framework\Event\Observer; use Magento\Framework\Event\Observer;
use Magento\Payment\Observer\AbstractDataAssignObserver; use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Api\Data\PaymentInterface;
...@@ -30,62 +32,84 @@ use Magento\Quote\Api\Data\PaymentInterface; ...@@ -30,62 +32,84 @@ use Magento\Quote\Api\Data\PaymentInterface;
class AdyenHppDataAssignObserver extends AbstractDataAssignObserver class AdyenHppDataAssignObserver extends AbstractDataAssignObserver
{ {
const BRAND_CODE = 'brand_code'; const BRAND_CODE = 'brand_code';
const ISSUER_ID = 'issuer_id';
const GENDER = 'gender';
const DOB = 'dob';
const TELEPHONE = 'telephone';
const DF_VALUE = 'df_value'; const DF_VALUE = 'df_value';
const SSN = 'ssn'; const GUEST_EMAIL = 'guestEmail';
const OWNER_NAME = 'ownerName'; const STATE_DATA = 'stateData';
const BANK_ACCOUNT_OWNER_NAME = 'bankAccountOwnerName';
const IBAN_NUMBER = 'ibanNumber';
const BANK_ACCOUNT_NUMBER = 'bankAccountNumber';
const BANK_LOCATIONID = 'bankLocationId';
/** /**
* Approved root level keys from additional data array
*
* @var array * @var array
*/ */
protected $additionalInformationList = [ private static $approvedAdditionalDataKeys = [
self::BRAND_CODE, self::BRAND_CODE,
self::ISSUER_ID,
self::GENDER,
self::DOB,
self::TELEPHONE,
self::DF_VALUE, self::DF_VALUE,
self::SSN, self::GUEST_EMAIL,
self::OWNER_NAME, self::STATE_DATA
self::BANK_ACCOUNT_OWNER_NAME,
self::IBAN_NUMBER,
self::BANK_ACCOUNT_NUMBER,
self::BANK_LOCATIONID
]; ];
/**
* @var CheckoutStateDataValidator
*/
protected $checkoutStateDataValidator;
/**
* AdyenHppDataAssignObserver constructor.
*
* @param CheckoutStateDataValidator $checkoutStateDataValidator
*/
public function __construct(
CheckoutStateDataValidator $checkoutStateDataValidator
) {
$this->checkoutStateDataValidator = $checkoutStateDataValidator;
}
/** /**
* @param Observer $observer * @param Observer $observer
* @return void * @return void
*/ */
public function execute(Observer $observer) public function execute(Observer $observer)
{ {
// Get request fields
$data = $this->readDataArgument($observer); $data = $this->readDataArgument($observer);
// Get additional data array
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA); $additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
if (!is_array($additionalData)) { if (!is_array($additionalData)) {
return; return;
} }
$paymentInfo = $this->readPaymentModelArgument($observer); // Get a validated additional data array
$additionalData = DataArrayValidator::getArrayOnlyWithApprovedKeys(
$additionalData,
self::$approvedAdditionalDataKeys
);
if (isset($additionalData[self::BRAND_CODE])) { // json decode state data
$paymentInfo->setCcType($additionalData[self::BRAND_CODE]); $stateData = [];
if (!empty($additionalData[self::STATE_DATA])) {
$stateData = json_decode($additionalData[self::STATE_DATA], true);
} }
foreach ($this->additionalInformationList as $additionalInformationKey) { // Get validated state data array
if (isset($additionalData[$additionalInformationKey])) { if (!empty($stateData)) {
$paymentInfo->setAdditionalInformation( $stateData = $this->checkoutStateDataValidator->getValidatedAdditionalData(
$additionalInformationKey, $stateData
$additionalData[$additionalInformationKey]
); );
} }
// Replace state data with the decoded and validated state data
$additionalData[self::STATE_DATA] = $stateData;
// Set additional data in the payment
$paymentInfo = $this->readPaymentModelArgument($observer);
foreach ($additionalData as $key => $data) {
$paymentInfo->setAdditionalInformation($key, $data);
}
// set ccType
if (!empty($additionalData[self::BRAND_CODE])) {
$paymentInfo->setCcType($additionalData[self::BRAND_CODE]);
} }
} }
} }
...@@ -14,10 +14,11 @@ ...@@ -14,10 +14,11 @@
} }
], ],
"require": { "require": {
"adyen/php-api-library": "^7.0", "adyen/php-api-library": "^8",
"magento/framework": ">=101.0.8 <102 || >=102.0.1", "magento/framework": ">=101.0.8 <102 || >=102.0.1",
"magento/module-vault": "101.*", "magento/module-vault": "101.*",
"magento/module-paypal": ">=100.2.6" "magento/module-paypal": ">=100.2.6",
"ext-json": "*"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "~6.5.0", "phpunit/phpunit": "~6.5.0",
......
...@@ -367,7 +367,7 @@ ...@@ -367,7 +367,7 @@
<argument name="transferFactory" xsi:type="object">Adyen\Payment\Gateway\Http\TransferFactory</argument> <argument name="transferFactory" xsi:type="object">Adyen\Payment\Gateway\Http\TransferFactory</argument>
<argument name="client" xsi:type="object">Adyen\Payment\Gateway\Http\Client\TransactionAuthorization <argument name="client" xsi:type="object">Adyen\Payment\Gateway\Http\Client\TransactionAuthorization
</argument> </argument>
<argument name="validator" xsi:type="object">GeneralResponseValidator</argument> <argument name="validator" xsi:type="object">CheckoutResponseValidator</argument>
<argument name="handler" xsi:type="object">AdyenPaymentCcVaultResponseHandlerComposite</argument> <argument name="handler" xsi:type="object">AdyenPaymentCcVaultResponseHandlerComposite</argument>
</arguments> </arguments>
</virtualType> </virtualType>
...@@ -557,9 +557,8 @@ ...@@ -557,9 +557,8 @@
<item name="payment" xsi:type="string">Adyen\Payment\Gateway\Request\PaymentDataBuilder</item> <item name="payment" xsi:type="string">Adyen\Payment\Gateway\Request\PaymentDataBuilder</item>
<item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item> <item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item>
<item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item> <item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item>
<item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcAuthorizationDataBuilder</item> <item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CheckoutDataBuilder</item>
<item name="vault" xsi:type="string">Adyen\Payment\Gateway\Request\VaultDataBuilder</item> <item name="vault" xsi:type="string">Adyen\Payment\Gateway\Request\VaultDataBuilder</item>
<item name="threeds2" xsi:type="string">Adyen\Payment\Gateway\Request\ThreeDS2DataBuilder</item>
</argument> </argument>
</arguments> </arguments>
</virtualType> </virtualType>
...@@ -606,7 +605,7 @@ ...@@ -606,7 +605,7 @@
<item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item> <item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item>
<item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item> <item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item>
<item name="oneclick" xsi:type="string">Adyen\Payment\Gateway\Request\OneclickAuthorizationDataBuilder</item> <item name="oneclick" xsi:type="string">Adyen\Payment\Gateway\Request\OneclickAuthorizationDataBuilder</item>
<item name="threeds2" xsi:type="string">Adyen\Payment\Gateway\Request\ThreeDS2DataBuilder</item> <item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CheckoutDataBuilder</item>
</argument> </argument>
</arguments> </arguments>
</virtualType> </virtualType>
...@@ -885,14 +884,6 @@ ...@@ -885,14 +884,6 @@
</arguments> </arguments>
</virtualType> </virtualType>
<!--General Response validator-->
<virtualType name="GeneralResponseValidator" type="Adyen\Payment\Gateway\Validator\GeneralResponseValidator">
<arguments>
<argument name="loggerInterface" xsi:type="object">Adyen\Payment\Logger\AdyenLogger</argument>
</arguments>
</virtualType>
<!--Checkout Response validator--> <!--Checkout Response validator-->
<virtualType name="CheckoutResponseValidator" type="Adyen\Payment\Gateway\Validator\CheckoutResponseValidator"> <virtualType name="CheckoutResponseValidator" type="Adyen\Payment\Gateway\Validator\CheckoutResponseValidator">
<arguments> <arguments>
...@@ -1017,8 +1008,8 @@ ...@@ -1017,8 +1008,8 @@
type="Adyen\Payment\Model\AdyenRequestMerchantSession"/> type="Adyen\Payment\Model\AdyenRequestMerchantSession"/>
<preference for="Adyen\Payment\Api\AdyenInitiateTerminalApiInterface" <preference for="Adyen\Payment\Api\AdyenInitiateTerminalApiInterface"
type="Adyen\Payment\Model\AdyenInitiateTerminalApi"/> type="Adyen\Payment\Model\AdyenInitiateTerminalApi"/>
<preference for="Adyen\Payment\Api\AdyenThreeDS2ProcessInterface" <preference for="Adyen\Payment\Api\AdyenPaymentDetailsInterface"
type="Adyen\Payment\Model\AdyenThreeDS2Process"/> type="Adyen\Payment\Model\AdyenPaymentDetails"/>
<preference for="Adyen\Payment\Api\AdyenOriginKeyInterface" <preference for="Adyen\Payment\Api\AdyenOriginKeyInterface"
type="Adyen\Payment\Model\AdyenOriginKey"/> type="Adyen\Payment\Model\AdyenOriginKey"/>
<preference for="Adyen\Payment\Api\AdyenOrderPaymentStatusInterface" <preference for="Adyen\Payment\Api\AdyenOrderPaymentStatusInterface"
......
...@@ -58,8 +58,8 @@ ...@@ -58,8 +58,8 @@
</resources> </resources>
</route> </route>
<route url="/V1/adyen/threeDS2Process" method="POST"> <route url="/V1/adyen/paymentDetails" method="POST">
<service class="Adyen\Payment\Api\AdyenThreeDS2ProcessInterface" method="initiate"/> <service class="Adyen\Payment\Api\AdyenPaymentDetailsInterface" method="initiate"/>
<resources> <resources>
<resource ref="anonymous"/> <resource ref="anonymous"/>
</resources> </resources>
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
/** @var Adyen\Payment\Block\Redirect\Redirect $block */
?>
<?php
if ($block->getRedirectMethod() == "GET") { ?>
<body>
<script>
window.location.replace("<?= $block->escapeJs($block->getRedirectUrl()); ?>");
</script>
</body>
<?php
} else { ?>
<body onload="document.getElementById('3dform').submit();">
<form method="POST" action="<?= $block->escapeHtml($block->getRedirectUrl()); ?>" id="3dform">
<input type="hidden" name="PaReq" value="<?= $block->escapeHtml($block->getPaReq()); ?>"/>
<input type="hidden" name="MD" value="<?= $block->escapeHtml($block->getMd()); ?>"/>
<input type="hidden" name="TermUrl" value="<?= $block->escapeHtml($block->getTermUrl()); ?>"/>
<noscript>
<br>
<br>
<div style="text-align: center">
<h1>Processing your 3-D Secure Transaction</h1>
<p>Please click continue to continue the processing of your 3-D Secure transaction.</p>
<input type="submit" class="button" value="continue"/>
</div>
</noscript>
</form>
</body>
<?php
} ?>
...@@ -1638,3 +1638,15 @@ ...@@ -1638,3 +1638,15 @@
overflow:auto; overflow:auto;
padding-top: 0; padding-top: 0;
} }
/**
* Configuration for Google Pay
*/
#googlePay.disabled {
cursor: pointer;
opacity: 0.75;
}
#googlePay.disabled > * {
pointer-events: none;
}
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0"?>
<!--
/** /**
* ###### * ######
* ###### * ######
...@@ -16,15 +14,29 @@ ...@@ -16,15 +14,29 @@
* *
* Adyen Payment module (https://www.adyen.com/) * Adyen Payment module (https://www.adyen.com/)
* *
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/) * Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details. * See LICENSE.txt for license details.
* *
* Author: Adyen <magento@adyen.com> * Author: Adyen <magento@adyen.com>
*/ */
--> define(
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd"> [
<container name="root"> ],
<block class="Adyen\Payment\Block\Redirect\Redirect" name="adyen-redirect-form" function () {
template="redirect/redirect.phtml" cacheable="false"/> 'use strict';
</container> return {
</layout> getOriginKey: function () {
return window.checkoutConfig.payment.adyen.originKey;
},
showLogo: function () {
return window.checkoutConfig.payment.adyen.showLogo;
},
getLocale: function () {
return window.checkoutConfig.payment.adyen.locale;
},
getCheckoutEnvironment: function () {
return window.checkoutConfig.payment.adyen.checkoutEnvironment;
},
};
}
);
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
define(
[
'ko'
],
function (ko) {
'use strict';
return ko.observableArray([]);
}
);
...@@ -6,74 +6,86 @@ define( ...@@ -6,74 +6,86 @@ define(
[ [
'underscore', 'underscore',
'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/model/quote',
'Adyen_Payment/js/model/adyen-method-list',
'Magento_Customer/js/model/customer', 'Magento_Customer/js/model/customer',
'Magento_Checkout/js/model/url-builder', 'Magento_Checkout/js/model/url-builder',
'mage/storage' 'mage/storage',
'Adyen_Payment/js/bundle',
'ko'
], ],
function (_, quote, methodList, customer, urlBuilder, storage) { function(
_,
quote,
customer,
urlBuilder,
storage,
adyenComponent,
ko
) {
'use strict'; 'use strict';
return { return {
paymentMethods: ko.observable({}),
/** /**
* Populate the list of payment methods * Retrieve the list of available payment methods from Adyen
* @param {Array} methods
*/
setPaymentMethods: function (methods) {
methodList(methods);
},
/**
* Get the list of available payment methods.
* @returns {Array}
*/
getAvailablePaymentMethods: function () {
return methodList();
},
/**
* Retrieve the list of available payment methods from the server
*/ */
retrieveAvailablePaymentMethods: function (callback) { retrievePaymentMethods: function() {
var self = this; // url for guest users
var serviceUrl = urlBuilder.createUrl(
'/guest-carts/:cartId/retrieve-adyen-payment-methods', {
cartId: quote.getQuoteId(),
});
// retrieve payment methods // url for logged in users
var serviceUrl,
payload;
if (customer.isLoggedIn()) { if (customer.isLoggedIn()) {
serviceUrl = urlBuilder.createUrl('/carts/mine/retrieve-adyen-payment-methods', {}); serviceUrl = urlBuilder.createUrl(
} else { '/carts/mine/retrieve-adyen-payment-methods', {});
serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/retrieve-adyen-payment-methods', {
cartId: quote.getQuoteId()
});
} }
payload = { // Construct payload for the retrieve payment methods request
var payload = {
cartId: quote.getQuoteId(), cartId: quote.getQuoteId(),
shippingAddress: quote.shippingAddress() shippingAddress: quote.shippingAddress(),
}; };
storage.post( return storage.post(
serviceUrl, serviceUrl,
JSON.stringify(payload) JSON.stringify(payload),
).done( );
function (response) { },
self.setPaymentMethods(response); getPaymentMethods: function() {
if (callback) { return this.paymentMethods;
callback(); },
} setPaymentMethods: function(paymentMethods) {
} this.paymentMethods(paymentMethods);
).fail(
function () {
self.setPaymentMethods([]);
}
)
}, },
getOrderPaymentStatus: function (orderId) { getOrderPaymentStatus: function(orderId) {
var serviceUrl = urlBuilder.createUrl('/adyen/orders/:orderId/payment-status', { var serviceUrl = urlBuilder.createUrl(
orderId: orderId '/adyen/orders/:orderId/payment-status', {
orderId: orderId,
}); });
return storage.get(serviceUrl); return storage.get(serviceUrl);
} },
/**
* The results that the components returns in the onComplete callback needs to be sent to the
* backend to the /adyen/paymentDetails endpoint and based on the response render a new
* component or place the order (validateThreeDS2OrPlaceOrder)
* @param response
*/
paymentDetails: function(data) {
var payload = {
'payload': JSON.stringify(data),
}; };
var serviceUrl = urlBuilder.createUrl('/adyen/paymentDetails',
{});
return storage.post(
serviceUrl,
JSON.stringify(payload),
true,
);
} }
};
},
); );
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
define(
[
'Magento_Checkout/js/model/url-builder',
'mage/storage'
],
function (urlBuilder, storage) {
'use strict';
return {
/**
* The results that the 3DS2 components returns in the onComplete callback needs to be sent to the
* backend to the /adyen/threeDS2Process endpoint and based on the response render a new threeDS2
* component or place the order (validateThreeDS2OrPlaceOrder)
* @param response
*/
processThreeDS2: function (data) {
var payload = {
"payload": JSON.stringify(data)
};
var serviceUrl = urlBuilder.createUrl('/adyen/threeDS2Process', {});
return storage.post(
serviceUrl,
JSON.stringify(payload),
true
);
}
};
}
);
!function(e,n){"object"===typeof exports&&"object"===typeof module?module.exports=n():"function"===typeof define&&define.amd?define([],n):"object"===typeof exports?exports.ThreedDS2Utils=n():e.ThreedDS2Utils=n()}(this,function(){return function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){"use strict";t.r(n);var r={container:void 0},o={"01":["250px","400px"],"02":["390px","400px"],"03":["500px","600px"],"04":["600px","400px"],"05":["100%","100%"]};function a(e){return o.hasOwnProperty(e)?e:"01"}var i={createIframe:function(e,n){var t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"0",o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"0",a=arguments.length>4?arguments[4]:void 0;if(!n||0===n.length)throw new Error("Name parameter missing for iframe");e instanceof HTMLElement?r.container=e:r.container=document.body;var i=document.createElement("iframe");i.classList.add(n+"Class"),i.width=t,i.height=o,i.name=n,i.setAttribute("frameborder","0"),i.setAttribute("border","0");var d=document.createTextNode("<p>Your browser does not support iframes.</p>");return i.appendChild(d),r.container.appendChild(i),function(e,n){e.attachEvent?e.attachEvent("onload",function(){n&&"function"===typeof n&&n(e.contentWindow)}):e.onload=function(){n&&"function"===typeof n&&n(e.contentWindow)}}(i,a),i},createForm:function(e,n,t,r,o){if(!e||!n||!t||!r||!o)throw new Error("Not all required parameters provided for form creation");if(0===e.length||0===n.length||0===t.length||0===r.length||0===o.length)throw new Error("Not all required parameters have suitable values");var a=document.createElement("form");a.style.display="none",a.name=e,a.action=n,a.method="POST",a.target=t;var i=document.createElement("input");return i.name=r,i.value=o,a.appendChild(i),a},getBrowserInfo:function(){var e=window&&window.screen?window.screen.width:"",n=window&&window.screen?window.screen.height:"",t=window&&window.screen?window.screen.colorDepth:"",r=window&&window.navigator?window.navigator.userAgent:"",o=!(!window||!window.navigator)&&navigator.javaEnabled(),a="";return window&&window.navigator&&(a=window.navigator.language?window.navigator.language:window.navigator.browserLanguage),{screenWidth:e,screenHeight:n,colorDepth:t,userAgent:r,timeZoneOffset:(new Date).getTimezoneOffset(),language:a,javaEnabled:o}},base64Url:{encode:function(e){var n=window.btoa(e).split("=")[0];return n=(n=n.replace("/+/g","-")).replace("///g","_")},decode:function(e){var n=e;switch((n=(n=n.replace("/-/g","+")).replace("/_/g","/")).length%4){case 0:break;case 2:n+="==";break;case 3:n+="=";break;default:window.console&&window.console.log&&window.console.log("### base64url::decodeBase64URL:: Illegal base64url string!")}try{return window.atob(n)}catch(e){throw new Error(e)}}},config:{challengeWindowSizes:o,validateChallengeWindowSize:a,getChallengeWindowSize:function(e){return o[a(e)]},THREEDS_METHOD_TIMEOUT:1e4,CHALLENGE_TIMEOUT:6e5}};n.default=i}]).default});
\ No newline at end of file
...@@ -24,11 +24,19 @@ ...@@ -24,11 +24,19 @@
define( define(
[ [
'uiComponent', 'uiComponent',
'Magento_Checkout/js/model/payment/renderer-list' 'Magento_Checkout/js/model/payment/renderer-list',
'Adyen_Payment/js/model/adyen-payment-service',
'Adyen_Payment/js/model/adyen-configuration',
'Magento_Checkout/js/model/quote',
'Magento_Checkout/js/model/full-screen-loader',
], ],
function ( function (
Component, Component,
rendererList rendererList,
adyenPaymentService,
adyenConfiguration,
quote,
fullScreenLoader
) { ) {
'use strict'; 'use strict';
rendererList.push( rendererList.push(
...@@ -66,6 +74,25 @@ define( ...@@ -66,6 +74,25 @@ define(
initialize: function () { initialize: function () {
this._super(); this._super();
var shippingAddressCountry = "";
quote.shippingAddress.subscribe(function(address) {
// In case the country hasn't changed don't retrieve new payment methods
if (shippingAddressCountry === quote.shippingAddress().countryId) {
return;
}
shippingAddressCountry = quote.shippingAddress().countryId;
fullScreenLoader.startLoader();
// Retrieve adyen payment methods
adyenPaymentService.retrievePaymentMethods().done(function(paymentMethods) {
paymentMethods = JSON.parse(paymentMethods);
adyenPaymentService.setPaymentMethods(paymentMethods);
fullScreenLoader.stopLoader();
}).fail(function() {
})
});
if (this.isGooglePayEnabled()) { if (this.isGooglePayEnabled()) {
var googlepayscript = document.createElement('script'); var googlepayscript = document.createElement('script');
googlepayscript.src = "https://pay.google.com/gp/p/js/pay.js"; googlepayscript.src = "https://pay.google.com/gp/p/js/pay.js";
......
...@@ -35,51 +35,57 @@ define( ...@@ -35,51 +35,57 @@ define(
'mage/url', 'mage/url',
'Magento_Vault/js/view/payment/vault-enabler', 'Magento_Vault/js/view/payment/vault-enabler',
'Adyen_Payment/js/model/adyen-payment-service', 'Adyen_Payment/js/model/adyen-payment-service',
'adyenCheckout' 'Adyen_Payment/js/bundle',
], ],
function (ko, $, Component, placeOrderAction, additionalValidators, quote, urlBuilder, fullScreenLoader, url, VaultEnabler, adyenPaymentService,AdyenCheckout) { function (
ko,
$,
Component,
placeOrderAction,
additionalValidators,
quote,
urlBuilder,
fullScreenLoader,
url,
VaultEnabler,
adyenPaymentService,
AdyenComponent
) {
'use strict'; 'use strict';
/**
* Shareble adyen checkout component
* @type {AdyenCheckout}
*/
var checkoutComponent;
return Component.extend({ return Component.extend({
self: this, self: this,
defaults: { defaults: {
template: 'Adyen_Payment/payment/google-pay-form', template: 'Adyen_Payment/payment/google-pay-form',
googlePayToken: null, googlePayToken: null,
googlePayAllowed: null googlePayAllowed: null,
}, },
/** /**
* @returns {Boolean} * @returns {Boolean}
*/ */
isShowLegend: function () { isShowLegend: function() {
return true; return true;
}, },
setPlaceOrderHandler: function (handler) { setPlaceOrderHandler: function(handler) {
this.placeOrderHandler = handler; this.placeOrderHandler = handler;
}, },
setValidateHandler: function (handler) { setValidateHandler: function(handler) {
this.validateHandler = handler; this.validateHandler = handler;
}, },
getCode: function () { getCode: function() {
return 'adyen_google_pay'; return 'adyen_google_pay';
}, },
isActive: function () { isActive: function() {
return true; return true;
}, },
initObservable: function () { initObservable: function() {
this._super() this._super().observe([
.observe([
'googlePayToken', 'googlePayToken',
'googlePayAllowed' 'googlePayAllowed',
]); ]);
return this; return this;
}, initialize: function () { },
var self = this; initialize: function() {
this.additionalValidators = additionalValidators; this.additionalValidators = additionalValidators;
this.vaultEnabler = new VaultEnabler(); this.vaultEnabler = new VaultEnabler();
this.vaultEnabler.setPaymentCode(this.getVaultCode()); this.vaultEnabler.setPaymentCode(this.getVaultCode());
...@@ -87,7 +93,7 @@ define( ...@@ -87,7 +93,7 @@ define(
this._super(); this._super();
}, },
renderGooglePay: function () { renderGooglePay: function() {
this.googlePayNode = document.getElementById('googlePay'); this.googlePayNode = document.getElementById('googlePay');
var self = this; var self = this;
...@@ -96,8 +102,8 @@ define( ...@@ -96,8 +102,8 @@ define(
originKey: self.getOriginKey(), originKey: self.getOriginKey(),
environment: self.getCheckoutEnvironment(), environment: self.getCheckoutEnvironment(),
risk: { risk: {
enabled: false enabled: false,
} },
}); });
var googlepay = self.checkoutComponent.create('paywithgoogle', { var googlepay = self.checkoutComponent.create('paywithgoogle', {
showPayButton: true, showPayButton: true,
...@@ -109,25 +115,24 @@ define( ...@@ -109,25 +115,24 @@ define(
// https://developers.google.com/pay/api/web/reference/object#MerchantInfo // https://developers.google.com/pay/api/web/reference/object#MerchantInfo
merchantIdentifier: self.getMerchantIdentifier(), merchantIdentifier: self.getMerchantIdentifier(),
merchantName: self.getMerchantAccount() merchantName: self.getMerchantAccount(),
}, },
// Payment // Payment
amount: self.formatAmount(quote.totals().grand_total, self.getFormat()), amount: self.formatAmount(quote.totals().grand_total, self.getFormat()),
currency: quote.totals().quote_currency_code, currency: quote.totals().quote_currency_code,
totalPriceStatus: 'FINAL', totalPriceStatus: 'FINAL',
// empty onSubmit to resolve javascript issues. // empty onSubmit to resolve javascript issues.
onSubmit: function() {}, onSubmit: function () {
},
onChange: function (state) { onChange: function (state) {
if (!!state.isValid) { if (!!state.isValid) {
self.googlePayToken(state.data.paymentMethod.googlePayToken); self.googlePayToken(state.data.paymentMethod.googlePayToken);
self.getPlaceOrderDeferredObject() self.getPlaceOrderDeferredObject().fail(
.fail(
function () { function () {
fullScreenLoader.stopLoader(); fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true); self.isPlaceOrderActionAllowed(true);
} },
).done( ).done(
function (orderId) { function (orderId) {
self.afterPlaceOrder(); self.afterPlaceOrder();
...@@ -135,21 +140,21 @@ define( ...@@ -135,21 +140,21 @@ define(
.done(function (responseJSON) { .done(function (responseJSON) {
self.validateThreeDSOrPlaceOrder(responseJSON) self.validateThreeDSOrPlaceOrder(responseJSON)
}); });
} },
); );
} }
}, },
buttonColor: 'black', // default/black/white buttonColor: 'black', // default/black/white
buttonType: 'long', // long/short buttonType: 'long', // long/short
showButton: true // show or hide the Google Pay button showButton: true, // show or hide the Google Pay button
}); });
var promise = googlepay.isAvailable(); googlepay.isAvailable().then(function() {
promise.then(function (success) {
self.googlePayAllowed(true); self.googlePayAllowed(true);
googlepay.mount(self.googlePayNode); googlepay.mount(self.googlePayNode);
$(self.googlePayNode).find('button').prop('disabled', true); self.googlePayNode.addEventListener('click', function () {
}, function (error) { self.validate();
});
}, function(error) {
console.log(error); console.log(error);
self.googlePayAllowed(false); self.googlePayAllowed(false);
}); });
...@@ -171,59 +176,55 @@ define( ...@@ -171,59 +176,55 @@ define(
} }
}, },
isGooglePayAllowed: function () { isGooglePayAllowed: function () {
if (this.googlePayAllowed()) { return !!this.googlePayAllowed();
return true;
}
return false;
}, },
getMerchantAccount: function () { getMerchantAccount: function() {
return window.checkoutConfig.payment.adyenGooglePay.merchantAccount; return window.checkoutConfig.payment.adyenGooglePay.merchantAccount;
}, },
showLogo: function () { showLogo: function() {
return window.checkoutConfig.payment.adyen.showLogo; return window.checkoutConfig.payment.adyen.showLogo;
}, },
getLocale: function () { getLocale: function() {
return window.checkoutConfig.payment.adyenGooglePay.locale; return window.checkoutConfig.payment.adyenGooglePay.locale;
}, },
getFormat: function () { getFormat: function() {
return window.checkoutConfig.payment.adyenGooglePay.format; return window.checkoutConfig.payment.adyenGooglePay.format;
}, },
getMerchantIdentifier: function () { getMerchantIdentifier: function() {
return window.checkoutConfig.payment.adyenGooglePay.merchantIdentifier; return window.checkoutConfig.payment.adyenGooglePay.merchantIdentifier;
}, },
context: function () { context: function() {
return this; return this;
}, },
validate: function (hideErrors) { validate: function(hideErrors) {
return this.additionalValidators.validate(hideErrors); return this.additionalValidators.validate(hideErrors);
}, },
getControllerName: function () { getControllerName: function() {
return window.checkoutConfig.payment.iframe.controllerName[this.getCode()]; return window.checkoutConfig.payment.iframe.controllerName[this.getCode()];
}, },
getPlaceOrderUrl: function () { getPlaceOrderUrl: function() {
return window.checkoutConfig.payment.iframe.placeOrderUrl[this.getCode()]; return window.checkoutConfig.payment.iframe.placeOrderUrl[this.getCode()];
}, },
/** /**
* Get data for place order * Get data for place order
* @returns {{method: *}} * @returns {{method: *}}
*/ */
getData: function () { getData: function() {
return { return {
'method': "adyen_google_pay", 'method': 'adyen_google_pay',
'additional_data': { 'additional_data': {
'token': this.googlePayToken() 'token': this.googlePayToken(),
} },
}; };
}, },
/** /**
* Return the formatted currency. Adyen accepts the currency in multiple formats. * Return the formatted currency. Adyen accepts the currency in multiple formats.
* @param $amount * @param amount
* @param $currency * @param format
* @return string * @return string
*/ */
formatAmount: function (amount, format) { formatAmount: function (amount, format) {
return Math.round(amount * (Math.pow(10, format))) return Math.round(amount * (Math.pow(10, format))).toString();
}, },
isVaultEnabled: function () { isVaultEnabled: function () {
return this.vaultEnabler.isVaultEnabled(); return this.vaultEnabler.isVaultEnabled();
...@@ -237,8 +238,8 @@ define( ...@@ -237,8 +238,8 @@ define(
getCheckoutEnvironment: function () { getCheckoutEnvironment: function () {
return window.checkoutConfig.payment.adyenGooglePay.checkoutEnvironment; return window.checkoutConfig.payment.adyenGooglePay.checkoutEnvironment;
}, },
onPaymentMethodContentChange: function (data, event) { onPaymentMethodContentChange: function () {
$(this.googlePayNode).find('button').prop('disabled', !this.validate()); $(this.googlePayNode).toggleClass('disabled', !this.validate());
} }
}); });
} }
......
...@@ -95,9 +95,9 @@ ...@@ -95,9 +95,9 @@
<div class="checkout-component-dock" afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}"></div> <div class="checkout-component-dock" afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}"></div>
</div> </div>
<div id="threeDS2Wrapper"> <div id="cc_actionModalWrapper">
<div id="threeDS2Modal"> <div id="cc_actionModal">
<div id="threeDS2Container"></div> <div id="cc_actionContainer"></div>
</div> </div>
</div> </div>
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
<!--/ko--> <!--/ko-->
</div> </div>
<div class="field number googlePay"> <div class="field number googlePay">
<div class="checkout-component-dock" afterRender="renderGooglePay()" data-bind="attr: { id: 'googlePay'}"> <div class="checkout-component-dock disabled" afterRender="renderGooglePay()" data-bind="attr: { id: 'googlePay'}">
<!-- ko ifnot: isGooglePayAllowed() --> <!-- ko ifnot: isGooglePayAllowed() -->
Google Pay is not available Google Pay is not available
<!--/ko--></div> <!--/ko--></div>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment