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 97b465fa authored by Rik ter Beek's avatar Rik ter Beek Committed by attilak

[PW-1192] Move plugin to ajax controller, remove plugins code, move sdk to 2.4.… (#439)

* Move plugin to ajax controller, remove plugins code, move sdk to 2.4.2(disable risk as it is not working), fix agreements not being updated by oneclick as removes the ONECLICK option. Minimize duplicate code by using model.

* Update view/frontend/web/js/view/payment/method-renderer/adyen-cc-method.js
Co-Authored-By: default avatarrikterbeek <rikterbeek@users.noreply.github.com>

* Update view/frontend/web/js/view/payment/method-renderer/adyen-cc-method.js
Co-Authored-By: default avatarrikterbeek <rikterbeek@users.noreply.github.com>

* PW-1173: Ignore OFFER_CLOSED for already authorised orders, or for or… (#436)

* PW-1173: Ignore OFFER_CLOSED for already authorised orders, or for orders that are not matching the paymentmethod of the notification
Set the ccType of boleto payments to the proper boleto variant.
reset order id on card placeorder

* PW-1173: use nonempty

* Move plugin to ajax controller, remove plugins code, move sdk to 2.4.2(disable risk as it is not working), fix agreements not being updated by oneclick as removes the ONECLICK option. Minimize duplicate code by using model.

* Update view/frontend/web/js/view/payment/method-renderer/adyen-cc-method.js
Co-Authored-By: default avatarrikterbeek <rikterbeek@users.noreply.github.com>

* Update view/frontend/web/js/view/payment/method-renderer/adyen-cc-method.js
Co-Authored-By: default avatarrikterbeek <rikterbeek@users.noreply.github.com>

* add errorMessage for oneclick
parent 29c8d721
......@@ -15,32 +15,20 @@
*
* Adyen Payment Module
*
* Copyright (c) 2018 Adyen B.V.
* Copyright (c) 2019 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Model;
namespace Adyen\Payment\Api;
class AdyenPaymentInformationManagement extends \Magento\Checkout\Model\PaymentInformationManagement
interface AdyenPaymentProcessInterface
{
/**
* {@inheritDoc}
* @param string $payload
* @return string
*/
public function savePaymentInformationAndPlaceOrder(
$cartId,
\Magento\Quote\Api\Data\PaymentInterface $paymentMethod,
\Magento\Quote\Api\Data\AddressInterface $billingAddress = null
) {
$this->savePaymentInformation($cartId, $paymentMethod, $billingAddress);
try {
$orderId = $this->cartManagement->placeOrder($cartId);
} catch (\Exception $e) {
throw $e;
}
return $orderId;
}
public function initiate($payload);
}
......@@ -38,8 +38,7 @@ class CcAuthorizationDataBuilder implements BuilderInterface
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
// retrieve payments response which we already got and saved in the
// Adyen\Payment\Plugin\PaymentInformationManagement::afterSavePaymentInformation
// retrieve payments response which we already got and saved in the payment controller
if ($response = $payment->getAdditionalInformation("paymentsResponse")) {
// the payments response needs to be passed to the next process because after this point we don't have
// access to the payment object therefore to the additionalInformation array
......
......@@ -48,10 +48,10 @@ class CheckoutPaymentsDetailsHandler implements HandlerInterface
*/
public function handle(array $handlingSubject, array $response)
{
$payment = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($handlingSubject);
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($handlingSubject);
/** @var OrderPaymentInterface $payment */
$payment = $payment->getPayment();
/** @var $payment */
$payment = $paymentDataObject->getPayment();
// set transaction not to processing by default wait for notification
$payment->setIsTransactionPending(true);
......@@ -69,7 +69,8 @@ class CheckoutPaymentsDetailsHandler implements HandlerInterface
}
if (!empty($response['additionalData']['recurring.recurringDetailReference']) &&
!$this->adyenHelper->isCreditCardVaultEnabled()
!$this->adyenHelper->isCreditCardVaultEnabled() &&
$payment->getMethodInstance()->getCode() !== \Adyen\Payment\Model\Ui\AdyenOneclickConfigProvider::CODE
) {
$order = $payment->getOrder();
$this->adyenHelper->createAdyenBillingAgreement($order, $response['additionalData']);
......
......@@ -35,8 +35,8 @@ class Data extends AbstractHelper
const LIVE = 'live';
const CHECKOUT_CONTEXT_URL_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/';
const CHECKOUT_CONTEXT_URL_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/';
const CHECKOUT_COMPONENT_JS_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/2.2.1/adyen.js';
const CHECKOUT_COMPONENT_JS_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/2.2.1/adyen.js';
const CHECKOUT_COMPONENT_JS_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/2.4.2/adyen.js';
const CHECKOUT_COMPONENT_JS_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/2.4.2/adyen.js';
/**
* @var \Magento\Framework\Encryption\EncryptorInterface
......@@ -1632,7 +1632,8 @@ class Data extends AbstractHelper
// Populate billing agreement data
$storeOneClick = $order->getPayment()->getAdditionalInformation('store_cc');
$billingAgreement->setCcBillingAgreement($additionalData, $storeOneClick);
$billingAgreement->setCcBillingAgreement($additionalData, $storeOneClick, $order->getStoreId());
if ($billingAgreement->isValid()) {
if (!$this->agreementResourceModel->getOrderRelation($billingAgreement->getAgreementId(),
......
This diff is collapsed.
......@@ -21,13 +21,11 @@
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Plugin;
namespace Adyen\Payment\Model;
use Adyen\Payment\Observer\AdyenHppDataAssignObserver;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
use Magento\Vault\Model\Ui\VaultConfigProvider;
use \Adyen\Payment\Api\AdyenPaymentProcessInterface;
class PaymentInformationManagement
class AdyenPaymentProcess implements AdyenPaymentProcessInterface
{
/**
* @var \Magento\Checkout\Model\Session
......@@ -70,31 +68,26 @@ class PaymentInformationManagement
private $threeDS2ResponseValidator;
/**
* PaymentInformationManagement constructor.
* AdyenThreeDS2Process constructor.
*
* @param \Magento\Checkout\Model\Session $checkoutSession
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Adyen\Payment\Helper\Requests $adyenRequestHelper
* @param \Magento\Framework\Model\Context $context
* @param \Adyen\Payment\Gateway\Http\TransferFactory $transferFactory
* @param \Adyen\Payment\Gateway\Http\Client\TransactionPayment $transactionPayment
* @param \Adyen\Payment\Gateway\Validator\CheckoutResponseValidator $checkoutResponseValidator
* @param \Adyen\Payment\Gateway\Validator\ThreeDS2ResponseValidator $threeDS2ResponseValidator
*/
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Checkout\Model\Session $checkoutSession,
\Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Helper\Requests $adyenRequestHelper,
\Magento\Framework\Model\Context $context,
\Adyen\Payment\Gateway\Http\TransferFactory $transferFactory,
\Adyen\Payment\Gateway\Http\Client\TransactionPayment $transactionPayment,
\Adyen\Payment\Gateway\Validator\CheckoutResponseValidator $checkoutResponseValidator,
\Adyen\Payment\Gateway\Validator\ThreeDS2ResponseValidator $threeDS2ResponseValidator
) {
)
{
$this->context = $context;
$this->checkoutSession = $checkoutSession;
$this->adyenHelper = $adyenHelper;
$this->adyenRequestHelper = $adyenRequestHelper;
$this->context = $context;
$this->transferFactory = $transferFactory;
$this->transactionPayment = $transactionPayment;
$this->checkoutResponseValidator = $checkoutResponseValidator;
......@@ -102,30 +95,20 @@ class PaymentInformationManagement
}
/**
* @param \Magento\Checkout\Model\PaymentInformationManagement $subject
* @param $response
* @api
* @param string $payload
* @return string
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function afterSavePaymentInformation(
\Magento\Checkout\Model\PaymentInformationManagement $subject,
$response
) {
public function initiate($payload)
{
// Decode payload from frontend
$payload = json_decode($payload, true);
// Get payment and cart information from session
$quote = $this->checkoutSession->getQuote();
$payment = $quote->getPayment();
// in case payments response is already there we don't need to perform another payments call
// we indicate it with the placeOrder additionalInformation
if ($payment->getAdditionalInformation('placeOrder')) {
$payment->unsAdditionalInformation('placeOrder');
$quote->save();
return $this->adyenHelper->buildThreeDS2ProcessResponseJson();
}
if (strpos($payment->getMethod(), "adyen_cc") !== 0 &&
strpos($payment->getMethod(), "adyen_oneclick") !== 0) {
return $response;
}
// Init request array
$request = [];
......@@ -137,7 +120,7 @@ class PaymentInformationManagement
// Customer data builder
$customerId = $quote->getCustomerId();
$billingAddress = $quote->getBillingAddress();
$request = $this->adyenRequestHelper->buildCustomerData($request, $customerId, $billingAddress, $payment);
$request = $this->adyenRequestHelper->buildCustomerData($request, $customerId, $billingAddress);
// Customer Ip data builder
$shopperIp = $quote->getRemoteIp();
......@@ -150,6 +133,7 @@ class PaymentInformationManagement
// PaymentDataBuilder
$currencyCode = $quote->getQuoteCurrencyCode();
$amount = $quote->getGrandTotal();
// Setting the orderid to null, so that we generate a new one for each /payments call
$quote->setReservedOrderId(null);
$reference = $quote->reserveOrderId()->getReservedOrderId();
......@@ -161,18 +145,18 @@ class PaymentInformationManagement
// 3DS2.0 data builder
$isThreeDS2Enabled = $this->adyenHelper->isCreditCardThreeDS2Enabled($storeId);
if ($isThreeDS2Enabled) {
$request = $this->adyenRequestHelper->buildThreeDS2Data($request, $payment, $quote->getStore());
$request = $this->adyenRequestHelper->buildThreeDS2Data($request, $payload, $quote->getStore());
}
// RecurringDataBuilder
$areaCode = $this->context->getAppState()->getAreaCode();
$request = $this->adyenRequestHelper->buildRecurringData($request, $areaCode, $storeId, $payment);
$request = $this->adyenRequestHelper->buildRecurringData($request, $areaCode, $storeId, $payload);
// CcAuthorizationDataBuilder
$request = $this->adyenRequestHelper->buildCCData($request, $payment, $storeId, $areaCode);
$request = $this->adyenRequestHelper->buildCCData($request, $payload, $storeId, $areaCode);
// Valut data builder
$request = $this->adyenRequestHelper->buildVaultData($request, $payment->getAdditionalInformation());
// Vault data builder
$request = $this->adyenRequestHelper->buildVaultData($request, $payload);
// Create and send request
$transferObject = $this->transferFactory->create($request);
......@@ -200,10 +184,6 @@ class PaymentInformationManagement
// Save the payments response because we are going to need it during the place order flow
$payment->setAdditionalInformation("paymentsResponse", $paymentsResponse);
// Setting the placeOrder to true enables the process to skip the payments call because the paymentsResponse
// is already in place - only set placeOrder to true when you have the paymentsResponse
$payment->setAdditionalInformation('placeOrder', true);
// To actually save the additional info changes into the quote
$quote->save();
......
......@@ -173,7 +173,7 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
* @param $contractDetail
* @return $this
*/
public function setCcBillingAgreement($contractDetail, $storeOneClick)
public function setCcBillingAgreement($contractDetail, $storeOneClick, $storeId)
{
$this
->setMethodCode('adyen_oneclick')
......@@ -212,9 +212,9 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
$expiryDate = explode('/', $contractDetail['expiryDate']);
if (!empty($contractDetail['pos_payment'])) {
$recurringType = $this->adyenHelper->getAdyenPosCloudConfigData('recurring_type');
$recurringType = $this->adyenHelper->getAdyenPosCloudConfigData('recurring_type', $storeId);
} else {
$recurringType = $this->adyenHelper->getRecurringTypeFromOneclickRecurringSetting();
$recurringType = $this->adyenHelper->getRecurringTypeFromOneclickRecurringSetting($storeId);
// for bcmc and maestro recurring is not allowed so don't set this
if ($recurringType === \Adyen\Payment\Model\RecurringType::ONECLICK_RECURRING &&
......
......@@ -869,14 +869,11 @@
type="Adyen\Payment\Model\AdyenRequestMerchantSession"/>
<preference for="Adyen\Payment\Api\AdyenInitiateTerminalApiInterface"
type="Adyen\Payment\Model\AdyenInitiateTerminalApi"/>
<preference for="Adyen\Payment\Api\AdyenPaymentProcessInterface"
type="Adyen\Payment\Model\AdyenPaymentProcess"/>
<preference for="Adyen\Payment\Api\AdyenThreeDS2ProcessInterface"
type="Adyen\Payment\Model\AdyenThreeDS2Process"/>
<preference for="Magento\Checkout\Api\PaymentInformationManagementInterface"
type="Adyen\Payment\Model\AdyenPaymentInformationManagement"/>
<type name="Magento\Vault\Api\PaymentTokenRepositoryInterface">
<plugin name="AdyenPaymentVaultDeleteToken" type="Adyen\Payment\Plugin\PaymentVaultDeleteToken" sortOrder="10"/>
</type>
<type name="\Magento\Checkout\Model\PaymentInformationManagement">
<plugin name="AdyenPaymentInformationManagement" type="Adyen\Payment\Plugin\PaymentInformationManagement" sortOrder="20" disabled="false"/>
</type>
</config>
\ No newline at end of file
......@@ -58,6 +58,13 @@
</resources>
</route>
<route url="/V1/adyen/payment" method="POST">
<service class="Adyen\Payment\Api\AdyenPaymentProcessInterface" method="initiate"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
<route url="/V1/adyen/threeDS2Process" method="POST">
<service class="Adyen\Payment\Api\AdyenThreeDS2ProcessInterface" method="initiate"/>
<resources>
......
......@@ -1214,5 +1214,7 @@
font-size: 13px;
text-decoration: underline
}
/* never show the close button as this will result in errors */
.threeDS2Modal .action-close {display:none; }
/* Checkout component Adyen styling end */
/**
* 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 {
/**
* Create a Payment to define if 3DS 2.0 flow needs to be activated
* @param response
*/
processPayment: function (data) {
var payload = {
"payload": JSON.stringify(data)
};
var serviceUrl = urlBuilder.createUrl('/adyen/payment', {});
return storage.post(
serviceUrl,
JSON.stringify(payload),
true
);
},
/**
* 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
);
}
};
}
);
......@@ -36,9 +36,11 @@ define(
'Magento_Checkout/js/model/full-screen-loader',
'Magento_Paypal/js/action/set-payment-method',
'Magento_Checkout/js/action/select-payment-method',
'Adyen_Payment/js/threeds2-js-utils'
'Adyen_Payment/js/threeds2-js-utils',
'Adyen_Payment/js/model/threeds2',
'mage/translate'
],
function ($, ko, Component, customer, creditCardData, additionalValidators, quote, installments, url, VaultEnabler, urlBuilder, storage, fullScreenLoader, setPaymentMethodAction, selectPaymentMethodAction, threeDS2Utils) {
function ($, ko, Component, customer, creditCardData, additionalValidators, quote, installments, url, VaultEnabler, urlBuilder, storage, fullScreenLoader, setPaymentMethodAction, selectPaymentMethodAction, threeDS2Utils, threeds2, $t) {
'use strict';
......@@ -64,7 +66,10 @@ define(
// initialize adyen component for general use
this.checkout = new AdyenCheckout({
locale: this.getLocale()
locale: this.getLocale(),
risk: {
enabled: false
}
});
return this;
......@@ -91,7 +96,7 @@ define(
* Returns true if card details can be stored
* @returns {*|boolean}
*/
getEnableStoreDetails: function() {
getEnableStoreDetails: function () {
return this.canCreateBillingAgreement() && !this.isVaultEnabled();
},
/**
......@@ -202,70 +207,72 @@ define(
* @param type
* @param token
*/
renderThreeDS2Component: function(type, token) {
renderThreeDS2Component: function (type, token) {
var self = this;
var threeDS2Node = document.getElementById('threeDS2Container');
if (type == "IdentifyShopper") {
fullScreenLoader.startLoader();
self.threeDS2Component = self.checkout
self.threeDS2IdentifyComponent = self.checkout
.create('threeDS2DeviceFingerprint', {
fingerprintToken: token,
onComplete: function(result) {
onComplete: function (result) {
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON)
}).error(function () {
fullScreenLoader.stopLoader();
});
},
onError: function () {
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
self.processThreeDS2(result.data);
this.messageContainer.addErrorMessage({
message: $t('Something went wrong. Please try again.')
});
}
});
self.threeDS2IdentifyComponent.mount(threeDS2Node);
} else if (type == "ChallengeShopper") {
$('#threeDS2Modal').modal({
fullScreenLoader.stopLoader();
var popupModal = $('#threeDS2Modal').modal({
// disable user to hide popup
clickableOverlay: false,
// empty buttons, we don't need that
buttons: []
buttons: [],
modalClass: 'threeDS2Modal'
});
$('#threeDS2Modal').modal("openModal");
self.threeDS2Component = self.checkout
popupModal.modal("openModal");
self.threeDS2ChallengeComponent = self.checkout
.create('threeDS2Challenge', {
challengeToken: token,
onComplete: function(result) {
self.processThreeDS2(result.data);
$('#threeDS2Modal').modal("closeModal");
}
onComplete: function (result) {
popupModal.modal("closeModal");
fullScreenLoader.startLoader();
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON);
}).error(function () {
popupModal.modal("closeModal");
fullScreenLoader.stopLoader();
});
}
self.threeDS2Component.mount(threeDS2Node);
},
/**
* 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 self = this;
fullScreenLoader.startLoader();
var payload = {
"payload": JSON.stringify(data)
};
var serviceUrl = urlBuilder.createUrl('/adyen/threeDS2Process', {});
storage.post(
serviceUrl,
JSON.stringify(payload),
true
).done(function(responseJSON) {
fullScreenLoader.stopLoader();
self.validateThreeDS2OrPlaceOrder(responseJSON)
}).error(function(responseJSON) {
onError: function () {
fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true);
this.messageContainer.addErrorMessage({
message: $t('Something went wrong. Please try again.')
});
}
});
self.threeDS2ChallengeComponent.mount(threeDS2Node);
}
},
/**
* Builds the payment details part of the payment information reqeust
......@@ -275,7 +282,7 @@ define(
getCcData: function () {
const browserInfo = threeDS2Utils.getBrowserInfo();
let data = {
var data = {
'method': this.item.method,
additional_data: {
'card_brand': this.variant(),
......@@ -302,9 +309,15 @@ define(
* Get data for place order
* @returns {{method: *}}
*/
getData: function() {
getData: function () {
return {
'method': this.item.method
'method': this.item.method,
additional_data: {
'card_brand': this.variant(),
'cc_type': this.creditCardType(),
'store_cc': this.storeCc,
'number_of_installments': this.installment()
}
};
},
/**
......@@ -334,28 +347,19 @@ define(
fullScreenLoader.startLoader();
self.isPlaceOrderActionAllowed(false);
//update payment method information if additional data was changed
selectPaymentMethodAction(this.getCcData());
setPaymentMethodAction(this.messageContainer).done(
function (responseJSON) {
fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true);
threeds2.processPayment(this.getCcData()).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON);
}).error(function() {
}).error(function () {
fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true);
});
return false;
}
return false;
},
/**
* Based on the response we can start a 3DS2 validation or place the order
* @param responseJSON
*/
validateThreeDS2OrPlaceOrder: function(responseJSON) {
validateThreeDS2OrPlaceOrder: function (responseJSON) {
var self = this;
var response = JSON.parse(responseJSON);
......@@ -367,6 +371,7 @@ define(
self.getPlaceOrderDeferredObject()
.fail(
function () {
fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true);
}
).done(
......
......@@ -81,7 +81,10 @@ define(
* @type {AdyenCheckout}
*/
self.checkoutComponent = new AdyenCheckout({
locale: self.getLocale()
locale: self.getLocale(),
risk: {
enabled: false
}
});
// reset variable:
......
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