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 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,11 +224,13 @@ 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();
/*
* 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();
// 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");
// reactivate the quote
......
......@@ -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;
}
......
......@@ -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
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;
$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);
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,12 +142,13 @@
</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"
......@@ -163,6 +164,7 @@
</button>
</div>
</div>
</form>
</div>
</div>
......@@ -142,7 +142,6 @@
<!-- /ko -->
</fieldset>
</form>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
......@@ -150,7 +149,6 @@
<!--/ko-->
</div>
<div class="actions-toolbar">
<div class="primary">
<button class="action primary checkout"
......@@ -163,6 +161,7 @@
</button>
</div>
</div>
</form>
</div>
</div>
......@@ -288,13 +288,13 @@
<!--/ko-->
</fieldset>
</form>
<div class="checkout-agreements-block">
<!-- ko foreach: $parents[1].getRegion('before-place-order') -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<div>
<span class="message message-error error hpp-message" data-bind="attr: {id: 'messages-' + value}"></span>
</div>
......@@ -303,12 +303,16 @@
<div class="primary">
<button class="action primary checkout"
type="submit"
data-bind="click: $parent.continueToAdyenBrandCode, enable: placeOrderAllowed() && (value == $parent.isBrandCodeChecked())"
data-bind="
click: $parent.continueToAdyenBrandCode,
enable: placeOrderAllowed() && (value == $parent.isBrandCodeChecked()),
css: {disabled: !$parent.isPlaceOrderActionAllowed()}"
disabled>
<span data-bind="text: $t('Place Order')"></span>
</button>
</div>
</div>
</form>
</div>
</div>
<!--/ko-->
......@@ -140,12 +140,13 @@
</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"
......@@ -159,6 +160,7 @@
</button>
</div>
</div>
</form>
</div>
</div>
<!--/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