We will work on Apr 26th (Saturday) and will be off from Apr 30th (Wednesday) until May 2nd (Friday) for public holiday in our country

Commit 21350d08 authored by cyattilakiss's avatar cyattilakiss Committed by GitHub

Merge pull request #710 from Adyen/develop

Release 6.1.0
parents bda6ce3c 540ffa7f
blank_issues_enabled: false
contact_links:
- name: Adyen Support
url: https://support.adyen.com/hc/en-us/requests/new?ticket_form_id=360000705420
about: For other questions, contact our support team
......@@ -224,12 +224,14 @@ class Redirect extends \Magento\Framework\App\Action\Action
$this->_redirect('checkout/onepage/success', ['_query' => ['utm_nooverride' => '1']]);
} else {
$order->addStatusHistoryComment(__('3D-secure validation was unsuccessful.'))->save();
// Move the order from PAYMENT_REVIEW to NEW, so that can be cancelled
$order->setState(\Magento\Sales\Model\Order::STATE_NEW);
$this->_adyenHelper->cancelOrder($order);
$this->messageManager->addErrorMessage("3D-secure validation was unsuccessful");
/*
* Since responseCode!='Authorised' the order could be cancelled immediately,
* but redirect payments can have multiple conflicting responses.
* The order will be cancelled if an Authorization Success=False notification is processed instead
*/
$order->addStatusHistoryComment(__('3D-secure validation was unsuccessful. This order will be cancelled when the related notification has been processed.'))->save();
$this->messageManager->addErrorMessage("3D-secure validation was unsuccessful");
// reactivate the quote
$session = $this->_getCheckout();
......
......@@ -64,7 +64,8 @@ class CancelDataBuilder implements BuilderInterface
"reference" => $order->getOrderIncrementId(),
"originalReference" => $pspReference
];
$request['clientConfig'] = ["storeId" => $payment->getOrder()->getStoreId()];
$request['clientConfig'] = ["storeId" => $order->getStoreId()];
return $request;
}
}
......@@ -63,9 +63,8 @@ class GooglePayAuthorizationDataBuilder implements BuilderInterface
$requestBody['paymentMethod']['type'] = 'paywithgoogle';
// get payment data
if ($token) {
$parsedToken = json_decode($token);
try {
$requestBody['paymentMethod']['paywithgoogle.token'] = $parsedToken;
$requestBody['paymentMethod']['paywithgoogle.token'] = $token;
} catch (\Exception $exception) {
$this->adyenLogger->addAdyenDebug("exception: " . $exception->getMessage());
}
......
<?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 Magento\Framework\App\Config\ScopeConfigInterface;
class Config
{
const XML_PAYMENT_PREFIX = "payment";
const XML_ADYEN_ABSTRACT_PREFIX = "adyen_abstract";
const XML_NOTIFICATIONS_CAN_CANCEL_FIELD = "notifications_can_cancel";
/**
* @var Magento\Framework\App\Config\ScopeConfigInterface
*/
protected $scopeConfig;
/**
* Config constructor.
* @param Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
*/
public function __construct(
ScopeConfigInterface $scopeConfig
) {
$this->scopeConfig = $scopeConfig;
}
/**
* Retrieve flag for notifications_can_cancel
*
* @param int $storeId
* @return bool
*/
public function getNotificationsCanCancel($storeId = null)
{
return (bool)$this->getConfigData(
self::XML_NOTIFICATIONS_CAN_CANCEL_FIELD,
self::XML_ADYEN_ABSTRACT_PREFIX,
$storeId,
true
);
}
/**
* Retrieve information from payment configuration
*
* @param string $field
* @param string $xmlPrefix
* @param int $storeId
* @param bool|false $flag
* @return bool|mixed
*/
private function getConfigData($field, $xmlPrefix, $storeId, $flag = false)
{
$path = implode("/", [self::XML_PAYMENT_PREFIX, $xmlPrefix, $field]);
if (!$flag) {
return $this->scopeConfig->getValue($path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeId);
} else {
return $this->scopeConfig->isSetFlag($path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeId);
}
}
}
......@@ -288,10 +288,13 @@ class Requests extends AbstractHelper
*/
public function buildBrowserData($request = [])
{
$request['browserInfo'] = [
'userAgent' => $_SERVER['HTTP_USER_AGENT'],
'acceptHeader' => $_SERVER['HTTP_ACCEPT']
];
if (!empty($_SERVER['HTTP_USER_AGENT'])) {
$request['browserInfo']['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
}
if (!empty($_SERVER['HTTP_ACCEPT'])) {
$request['browserInfo']['acceptHeader'] = $_SERVER['HTTP_ACCEPT'];
}
return $request;
}
......@@ -324,7 +327,7 @@ class Requests extends AbstractHelper
$request['origin'] = $this->adyenHelper->getOrigin();
$request['channel'] = 'web';
}
return $request;
}
......
......@@ -37,17 +37,11 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
*/
private $adyenHelper;
/**
* @var \Magento\Sales\Model\OrderFactory
*/
private $orderFactory;
/**
* @var
*/
private $order;
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
......@@ -58,6 +52,8 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
*
* @param \Magento\Checkout\Model\Session $checkoutSession
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Sales\Model\OrderFactory $orderFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
*/
public function __construct(
\Magento\Checkout\Model\Session $checkoutSession,
......@@ -87,8 +83,15 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
throw new \Magento\Framework\Exception\LocalizedException(__('3D secure 2.0 failed because the request was not a valid JSON'));
}
// Get payment and cart information from session
$order = $this->getOrder();
if (empty($payload['orderId'])) {
$order = $this->getOrder();
// In the next major release remove support for retrieving order from session and throw exception instead
//throw new \Magento\Framework\Exception\LocalizedException(__('3D secure 2.0 failed because of a missing order id'));
} else {
// Create order by order id
$order = $this->orderFactory->create()->load($payload['orderId']);
}
$payment = $order->getPayment();
// Init payments/details request
......@@ -139,7 +142,6 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
// To actually save the additional info changes into the quote
$order->save();
$response = [];
if($result['resultCode'] != 'Authorised') {
......@@ -163,13 +165,13 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
* Get order object
*
* @return \Magento\Sales\Model\Order
* @deprecated Will be removed in 7.0.0
*/
protected function getOrder()
{
if (!$this->order) {
$incrementId = $this->checkoutSession->getLastRealOrderId();
$this->order = $this->orderFactory->create()->loadByIncrementId($incrementId);
}
return $this->order;
$incrementId = $this->checkoutSession->getLastRealOrderId();
$order = $this->orderFactory->create()->loadByIncrementId($incrementId);
return $order;
}
}
......@@ -235,6 +235,11 @@ class Cron
*/
private $timezone;
/**
* @var \Adyen\Payment\Helper\Config
*/
protected $configHelper;
/**
* Cron constructor.
*
......@@ -282,7 +287,8 @@ class Cron
\Magento\Sales\Model\Order\Payment\Transaction\Builder $transactionBuilder,
\Magento\Framework\Serialize\SerializerInterface $serializer,
\Magento\Framework\Notification\NotifierInterface $notifierPool,
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $timezone
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $timezone,
\Adyen\Payment\Helper\Config $configHelper
) {
$this->_scopeConfig = $scopeConfig;
$this->_adyenLogger = $adyenLogger;
......@@ -307,6 +313,7 @@ class Cron
$this->serializer = $serializer;
$this->notifierPool = $notifierPool;
$this->timezone = $timezone;
$this->configHelper = $configHelper;
}
/**
......@@ -432,7 +439,9 @@ class Cron
$this->_eventCode == Notification::ORDER_CLOSED
) {
// Move the order from PAYMENT_REVIEW to NEW, so that can be cancelled
if ($this->_order->getState() === \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW) {
if ($this->_order->getState() === \Magento\Sales\Model\Order::STATE_PAYMENT_REVIEW &&
$this->configHelper->getNotificationsCanCancel($this->_order->getStoreId())
) {
$this->_order->setState(\Magento\Sales\Model\Order::STATE_NEW);
}
$this->_holdCancelOrder(false);
......@@ -829,6 +838,11 @@ class Cron
*/
protected function _holdCancelOrder($ignoreHasInvoice)
{
if (!$this->configHelper->getNotificationsCanCancel($this->_order->getStoreId())) {
$this->_adyenLogger->addAdyenNotificationCronjob('Order cannot be canceled based on the plugin configuration');
return;
}
$orderStatus = $this->_getConfigData(
'payment_cancelled',
'adyen_abstract',
......@@ -992,7 +1006,7 @@ class Cron
break;
}
if (!$this->_order->canCancel()) {
if (!$this->_order->canCancel() && $this->configHelper->getNotificationsCanCancel($this->_order->getStoreId())) {
// Move the order from PAYMENT_REVIEW to NEW, so that can be cancelled
$this->_order->setState(\Magento\Sales\Model\Order::STATE_NEW);
}
......@@ -1951,7 +1965,9 @@ class Cron
private function addNotificationErrorComment($errorMessage)
{
$comment = __('The order failed to update: %1', $errorMessage);
$this->_order->addStatusHistoryComment($comment);
$this->_order->save();
if ($this->_order) {
$this->_order->addStatusHistoryComment($comment);
$this->_order->save();
}
}
}
......@@ -50,7 +50,7 @@ We have defined this:
```
## Support
You can create issues on our Magento Repository. In case of specific problems with your account, please contact <a href="mailto:support@adyen.com">support@adyen.com</a>.
If you have a feature request, or spotted a bug or a technical problem, create a GitHub issue. For other questions, contact our [support team](https://support.adyen.com/hc/en-us/requests/new?ticket_form_id=360000705420).
## API Library
This module is using the Adyen APIs Library for PHP for all (API) connections to Adyen.
......
......@@ -2,7 +2,7 @@
"name": "adyen/module-payment",
"description": "Official Magento2 Plugin to connect to Payment Service Provider Adyen.",
"type": "magento2-module",
"version": "6.0.0",
"version": "6.1.0",
"license": [
"OSL-3.0",
"AFL-3.0"
......
......@@ -38,6 +38,7 @@
<enable_oneclick>1</enable_oneclick>
<enable_recurring>0</enable_recurring>
<group>adyen</group>
<notifications_can_cancel>1</notifications_can_cancel>
</adyen_abstract>
<adyen_cc>
<active>1</active>
......
......@@ -1047,4 +1047,34 @@
<argument name="resourceModel" xsi:type="string">Adyen\Payment\Model\ResourceModel\Notification</argument>
</arguments>
</virtualType>
<!--Sensitive and system-specific configuration-->
<type name="Magento\Config\Model\Config\TypePool">
<arguments>
<argument name="environment" xsi:type="array">
<item name="payment/adyen_abstract/demo_mode" xsi:type="string">1</item>
<item name="payment/adyen_abstract/debug" xsi:type="string">1</item>
<item name="payment/adyen_apple_pay/full_path_location_pem_file_test" xsi:type="string">1</item>
<item name="payment/adyen_apple_pay/full_path_location_pem_file_live" xsi:type="string">1</item>
</argument>
<argument name="sensitive" xsi:type="array">
<item name="payment/adyen_abstract/merchant_account" xsi:type="string">1</item>
<item name="payment/adyen_abstract/api_key_test" xsi:type="string">1</item>
<item name="payment/adyen_abstract/api_key_live" xsi:type="string">1</item>
<item name="payment/adyen_abstract/notification_username" xsi:type="string">1</item>
<item name="payment/adyen_abstract/notification_password" xsi:type="string">1</item>
<item name="payment/adyen_abstract/live_endpoint_url_prefix" xsi:type="string">1</item>
<item name="payment/adyen_pos_cloud/pos_merchant_account" xsi:type="string">1</item>
<item name="payment/adyen_pos_cloud/api_key_test" xsi:type="string">1</item>
<item name="payment/adyen_pos_cloud/api_key_live" xsi:type="string">1</item>
<item name="payment/adyen_pos_cloud/pos_store_id" xsi:type="string">1</item>
<item name="payment/adyen_pay_by_mail/skin_code" xsi:type="string">1</item>
<item name="payment/adyen_pay_by_mail/hmac_test" xsi:type="string">1</item>
<item name="payment/adyen_pay_by_mail/hmac_live" xsi:type="string">1</item>
<item name="payment/adyen_apple_pay/merchant_identifier_test" xsi:type="string">1</item>
<item name="payment/adyen_apple_pay/merchant_identifier_live" xsi:type="string">1</item>
<item name="payment/adyen_google_pay/merchant_identifier" xsi:type="string">1</item>
</argument>
</arguments>
</type>
</config>
......@@ -213,7 +213,7 @@ define(
* @param type
* @param token
*/
renderThreeDS2Component: function (type, token) {
renderThreeDS2Component: function (type, token, orderId) {
var self = this;
var threeDS2Node = document.getElementById('threeDS2Container');
......@@ -223,8 +223,10 @@ define(
fingerprintToken: token,
onComplete: function (result) {
self.threeDS2IdentifyComponent.unmount();
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON)
var request = result.data;
request.orderId = orderId;
threeds2.processThreeDS2(request).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId)
}).fail(function (result) {
errorProcessor.process(result, self.messageContainer);
self.isPlaceOrderActionAllowed(true);
......@@ -262,8 +264,10 @@ define(
self.threeDS2ChallengeComponent.unmount();
self.closeModal(popupModal);
fullScreenLoader.startLoader();
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON);
var request = result.data;
request.orderId = orderId;
threeds2.processThreeDS2(request).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId);
}).fail(function (result) {
errorProcessor.process(result, self.messageContainer);
self.isPlaceOrderActionAllowed(true);
......@@ -357,11 +361,11 @@ define(
self.isPlaceOrderActionAllowed(true);
}
).done(
function (response) {
function (orderId) {
self.afterPlaceOrder();
adyenPaymentService.getOrderPaymentStatus(response)
adyenPaymentService.getOrderPaymentStatus(orderId)
.done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON)
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId)
});
}
);
......@@ -372,13 +376,13 @@ define(
* Based on the response we can start a 3DS2 validation or place the order
* @param responseJSON
*/
validateThreeDS2OrPlaceOrder: function (responseJSON) {
validateThreeDS2OrPlaceOrder: function (responseJSON, orderId) {
var self = this;
var response = JSON.parse(responseJSON);
if (!!response.threeDS2) {
// render component
self.renderThreeDS2Component(response.type, response.token);
self.renderThreeDS2Component(response.type, response.token, orderId);
} else {
window.location.replace(url.build(
window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl)
......
......@@ -231,11 +231,11 @@ define(
self.isPlaceOrderActionAllowed(true);
}
).done(
function (response) {
function (orderId) {
self.afterPlaceOrder();
adyenPaymentService.getOrderPaymentStatus(response)
adyenPaymentService.getOrderPaymentStatus(orderId)
.done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON)
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId)
});
}
);
......@@ -310,13 +310,13 @@ define(
* Based on the response we can start a 3DS2 validation or place the order
* @param responseJSON
*/
validateThreeDS2OrPlaceOrder: function (responseJSON) {
validateThreeDS2OrPlaceOrder: function (responseJSON, orderId) {
var self = this;
var response = JSON.parse(responseJSON);
if (!!response.threeDS2) {
// render component
self.renderThreeDS2Component(response.type, response.token);
self.renderThreeDS2Component(response.type, response.token, orderId);
} else {
window.location.replace(url.build(window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl));
}
......@@ -332,7 +332,7 @@ define(
* @param type
* @param token
*/
renderThreeDS2Component: function (type, token) {
renderThreeDS2Component: function (type, token, orderId) {
var self = this;
var threeDS2Node = document.getElementById('threeDS2ContainerOneClick');
......@@ -341,8 +341,10 @@ define(
self.threeDS2Component = checkout.create('threeDS2DeviceFingerprint', {
fingerprintToken: token,
onComplete: function (result) {
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON)
var request = result.data;
request.orderId = orderId;
threeds2.processThreeDS2(request).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId)
}).fail(function (result) {
errorProcessor.process(result, self.getMessageContainer());
self.isPlaceOrderActionAllowed(true);
......@@ -375,8 +377,10 @@ define(
onComplete: function (result) {
popupModal.modal("closeModal");
fullScreenLoader.startLoader();
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON)
var request = result.data;
request.orderId = orderId;
threeds2.processThreeDS2(request).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId)
}).fail(function (result) {
errorProcessor.process(result, self.getMessageContainer());
self.isPlaceOrderActionAllowed(true);
......
......@@ -142,27 +142,29 @@
</div>
</fieldset>
</form>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div class="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
type="submit"
data-bind="
click: placeOrder,
attr: {title: $t('Place Order')},
enable: (getCode() == isChecked()),
css: {disabled: !isPlaceOrderActionAllowed()}
"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
</div>
<div class="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
type="submit"
data-bind="
click: placeOrder,
attr: {title: $t('Place Order')},
enable: (getCode() == isChecked()),
css: {disabled: !isPlaceOrderActionAllowed()}
"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
</div>
</div>
</form>
</div>
</div>
......@@ -142,27 +142,26 @@
<!-- /ko -->
</fieldset>
</form>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div class="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
type="submit"
data-bind="click: placeOrder,
attr: {title: $t('Place Order')},
enable: isButtonActive()"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
<div class="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
type="submit"
data-bind="click: placeOrder,
attr: {title: $t('Place Order')},
enable: isButtonActive()"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
</div>
</div>
</div>
</form>
</div>
</div>
......@@ -140,25 +140,27 @@
</div>
</fieldset>
</form>
<div class="checkout-agreements-block">
<!-- ko foreach: $parents[1].getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div class="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
type="submit"
data-bind="
click: placeOrder,
attr: {title: $t('Place Order')},
enable: isButtonActive()"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
<div class="checkout-agreements-block">
<!-- ko foreach: $parents[1].getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
</div>
<div class="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
type="submit"
data-bind="
click: placeOrder,
attr: {title: $t('Place Order')},
enable: isButtonActive()"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
</div>
</div>
</form>
</div>
</div>
<!--/ko-->
\ No newline at end of file
<!--/ko-->
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