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 8da089ce authored by Attila Kiss's avatar Attila Kiss Committed by GitHub

[PW-3130] Use the generic component for stored payment methods (#919)

* Tokenize payment methods in payment response handler

Do not save recurring details "manually" for /payments/details response

* Standardise Oneclick Observer

* Use generic component for recurring payments

* sonarcloud suggestions

* Remove unused div
parent 3f7ebc9e
...@@ -55,20 +55,6 @@ class OneclickAuthorizationDataBuilder implements BuilderInterface ...@@ -55,20 +55,6 @@ class OneclickAuthorizationDataBuilder implements BuilderInterface
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject); $paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment(); $payment = $paymentDataObject->getPayment();
// If ccType is set use this. For bcmc you need bcmc otherwise it will fail
$requestBody['paymentMethod']['type'] = "scheme";
if ($variant = $payment->getAdditionalInformation(AdyenOneclickDataAssignObserver::VARIANT)) {
$requestBody['paymentMethod']['type'] = $variant;
}
if ($securityCode = $payment->getAdditionalInformation(
AdyenOneclickDataAssignObserver::ENCRYPTED_SECURITY_CODE
)) {
$requestBody['paymentMethod']['encryptedSecurityCode'] = $securityCode;
}
$payment->unsAdditionalInformation(AdyenOneclickDataAssignObserver::ENCRYPTED_SECURITY_CODE);
if ($payment->getAdditionalInformation('customer_interaction')) { if ($payment->getAdditionalInformation('customer_interaction')) {
$shopperInteraction = "Ecommerce"; $shopperInteraction = "Ecommerce";
} else { } else {
...@@ -76,9 +62,7 @@ class OneclickAuthorizationDataBuilder implements BuilderInterface ...@@ -76,9 +62,7 @@ class OneclickAuthorizationDataBuilder implements BuilderInterface
} }
$requestBody['shopperInteraction'] = $shopperInteraction; $requestBody['shopperInteraction'] = $shopperInteraction;
$requestBody['paymentMethod']['recurringDetailReference'] = $payment->getAdditionalInformation(
AdyenOneclickDataAssignObserver::RECURRING_DETAIL_REFERENCE
);
// if it is a sepadirectdebit set selectedBrand to sepadirectdebit in the case of oneclick // if it is a sepadirectdebit set selectedBrand to sepadirectdebit in the case of oneclick
if ($payment->getCcType() == "sepadirectdebit") { if ($payment->getCcType() == "sepadirectdebit") {
......
...@@ -1713,7 +1713,7 @@ class Data extends AbstractHelper ...@@ -1713,7 +1713,7 @@ class Data extends AbstractHelper
$billingAgreement->getAgreementId(), $billingAgreement->getAgreementId(),
$order->getId() $order->getId()
)) { )) {
// save into sales_billing_agreement_order // save into billing_agreement_order
$billingAgreement->addOrderRelation($order); $billingAgreement->addOrderRelation($order);
} }
// add to order to save agreement // add to order to save agreement
...@@ -1733,6 +1733,7 @@ class Data extends AbstractHelper ...@@ -1733,6 +1733,7 @@ class Data extends AbstractHelper
$comment = $order->addStatusHistoryComment($message); $comment = $order->addStatusHistoryComment($message);
$order->addRelatedObject($comment); $order->addRelatedObject($comment);
$order->save();
} }
} }
......
...@@ -27,6 +27,7 @@ use Adyen\Payment\Logger\AdyenLogger; ...@@ -27,6 +27,7 @@ use Adyen\Payment\Logger\AdyenLogger;
use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\Data\OrderPaymentInterface; use Magento\Sales\Api\Data\OrderPaymentInterface;
use Magento\Sales\Model\Order; use Magento\Sales\Model\Order;
use Adyen\Payment\Helper\Vault;
class PaymentResponseHandler class PaymentResponseHandler
{ {
...@@ -41,12 +42,36 @@ class PaymentResponseHandler ...@@ -41,12 +42,36 @@ class PaymentResponseHandler
const ERROR = 'Error'; const ERROR = 'Error';
const CANCELLED = 'Cancelled'; const CANCELLED = 'Cancelled';
/**
* @var AdyenLogger
*/
private $adyenLogger; private $adyenLogger;
/**
* @var Data
*/
private $adyenHelper;
/**
* @var Vault
*/
private $vaultHelper;
/**
* PaymentResponseHandler constructor.
*
* @param AdyenLogger $adyenLogger
* @param Data $adyenHelper
* @param \Adyen\Payment\Helper\Vault $vaultHelper
*/
public function __construct( public function __construct(
AdyenLogger $adyenLogger AdyenLogger $adyenLogger,
Data $adyenHelper,
Vault $vaultHelper
) { ) {
$this->adyenLogger = $adyenLogger; $this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
$this->vaultHelper = $vaultHelper;
} }
public function formatPaymentResponse($resultCode, $action = null, $additionalData = null) public function formatPaymentResponse($resultCode, $action = null, $additionalData = null)
...@@ -144,6 +169,24 @@ class PaymentResponseHandler ...@@ -144,6 +169,24 @@ class PaymentResponseHandler
} }
break; break;
case self::AUTHORISED: case self::AUTHORISED:
if (!empty($paymentsResponse['pspReference'])) {
// set pspReference as transactionId
$payment->setCcTransId($paymentsResponse['pspReference']);
$payment->setLastTransId($paymentsResponse['pspReference']);
// set transaction
$payment->setTransactionId($paymentsResponse['pspReference']);
}
if (!empty($paymentsResponse['additionalData']['recurring.recurringDetailReference']) &&
$payment->getMethodInstance()->getCode() !== \Adyen\Payment\Model\Ui\AdyenOneclickConfigProvider::CODE) {
if ($this->adyenHelper->isCreditCardVaultEnabled()) {
$this->vaultHelper->saveRecurringDetails($payment, $paymentsResponse['additionalData']);
} else {
$order = $payment->getOrder();
$this->adyenHelper->createAdyenBillingAgreement($order, $paymentsResponse['additionalData']);
}
}
case self::IDENTIFY_SHOPPER: case self::IDENTIFY_SHOPPER:
case self::CHALLENGE_SHOPPER: case self::CHALLENGE_SHOPPER:
break; break;
......
...@@ -27,7 +27,6 @@ use Adyen\AdyenException; ...@@ -27,7 +27,6 @@ use Adyen\AdyenException;
use Adyen\Payment\Api\AdyenPaymentDetailsInterface; use Adyen\Payment\Api\AdyenPaymentDetailsInterface;
use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\Data;
use Adyen\Payment\Helper\PaymentResponseHandler; use Adyen\Payment\Helper\PaymentResponseHandler;
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\Framework\Exception\LocalizedException; use Magento\Framework\Exception\LocalizedException;
...@@ -50,11 +49,6 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface ...@@ -50,11 +49,6 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface
*/ */
private $adyenLogger; private $adyenLogger;
/**
* @var Vault
*/
private $vaultHelper;
/** /**
* @var OrderRepositoryInterface * @var OrderRepositoryInterface
*/ */
...@@ -71,7 +65,6 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface ...@@ -71,7 +65,6 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface
* @param Session $checkoutSession * @param Session $checkoutSession
* @param Data $adyenHelper * @param Data $adyenHelper
* @param AdyenLogger $adyenLogger * @param AdyenLogger $adyenLogger
* @param Vault $vaultHelper
* @param OrderRepositoryInterface $orderRepository * @param OrderRepositoryInterface $orderRepository
* @param PaymentResponseHandler $paymentResponseHandler * @param PaymentResponseHandler $paymentResponseHandler
*/ */
...@@ -79,14 +72,12 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface ...@@ -79,14 +72,12 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface
Session $checkoutSession, Session $checkoutSession,
Data $adyenHelper, Data $adyenHelper,
AdyenLogger $adyenLogger, AdyenLogger $adyenLogger,
Vault $vaultHelper,
OrderRepositoryInterface $orderRepository, OrderRepositoryInterface $orderRepository,
PaymentResponseHandler $paymentResponseHandler PaymentResponseHandler $paymentResponseHandler
) { ) {
$this->checkoutSession = $checkoutSession; $this->checkoutSession = $checkoutSession;
$this->adyenHelper = $adyenHelper; $this->adyenHelper = $adyenHelper;
$this->adyenLogger = $adyenLogger; $this->adyenLogger = $adyenLogger;
$this->vaultHelper = $vaultHelper;
$this->orderRepository = $orderRepository; $this->orderRepository = $orderRepository;
$this->paymentResponseHandler = $paymentResponseHandler; $this->paymentResponseHandler = $paymentResponseHandler;
} }
...@@ -139,14 +130,7 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface ...@@ -139,14 +130,7 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface
throw new LocalizedException(__('Payment details call failed')); throw new LocalizedException(__('Payment details call failed'));
} }
//TODO test this with payments that return additionalData // Handle response
//TODO check for Authorized result code and move to the handler
if (!empty($paymentDetails['additionalData'])) {
$this->vaultHelper->saveRecurringDetails($payment, $paymentDetails['additionalData']);
}
//TODO check if order save is necessary to save additionalData
if (!$this->paymentResponseHandler->handlePaymentResponse($paymentDetails, $payment, $order)) { if (!$this->paymentResponseHandler->handlePaymentResponse($paymentDetails, $payment, $order)) {
$this->checkoutSession->restoreQuote(); $this->checkoutSession->restoreQuote();
throw new LocalizedException(__('The payment is REFUSED.')); throw new LocalizedException(__('The payment is REFUSED.'));
......
...@@ -37,6 +37,7 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver ...@@ -37,6 +37,7 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
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'; const STATE_DATA = 'stateData';
const STORE_PAYMENT_METHOD = 'storePaymentMethod';
/** /**
* Approved root level keys from additional data array * Approved root level keys from additional data array
...@@ -113,5 +114,10 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver ...@@ -113,5 +114,10 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
if (!empty($additionalData[self::CC_TYPE])) { if (!empty($additionalData[self::CC_TYPE])) {
$paymentInfo->setCcType($additionalData[self::CC_TYPE]); $paymentInfo->setCcType($additionalData[self::CC_TYPE]);
} }
// set storeCc
if (!empty($stateData[self::STORE_PAYMENT_METHOD])) {
$paymentInfo->setAdditionalInformation(self::STORE_CC, $stateData[self::STORE_PAYMENT_METHOD]);
}
} }
} }
...@@ -23,39 +23,34 @@ ...@@ -23,39 +23,34 @@
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;
class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
{ {
const RECURRING_DETAIL_REFERENCE = 'recurring_detail_reference'; const CC_TYPE = 'cc_type';
const ENCRYPTED_SECURITY_CODE = 'cvc'; const BRAND = 'brand';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments'; const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
const VARIANT = 'variant'; const STATE_DATA = 'stateData';
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';
/** /**
* Approved root level keys from additional data array
*
* @var array * @var array
*/ */
protected $additionalInformationList = [ private static $approvedAdditionalDataKeys = [
self::RECURRING_DETAIL_REFERENCE, self::STATE_DATA,
self::ENCRYPTED_SECURITY_CODE,
self::NUMBER_OF_INSTALLMENTS, self::NUMBER_OF_INSTALLMENTS,
self::VARIANT,
self::JAVA_ENABLED,
self::SCREEN_COLOR_DEPTH,
self::SCREEN_WIDTH,
self::SCREEN_HEIGHT,
self::TIMEZONE_OFFSET,
self::LANGUAGE
]; ];
/**
* @var CheckoutStateDataValidator
*/
private $checkoutStateDataValidator;
/** /**
* @var \Adyen\Payment\Helper\Data * @var \Adyen\Payment\Helper\Data
*/ */
...@@ -72,9 +67,11 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver ...@@ -72,9 +67,11 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
* @param \Adyen\Payment\Helper\Data $adyenHelper * @param \Adyen\Payment\Helper\Data $adyenHelper
*/ */
public function __construct( public function __construct(
CheckoutStateDataValidator $checkoutStateDataValidator,
\Adyen\Payment\Helper\Data $adyenHelper, \Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Model\Context $context \Magento\Framework\Model\Context $context
) { ) {
$this->checkoutStateDataValidator = $checkoutStateDataValidator;
$this->adyenHelper = $adyenHelper; $this->adyenHelper = $adyenHelper;
$this->appState = $context->getAppState(); $this->appState = $context->getAppState();
} }
...@@ -85,27 +82,47 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver ...@@ -85,27 +82,47 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
*/ */
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
$variant = $additionalData['variant']; $stateData = [];
$ccType = $this->adyenHelper->getMagentoCreditCartType($variant); if (!empty($additionalData[self::STATE_DATA])) {
$paymentInfo->setCcType($ccType); $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($stateData[self::BRAND])) {
$ccType = $this->adyenHelper->getMagentoCreditCartType($stateData[self::BRAND]);
$paymentInfo->setCcType($ccType);
} }
// set customerInteraction // set customerInteraction
...@@ -115,11 +132,6 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver ...@@ -115,11 +132,6 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
} else { } else {
$paymentInfo->setAdditionalInformation('customer_interaction', false); $paymentInfo->setAdditionalInformation('customer_interaction', false);
} }
// set ccType
$variant = $additionalData['variant'];
$ccType = $this->adyenHelper->getMagentoCreditCartType($variant);
$paymentInfo->setAdditionalInformation('cc_type', $ccType);
} }
/** /**
......
...@@ -29,21 +29,17 @@ define( ...@@ -29,21 +29,17 @@ define(
'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Checkout/js/model/payment/additional-validators',
'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/model/quote',
'Magento_Checkout/js/checkout-data', 'Magento_Checkout/js/checkout-data',
'Magento_Checkout/js/action/redirect-on-success',
'uiLayout', 'uiLayout',
'Magento_Ui/js/model/messages', 'Magento_Ui/js/model/messages',
'mage/url', 'mage/url',
'Magento_Checkout/js/model/full-screen-loader', 'Magento_Checkout/js/model/full-screen-loader',
'Magento_Paypal/js/action/set-payment-method',
'Magento_Checkout/js/model/url-builder',
'mage/storage',
'Magento_Checkout/js/action/place-order', 'Magento_Checkout/js/action/place-order',
'Magento_Checkout/js/model/error-processor', 'Magento_Checkout/js/model/error-processor',
'Adyen_Payment/js/model/adyen-payment-service', 'Adyen_Payment/js/model/adyen-payment-service',
'Adyen_Payment/js/bundle', 'Adyen_Payment/js/bundle',
], 'Adyen_Payment/js/model/adyen-configuration',
],
function( function(
ko, ko,
_, _,
$, $,
...@@ -52,19 +48,16 @@ function( ...@@ -52,19 +48,16 @@ function(
additionalValidators, additionalValidators,
quote, quote,
checkoutData, checkoutData,
redirectOnSuccessAction,
layout, layout,
Messages, Messages,
url, url,
fullScreenLoader, fullScreenLoader,
setPaymentMethodAction,
urlBuilder,
storage,
placeOrderAction, placeOrderAction,
errorProcessor, errorProcessor,
adyenPaymentService, adyenPaymentService,
AdyenComponent AdyenComponent,
) { adyenConfiguration,
) {
'use strict'; 'use strict';
...@@ -77,7 +70,8 @@ function( ...@@ -77,7 +70,8 @@ function(
var isValid = ko.observable(false); var isValid = ko.observable(false);
return Component.extend({ return Component.extend({
isPlaceOrderActionAllowed: ko.observable(quote.billingAddress() != null), isPlaceOrderActionAllowed: ko.observable(
quote.billingAddress() != null),
defaults: { defaults: {
template: 'Adyen_Payment/payment/oneclick-form', template: 'Adyen_Payment/payment/oneclick-form',
recurringDetailReference: '', recurringDetailReference: '',
...@@ -87,29 +81,29 @@ function( ...@@ -87,29 +81,29 @@ function(
initObservable: function() { initObservable: function() {
this._super().observe([ this._super().observe([
'recurringDetailReference', 'recurringDetailReference',
'creditCardType',
'encryptedCreditCardVerificationNumber',
'variant', 'variant',
'numberOfInstallments', 'numberOfInstallments',
]); ]);
return this; return this;
}, },
initialize: function() { initialize: function() {
var self = this; let self = this;
this._super(); this._super();
// create component needs to be in initialize method // create component needs to be in initialize method
var messageComponents = {}; let messageComponents = {};
_.map(window.checkoutConfig.payment.adyenOneclick.billingAgreements, _.map(
function(value) { window.checkoutConfig.payment.adyenOneclick.billingAgreements,
function(billingAgreement) {
var messageContainer = new Messages(); let messageContainer = new Messages();
var name = 'messages-' + value.reference_id; let name = 'messages-' + billingAgreement.reference_id;
var messagesComponent = { let messagesComponent = {
parent: self.name, parent: self.name,
name: 'messages-' + value.reference_id, name: 'messages-' + billingAgreement.reference_id,
// name: self.name + '.messages', // name: self.name + '.messages',
displayArea: 'messages-' + value.reference_id, displayArea: 'messages-' +
billingAgreement.reference_id,
component: 'Magento_Ui/js/view/messages', component: 'Magento_Ui/js/view/messages',
config: { config: {
messageContainer: messageContainer, messageContainer: messageContainer,
...@@ -120,6 +114,80 @@ function( ...@@ -120,6 +114,80 @@ function(
messageComponents[name] = messageContainer; messageComponents[name] = messageContainer;
}); });
this.messageComponents = messageComponents; this.messageComponents = messageComponents;
let paymentMethodsObserver = adyenPaymentService.getPaymentMethods();
let paymentMethodsResponse = paymentMethodsObserver();
if (!!paymentMethodsResponse) {
this.checkoutComponent = new AdyenCheckout({
locale: adyenConfiguration.getLocale(),
originKey: adyenConfiguration.getOriginKey(),
environment: adyenConfiguration.getCheckoutEnvironment(),
paymentMethodsResponse: paymentMethodsResponse.paymentMethodsResponse,
onAdditionalDetails: this.handleOnAdditionalDetails.bind(this),
},
);
}
},
handleOnAdditionalDetails: function(result) {
var self = this;
var request = result.data;
request.orderId = self.orderId;
fullScreenLoader.stopLoader();
// TODO outsource creating the modal
var popupModal = $('#oneclick_actionModal').modal({
// disable user to hide popup
clickableOverlay: false,
responsive: true,
innerScroll: false,
// empty buttons, we don't need that
buttons: [],
modalClass: 'oneclick_actionModal',
});
popupModal.modal('openModal');
adyenPaymentService.paymentDetails(request).
done(function(responseJSON) {
self.handleAdyenResult(responseJSON,
self.orderId);
}).
fail(function(response) {
errorProcessor.process(response,
self.messageContainer);
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
},
/**
* Based on the response we can start a 3DS2 validation or place the order
* @param responseJSON
*/
handleAdyenResult: function(responseJSON, orderId) {
var self = this;
var response = JSON.parse(responseJSON);
if (!!response.isFinal) {
// Status is final redirect to the redirectUrl
window.location.replace(url.build(
window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl,
));
} else {
// Handle action
self.handleAction(response.action, orderId);
}
},
handleAction: function(action, orderId) {
try {
this.checkoutComponent.createFromAction(
action).
mount('#oneclick_actionContainer');
} catch (e) {
console.log(e);
}
}, },
/** /**
* List all Adyen billing agreements * List all Adyen billing agreements
...@@ -130,26 +198,16 @@ function( ...@@ -130,26 +198,16 @@ function(
getAdyenBillingAgreements: function() { getAdyenBillingAgreements: function() {
var self = this; var self = this;
// shareable adyen checkout component
var checkout = new AdyenCheckout({
locale: self.getLocale(),
originKey: self.getOriginKey(),
environment: self.getCheckoutEnvironment(),
risk: {
enabled: false,
},
});
// convert to list so you can iterate // convert to list so you can iterate
var paymentList = _.map( var paymentList = _.map(
window.checkoutConfig.payment.adyenOneclick.billingAgreements, window.checkoutConfig.payment.adyenOneclick.billingAgreements,
function(value) { function(billingAgreement) {
var creditCardExpMonth, creditCardExpYear = false; var creditCardExpMonth, creditCardExpYear = false;
if (value.agreement_data.card) { if (billingAgreement.agreement_data.card) {
creditCardExpMonth = value.agreement_data.card.expiryMonth; creditCardExpMonth = billingAgreement.agreement_data.card.expiryMonth;
creditCardExpYear = value.agreement_data.card.expiryYear; creditCardExpYear = billingAgreement.agreement_data.card.expiryYear;
} }
// pre-define installments if they are set // pre-define installments if they are set
...@@ -158,23 +216,26 @@ function( ...@@ -158,23 +216,26 @@ function(
var dividedString = ''; var dividedString = '';
var dividedAmount = 0; var dividedAmount = 0;
if (value.number_of_installments) { if (billingAgreement.number_of_installments) {
for (i = 0; i < value.number_of_installments.length; i++) { for (i = 0; i <
billingAgreement.number_of_installments.length; i++) {
dividedAmount = (grandTotal / dividedAmount = (grandTotal /
value.number_of_installments[i]).toFixed( billingAgreement.number_of_installments[i]).toFixed(
quote.getPriceFormat().precision); quote.getPriceFormat().precision);
dividedString = value.number_of_installments[i] + ' x ' + dividedString = billingAgreement.number_of_installments[i] +
dividedAmount + ' ' + quote.totals().quote_currency_code; ' x ' +
dividedAmount + ' ' +
quote.totals().quote_currency_code;
installments.push({ installments.push({
key: [dividedString], key: [dividedString],
value: value.number_of_installments[i], value: billingAgreement.number_of_installments[i],
}); });
} }
} }
var messageContainer = self.messageComponents['messages-' + var messageContainer = self.messageComponents['messages-' +
value.reference_id]; billingAgreement.reference_id];
// for recurring enable the placeOrder button at all times // for recurring enable the placeOrder button at all times
var placeOrderAllowed = true; var placeOrderAllowed = true;
...@@ -186,21 +247,24 @@ function( ...@@ -186,21 +247,24 @@ function(
} }
return { return {
'label': value.agreement_label, 'label': billingAgreement.agreement_label,
'value': value.reference_id, 'value': billingAgreement.reference_id,
'agreement_data': value.agreement_data, 'agreement_data': billingAgreement.agreement_data,
'logo': value.logo, 'logo': billingAgreement.logo,
'installment': '', 'installment': '',
'number_of_installments': value.number_of_installments, 'number_of_installments': billingAgreement.number_of_installments,
'method': self.item.method, 'method': self.item.method,
'encryptedCreditCardVerificationNumber': '', 'creditCardExpMonth': ko.observable(
'creditCardExpMonth': ko.observable(creditCardExpMonth), creditCardExpMonth),
'creditCardExpYear': ko.observable(creditCardExpYear), 'creditCardExpYear': ko.observable(
creditCardExpYear),
'getInstallments': ko.observableArray(installments), 'getInstallments': ko.observableArray(installments),
'placeOrderAllowed': ko.observable(placeOrderAllowed), 'placeOrderAllowed': ko.observable(
placeOrderAllowed),
isButtonActive: function() { isButtonActive: function() {
return self.isActive() && this.getCode() == self.isChecked() && return self.isActive() && this.getCode() ==
self.isChecked() &&
self.isBillingAgreementChecked() && self.isBillingAgreementChecked() &&
this.placeOrderAllowed() && this.placeOrderAllowed() &&
self.isPlaceOrderActionAllowed(); self.isPlaceOrderActionAllowed();
...@@ -215,34 +279,40 @@ function( ...@@ -215,34 +279,40 @@ function(
* @returns {boolean} * @returns {boolean}
*/ */
placeOrder: function(data, event) { placeOrder: function(data, event) {
var self = this; var innerSelf = this;
if (event) { if (event) {
event.preventDefault(); event.preventDefault();
} }
// only use installments for cards // only use installments for cards
if (self.agreement_data.card) { if (this.agreement_data.card) {
if (self.hasVerification()) { if (this.hasVerification()) {
var options = {enableValidations: false}; var options = {enableValidations: false};
} }
numberOfInstallments(self.installment); numberOfInstallments(this.installment);
} }
if (this.validate() && additionalValidators.validate()) { if (this.validate() &&
additionalValidators.validate()) {
fullScreenLoader.startLoader(); fullScreenLoader.startLoader();
self.isPlaceOrderActionAllowed(false); this.isPlaceOrderActionAllowed(false);
self.getPlaceOrderDeferredObject().fail( this.getPlaceOrderDeferredObject().fail(
function() { function() {
fullScreenLoader.stopLoader(); fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true); innerSelf.isPlaceOrderActionAllowed(
true);
}, },
).done( ).done(
function(orderId) { function(orderId) {
self.afterPlaceOrder(); innerSelf.afterPlaceOrder();
adyenPaymentService.getOrderPaymentStatus(orderId).
self.orderId = orderId;
adyenPaymentService.getOrderPaymentStatus(
orderId).
done(function(responseJSON) { done(function(responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, self.handleAdyenResult(
responseJSON,
orderId); orderId);
}); });
}, },
...@@ -257,13 +327,9 @@ function( ...@@ -257,13 +327,9 @@ function(
* sets up the callbacks for card components * sets up the callbacks for card components
*/ */
renderSecureCVC: function() { renderSecureCVC: function() {
var self = this; if (!this.getOriginKey()) {
if (!self.getOriginKey()) {
return; return;
} }
var oneClickCardNode = document.getElementById(
'cvcContainer-' + self.value);
var hideCVC = false; var hideCVC = false;
// hide cvc if contract has been stored as recurring // hide cvc if contract has been stored as recurring
...@@ -271,136 +337,27 @@ function( ...@@ -271,136 +337,27 @@ function(
hideCVC = true; hideCVC = true;
} }
var oneClickCard = checkout.create('card', { try {
this.component = self.checkoutComponent.create(
'card', {
hideCVC: hideCVC, hideCVC: hideCVC,
brand: self.agreement_data.variant, brand: this.agreement_data.variant,
storedPaymentMethodId: this.value, storedPaymentMethodId: this.value,
expiryMonth: self.agreement_data.card.expiryMonth, expiryMonth: this.agreement_data.card.expiryMonth,
expiryYear: self.agreement_data.card.expiryYear, expiryYear: this.agreement_data.card.expiryYear,
holderName: self.agreement_data.card.holderName, holderName: this.agreement_data.card.holderName,
onChange: function(state, component) { onChange: this.handleOnChange.bind(this)
if (state.isValid) { }).mount('#cvcContainer-' + this.value);
self.placeOrderAllowed(true); } catch (err) {
isValid(true); console.log(err);
// The component does not exist yet
if (typeof state.data !== 'undefined' &&
typeof state.data.paymentMethod !== 'undefined' &&
typeof state.data.paymentMethod.encryptedSecurityCode !==
'undefined'
) {
self.encryptedCreditCardVerificationNumber = state.data.paymentMethod.encryptedSecurityCode;
}
} else {
self.encryptedCreditCardVerificationNumber = '';
if (self.agreement_data.variant != 'maestro') {
self.placeOrderAllowed(false);
isValid(false);
}
}
},
}).mount(oneClickCardNode);
window.adyencheckout = oneClickCard;
},
/**
* Based on the response we can start a 3DS2 validation or place the order
* @param responseJSON
*/
validateThreeDS2OrPlaceOrder: function(responseJSON, orderId) {
var self = this;
var response = JSON.parse(responseJSON);
if (!!response.threeDS2) {
// render component
self.renderThreeDS2Component(response.type, response.token,
orderId);
} else {
window.location.replace(url.build(
window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl));
} }
},
/**
* Rendering the 3DS2.0 components
* To do the device fingerprint at the response of IdentifyShopper render the threeDS2DeviceFingerprint
* component
* To render the challenge for the customer at the response of ChallengeShopper render the
* threeDS2Challenge component
* Both of them is going to be rendered in a Magento dialog popup
*
* @param type
* @param token
*/
renderThreeDS2Component: function(type, token, orderId) {
var self = this;
var threeDS2Node = document.getElementById(
'threeDS2ContainerOneClick');
if (type == 'IdentifyShopper') {
self.threeDS2Component = checkout.create(
'threeDS2DeviceFingerprint', {
fingerprintToken: token,
onComplete: function(result) {
var request = result.data;
request.orderId = orderId;
adyenPaymentService.paymentDetails(request).
done(function(responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON,
orderId);
}).
fail(function(result) {
errorProcessor.process(result,
self.getMessageContainer());
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
},
onError: function(error) {
console.log(JSON.stringify(error));
},
});
} else if (type == 'ChallengeShopper') {
fullScreenLoader.stopLoader();
var popupModal = $('#threeDS2ModalOneClick').modal({
// disable user to hide popup
clickableOverlay: false,
responsive: true,
innerScroll: false,
// empty buttons, we don't need that
buttons: [],
modalClass: 'threeDS2Modal',
});
popupModal.modal('openModal');
self.threeDS2Component = checkout.create('threeDS2Challenge',
{
challengeToken: token,
onComplete: function(result) {
popupModal.modal('closeModal');
fullScreenLoader.startLoader();
var request = result.data;
request.orderId = orderId;
adyenPaymentService.paymentDetails(request).
done(function(responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON,
orderId);
}).
fail(function(result) {
errorProcessor.process(result,
self.getMessageContainer());
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
}, },
onError: function(error) { handleOnChange: function(state, component) {
console.log(JSON.stringify(error)); this.placeOrderAllowed(
}, !!state.isValid);
}); isValid(!!state.isValid);
}
self.threeDS2Component.mount(threeDS2Node);
}, },
/** /**
* Builds the payment details part of the payment information reqeust * Builds the payment details part of the payment information reqeust
...@@ -409,23 +366,17 @@ function( ...@@ -409,23 +366,17 @@ function(
*/ */
getData: function() { getData: function() {
var self = this; var self = this;
// todo use state.data
var browserInfo = []; let stateData;
if ('component' in self) {
stateData = self.component.data;
}
return { return {
'method': self.method, 'method': self.method,
additional_data: { additional_data: {
variant: variant(),
recurring_detail_reference: recurringDetailReference(),
store_cc: true,
number_of_installments: numberOfInstallments(), number_of_installments: numberOfInstallments(),
cvc: self.encryptedCreditCardVerificationNumber, stateData: JSON.stringify(stateData),
java_enabled: browserInfo.javaEnabled,
screen_color_depth: browserInfo.colorDepth,
screen_width: browserInfo.screenWidth,
screen_height: browserInfo.screenHeight,
timezone_offset: browserInfo.timeZoneOffset,
language: browserInfo.language,
}, },
}; };
}, },
...@@ -442,7 +393,8 @@ function( ...@@ -442,7 +393,8 @@ function(
// bcmc does not have any cvc // bcmc does not have any cvc
if (!validate || if (!validate ||
(isValid() == false && variant() != 'bcmc' && variant() != (isValid() == false && variant() !=
'bcmc' && variant() !=
'maestro')) { 'maestro')) {
return false; return false;
} }
...@@ -456,13 +408,14 @@ function( ...@@ -456,13 +408,14 @@ function(
return self.hasVerification(); return self.hasVerification();
}, },
getMessageName: function() { getMessageName: function() {
return 'messages-' + value.reference_id; return 'messages-' +
billingAgreement.reference_id;
}, },
getMessageContainer: function() { getMessageContainer: function() {
return messageContainer; return messageContainer;
}, },
getOriginKey: function() { getOriginKey: function() {
return self.getOriginKey(); return adyenConfiguration.getOriginKey();
}, },
isPlaceOrderActionAllowed: function() { isPlaceOrderActionAllowed: function() {
return self.isPlaceOrderActionAllowed(); // needed for placeOrder method return self.isPlaceOrderActionAllowed(); // needed for placeOrder method
...@@ -472,7 +425,8 @@ function( ...@@ -472,7 +425,8 @@ function(
}, },
getPlaceOrderDeferredObject: function() { getPlaceOrderDeferredObject: function() {
return $.when( return $.when(
placeOrderAction(this.getData(), this.getMessageContainer()), placeOrderAction(this.getData(),
this.getMessageContainer()),
); );
}, },
}; };
...@@ -509,6 +463,7 @@ function( ...@@ -509,6 +463,7 @@ function(
return true; return true;
}, },
isBillingAgreementChecked: ko.computed(function() { isBillingAgreementChecked: ko.computed(function() {
if (!quote.paymentMethod()) { if (!quote.paymentMethod()) {
...@@ -520,17 +475,20 @@ function( ...@@ -520,17 +475,20 @@ function(
} }
return null; return null;
}), }),
placeOrderHandler: null,
validateHandler: null, getPlaceOrderUrl: function() {
return window.checkoutConfig.payment.iframe.placeOrderUrl[this.getCode()];
},
hasVerification: function() {
return window.checkoutConfig.payment.adyenOneclick.hasCustomerInteraction;
},
setPlaceOrderHandler: function(handler) { setPlaceOrderHandler: function(handler) {
this.placeOrderHandler = handler; this.placeOrderHandler = handler;
}, },
setValidateHandler: function(handler) { setValidateHandler: function(handler) {
this.validateHandler = handler; this.validateHandler = handler;
}, },
getPlaceOrderUrl: function() {
return window.checkoutConfig.payment.iframe.placeOrderUrl[this.getCode()];
},
getCode: function() { getCode: function() {
return window.checkoutConfig.payment.adyenOneclick.methodCode; return window.checkoutConfig.payment.adyenOneclick.methodCode;
}, },
...@@ -543,26 +501,9 @@ function( ...@@ -543,26 +501,9 @@ function(
context: function() { context: function() {
return this; return this;
}, },
canCreateBillingAgreement: function() {
return window.checkoutConfig.payment.adyenCc.canCreateBillingAgreement;
},
isShowLegend: function() { isShowLegend: function() {
return true; return true;
}, },
hasVerification: function() {
return window.checkoutConfig.payment.adyenOneclick.hasCustomerInteraction;
},
getLocale: function() {
return window.checkoutConfig.payment.adyenOneclick.locale;
},
getOriginKey: function() {
return window.checkoutConfig.payment.adyen.originKey;
},
getCheckoutEnvironment: function() {
return window.checkoutConfig.payment.adyen.checkoutEnvironment;
},
}); });
} },
);
)
;
...@@ -71,6 +71,12 @@ ...@@ -71,6 +71,12 @@
<fieldset <fieldset
data-bind="attr: {class: 'fieldset payment items ccard ' + getCode(), id: 'payment_form_' + $parent.getCode() + '_' + value}"> data-bind="attr: {class: 'fieldset payment items ccard ' + getCode(), id: 'payment_form_' + $parent.getCode() + '_' + value}">
<div id="oneclick_actionModalWrapper">
<div id="oneclick_actionModal">
<div id="oneclick_actionContainer"></div>
</div>
</div>
<!-- ko if: agreement_data.card --> <!-- ko if: agreement_data.card -->
<div class="field number"> <div class="field number">
<label class="label"> <label class="label">
...@@ -135,10 +141,6 @@ ...@@ -135,10 +141,6 @@
</div> </div>
<!-- /ko --> <!-- /ko -->
<div id="threeDS2ModalOneClick">
<div id="threeDS2ContainerOneClick"></div>
</div>
</fieldset> </fieldset>
<div class="checkout-agreements-block"> <div class="checkout-agreements-block">
......
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