Commit 769f2ee6 authored by Attila Kiss's avatar Attila Kiss Committed by GitHub

7.0.0-rc.1 changes (#922)

* [PW-2029] Configuration to charge orders based on storeview or global currency (#851)

* [PW-2029] New charged currency config field

* [PW-2029] Charged currency default value

* [PW-2029] Charged currency config getter

* [PW-2029] Removing unused setOpenInvoiceData() in Redirect block class

* [PW-2029] New charged currency column for sales_order table

* [PW-2029] Event observer to save order's charged currency for future use in refunds

* [PW-2029] ChargedCurrency.php helper class for orders, quotes, stores and refunds

* [PW-2029] Using the ChargedRefund helper

* [PW-2029] Fix broken unit test because of new AdyenInitiateTerminalApi dependency

* [PW-2029] AdyenAmountCurrency model

* [PW-2029] Using AdyenAmountCurrency model

* [PW-2029] Adding discount and tax amount for items in ChargedCurrency model

* [PW-2029] Setting discount and tax amount for items

* [PW-2029] Getting tax and discount amount for items in CheckoutDataBuilder

* [PW-2029] Adjusting CaptureDataBuilder to use new AmountCurrency model

* [PW-2029] ChargedCurrency php docs

* [PW-2029] Removing use statements from AdyenSalesOrderChargedCurrencyObserver

* [PW-2029] Saving base or display in adyen_charged_currency instead of currency code on order placement

* [PW-2029] Using new AdyenAmountCurrency model

* [PW-2029] AdyenAmountCurrency for partial PBM

* [PW-2029] AdyenAmountCurrency in Capture and Refund builders

* [PW-2029] Renaming orderAmount var for code smell

* [PW-2029] Removing redundant boolean literal

* Version 7.0.0 bump

* [PW-2029] Extra usages of ChargedCurrency helper

* [PW-2029] Removed charged currency config field from admin panel

* [PW-2029] Adjusting usage of currency in Cron.php

* [PW-2029] Code styling

* Fix phpcs
Co-authored-by: default avatarattilak <attila.kiss@adyen.com>

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

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

Add the AdyenComponent var in the requireJS paramas

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

* Refactor threeds2 to paymentDetails

* paymentDetails.paymentDetails -> paymentDetails.process

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

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

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

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

* payment methods response validation

* Remove getConnectedTerminals

* Refactor

* Fix suggestions

* Refactor paymentmethods

* Refactor method names

* Refactor payment method request

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

* Use bundle instead of the component

* Store action and additionalData from /payments response

* [WIP] handle paymentDetails for card payments

* Remove custom redirect page

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

* Store and return details

Store action, resultCode, additionalData, pspReference, nad paymentData

* Show challenge in a popup for 3DS2

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

* Use bundle instead of the component

* Store action and additionalData from /payments response

* [WIP] handle paymentDetails for card payments

* Remove custom redirect page

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

* Store and return details

Store action, resultCode, additionalData, pspReference, nad paymentData

* Show challenge in a popup for 3DS2

* Remove GeneralResponseValidator.php

Change wrong phpdocs as well

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

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

* Remove methodlist

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

* Rename retrieveAvailablePaymentMethods to getPaymentMethods

and return a promise instead of setting the methods when done

* Remove threeds2-js-utils.js and usage

* Add adyen-configuration.js

* Initialize checkout component and store it

* Use the new paymentMethods response from the component

* Move logic from CcAuthorizationDataBuilder to CheckoutDataBuilder

Remove CcAuthorizationDataBuilder.php

* require php api library version 8

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

* Move logic from ThreeDS2DataBuilder to CheckoutDataBuilder

Remove ThreeDS2DataBuilder.php

* Simplify adyen-cc-method.js

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

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

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

* Adjust the AdyenCcDataAssignObserver to handle the full state data

* Update generic component to the latest bundle

* Fix 3DS1 response in CheckoutResponseValidator.php

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

* Standardise cc and alternative payment methods observers

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

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

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

* Standardise alternative payment methods frontend

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

* Remove line item itemId from checkout requests

Version 64 does not support it anymore

* Adjust personal details request structure to checkout version 64

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

* Make paymentMethods array observable

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

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

* Fix code smells

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

* Fix bug sonar after sonarcloud check

* Add legend field

* Add legend field in the correct place

* Update Helper/Requests.php
Co-authored-by: default avatarAttila Kiss <42297201+cyattilakiss@users.noreply.github.com>
Co-authored-by: default avatarAttila Kiss <42297201+cyattilakiss@users.noreply.github.com>
Co-authored-by: default avatarÁngel Campos <angel.campos@adyen.com>
Co-authored-by: default avatarmarcoss <marcos.silvagarcia@adyen.com>
Co-authored-by: default avatarMarcos Garcia <marcos.asgarcia@gmail.com>
Co-authored-by: default avatarattilak <attila.kiss@adyen.com>

* [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

* Bump version to 7.0.0-rc.1

* [PW-3111] Use getOrigin helper function for returnUrl parameter in redirect controller (#924)

* Add PWA origin for the getRedirectUrl() in the transparent redirect

Add support for PWA dedicated frontend urls per store

* Add query when redirecting to the result controller

* Delete Redirect.php - not used anymore

* Add merchant reference in the return url as get param to support PWA

* Store details in the payment additional information object

* [WIP] use result as a generic handler for redirects

Validate all the redirects via payments/details
Validate the parameters for payments/details with the details list from
the first payments response

* [WIP] use result as a generic handler for redirects

* Update Controller/Process/Result.php
Co-authored-by: default avatarÁngel Campos <angel.campos@adyen.com>
Co-authored-by: default avatarÁngel Campos <angel.campos@adyen.com>

* FIxes while retesting (#928)

* Remove unused legend

* Add support for bcmc separate component

* Fix google pay

* Fix Google pay terms and conditions validation

* handle 3DS1 with Google pay (#930)

* Close popup when payment failed

* Fetching currency code for payment methods call (#931)

* Do not render modal when it is only a redirect component (#932)

* New version to trigger upgrade scripts is 7.0.0 (#933)

* Adding charged currency hidden config field (#935)
Co-authored-by: default avatarÁngel Campos <angel.campos@adyen.com>
Co-authored-by: default avatarAlexandros Moraitis <alexandros.moraitis@adyen.com>
Co-authored-by: default avatarmarcoss <marcos.silvagarcia@adyen.com>
Co-authored-by: default avatarMarcos Garcia <marcos.asgarcia@gmail.com>
parent 8e021bab
......@@ -24,7 +24,7 @@
namespace Adyen\Payment\Api;
interface AdyenThreeDS2ProcessInterface
interface AdyenPaymentDetailsInterface
{
/**
* @param string $payload
......
......@@ -23,6 +23,9 @@
namespace Adyen\Payment\Block\Checkout;
use Adyen\Payment\Helper\ChargedCurrency;
use Adyen\Payment\Model\AdyenAmountCurrency;
/**
* Billing agreement information on Order success page
*/
......@@ -55,6 +58,11 @@ class Success extends \Magento\Framework\View\Element\Template
*/
protected $storeManager;
/**
* @var ChargedCurrency
*/
protected $chargedCurrency;
/**
* Success constructor.
*
......@@ -71,6 +79,7 @@ class Success extends \Magento\Framework\View\Element\Template
\Magento\Framework\Pricing\Helper\Data $priceHelper,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Store\Model\StoreManagerInterface $storeManager,
ChargedCurrency $chargedCurrency,
array $data = []
) {
$this->checkoutSession = $checkoutSession;
......@@ -78,6 +87,7 @@ class Success extends \Magento\Framework\View\Element\Template
$this->priceHelper = $priceHelper;
$this->adyenHelper = $adyenHelper;
$this->storeManager = $storeManager;
$this->chargedCurrency = $chargedCurrency;
parent::__construct($context, $data);
}
......@@ -212,4 +222,12 @@ class Success extends \Magento\Framework\View\Element\Template
}
return $this->order;
}
/**
* @return AdyenAmountCurrency
*/
public function geAdyenAmountCurrency()
{
return $this->chargedCurrency->getOrderAmountCurrency($this->order, false);
}
}
......@@ -23,6 +23,8 @@
namespace Adyen\Payment\Block\Form;
use Adyen\Payment\Helper\ChargedCurrency;
class Oneclick extends \Adyen\Payment\Block\Form\Cc
{
/**
......@@ -35,6 +37,11 @@ class Oneclick extends \Adyen\Payment\Block\Form\Cc
*/
protected $_sessionQuote;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
/**
* Oneclick constructor.
*
......@@ -42,6 +49,8 @@ class Oneclick extends \Adyen\Payment\Block\Form\Cc
* @param \Magento\Payment\Model\Config $paymentConfig
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Checkout\Model\Session $checkoutSession
* @param \Magento\Backend\Model\Session\Quote $sessionQuote
* @param ChargedCurrency $chargedCurrency
* @param array $data
*/
public function __construct(
......@@ -50,10 +59,12 @@ class Oneclick extends \Adyen\Payment\Block\Form\Cc
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Checkout\Model\Session $checkoutSession,
\Magento\Backend\Model\Session\Quote $sessionQuote,
ChargedCurrency $chargedCurrency,
array $data = []
) {
parent::__construct($context, $paymentConfig, $adyenHelper, $checkoutSession, $data);
$this->_sessionQuote = $sessionQuote;
$this->chargedCurrency = $chargedCurrency;
}
/**
......@@ -63,7 +74,8 @@ class Oneclick extends \Adyen\Payment\Block\Form\Cc
{
$customerId = $this->_sessionQuote->getCustomerId();
$storeId = $this->_sessionQuote->getStoreId();
$grandTotal = $this->_sessionQuote->getQuote()->getGrandTotal();
$grandTotal = $this->chargedCurrency->getQuoteAmountCurrency($this->_sessionQuote->getQuote())->getAmount();
// For backend only allow recurring payments
$recurringType = \Adyen\Payment\Model\RecurringType::RECURRING;
......
......@@ -23,8 +23,28 @@
namespace Adyen\Payment\Block\Info;
use Adyen\Payment\Helper\ChargedCurrency;
use Magento\Framework\View\Element\Template;
class Hpp extends AbstractInfo
{
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Model\ResourceModel\Order\Payment\CollectionFactory $adyenOrderPaymentCollectionFactory,
Template\Context $context,
ChargedCurrency $chargedCurrency,
array $data = []
) {
$this->chargedCurrency = $chargedCurrency;
parent::__construct($adyenHelper, $adyenOrderPaymentCollectionFactory, $context, $data);
}
/**
* @var string
*/
......@@ -75,6 +95,14 @@ class Hpp extends AbstractInfo
return $this->getInfo()->getOrder();
}
/**
* @return \Adyen\Payment\Model\AdyenAmountCurrency
*/
public function getOrderAmountCurrency()
{
return $this->chargedCurrency->getOrderAmountCurrency($this->getInfo()->getOrder(), false);
}
/**
* @return null
* @throws \Magento\Framework\Exception\LocalizedException
......
......@@ -23,6 +23,7 @@
namespace Adyen\Payment\Block\Info;
use Adyen\Payment\Helper\ChargedCurrency;
use Magento\Framework\View\Element\Template;
class PaymentLink extends AbstractInfo
......@@ -37,16 +38,23 @@ class PaymentLink extends AbstractInfo
*/
private $payByMail;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Model\ResourceModel\Order\Payment\CollectionFactory $adyenOrderPaymentCollectionFactory,
Template\Context $context,
\Magento\Framework\Registry $registry,
\Adyen\Payment\Gateway\Command\PayByMailCommand $payByMailCommand,
ChargedCurrency $chargedCurrency,
array $data = []
) {
$this->registry = $registry;
$this->payByMail = $payByMailCommand;
$this->chargedCurrency = $chargedCurrency;
parent::__construct($adyenHelper, $adyenOrderPaymentCollectionFactory, $context, $data);
}
......@@ -74,7 +82,8 @@ class PaymentLink extends AbstractInfo
*/
public function getPaymentLinkUrl()
{
return $this->payByMail->generatePaymentUrl($this->getPayment(), $this->getOrder()->getTotalDue());
$adyenAmountCurrency = $this->chargedCurrency->getOrderAmountCurrency($this->getOrder(), false);
return $this->payByMail->generatePaymentUrl($this->getPayment(), $adyenAmountCurrency->getAmountDue());
}
/**
......
This diff is collapsed.
......@@ -23,6 +23,7 @@
namespace Adyen\Payment\Block\Transparent;
use Adyen\Payment\Helper\Data;
use Adyen\Service\Validator\DataArrayValidator;
use Magento\Framework\View\Element\Template;
......@@ -32,12 +33,20 @@ class Redirect extends Template
* @var \Magento\Framework\UrlInterface
*/
private $url;
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
protected $adyenLogger;
/**
* @var Data
*/
protected $adyenHelper;
/**
* Redirect constructor.
*
* @param Template\Context $context
* @param \Magento\Framework\UrlInterface $url
* @param array $data
......@@ -46,24 +55,41 @@ class Redirect extends Template
Template\Context $context,
\Magento\Framework\UrlInterface $url,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
Data $adyenHelper,
array $data = []
) {
$this->url = $url;
$this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
parent::__construct($context, $data);
}
/**
* Returns url for redirect.
*
* @return string|null
*/
public function getRedirectUrl()
{
return $this->url->getUrl("adyen/process/redirect"); //TODO this will be replaced by getOrigin() for PWA integrations
$pwaOrigin = $this->adyenHelper->getAdyenAbstractConfigData("payment_origin_url", $this->_storeManager->getStore()->getId());
if ($pwaOrigin) {
$returnUrl = $pwaOrigin . "/adyen/process/result";
} else {
$returnUrl = $this->url->getUrl("adyen/process/result");
}
if (!empty($this->getRequest()->getQueryValue())) {
$query = http_build_query($this->getRequest()->getQueryValue(), '', '&');
$returnUrl .= '?' . $query;
}
return $returnUrl;
}
/**
* Returns params to be redirected.
*
* @return array
*/
public function getPostParams()
......
This diff is collapsed.
......@@ -24,6 +24,8 @@
namespace Adyen\Payment\Controller\Process;
use \Adyen\Payment\Model\Notification;
use Adyen\Service\Validator\DataArrayValidator;
use Magento\Framework\App\Request\Http as Http;
class Result extends \Magento\Framework\App\Action\Action
{
......@@ -89,6 +91,13 @@ class Result extends \Magento\Framework\App\Action\Action
$this->_adyenLogger = $adyenLogger;
$this->storeManager = $storeManager;
parent::__construct($context);
if (interface_exists(\Magento\Framework\App\CsrfAwareActionInterface::class)) {
$request = $this->getRequest();
if ($request instanceof Http && $request->isPost()) {
$request->setParam('isAjax', true);
$request->getHeaders()->addHeaderLine('X_REQUESTED_WITH', 'XMLHttpRequest');
}
}
}
/**
......@@ -96,6 +105,7 @@ class Result extends \Magento\Framework\App\Action\Action
*/
public function execute()
{
// GET and POST params together
$response = $this->getRequest()->getParams();
$this->_adyenLogger->addAdyenResult(print_r($response, true));
......@@ -153,6 +163,7 @@ class Result extends \Magento\Framework\App\Action\Action
$this->_adyenLogger->addAdyenResult('Processing ResultUrl');
// TODO check if needed since response is validated when calling this function
if (empty($response)) {
$this->_adyenLogger->addAdyenResult(
'Response is empty, please check your webserver that the result url accepts parameters'
......@@ -164,26 +175,20 @@ class Result extends \Magento\Framework\App\Action\Action
}
// If the merchant signature is present, authenticate the result url
// TODO validate if merchant signature is still used or can be removed
if (!empty($response['merchantSig'])) {
// authenticate result url
$authStatus = $this->_authenticate($response);
if (!$authStatus) {
throw new \Magento\Framework\Exception\LocalizedException(__('ResultUrl authentification failure'));
}
// Otherwise validate the pazload and get back the response that can be used to finish the order
} else {
// send the payload verification payment\details request to validate the response
$response = $this->validatePayloadAndReturnResponse($response);
}
$incrementId = null;
// send the payload verification payment\details request to validate the response
$response = $this->validatePayloadAndReturnResponse($response);
if (!empty($response['merchantReference'])) {
$incrementId = $response['merchantReference'];
}
$order = $this->_order;
$order = $this->_getOrder($incrementId);
if ($order->getId()) {
$this->_eventManager->dispatch(
'adyen_payment_process_resulturl_before',
[
......@@ -191,6 +196,8 @@ class Result extends \Magento\Framework\App\Action\Action
'adyen_response' => $response
]
);
// TODO is handled in the response?
if (isset($response['handled'])) {
return $response['handled_response'];
}
......@@ -205,11 +212,6 @@ class Result extends \Magento\Framework\App\Action\Action
'adyen_response' => $response
]
);
} else {
throw new \Magento\Framework\Exception\LocalizedException(
__('Order does not exists with increment_id: %1', $incrementId)
);
}
return $result;
}
......@@ -382,42 +384,58 @@ class Result extends \Magento\Framework\App\Action\Action
* @return mixed
* @throws \Adyen\AdyenException
*/
protected function validatePayloadAndReturnResponse($response)
protected function validatePayloadAndReturnResponse($result)
{
$client = $this->_adyenHelper->initializeAdyenClient($this->storeManager->getStore()->getId());
$service = $this->_adyenHelper->createAdyenCheckoutService($client);
$request = [];
if (!empty($result['merchantReference'])) {
//TODO Replace with order repository search for best practice
$order = $this->_orderFactory->create()->loadByIncrementId($result['merchantReference']);
} else {
$order = $this->_session->getLastRealOrder();
}
if (!empty($this->_session->getLastRealOrder()) &&
!empty($this->_session->getLastRealOrder()->getPayment())
) {
if (!empty($this->_session->getLastRealOrder()->getPayment()->getAdditionalInformation('paymentData'))) {
$request['paymentData'] = $this->_session->getLastRealOrder()->getPayment()->
getAdditionalInformation('paymentData');
if (!$order->getId()) {
throw new \Magento\Framework\Exception\LocalizedException(
__('Order cannot be loaded')
);
}
// remove paymentData from db
$this->_session->getLastRealOrder()->getPayment()->unsAdditionalInformation('paymentData');
$this->_session->getLastRealOrder()->getPayment()->save();
$payment = $order->getPayment();
$request = [];
// filter details to match the keys
$allowedParams = $payment->getAdditionalInformation('details');
$details = $result;
if (!empty($allowedParams)) {
$allowedParamsArray = [];
// TODO build a validator class which also validates the type of the param
foreach ($allowedParams as $allowedParam) {
$allowedParamsArray[] = $allowedParam['key'];
}
$details = DataArrayValidator::getArrayOnlyWithApprovedKeys($details, $allowedParamsArray);
}
$request["details"] = $details;
if (!empty($payment)) {
// for pending payment that redirect we store this under adyenPaymentData
// TODO: refactor the code in the plugin that all paymentData is stored in paymentData and not in adyenPaymentData
if (!empty($this->_session->getLastRealOrder()->getPayment()->getAdditionalInformation('adyenPaymentData'))) {
$request['paymentData'] = $this->_session->getLastRealOrder()->getPayment()->
getAdditionalInformation("adyenPaymentData");
if (!empty($payment->getAdditionalInformation('adyenPaymentData'))) {
$request['paymentData'] = $payment->getAdditionalInformation("adyenPaymentData");
// remove paymentData from db
$this->_session->getLastRealOrder()->getPayment()->unsAdditionalInformation('adyenPaymentData');
$this->_session->getLastRealOrder()->getPayment()->save();
$payment->unsAdditionalInformation('adyenPaymentData');
$payment->save();
}
} else {
$this->_adyenLogger->addError("Can't load the order id from the session");
$this->_adyenLogger->addError("Payment object cannot be loaded from order");
}
$request["details"] = $response;
if (!empty($this->_session->getLastRealOrder()) &&
// TODO check if this is ever reached
/*if (!empty($this->_session->getLastRealOrder()) &&
!empty($this->_session->getLastRealOrder()->getPayment()) &&
!empty($this->_session->getLastRealOrder()->getPayment()->getAdditionalInformation("details"))
) {
......@@ -427,10 +445,20 @@ class Result extends \Magento\Framework\App\Action\Action
if ($key !== false) {
$request["details"] = ["returnUrlQueryString" => http_build_query($response)];
}
}
}*/
try {
$response = $service->paymentsDetails($request);
if (!empty($response['merchantReference'])) {
if ($order->getIncrementId() === $response['merchantReference']) {
$this->_order = $order;
}
} else {
// TODO error handling
$this->_adyenLogger->addError("Wrong merchantReference was set in the query or in the session");
// TODO error page
}
} catch (\Adyen\AdyenException $e) {
$response['error'] = $e->getMessage();
}
......
......@@ -23,7 +23,7 @@
namespace Adyen\Payment\Gateway\Command;
use Magento\Payment\Gateway\Command;
use Adyen\Payment\Helper\ChargedCurrency;
use Magento\Payment\Gateway\CommandInterface;
class PayByMailCommand implements CommandInterface
......@@ -38,19 +38,26 @@ class PayByMailCommand implements CommandInterface
*/
protected $_adyenLogger;
/**
* @var ChargedCurrency
*/
protected $chargedCurrency;
/**
* PayByMailCommand constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\Locale\ResolverInterface $resolver
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param ChargedCurrency $chargedCurrency
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
ChargedCurrency $chargedCurrency
) {
$this->_adyenHelper = $adyenHelper;
$this->_adyenLogger = $adyenLogger;
$this->chargedCurrency = $chargedCurrency;
}
/**
......@@ -127,7 +134,6 @@ class PayByMailCommand implements CommandInterface
$order = $payment->getOrder();
$realOrderId = $order->getRealOrderId();
$orderCurrencyCode = $order->getOrderCurrencyCode();
$storeId = $order->getStore()->getId();
// check if paybymail has it's own skin
......@@ -143,10 +149,15 @@ class PayByMailCommand implements CommandInterface
$hmacKey = $this->_adyenHelper->getHmacPayByMail();
}
$adyenAmount = $this->chargedCurrency->getOrderAmountCurrency($order);
$orderCurrencyCode = $adyenAmount->getCurrencyCode();
//Use the $paymentAmount arg as total if this is a partial payment, full amount if not
$amount = $this->_adyenHelper->formatAmount(
$paymentAmount ?: $order->getGrandTotal(),
$paymentAmount ?: $adyenAmount->getAmount(),
$orderCurrencyCode
);
$merchantAccount = trim($this->_adyenHelper->getAdyenAbstractConfigData('merchant_account', $storeId));
$shopperEmail = $order->getCustomerEmail();
$customerId = $order->getCustomerId();
......
......@@ -23,6 +23,7 @@
namespace Adyen\Payment\Gateway\Request;
use Adyen\Payment\Helper\ChargedCurrency;
use Magento\Payment\Gateway\Request\BuilderInterface;
/**
......@@ -35,14 +36,23 @@ class CaptureDataBuilder implements BuilderInterface
*/
private $adyenHelper;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
/**
* CaptureDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param ChargedCurrency $chargedCurrency
*/
public function __construct(\Adyen\Payment\Helper\Data $adyenHelper)
{
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
ChargedCurrency $chargedCurrency
) {
$this->adyenHelper = $adyenHelper;
$this->chargedCurrency = $chargedCurrency;
}
/**
......@@ -55,13 +65,12 @@ class CaptureDataBuilder implements BuilderInterface
{
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$amount = \Magento\Payment\Gateway\Helper\SubjectReader::readAmount($buildSubject);
$payment = $paymentDataObject->getPayment();
$order = $payment->getOrder();
$pspReference = $payment->getCcTransId();
$currency = $payment->getOrder()->getOrderCurrencyCode();
$orderAmountCurrency = $this->chargedCurrency->getOrderAmountCurrency($order, false);
$currency = $orderAmountCurrency->getCurrencyCode();
$amount = $orderAmountCurrency->getAmount();
$amount = $this->adyenHelper->formatAmount($amount, $currency);
$modificationAmount = ['currency' => $currency, 'value' => $amount];
......@@ -93,27 +102,32 @@ class CaptureDataBuilder implements BuilderInterface
{
$formFields = [];
$count = 0;
$currency = $payment->getOrder()->getOrderCurrencyCode();
$order = $payment->getOrder();
$invoices = $order->getInvoiceCollection();
$invoices = $payment->getOrder()->getInvoiceCollection();
$currency = $this->chargedCurrency
->getOrderAmountCurrency($payment->getOrder(), false)
->getCurrencyCode();
// The latest invoice will contain only the selected items(and quantities) for the (partial) capture
$latestInvoice = $invoices->getLastItem();
/* @var \Magento\Sales\Model\Order\Invoice\Item $invoiceItem */
foreach ($latestInvoice->getItems() as $invoiceItem) {
if ($invoiceItem->getOrderItem()->getParentItem()) {
continue;
}
++$count;
$itemAmountCurrency = $this->chargedCurrency->getInvoiceItemAmountCurrency($invoiceItem);
$numberOfItems = (int)$invoiceItem->getQty();
$formFields = $this->adyenHelper->createOpenInvoiceLineItem(
$formFields,
$count,
$invoiceItem->getName(),
$invoiceItem->getPrice(),
$itemAmountCurrency->getAmount(),
$currency,
$invoiceItem->getTaxAmount(),
$invoiceItem->getPriceInclTax(),
$itemAmountCurrency->getTaxAmount(),
$itemAmountCurrency->getAmount() + $itemAmountCurrency->getTaxAmount(),
$invoiceItem->getOrderItem()->getTaxPercent(),
$numberOfItems,
$payment,
......@@ -124,13 +138,14 @@ class CaptureDataBuilder implements BuilderInterface
// Shipping cost
if ($latestInvoice->getShippingAmount() > 0) {
++$count;
$adyenInvoiceShippingAmount = $this->chargedCurrency->getInvoiceShippingAmountCurrency($latestInvoice);
$formFields = $this->adyenHelper->createOpenInvoiceLineShipping(
$formFields,
$count,
$payment->getOrder(),
$latestInvoice->getShippingAmount(),
$latestInvoice->getShippingTaxAmount(),
$currency,
$order,
$adyenInvoiceShippingAmount->getAmount(),
$adyenInvoiceShippingAmount->getTaxAmount(),
$adyenInvoiceShippingAmount->getCurrencyCode(),
$payment
);
}
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2019 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
class CcAuthorizationDataBuilder implements BuilderInterface
{
/**
* @param array $buildSubject
* @return mixed
*/
public function build(array $buildSubject)
{
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$requestBody = [];
// If ccType is set use this. For bcmc you need bcmc otherwise it will fail
$requestBody['paymentMethod']['type'] = "scheme";
if ($cardNumber = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER)) {
$requestBody['paymentMethod']['encryptedCardNumber'] = $cardNumber;
}
if ($expiryMonth = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH)) {
$requestBody['paymentMethod']['encryptedExpiryMonth'] = $expiryMonth;
}
if ($expiryYear = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR)) {
$requestBody['paymentMethod']['encryptedExpiryYear'] = $expiryYear;
}
if ($holderName = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME)) {
$requestBody['paymentMethod']['holderName'] = $holderName;
}
if ($securityCode = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE)) {
$requestBody['paymentMethod']['encryptedSecurityCode'] = $securityCode;
}
// Remove from additional data
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME);
// if installments is set and card type is credit card add it into the request
$numberOfInstallments = $payment->getAdditionalInformation(
AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS
) ?: 0;
$comboCardType = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::COMBO_CARD_TYPE) ?: 'credit';
if ($numberOfInstallments > 0) {
$requestBody['installments']['value'] = $numberOfInstallments;
}
// if card type is debit then change the issuer type and unset the installments field
if ($comboCardType == 'debit') {
if ($selectedDebitBrand = $this->getSelectedDebitBrand($payment->getAdditionalInformation('cc_type'))) {
$requestBody['additionalData']['overwriteBrand'] = true;
$requestBody['selectedBrand'] = $selectedDebitBrand;
$requestBody['paymentMethod']['type'] = $selectedDebitBrand;
}
unset($requestBody['installments']);
}
$request['body'] = $requestBody;
return $request;
}
/**
* @param string $brand
* @return string
*/
private function getSelectedDebitBrand($brand)
{
if ($brand == 'VI') {
return 'electron';
}
if ($brand == 'MC') {
return 'maestro';
}
return null;
}
}
This diff is collapsed.
......@@ -39,6 +39,11 @@ class GooglePayAuthorizationDataBuilder implements BuilderInterface
*/
private $adyenLogger;
/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
private $storeManager;
/**
* GooglePayAuthorizationDataBuilder constructor.
*
......@@ -46,10 +51,12 @@ class GooglePayAuthorizationDataBuilder implements BuilderInterface
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Magento\Store\Model\StoreManagerInterface $storeManager
) {
$this->adyenHelper = $adyenHelper;
$this->adyenLogger = $adyenLogger;
$this->storeManager = $storeManager;
}
public function build(array $buildSubject)
......@@ -57,6 +64,8 @@ class GooglePayAuthorizationDataBuilder implements BuilderInterface
$requestBody = [];
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
/** @var \Magento\Sales\Model\Order $order */
$order = $payment->getOrder();
$token = $payment->getAdditionalInformation('token');
$requestBody['paymentMethod']['type'] = 'paywithgoogle';
......@@ -67,6 +76,10 @@ class GooglePayAuthorizationDataBuilder implements BuilderInterface
$this->adyenLogger->addAdyenDebug("PaymentToken is empty");
}
$requestBody['returnUrl'] = $this->storeManager->getStore()->getBaseUrl(
\Magento\Framework\UrlInterface::URL_TYPE_LINK
) . 'adyen/transparent/redirect?merchantReference=' . $order->getIncrementId();
$request['body'] = $requestBody;
return $request;
......
......@@ -55,20 +55,6 @@ class OneclickAuthorizationDataBuilder implements BuilderInterface
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$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')) {
$shopperInteraction = "Ecommerce";
} else {
......@@ -76,9 +62,7 @@ class OneclickAuthorizationDataBuilder implements BuilderInterface
}
$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 ($payment->getCcType() == "sepadirectdebit") {
......
......@@ -23,6 +23,7 @@
namespace Adyen\Payment\Gateway\Request;
use Adyen\Payment\Helper\ChargedCurrency;
use Magento\Payment\Gateway\Request\BuilderInterface;
class PaymentDataBuilder implements BuilderInterface
......@@ -32,14 +33,23 @@ class PaymentDataBuilder implements BuilderInterface
*/
private $adyenRequestsHelper;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
/**
* PaymentDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
* @param ChargedCurrency $chargedCurrency
*/
public function __construct(\Adyen\Payment\Helper\Requests $adyenRequestsHelper)
{
public function __construct(
\Adyen\Payment\Helper\Requests $adyenRequestsHelper,
ChargedCurrency $chargedCurrency
) {
$this->adyenRequestsHelper = $adyenRequestsHelper;
$this->chargedCurrency = $chargedCurrency;
}
/**
......@@ -55,8 +65,9 @@ class PaymentDataBuilder implements BuilderInterface
$payment = $paymentDataObject->getPayment();
$fullOrder = $payment->getOrder();
$currencyCode = $fullOrder->getOrderCurrencyCode();
$amount = $fullOrder->getGrandTotal();
$amountCurrency = $this->chargedCurrency->getOrderAmountCurrency($fullOrder);
$currencyCode = $amountCurrency->getCurrencyCode();
$amount = $amountCurrency->getAmount();
$reference = $order->getOrderIncrementId();
$paymentMethod = $payment->getMethod();
......
......@@ -23,6 +23,7 @@
namespace Adyen\Payment\Gateway\Request;
use Adyen\Payment\Helper\ChargedCurrency;
use Magento\Payment\Gateway\Request\BuilderInterface;
/**
......@@ -45,20 +46,28 @@ class RefundDataBuilder implements BuilderInterface
*/
protected $adyenInvoiceCollectionFactory;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
/**
* RefundDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Adyen\Payment\Model\ResourceModel\Order\Payment\CollectionFactory $orderPaymentCollectionFactory
* @param ChargedCurrency $chargedCurrency
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Model\ResourceModel\Order\Payment\CollectionFactory $orderPaymentCollectionFactory,
\Adyen\Payment\Model\ResourceModel\Invoice\CollectionFactory $adyenInvoiceCollectionFactory
\Adyen\Payment\Model\ResourceModel\Invoice\CollectionFactory $adyenInvoiceCollectionFactory,
ChargedCurrency $chargedCurrency
) {
$this->adyenHelper = $adyenHelper;
$this->orderPaymentCollectionFactory = $orderPaymentCollectionFactory;
$this->adyenInvoiceCollectionFactory = $adyenInvoiceCollectionFactory;
$this->chargedCurrency = $chargedCurrency;
}
/**
......@@ -69,16 +78,16 @@ class RefundDataBuilder implements BuilderInterface
{
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$amount = \Magento\Payment\Gateway\Helper\SubjectReader::readAmount($buildSubject);
$buildSubjectAmount = \Magento\Payment\Gateway\Helper\SubjectReader::readAmount($buildSubject);
$order = $paymentDataObject->getOrder();
$payment = $paymentDataObject->getPayment();
$pspReference = $payment->getCcTransId();
$currency = $payment->getOrder()->getOrderCurrencyCode();
$orderAmountCurrency = $this->chargedCurrency->getOrderAmountCurrency($payment->getOrder(), false);
$currency = $orderAmountCurrency->getCurrencyCode();
$amount = $orderAmountCurrency->getAmount();
$storeId = $order->getStoreId();
$method = $payment->getMethod();
$merchantAccount = $this->adyenHelper->getAdyenMerchantAccount($method, $storeId);
$grandTotal = $payment->getOrder()->getGrandTotal();
// check if it contains a split payment
$orderPaymentCollection = $this->orderPaymentCollectionFactory
......@@ -101,7 +110,7 @@ class RefundDataBuilder implements BuilderInterface
$orderPaymentCollection->addPaymentFilterDescending($payment->getId());
} elseif ($refundStrategy == "3") {
// refund based on ratio
$ratio = $amount / $grandTotal;
$ratio = $buildSubjectAmount / $amount;
$orderPaymentCollection->addPaymentFilterAscending($payment->getId());
}
......@@ -185,7 +194,9 @@ class RefundDataBuilder implements BuilderInterface
{
$formFields = [];
$count = 0;
$currency = $payment->getOrder()->getOrderCurrencyCode();
$currency = $this->chargedCurrency
->getOrderAmountCurrency($payment->getOrder(), false)
->getCurrencyCode();
/**
* @var \Magento\Sales\Model\Order\Creditmemo $creditMemo
......@@ -194,16 +205,18 @@ class RefundDataBuilder implements BuilderInterface
foreach ($creditMemo->getItems() as $refundItem) {
++$count;
$itemAmountCurrency = $this->chargedCurrency->getCreditMemoItemAmountCurrency($refundItem);
$numberOfItems = (int)$refundItem->getQty();
$formFields = $this->adyenHelper->createOpenInvoiceLineItem(
$formFields,
$count,
$refundItem->getName(),
$refundItem->getPrice(),
$itemAmountCurrency->getAmount(),
$currency,
$refundItem->getTaxAmount(),
$refundItem->getPriceInclTax(),
$itemAmountCurrency->getTaxAmount(),
$itemAmountCurrency->getAmount() + $itemAmountCurrency->getTaxAmount(),
$refundItem->getOrderItem()->getTaxPercent(),
$numberOfItems,
$payment,
......
......@@ -33,7 +33,7 @@ class CancelResponseValidator extends AbstractValidator
private $adyenLogger;
/**
* GeneralResponseValidator constructor.
* CancelResponseValidator constructor.
*
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
......
......@@ -33,7 +33,7 @@ class CaptureResponseValidator extends AbstractValidator
private $adyenLogger;
/**
* GeneralResponseValidator constructor.
* CaptureResponseValidator constructor.
*
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
......
......@@ -38,10 +38,11 @@ class CheckoutResponseValidator extends AbstractValidator
private $adyenHelper;
/**
* GeneralResponseValidator constructor.
* CheckoutResponseValidator constructor.
*
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param \Adyen\Payment\Helper\Data $adyenHelper
*/
public function __construct(
\Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory,
......@@ -67,28 +68,36 @@ class CheckoutResponseValidator extends AbstractValidator
$isValid = true;
$errorMessages = [];
$resultCode = array_key_exists("resultCode", $response) ? $response['resultCode']:'';
// validate result
if (!empty($resultCode)) {
if (!empty($response['resultCode'])) {
$resultCode = $response['resultCode'];
$payment->setAdditionalInformation('resultCode', $resultCode);
switch ($resultCode) {
case "IdentifyShopper":
$payment->setAdditionalInformation('threeDSType', $resultCode);
$payment->setAdditionalInformation(
'threeDS2Token',
$response['authentication']['threeds2.fingerprintToken']
);
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']);
break;
case "ChallengeShopper":
$payment->setAdditionalInformation('threeDSType', $resultCode);
$payment->setAdditionalInformation(
'threeDS2Token',
$response['authentication']['threeds2.challengeToken']
);
if (!empty($response['action'])) {
$payment->setAdditionalInformation('action', $response['action']);
}
if (!empty($response['additionalData'])) {
$payment->setAdditionalInformation('additionalData', $response['additionalData']);
}
if (!empty($response['pspReference'])) {
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
}
if (!empty($response['paymentData'])) {
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']);
break;
}
if (!empty($response['details'])) {
$payment->setAdditionalInformation('details', $response['details']);
}
switch ($resultCode) {
case "Authorised":
case "Received":
// TODO refactor since the full additionalData is stored in additionalInformation already
// For banktransfers store all bankTransfer details
if (!empty($response['additionalData']['bankTransfer.owner'])) {
foreach ($response['additionalData'] as $key => $value) {
......@@ -106,6 +115,31 @@ class CheckoutResponseValidator extends AbstractValidator
}
}
// TODO doudle check this
if (isset($response['additionalData']) && is_array($response['additionalData'])) {
$additionalData = $response['additionalData'];
if (isset($additionalData['boletobancario.dueDate'])) {
$payment->setAdditionalInformation(
'dueDate',
$additionalData['boletobancario.dueDate']
);
}
if (isset($additionalData['boletobancario.expirationDate'])) {
$payment->setAdditionalInformation(
'expirationDate',
$additionalData['boletobancario.expirationDate']
);
}
if (isset($additionalData['boletobancario.url'])) {
$payment->setAdditionalInformation(
'url',
$additionalData['boletobancario.url']
);
}
}
// Save cc_type if available in the response
if (!empty($response['additionalData']['paymentMethod'])) {
$ccType = $this->adyenHelper->getMagentoCreditCartType(
......@@ -114,90 +148,15 @@ class CheckoutResponseValidator extends AbstractValidator
$payment->setAdditionalInformation('cc_type', $ccType);
$payment->setCcType($ccType);
}
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
break;
case "IdentifyShopper":
case "ChallengeShopper":
case "PresentToShopper":
if (!empty($response['action'])) {
$payment->setAdditionalInformation('action', $response['action']);
}
if (!empty($response['pspReference'])) {
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
}
break;
case 'Pending':
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']);
if (!empty($response['action'])) {
$payment->setAdditionalInformation('action', $response['action']);
}
break;
case "RedirectShopper":
$payment->setAdditionalInformation('threeDSType', $resultCode);
$redirectUrl = null;
$paymentData = null;
if (!empty($response['redirect']['url'])) {
$redirectUrl = $response['redirect']['url'];
}
if (!empty($response['redirect']['method'])) {
$redirectMethod = $response['redirect']['method'];
}
if (!empty($response['paymentData'])) {
$paymentData = $response['paymentData'];
}
// If the redirect data is there then the payment is a card payment with 3d secure
if (
isset($response['redirect']['data']['PaReq']) &&
isset($response['redirect']['data']['MD'])
) {
$paReq = null;
$md = null;
$payment->setAdditionalInformation('3dActive', true);
if (!empty($response['redirect']['data']['PaReq'])) {
$paReq = $response['redirect']['data']['PaReq'];
}
if (!empty($response['redirect']['data']['MD'])) {
$md = $response['redirect']['data']['MD'];
}
if ($paReq && $md && $redirectUrl && $paymentData && $redirectMethod) {
$payment->setAdditionalInformation('redirectUrl', $redirectUrl);
$payment->setAdditionalInformation('redirectMethod', $redirectMethod);
$payment->setAdditionalInformation('paRequest', $paReq);
$payment->setAdditionalInformation('md', $md);
$payment->setAdditionalInformation('paymentData', $paymentData);
} else {
$isValid = false;
$errorMsg = __('3D secure is not valid.');
$this->adyenLogger->error($errorMsg);
$errorMessages[] = $errorMsg;
}
// otherwise it is an alternative payment method which only requires the
// redirect url to be present
} else {
// Flag to show we are in the checkoutAPM flow
$payment->setAdditionalInformation('checkoutAPM', true);
if (!empty($response['details'])) {
$payment->setAdditionalInformation('details', $response['details']);
}
if ($redirectUrl && $paymentData && $redirectMethod) {
$payment->setAdditionalInformation('redirectUrl', $redirectUrl);
$payment->setAdditionalInformation('redirectMethod', $redirectMethod);
$payment->setAdditionalInformation('paymentData', $paymentData);
} else {
$isValid = false;
$errorMsg = __('Payment method is not valid.');
$this->adyenLogger->error($errorMsg);
$errorMessages[] = $errorMsg;
}
}
// nothing extra
break;
case "Refused":
$errorMsg = __('The payment is REFUSED.');
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Gateway\Validator;
use Magento\Payment\Gateway\Validator\AbstractValidator;
class GeneralResponseValidator extends AbstractValidator
{
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
private $adyenLogger;
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* GeneralResponseValidator constructor.
*
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
*/
public function __construct(
\Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Adyen\Payment\Helper\Data $adyenHelper
) {
$this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
parent::__construct($resultFactory);
}
/**
* @param array $validationSubject
* @return \Magento\Payment\Gateway\Validator\ResultInterface
*/
public function validate(array $validationSubject)
{
$response = \Magento\Payment\Gateway\Helper\SubjectReader::readResponse($validationSubject);
$paymentDataObjectInterface = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($validationSubject);
$payment = $paymentDataObjectInterface->getPayment();
$payment->setAdditionalInformation('3dActive', false);
$isValid = true;
$errorMessages = [];
// validate result
if (!empty($response['resultCode'])) {
switch ($response['resultCode']) {
case "Authorised":
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
// Save cc_type if available in the response
if (!empty($response['additionalData']['paymentMethod'])) {
$ccType = $this->adyenHelper->getMagentoCreditCartType(
$response['additionalData']['paymentMethod']
);
$payment->setAdditionalInformation('cc_type', $ccType);
$payment->setCcType($ccType);
}
break;
case "Received":
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
// set additionalData
if (isset($response['additionalData']) && is_array($response['additionalData'])) {
$additionalData = $response['additionalData'];
if (isset($additionalData['boletobancario.dueDate'])) {
$payment->setAdditionalInformation(
'dueDate',
$additionalData['boletobancario.dueDate']
);
}
if (isset($additionalData['boletobancario.expirationDate'])) {
$payment->setAdditionalInformation(
'expirationDate',
$additionalData['boletobancario.expirationDate']
);
}
if (isset($additionalData['boletobancario.url'])) {
$payment->setAdditionalInformation(
'url',
$additionalData['boletobancario.url']
);
}
}
break;
case "RedirectShopper":
$payment->setAdditionalInformation('3dActive', true);
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
$redirectUrl = $response['issuerUrl'];
$paReq = $response['paRequest'];
$md = $response['md'];
if (!empty($paReq) && !empty($md) && !empty($redirectUrl)) {
$payment->setAdditionalInformation('redirectUrl', $redirectUrl);
$payment->setAdditionalInformation('paRequest', $response['paRequest']);
$payment->setAdditionalInformation('md', $response['md']);
} else {
$isValid = false;
$errorMsg = __('3D secure is not valid.');
$this->adyenLogger->error($errorMsg);
$errorMessages[] = $errorMsg;
}
break;
case "Refused":
$errorMsg = __('The payment is REFUSED.');
// this will result the specific error
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
break;
default:
$errorMsg = __('Error with payment method please select different payment method.');
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
break;
}
} else {
$errorMsg = __('Error with payment method please select different payment method.');
if (!empty($response['error'])) {
$this->adyenLogger->error($response['error']);
}
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
}
return $this->createResult($isValid, $errorMessages);
}
}
......@@ -25,6 +25,7 @@
namespace Adyen\Payment\Gateway\Validator;
use Adyen\Payment\Helper\ChargedCurrency;
use Magento\Payment\Gateway\Validator\AbstractValidator;
class InstallmentValidator extends AbstractValidator
......@@ -49,6 +50,11 @@ class InstallmentValidator extends AbstractValidator
*/
private $quoteRepository;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
/**
* InstallmentValidator constructor.
*
......@@ -63,12 +69,14 @@ class InstallmentValidator extends AbstractValidator
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Serialize\SerializerInterface $serializer,
\Magento\Quote\Model\QuoteRepository $quoteRepository
\Magento\Quote\Model\QuoteRepository $quoteRepository,
ChargedCurrency $chargedCurrency
) {
$this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
$this->serializer = $serializer;
$this->quoteRepository = $quoteRepository;
$this->chargedCurrency = $chargedCurrency;
parent::__construct($resultFactory);
}
......@@ -86,7 +94,7 @@ class InstallmentValidator extends AbstractValidator
}
$installmentsEnabled = $this->adyenHelper->getAdyenCcConfigData('enable_installments');
if ($quote && $installmentsEnabled) {
$grandTotal = $quote->getGrandTotal();
$grandTotal = $this->chargedCurrency->getQuoteAmountCurrency($quote)->getAmount();
$installmentsAvailable = $this->adyenHelper->getAdyenCcConfigData('installments');
$installmentSelected = $payment->getAdditionalInformation('number_of_installments');
$ccType = $payment->getAdditionalInformation('cc_type');
......
......@@ -33,7 +33,7 @@ class RefundResponseValidator extends AbstractValidator
private $adyenLogger;
/**
* GeneralResponseValidator constructor.
* RefundResponseValidator constructor.
*
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Helper;
use Adyen\Payment\Model\AdyenAmountCurrency;
use Magento\Quote\Model\Quote;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Invoice;
use Magento\Store\Model\Store;
use Magento\Sales\Api\Data\CreditmemoItemInterface;
class ChargedCurrency
{
/**
* @var string
* Charged currency value when Global/Website is selected
*/
const BASE = "base";
/**
* @var Config
*/
private $config;
public function __construct(
Config $config
) {
$this->config = $config;
}
/**
* @param Order $order
* @param bool $orderPlacement true if fetching the order's data when it is being placed,
* false to get the data according to the charged_currency already saved for the order
*
* @return AdyenAmountCurrency
*/
public function getOrderAmountCurrency(Order $order, bool $orderPlacement = true)
{
$chargedCurrency = $orderPlacement
? $this->config->getChargedCurrency($order->getStoreId())
: $order->getAdyenChargedCurrency();
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
$order->getBaseGrandTotal(),
$order->getGlobalCurrencyCode(),
null,
null,
$order->getBaseTotalDue()
);
}
return new AdyenAmountCurrency(
$order->getGrandTotal(),
$order->getOrderCurrencyCode(),
null,
null,
$order->getTotalDue()
);
}
/**
* @param Quote $quote
* @return AdyenAmountCurrency
*/
public function getQuoteAmountCurrency(Quote $quote)
{
$chargedCurrency = $this->config->getChargedCurrency($quote->getStoreId());
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency($quote->getBaseGrandTotal(), $quote->getBaseCurrencyCode());
}
return new AdyenAmountCurrency($quote->getGrandTotal(), $quote->getQuoteCurrencyCode());
}
/**
* @param Quote\Item $item
* @return AdyenAmountCurrency
*/
public function getQuoteItemAmountCurrency(Quote\Item $item)
{
$chargedCurrency = $this->config->getChargedCurrency($item->getStoreId());
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
$item->getBasePrice(),
$item->getQuote()->getBaseCurrencyCode(),
$item->getBaseDiscountAmount(),
($item->getTaxPercent() / 100) * $item->getBasePrice()
);
}
return new AdyenAmountCurrency(
$item->getRowTotal() / $item->getQty(),
$item->getQuote()->getQuoteCurrencyCode(),
$item->getDiscountAmount(),
($item->getTaxPercent() / 100) * ($item->getRowTotal() / $item->getQty())
);
}
/**
* @param Invoice\Item $item
* @return AdyenAmountCurrency
*/
public function getInvoiceItemAmountCurrency(Invoice\Item $item)
{
$chargedCurrency = $item->getInvoice()->getOrder()->getAdyenChargedCurrency();
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
$item->getBasePrice(),
$item->getInvoice()->getBaseCurrencyCode(),
null,
$item->getBaseTaxAmount()
);
}
return new AdyenAmountCurrency(
$item->getPrice(),
$item->getInvoice()->getBaseCurrencyCode(),
null,
$item->getTaxAmount()
);
}
/**
* @param CreditmemoItemInterface $item
* @return AdyenAmountCurrency
*/
public function getCreditMemoItemAmountCurrency(CreditmemoItemInterface $item)
{
$chargedCurrency = $item->getCreditMemo()->getInvoice()->getOrder()->getAdyenChargedCurrency();
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
$item->getBasePrice(),
$item->getInvoice()->getBaseCurrencyCode(),
null,
$item->getBaseTaxAmount()
);
}
return new AdyenAmountCurrency(
$item->getPrice(),
$item->getCreditMemo()->getInvoice()->getBaseCurrencyCode(),
null,
$item->getTaxAmount()
);
}
/**
* @param CreditmemoItemInterface $item
* @return AdyenAmountCurrency
*/
public function getQuoteShippingAmountCurrency(Quote $quote)
{
$chargedCurrency = $this->config->getChargedCurrency($quote->getStoreId());
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
$quote->getShippingAddress()->getBaseShippingAmount(),
$quote->getBaseCurrencyCode(),
$quote->getShippingAddress()->getBaseShippingDiscountAmount(),
$quote->getShippingAddress()->getBaseShippingTaxAmount()
);
}
return new AdyenAmountCurrency(
$quote->getShippingAddress()->getShippingAmount(),
$quote->getCurrencyCode(),
$quote->getShippingAddress()->getShippingDiscountAmount(),
$quote->getShippingAddress()->getShippingTaxAmount()
);
}
/**
* @param \Magento\Sales\Model\Order\Invoice $invoice
* @return AdyenAmountCurrency
*/
public function getInvoiceShippingAmountCurrency(Invoice $invoice)
{
$chargedCurrency = $invoice->getOrder()->getAdyenChargedCurrency();
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
$invoice->getBaseShippingAmount(),
$invoice->getBaseCurrencyCode(),
null,
$invoice->getBaseShippingTaxAmount()
);
}
return new AdyenAmountCurrency(
$invoice->getShippingAmount(),
$invoice->getOrderCurrencyCode(),
null,
$invoice->getShippingTaxAmount()
);
}
}
......@@ -35,6 +35,7 @@ class Config
const XML_NOTIFICATIONS_IP_CHECK = "notifications_ip_check";
const XML_NOTIFICATIONS_HMAC_KEY_LIVE = "notification_hmac_key_live";
const XML_NOTIFICATIONS_HMAC_KEY_TEST = "notification_hmac_key_test";
const XML_CHARGED_CURRENCY = "charged_currency";
/**
* @var Magento\Framework\App\Config\ScopeConfigInterface
......@@ -153,6 +154,17 @@ class Config
return $this->adyenHelper->getAdyenHppVaultConfigDataFlag('active', $storeId);
}
/**
* Retrive charged currency selection (base or display)
*
* @param null|int|string $storeId
* @return mixed
*/
public function getChargedCurrency($storeId = null)
{
return $this->adyenHelper->getAdyenAbstractConfigData(self::XML_CHARGED_CURRENCY, $storeId);
}
/**
* Retrieve information from payment configuration
*
......
......@@ -15,59 +15,69 @@
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2019 Adyen BV (https://www.adyen.com/)
* Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Gateway\Request;
namespace Adyen\Payment\Helper;
use Magento\Payment\Gateway\Request\BuilderInterface;
class ThreeDS2DataBuilder implements BuilderInterface
class ConnectedTerminals
{
/**
* @var \Magento\Framework\App\State
* @var \Magento\Checkout\Model\Session
*/
private $appState;
protected $session;
/**
* @var \Adyen\Payment\Helper\Requests
* @var \Adyen\Payment\Helper\Data
*/
private $adyenRequestsHelper;
protected $adyenHelper;
/**
* ThreeDS2DataBuilder constructor.
*
* @param \Magento\Framework\Model\Context $context
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/
public function __construct(
\Magento\Framework\Model\Context $context,
\Adyen\Payment\Helper\Requests $adyenRequestsHelper
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Checkout\Model\Session $session
) {
$this->appState = $context->getAppState();
$this->adyenRequestsHelper = $adyenRequestsHelper;
$this->adyenHelper = $adyenHelper;
$this->session = $session;
}
/**
* @param array $buildSubject
* @return array
* @return array|mixed
* @throws \Adyen\AdyenException
* @throws \Magento\Framework\Exception\LocalizedException
* @throws \Magento\Framework\Exception\NoSuchEntityException
*/
public function build(array $buildSubject)
public function getConnectedTerminals()
{
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$order = $paymentDataObject->getOrder();
$additionalInformation = $payment->getAdditionalInformation();
$request['body'] = $this->adyenRequestsHelper->buildThreeDS2Data(
$additionalInformation,
$order->getStoreId(),
[]
$storeId = $this->session->getQuote()->getStoreId();
// initialize the adyen client
$client = $this->adyenHelper->initializeAdyenClient($storeId, $this->adyenHelper->getPosApiKey($storeId));
// initialize service
$service = $this->adyenHelper->createAdyenPosPaymentService($client);
$requestParams = [
"merchantAccount" => $this->adyenHelper->getAdyenMerchantAccount('adyen_pos_cloud', $storeId),
];
// In case the POS store id is set, provide in the request
if (!empty($this->adyenHelper->getPosStoreId($storeId))) {
$requestParams['store'] = $this->adyenHelper->getPosStoreId($storeId);
}
try {
$responseData = $service->getConnectedTerminals($requestParams);
} catch (\Adyen\AdyenException $e) {
$this->adyenLogger->error(
"The getConnectedTerminals response is empty check your Adyen configuration in Magento."
);
return $request;
// return empty result
return [];
}
return $responseData;
}
}
......@@ -1716,7 +1716,7 @@ class Data extends AbstractHelper
$billingAgreement->getAgreementId(),
$order->getId()
)) {
// save into sales_billing_agreement_order
// save into billing_agreement_order
$billingAgreement->addOrderRelation($order);
}
// add to order to save agreement
......@@ -1736,6 +1736,7 @@ class Data extends AbstractHelper
$comment = $order->addStatusHistoryComment($message);
$order->addRelatedObject($comment);
$order->save();
}
}
......
This diff is collapsed.
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Helper;
use Adyen\Payment\Logger\AdyenLogger;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\Data\OrderPaymentInterface;
use Magento\Sales\Model\Order;
use Adyen\Payment\Helper\Vault;
class PaymentResponseHandler
{
const AUTHORISED = 'Authorised';
const REFUSED = 'Refused';
const REDIRECT_SHOPPER = 'RedirectShopper';
const IDENTIFY_SHOPPER = 'IdentifyShopper';
const CHALLENGE_SHOPPER = 'ChallengeShopper';
const RECEIVED = 'Received';
const PENDING = 'Pending';
const PRESENT_TO_SHOPPER = 'PresentToShopper';
const ERROR = 'Error';
const CANCELLED = 'Cancelled';
/**
* @var 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(
AdyenLogger $adyenLogger,
Data $adyenHelper,
Vault $vaultHelper
) {
$this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
$this->vaultHelper = $vaultHelper;
}
public function formatPaymentResponse($resultCode, $action = null, $additionalData = null)
{
switch ($resultCode) {
case self::AUTHORISED:
case self::REFUSED:
case self::ERROR:
return [
"isFinal" => true,
"resultCode" => $resultCode,
];
case self::REDIRECT_SHOPPER:
case self::IDENTIFY_SHOPPER:
case self::CHALLENGE_SHOPPER:
case self::PENDING:
return [
"isFinal" => false,
"resultCode" => $resultCode,
"action" => $action
];
case self::PRESENT_TO_SHOPPER:
return [
"isFinal" => true,
"resultCode" => $resultCode,
"action" => $action
];
case self::RECEIVED:
return [
"isFinal" => true,
"resultCode" => $resultCode,
"additionalData" => $additionalData
];
default:
return [
"isFinal" => true,
"resultCode" => self::ERROR,
];
}
}
/**
* @param $paymentsResponse
* @param OrderPaymentInterface $payment
* @param OrderInterface|null $order
* @return bool
*/
public function handlePaymentResponse($paymentsResponse, $payment, $order = null)
{
if (empty($paymentsResponse)) {
$this->adyenLogger->error("Payment details call failed, paymentsResponse is empty");
return false;
}
if (!empty($paymentsResponse['resultCode']))
$payment->setAdditionalInformation('resultCode', $paymentsResponse['resultCode']);
if (!empty($paymentsResponse['action'])) {
$payment->setAdditionalInformation('action', $paymentsResponse['action']);
}
if (!empty($paymentsResponse['additionalData'])) {
$payment->setAdditionalInformation('additionalData', $paymentsResponse['additionalData']);
}
if (!empty($paymentsResponse['pspReference'])) {
$payment->setAdditionalInformation('pspReference', $paymentsResponse['pspReference']);
}
if (!empty($paymentsResponse['paymentData'])) {
$payment->setAdditionalInformation('adyenPaymentData', $paymentsResponse['paymentData']);
}
if (!empty($paymentsResponse['details'])) {
$payment->setAdditionalInformation('details', $paymentsResponse['details']);
}
switch ($paymentsResponse['resultCode']) {
case self::PRESENT_TO_SHOPPER:
case self::PENDING:
case self::RECEIVED:
break;
//We don't need to handle these resultCodes
case self::REDIRECT_SHOPPER:
$this->adyenLogger->addAdyenResult("Customer was redirected.");
if ($order) {
$order->addStatusHistoryComment(
__(
'Customer was redirected to an external payment page. (In case of card payments the shopper is redirected to the bank for 3D-secure validation.) Once the shopper is authenticated,
the order status will be updated accordingly.
<br />Make sure that your notifications are being processed!
<br />If the order is stuck on this status, the shopper abandoned the session.
The payment can be seen as unsuccessful.
<br />The order can be automatically cancelled based on the OFFER_CLOSED notification.
Please contact Adyen Support to enable this.'
)
)->save();
}
break;
case self::AUTHORISED:
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::CHALLENGE_SHOPPER:
break;
//These resultCodes cancel the order and log an error
case self::REFUSED:
case self::ERROR:
default:
if (!$order->canCancel()) {
$order->setState(Order::STATE_NEW);
}
//TODO check if order gets cancelled
$order->cancel();
$this->adyenLogger->error(
sprintf("Payment details call failed for action, resultCode is %s Raw API responds: %s",
$paymentsResponse['resultCode'],
print_r($paymentsResponse, true)
));
return false;
}
return true;
}
}
......@@ -116,36 +116,10 @@ class Requests extends AbstractHelper
// In case of virtual product and guest checkout there is a workaround to get the guest's email address
if (!empty($additionalData['guestEmail'])) {
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod($paymentMethod) &&
!$this->adyenHelper->isPaymentMethodAfterpayTouchMethod($paymentMethod)
) {
$request['paymentMethod']['personalDetails']['shopperEmail'] = $additionalData['guestEmail'];
} else {
$request['shopperEmail'] = $additionalData['guestEmail'];
}
}
if (!empty($billingAddress)) {
// Openinvoice (klarna and afterpay BUT not afterpay touch) methods requires different request format
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod($paymentMethod) &&
!$this->adyenHelper->isPaymentMethodAfterpayTouchMethod($paymentMethod)
) {
if ($customerEmail = $billingAddress->getEmail()) {
$request['paymentMethod']['personalDetails']['shopperEmail'] = $customerEmail;
}
if ($customerTelephone = trim($billingAddress->getTelephone())) {
$request['paymentMethod']['personalDetails']['telephoneNumber'] = $customerTelephone;
}
if ($firstName = $billingAddress->getFirstname()) {
$request['paymentMethod']['personalDetails']['firstName'] = $firstName;
}
if ($lastName = $billingAddress->getLastname()) {
$request['paymentMethod']['personalDetails']['lastName'] = $lastName;
}
} else {
if ($customerEmail = $billingAddress->getEmail()) {
$request['shopperEmail'] = $customerEmail;
}
......@@ -161,7 +135,6 @@ class Requests extends AbstractHelper
if ($lastName = $billingAddress->getLastname()) {
$request['shopperName']['lastName'] = $lastName;
}
}
if ($countryId = $billingAddress->getCountryId()) {
$request['countryCode'] = $countryId;
......@@ -353,8 +326,6 @@ class Requests extends AbstractHelper
$request['origin'] = $this->adyenHelper->getOrigin($storeId);
$request['channel'] = 'web';
}
return $request;
}
/**
......
......@@ -15,38 +15,57 @@
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
/** @var Adyen\Payment\Block\Redirect\Redirect $block */
?>
<?php
if ($block->getRedirectMethod() == "GET") { ?>
<body>
<script>
window.location.replace("<?= $block->escapeJs($block->getRedirectUrl()); ?>");
</script>
</body>
<?php
} else { ?>
<body onload="document.getElementById('3dform').submit();">
<form method="POST" action="<?= $block->escapeHtml($block->getRedirectUrl()); ?>" id="3dform">
<input type="hidden" name="PaReq" value="<?= $block->escapeHtml($block->getPaReq()); ?>"/>
<input type="hidden" name="MD" value="<?= $block->escapeHtml($block->getMd()); ?>"/>
<input type="hidden" name="TermUrl" value="<?= $block->escapeHtml($block->getTermUrl()); ?>"/>
<noscript>
<br>
<br>
<div style="text-align: center">
<h1>Processing your 3-D Secure Transaction</h1>
<p>Please click continue to continue the processing of your 3-D Secure transaction.</p>
<input type="submit" class="button" value="continue"/>
</div>
</noscript>
</form>
</body>
<?php
} ?>
namespace Adyen\Payment\Model;
class AdyenAmountCurrency
{
protected $amount;
protected $discountAmount;
protected $taxAmount;
protected $currencyCode;
protected $amountDue;
public function __construct($amount, $currencyCode, $discountAmount = 0, $taxAmount = 0, $amountDue = 0)
{
$this->amount = $amount;
$this->currencyCode = $currencyCode;
$this->discountAmount = $discountAmount;
$this->taxAmount = $taxAmount;
$this->amountDue = $amountDue;
}
public function getAmount()
{
return $this->amount;
}
public function getCurrencyCode()
{
return $this->currencyCode;
}
public function getDiscountAmount()
{
return $this->discountAmount;
}
public function getTaxAmount()
{
return $this->taxAmount;
}
public function getAmountDue()
{
return $this->amountDue;
}
}
......@@ -25,6 +25,7 @@
namespace Adyen\Payment\Model;
use Adyen\Payment\Api\AdyenInitiateTerminalApiInterface;
use Adyen\Payment\Helper\ChargedCurrency;
use Adyen\Payment\Model\Ui\AdyenPosCloudConfigProvider;
use Magento\Quote\Model\Quote;
......@@ -60,6 +61,11 @@ class AdyenInitiateTerminalApi implements AdyenInitiateTerminalApiInterface
*/
protected $productMetadata;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
/**
* AdyenInitiateTerminalApi constructor.
*
......@@ -69,6 +75,7 @@ class AdyenInitiateTerminalApi implements AdyenInitiateTerminalApiInterface
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Framework\App\ProductMetadataInterface $productMetadata
* @param array $data
* @param ChargedCurrency $chargedCurrency
* @throws \Adyen\AdyenException
*/
public function __construct(
......@@ -77,12 +84,14 @@ class AdyenInitiateTerminalApi implements AdyenInitiateTerminalApiInterface
\Magento\Checkout\Model\Session $checkoutSession,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\App\ProductMetadataInterface $productMetadata,
ChargedCurrency $chargedCurrency,
array $data = []
) {
$this->adyenHelper = $adyenHelper;
$this->adyenLogger = $adyenLogger;
$this->checkoutSession = $checkoutSession;
$this->productMetadata = $productMetadata;
$this->chargedCurrency = $chargedCurrency;
$this->storeId = $storeManager->getStore()->getId();
// initialize client
......@@ -124,6 +133,7 @@ class AdyenInitiateTerminalApi implements AdyenInitiateTerminalApiInterface
$quote = $this->checkoutSession->getQuote();
$payment = $quote->getPayment();
$adyenAmountCurrency = $this->chargedCurrency->getQuoteAmountCurrency($quote);
$payment->setMethod(AdyenPosCloudConfigProvider::CODE);
$reference = $quote->reserveOrderId()->getReservedOrderId();
......@@ -162,8 +172,8 @@ class AdyenInitiateTerminalApi implements AdyenInitiateTerminalApiInterface
[
'AmountsReq' =>
[
'Currency' => $quote->getCurrency()->getQuoteCurrencyCode(),
'RequestedAmount' => doubleval($quote->getGrandTotal())
'Currency' => $adyenAmountCurrency->getCurrencyCode(),
'RequestedAmount' => doubleval($adyenAmountCurrency->getAmount())
]
]
]
......
......@@ -24,43 +24,54 @@
namespace Adyen\Payment\Model;
use Adyen\Payment\Model\Ui\AdyenCcConfigProvider;
use Adyen\Payment\Api\AdyenOrderPaymentStatusInterface;
use Adyen\Payment\Helper\Data;
use Adyen\Payment\Helper\PaymentResponseHandler;
use Adyen\Payment\Logger\AdyenLogger;
use Magento\Sales\Api\OrderRepositoryInterface;
use Adyen\Payment\Model\Ui\AdyenGooglePayConfigProvider;
use Adyen\Payment\Model\Ui\AdyenHppConfigProvider;
use Adyen\Payment\Model\Ui\AdyenOneclickConfigProvider;
use \Magento\Framework\Exception\NoSuchEntityException;
class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentStatusInterface
class AdyenOrderPaymentStatus implements AdyenOrderPaymentStatusInterface
{
/**
* @var \Magento\Sales\Api\OrderRepositoryInterface
* @var OrderRepositoryInterface
*/
protected $orderRepository;
/**
* @var \Adyen\Payment\Logger\AdyenLogger
* @var AdyenLogger
*/
protected $adyenLogger;
/**
* @var \Adyen\Payment\Helper\Data
* @var Data
*/
protected $adyenHelper;
/**
* @var PaymentResponseHandler
*/
private $paymentResponseHandler;
/**
* AdyenOrderPaymentStatus constructor.
*
* @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param OrderRepositoryInterface $orderRepository
* @param AdyenLogger $adyenLogger
* @param Data $adyenHelper
* @param PaymentResponseHandler $paymentResponseHandler
*/
public function __construct(
\Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Adyen\Payment\Helper\Data $adyenHelper
OrderRepositoryInterface $orderRepository,
AdyenLogger $adyenLogger,
Data $adyenHelper,
PaymentResponseHandler $paymentResponseHandler
) {
$this->orderRepository = $orderRepository;
$this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
$this->paymentResponseHandler = $paymentResponseHandler;
}
/**
......@@ -69,39 +80,23 @@ class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentSta
*/
public function getOrderPaymentStatus($orderId)
{
try {
$order = $this->orderRepository->get($orderId);
$payment = $order->getPayment();
if ($payment->getMethod() === AdyenCcConfigProvider::CODE ||
$payment->getMethod() === AdyenOneclickConfigProvider::CODE
) {
$additionalInformation = $payment->getAdditionalInformation();
$type = null;
if (!empty($additionalInformation['threeDSType'])) {
$type = $additionalInformation['threeDSType'];
}
$token = null;
if (!empty($additionalInformation['threeDS2Token'])) {
$token = $additionalInformation['threeDS2Token'];
}
return $this->adyenHelper->buildThreeDS2ProcessResponseJson($type, $token);
} catch (NoSuchEntityException $exception) {
$this->adyenLogger->addError('Order not found.');
return json_encode(
$this->paymentResponseHandler->formatPaymentResponse(PaymentResponseHandler::ERROR)
);
}
/**
* If payment method result is Pending and action is provided provide component action back to checkout
*/
if ($payment->getMethod() === AdyenHppConfigProvider::CODE) {
$payment = $order->getPayment();
$additionalInformation = $payment->getAdditionalInformation();
if (
!empty($additionalInformation['action']) &&
$additionalInformation['resultCode'] == 'Pending'
) {
return json_encode(['action' => $additionalInformation['action']]);
}
if (empty($additionalInformation['resultCode'])) {
$this->adyenLogger->addInfo('resultCode is empty in the payment\'s additional information');
return json_encode(
$this->paymentResponseHandler->formatPaymentResponse(PaymentResponseHandler::ERROR)
);
}
/**
* If payment method is google pay
......@@ -113,6 +108,10 @@ class AdyenOrderPaymentStatus implements \Adyen\Payment\Api\AdyenOrderPaymentSta
}
}
return true;
return json_encode($this->paymentResponseHandler->formatPaymentResponse(
$additionalInformation['resultCode'],
!empty($additionalInformation['action']) ? $additionalInformation['action'] : null,
!empty($additionalInformation['additionalData']) ? $additionalInformation['additionalData'] : null
));
}
}
......@@ -23,14 +23,16 @@
namespace Adyen\Payment\Model;
use Adyen\Payment\Api\AdyenThreeDS2ProcessInterface;
use Adyen\AdyenException;
use Adyen\Payment\Api\AdyenPaymentDetailsInterface;
use Adyen\Payment\Helper\Data;
use Adyen\Payment\Helper\Vault;
use Adyen\Payment\Helper\PaymentResponseHandler;
use Adyen\Payment\Logger\AdyenLogger;
use Magento\Checkout\Model\Session;
use Magento\Sales\Model\OrderFactory;
use Magento\Framework\Exception\LocalizedException;
use Magento\Sales\Api\OrderRepositoryInterface;
class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
class AdyenPaymentDetails implements AdyenPaymentDetailsInterface
{
/**
* @var Session
......@@ -43,41 +45,41 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
private $adyenHelper;
/**
* @var OrderFactory
* @var AdyenLogger
*/
private $orderFactory;
private $adyenLogger;
/**
* @var AdyenLogger
* @var OrderRepositoryInterface
*/
private $adyenLogger;
private $orderRepository;
/**
* @var Vault
* @var PaymentResponseHandler
*/
private $vaultHelper;
private $paymentResponseHandler;
/**
* AdyenThreeDS2Process constructor.
* AdyenPaymentDetails constructor.
*
* @param Session $checkoutSession
* @param Data $adyenHelper
* @param OrderFactory $orderFactory
* @param AdyenLogger $adyenLogger
* @param Vault $vaultHelper
* @param OrderRepositoryInterface $orderRepository
* @param PaymentResponseHandler $paymentResponseHandler
*/
public function __construct(
Session $checkoutSession,
Data $adyenHelper,
OrderFactory $orderFactory,
AdyenLogger $adyenLogger,
Vault $vaultHelper
OrderRepositoryInterface $orderRepository,
PaymentResponseHandler $paymentResponseHandler
) {
$this->checkoutSession = $checkoutSession;
$this->adyenHelper = $adyenHelper;
$this->orderFactory = $orderFactory;
$this->adyenLogger = $adyenLogger;
$this->vaultHelper = $vaultHelper;
$this->orderRepository = $orderRepository;
$this->paymentResponseHandler = $paymentResponseHandler;
}
/**
......@@ -92,130 +94,58 @@ class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
// Validate JSON that has just been parsed if it was in a valid format
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \Magento\Framework\Exception\LocalizedException(
__('3D secure 2.0 failed because the request was not a valid JSON')
);
throw new LocalizedException(__('Payment details call failed because the request was not a valid JSON'));
}
//Get order from payload and remove orderId from the array
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'));
throw new LocalizedException
(__('Payment details call failed because of a missing order ID'));
} else {
// Create order by order id
$order = $this->orderFactory->create()->load($payload['orderId']);
// don't send orderId to adyen. Improve that orderId and state.data are separated in payload
$order = $this->orderRepository->get($payload['orderId']);
//TODO send state.data from frontend so no unsetting is necessary
unset($payload['orderId']);
}
$payment = $order->getPayment();
// Init payments/details request
$result = [];
if ($paymentData = $payment->getAdditionalInformation("adyenPaymentData")) {
// Add payment data into the request object
$request = [
"paymentData" => $paymentData
];
$payload["paymentData"] = $paymentData;
// unset payment data from additional information
$payment->unsAdditionalInformation("adyenPaymentData");
} else {
$this->adyenLogger->error("3D secure 2.0 failed, payment data not found");
throw new \Magento\Framework\Exception\LocalizedException(
__('3D secure 2.0 failed, payment data not found')
);
}
// Depends on the component's response we send a fingerprint or the challenge result
if (!empty($payload['details']['threeds2.fingerprint'])) {
$request['details']['threeds2.fingerprint'] = $payload['details']['threeds2.fingerprint'];
} elseif (!empty($payload['details']['threeds2.challengeResult'])) {
$request['details']['threeds2.challengeResult'] = $payload['details']['threeds2.challengeResult'];
} elseif (!empty($payload)) {
$request = $payload;
$message = "Payment details call failed, payment data not found";
$this->adyenLogger->error($message);
throw new LocalizedException(__($message));
}
// Send the request
try {
$client = $this->adyenHelper->initializeAdyenClient($order->getStoreId());
$service = $this->adyenHelper->createAdyenCheckoutService($client);
$result = $service->paymentsDetails($request);
} catch (\Adyen\AdyenException $e) {
$this->adyenLogger->error("3D secure 2.0 failed" . $e->getMessage());
throw new \Magento\Framework\Exception\LocalizedException(__('3D secure 2.0 failed'));
$paymentDetails = $service->paymentsDetails($payload);
} catch (AdyenException $e) {
$this->adyenLogger->error("Payment details call failed: " . $e->getMessage());
throw new LocalizedException(__('Payment details call failed'));
}
// Check if result is challenge shopper, if yes return the token
if (!empty($result['resultCode']) &&
$result['resultCode'] === 'ChallengeShopper' &&
!empty($result['authentication']['threeds2.challengeToken'])
) {
return $this->adyenHelper->buildThreeDS2ProcessResponseJson(
$result['resultCode'],
$result['authentication']['threeds2.challengeToken']
);
}
//Fallback for 3DS in case of redirect
if (!empty($result['resultCode']) &&
$result['resultCode'] === 'RedirectShopper'
) {
$response['type'] = $result['resultCode'];
$response['action']= $result['action'];
return json_encode($response);
}
// Save the payments response because we are going to need it during the place order flow
$payment->setAdditionalInformation("paymentsResponse", $result);
if (!empty($result['additionalData'])) {
$this->vaultHelper->saveRecurringDetails($payment, $result['additionalData']);
}
// To actually save the additional info changes into the quote
$order->save();
$response = [];
if ($result['resultCode'] != 'Authorised') {
// Handle response
if (!$this->paymentResponseHandler->handlePaymentResponse($paymentDetails, $payment, $order)) {
$this->checkoutSession->restoreQuote();
// Always cancel the order if the paymenth has failed
if (!$order->canCancel()) {
$order->setState(\Magento\Sales\Model\Order::STATE_NEW);
throw new LocalizedException(__('The payment is REFUSED.'));
}
$order->cancel()->save();
$this->adyenLogger->error(
sprintf("Payment details call failed for action or 3ds2 payment method, resultcode is %s Raw API responds: %s",
$result['resultCode'],
print_r($result, true)
));
throw new \Magento\Framework\Exception\LocalizedException(__('The payment is REFUSED.'));
$action = null;
if (!empty($paymentDetails['action'])) {
$action = $paymentDetails['action'];
}
$response['result'] = $result['resultCode'];
return json_encode($response);
$additionalData = null;
if (!empty($paymentDetails['additionalData'])) {
$additionalData = $paymentDetails['additionalData'];
}
/**
* Get order object
*
* @return \Magento\Sales\Model\Order
* @deprecated Will be removed in 7.0.0
*/
protected function getOrder()
{
$incrementId = $this->checkoutSession->getLastRealOrderId();
$order = $this->orderFactory->create()->loadByIncrementId($incrementId);
return $order;
return json_encode($this->paymentResponseHandler->formatPaymentResponse($paymentDetails['resultCode'], $action, $additionalData));
}
}
<?xml version="1.0"?>
<!--
<?php
/**
* ######
* ######
......@@ -16,15 +15,23 @@
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
-->
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
<container name="root">
<block class="Adyen\Payment\Block\Redirect\Redirect" name="adyen-redirect-form"
template="redirect/redirect.phtml" cacheable="false"/>
</container>
</layout>
namespace Adyen\Payment\Model\Config\Source;
use Magento\Framework\Data\OptionSourceInterface;
class ChargedCurrency implements OptionSourceInterface
{
public function toOptionArray()
{
return array(
['value' => 'display', 'label' => 'Display currency'],
['value' => 'base', 'label' => 'Global/Website currency']
);
}
}
......@@ -23,12 +23,14 @@
namespace Adyen\Payment\Model;
use Adyen\Payment\Helper\ChargedCurrency;
use Adyen\Payment\Helper\Vault;
use Adyen\Payment\Model\Ui\AdyenCcConfigProvider;
use Adyen\Payment\Model\Ui\AdyenHppConfigProvider;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Framework\Webapi\Exception;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Email\Sender\OrderSender;
use Magento\Sales\Model\Order\Email\Sender\InvoiceSender;
use Magento\Framework\App\Area;
......@@ -159,6 +161,21 @@ class Cron
*/
protected $_value;
/**
* @var
*/
protected $_currency;
/**
* @var
*/
protected $orderAmount;
/**
* @var
*/
protected $orderCurrency;
/**
* @var
*/
......@@ -269,6 +286,11 @@ class Cron
*/
protected $encryptor;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
/**
* Cron constructor.
*
......@@ -300,6 +322,7 @@ class Cron
* @param PaymentTokenFactoryInterface $paymentTokenFactory
* @param PaymentTokenRepositoryInterface $paymentTokenRepository
* @param EncryptorInterface $encryptor
* @param ChargedCurrency $chargedCurrency
*/
public function __construct(
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
......@@ -329,7 +352,8 @@ class Cron
PaymentTokenManagement $paymentTokenManagement,
PaymentTokenFactoryInterface $paymentTokenFactory,
PaymentTokenRepositoryInterface $paymentTokenRepository,
EncryptorInterface $encryptor
EncryptorInterface $encryptor,
ChargedCurrency $chargedCurrency
) {
$this->_scopeConfig = $scopeConfig;
$this->_adyenLogger = $adyenLogger;
......@@ -359,6 +383,7 @@ class Cron
$this->paymentTokenFactory = $paymentTokenFactory;
$this->paymentTokenRepository = $paymentTokenRepository;
$this->encryptor = $encryptor;
$this->chargedCurrency = $chargedCurrency;
}
/**
......@@ -671,6 +696,7 @@ class Cron
$this->_paymentMethod = $notification->getPaymentMethod();
$this->_reason = $notification->getReason();
$this->_value = $notification->getAmountValue();
$this->_currency = $notification->getAmountCurrency();
$this->_live = $notification->getLive();
$additionalData = !empty($notification->getAdditionalData()) ? $this->serializer->unserialize(
......@@ -728,6 +754,20 @@ class Cron
$this->ratepayDescriptor = $ratepayDescriptor;
}
}
$this->declareOrderVariables();
}
/**
* Declare private variables with order charged amount and currency
*
* @return void
*/
private function declareOrderVariables()
{
$orderAmountCurrency = $this->chargedCurrency->getOrderAmountCurrency($this->_order, false);
$this->orderAmount = $orderAmountCurrency->getAmount();
$this->orderCurrency = $orderAmountCurrency->getCurrencyCode();
}
/**
......@@ -757,17 +797,15 @@ class Cron
$success = (!empty($this->_reason)) ? "$successResult <br />reason:$this->_reason" : $successResult;
if ($this->_eventCode == Notification::REFUND || $this->_eventCode == Notification::CAPTURE) {
$currency = $this->_order->getOrderCurrencyCode();
// check if it is a full or partial refund
$amount = $this->_value;
$orderAmount = (int)$this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $currency);
$formattedOrderAmount = (int)$this->_adyenHelper->formatAmount($this->orderAmount, $this->orderCurrency);
$this->_adyenLogger->addAdyenNotificationCronjob(
'amount notification:' . $amount . ' amount order:' . $orderAmount
'amount notification:' . $amount . ' amount order:' . $formattedOrderAmount
);
if ($amount == $orderAmount) {
if ($amount == $formattedOrderAmount) {
$this->_order->setData(
'adyen_notification_event_code',
$this->_eventCode . " : " . strtoupper($successResult)
......@@ -1417,9 +1455,8 @@ class Cron
->getFirstItem();
if ($orderPayment->getId() > 0) {
$currency = $this->_order->getOrderCurrencyCode();
$amountRefunded = $amountRefunded = $orderPayment->getTotalRefunded() +
$this->_adyenHelper->originalAmount($this->_value, $currency);
$amountRefunded = $orderPayment->getTotalRefunded() +
$this->_adyenHelper->originalAmount($this->_value, $this->_currency);
$orderPayment->setUpdatedAt(new \DateTime());
$orderPayment->setTotalRefunded($amountRefunded);
$orderPayment->save();
......@@ -1440,8 +1477,7 @@ class Cron
// refund is done through adyen backoffice so create a credit memo
$order = $this->_order;
if ($order->canCreditmemo()) {
$currency = $this->_order->getOrderCurrencyCode();
$amount = $this->_adyenHelper->originalAmount($this->_value, $currency);
$amount = $this->_adyenHelper->originalAmount($this->_value, $this->_currency);
$order->getPayment()->registerRefundNotification($amount);
$this->_adyenLogger->addAdyenNotificationCronjob('Created credit memo for order');
......@@ -1615,8 +1651,7 @@ class Cron
}
// validate if amount is total amount
$orderCurrencyCode = $this->_order->getOrderCurrencyCode();
$amount = $this->_adyenHelper->originalAmount($this->_value, $orderCurrencyCode);
$amount = $this->_adyenHelper->originalAmount($this->_value, $this->_currency);
try {
// add to order payment
......@@ -1640,7 +1675,7 @@ class Cron
);
}
if ($this->_isTotalAmount($paymentObj->getEntityId(), $orderCurrencyCode)) {
if ($this->_isTotalAmount($paymentObj->getEntityId(), $this->orderCurrency)) {
$this->_createInvoice();
} else {
$this->_adyenLogger->addAdyenNotificationCronjob(
......@@ -1877,7 +1912,10 @@ class Cron
);
// get total amount of the order
$grandTotal = (int)$this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $orderCurrencyCode);
$grandTotal = (int)$this->_adyenHelper->formatAmount(
$this->orderAmount,
$this->orderCurrency
);
// check if total amount of the order is authorised
$res = $this->_adyenOrderPaymentCollectionFactory
......@@ -1886,16 +1924,16 @@ class Cron
if ($res && isset($res[0]) && is_array($res[0])) {
$amount = $res[0]['total_amount'];
$orderAmount = $this->_adyenHelper->formatAmount($amount, $orderCurrencyCode);
$formattedOrderAmount = $this->_adyenHelper->formatAmount($amount, $orderCurrencyCode);
$this->_adyenLogger->addAdyenNotificationCronjob(
sprintf(
'The grandtotal amount is %s and the total order amount that is authorised is: %s',
$grandTotal,
$orderAmount
$formattedOrderAmount
)
);
if ($grandTotal == $orderAmount) {
if ($grandTotal == $formattedOrderAmount) {
$this->_adyenLogger->addAdyenNotificationCronjob('AUTHORISATION has the full amount');
return true;
} else {
......@@ -2001,14 +2039,13 @@ class Cron
$this->_adyenLogger->addAdyenNotificationCronjob('Set order to authorised');
// if full amount is captured create invoice
$currency = $this->_order->getOrderCurrencyCode();
$amount = $this->_value;
$orderAmount = (int)$this->_adyenHelper->formatAmount($this->_order->getGrandTotal(), $currency);
$formattedOrderAmount = (int)$this->_adyenHelper->formatAmount($this->orderAmount, $this->orderCurrency);
// create invoice for the capture notification if you are on manual capture
if ($createInvoice == true && $amount == $orderAmount) {
if ($createInvoice && $amount == $formattedOrderAmount) {
$this->_adyenLogger->addAdyenNotificationCronjob(
'amount notification:' . $amount . ' amount order:' . $orderAmount
'amount notification:' . $amount . ' amount order:' . $formattedOrderAmount
);
$this->_createInvoice();
}
......
......@@ -116,7 +116,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
'vaultCode' => self::CC_VAULT_CODE,
'isActive' => true,
'redirectUrl' => $this->_urlBuilder->getUrl(
'adyen/process/redirect/',
'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()]
)
]
......
......@@ -73,6 +73,9 @@ class AdyenGenericConfigProvider implements ConfigProviderInterface
$config['payment']['adyen']['checkoutEnvironment'] = $this->adyenHelper->getCheckoutEnvironment(
$this->storeManager->getStore()->getId()
);
$config['payment']['adyen']['locale'] = $this->adyenHelper->getStoreLocale(
$this->storeManager->getStore()->getId()
);
return $config;
}
......
......@@ -24,6 +24,7 @@
namespace Adyen\Payment\Model\Ui;
use Adyen\Payment\Helper\ChargedCurrency;
use Magento\Checkout\Model\ConfigProviderInterface;
use Magento\Payment\Helper\Data as PaymentHelper;
......@@ -60,6 +61,11 @@ class AdyenGooglePayConfigProvider implements ConfigProviderInterface
*/
private $storeManager;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
/**
* AdyenGooglePayConfigProvider constructor.
*
......@@ -67,6 +73,7 @@ class AdyenGooglePayConfigProvider implements ConfigProviderInterface
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\App\RequestInterface $request
* @param \Magento\Framework\UrlInterface $urlBuilder
* @param ChargedCurrency $chargedCurrency
*/
public function __construct(
PaymentHelper $paymentHelper,
......@@ -74,7 +81,8 @@ class AdyenGooglePayConfigProvider implements ConfigProviderInterface
\Magento\Framework\App\RequestInterface $request,
\Magento\Framework\UrlInterface $urlBuilder,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Checkout\Model\Session $checkoutSession
\Magento\Checkout\Model\Session $checkoutSession,
ChargedCurrency $chargedCurrency
) {
$this->paymentHelper = $paymentHelper;
$this->adyenHelper = $adyenHelper;
......@@ -82,6 +90,7 @@ class AdyenGooglePayConfigProvider implements ConfigProviderInterface
$this->urlBuilder = $urlBuilder;
$this->storeManager = $storeManager;
$this->checkoutSession = $checkoutSession;
$this->chargedCurrency = $chargedCurrency;
}
/**
......@@ -97,7 +106,7 @@ class AdyenGooglePayConfigProvider implements ConfigProviderInterface
self::CODE => [
'isActive' => true,
'redirectUrl' => $this->urlBuilder->getUrl(
'adyen/process/redirect/',
'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()]
),
'successUrl' => $this->urlBuilder->getUrl(
......@@ -123,7 +132,7 @@ class AdyenGooglePayConfigProvider implements ConfigProviderInterface
);
$quote = $this->checkoutSession->getQuote();
$currency = $quote->getCurrency();
$currency = $this->chargedCurrency->getQuoteAmountCurrency($quote)->getCurrencyCode();
$adyenGooglePayConfig['format'] = $this->adyenHelper->decimalNumbers($currency);
$adyenGooglePayConfig['merchantIdentifier'] = $this->adyenHelper->getAdyenGooglePayMerchantIdentifier($this->storeManager->getStore()->getId());
......
......@@ -117,7 +117,7 @@ class AdyenHppConfigProvider implements ConfigProviderInterface
self::CODE => [
'isActive' => true,
'redirectUrl' => $this->urlBuilder->getUrl(
'adyen/process/redirect',
'checkout/onepage/success',
['_secure' => $this->getRequest()->isSecure()]
)
]
......
......@@ -23,6 +23,7 @@
namespace Adyen\Payment\Model\Ui;
use Adyen\Payment\Helper\ChargedCurrency;
use Magento\Checkout\Model\ConfigProviderInterface;
use Magento\Payment\Helper\Data as PaymentHelper;
......@@ -70,6 +71,11 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
*/
private $ccConfig;
/**
* @var ChargedCurrency
*/
private $chargedCurrency;
/**
* AdyenOneclickConfigProvider constructor.
*
......@@ -80,6 +86,7 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Framework\UrlInterface $urlBuilder
* @param \Magento\Payment\Model\CcConfig $ccConfig
* @param ChargedCurrency $chargedCurrency
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
......@@ -88,7 +95,8 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
\Magento\Checkout\Model\Session $session,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\UrlInterface $urlBuilder,
\Magento\Payment\Model\CcConfig $ccConfig
\Magento\Payment\Model\CcConfig $ccConfig,
ChargedCurrency $chargedCurrency
) {
$this->_adyenHelper = $adyenHelper;
$this->_request = $request;
......@@ -97,6 +105,7 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
$this->_storeManager = $storeManager;
$this->_urlBuilder = $urlBuilder;
$this->ccConfig = $ccConfig;
$this->chargedCurrency = $chargedCurrency;
}
/**
......@@ -112,7 +121,7 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
self::CODE => [
'isActive' => true,
'redirectUrl' => $this->_urlBuilder->getUrl(
'adyen/process/redirect/',
'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()]
)
]
......@@ -178,7 +187,7 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
if ($this->_customerSession->isLoggedIn()) {
$customerId = $this->_customerSession->getCustomerId();
$storeId = $this->_storeManager->getStore()->getId();
$grandTotal = $this->_getQuote()->getGrandTotal();
$grandTotal = $this->chargedCurrency->getQuoteAmountCurrency($this->_getQuote())->getAmount();
$recurringType = $this->_getRecurringContractType();
$billingAgreements = $this->_adyenHelper->getOneClickPaymentMethods(
......
......@@ -84,7 +84,7 @@ class AdyenPayByMailConfigProvider implements ConfigProviderInterface
self::CODE => [
'isActive' => true,
'redirectUrl' => $this->_urlBuilder->getUrl(
'adyen/process/redirect',
'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()]
)
]
......
......@@ -43,9 +43,9 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface
protected $urlBuilder;
/**
* @var \Adyen\Payment\Helper\PaymentMethods
* @var \Adyen\Payment\Helper\ConnectedTerminals
*/
protected $paymentMethodsHelper;
protected $connectedTerminalsHelper;
/**
* @var \Adyen\Payment\Helper\Data
......@@ -62,20 +62,20 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface
*
* @param \Magento\Framework\App\RequestInterface $request
* @param \Magento\Framework\UrlInterface $urlBuilder
* @param \Adyen\Payment\Helper\PaymentMethods $paymentMethodsHelper
* @param \Adyen\Payment\Helper\ConnectedTerminals $connectedTerminalsHelper
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\Serialize\SerializerInterface $serializer
*/
public function __construct(
\Magento\Framework\App\RequestInterface $request,
\Magento\Framework\UrlInterface $urlBuilder,
\Adyen\Payment\Helper\PaymentMethods $paymentMethodsHelper,
\Adyen\Payment\Helper\ConnectedTerminals $connectedTerminalsHelper,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Serialize\SerializerInterface $serializer
) {
$this->request = $request;
$this->urlBuilder = $urlBuilder;
$this->paymentMethodsHelper = $paymentMethodsHelper;
$this->connectedTerminalsHelper = $connectedTerminalsHelper;
$this->adyenHelper = $adyenHelper;
$this->serializer = $serializer;
}
......@@ -137,7 +137,7 @@ class AdyenPosCloudConfigProvider implements ConfigProviderInterface
*/
protected function getConnectedTerminals()
{
$connectedTerminals = $this->paymentMethodsHelper->getConnectedTerminals();
$connectedTerminals = $this->connectedTerminalsHelper->getConnectedTerminals();
if (!empty($connectedTerminals['uniqueTerminalIds'])) {
return $connectedTerminals['uniqueTerminalIds'];
......
......@@ -15,7 +15,7 @@
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
......@@ -26,77 +26,98 @@ namespace Adyen\Payment\Observer;
use Magento\Framework\Event\Observer;
use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface;
use \Adyen\Service\Validator\CheckoutStateDataValidator;
use \Adyen\Service\Validator\DataArrayValidator;
class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
{
const CC_TYPE = 'cc_type';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
const STORE_CC = 'store_cc';
const ENCRYPTED_CREDIT_CARD_NUMBER = 'number';
const ENCRYPTED_SECURITY_CODE = 'cvc';
const ENCRYPTED_EXPIRY_MONTH = 'expiryMonth';
const ENCRYPTED_EXPIRY_YEAR = 'expiryYear';
const HOLDER_NAME = 'holderName';
const VARIANT = 'variant';
const JAVA_ENABLED = 'java_enabled';
const SCREEN_COLOR_DEPTH = 'screen_color_depth';
const SCREEN_WIDTH = 'screen_width';
const SCREEN_HEIGHT = 'screen_height';
const TIMEZONE_OFFSET = 'timezone_offset';
const LANGUAGE = 'language';
const GUEST_EMAIL = 'guestEmail';
const COMBO_CARD_TYPE = 'combo_card_type';
const STATE_DATA = 'stateData';
const STORE_PAYMENT_METHOD = 'storePaymentMethod';
/**
* Approved root level keys from additional data array
*
* @var array
*/
protected $additionalInformationList = [
self::CC_TYPE,
self::NUMBER_OF_INSTALLMENTS,
self::STORE_CC,
self::ENCRYPTED_CREDIT_CARD_NUMBER,
self::ENCRYPTED_SECURITY_CODE,
self::ENCRYPTED_EXPIRY_MONTH,
self::ENCRYPTED_EXPIRY_YEAR,
self::HOLDER_NAME,
self::VARIANT,
self::JAVA_ENABLED,
self::SCREEN_COLOR_DEPTH,
self::SCREEN_WIDTH,
self::SCREEN_HEIGHT,
self::TIMEZONE_OFFSET,
self::LANGUAGE,
private static $approvedAdditionalDataKeys = [
self::STATE_DATA,
self::GUEST_EMAIL,
self::COMBO_CARD_TYPE
self::COMBO_CARD_TYPE,
self::NUMBER_OF_INSTALLMENTS
];
/**
* @var CheckoutStateDataValidator
*/
protected $checkoutStateDataValidator;
/**
* AdyenCcDataAssignObserver constructor.
*
* @param CheckoutStateDataValidator $checkoutStateDataValidator
*/
public function __construct(
CheckoutStateDataValidator $checkoutStateDataValidator
) {
$this->checkoutStateDataValidator = $checkoutStateDataValidator;
}
/**
* @param Observer $observer
* @return void
*/
public function execute(Observer $observer)
{
// Get request fields
$data = $this->readDataArgument($observer);
// Get additional data array
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
if (!is_array($additionalData)) {
return;
}
$paymentInfo = $this->readPaymentModelArgument($observer);
// Get a validated additional data array
$additionalData = DataArrayValidator::getArrayOnlyWithApprovedKeys(
$additionalData,
self::$approvedAdditionalDataKeys
);
// set ccType
if (!empty($additionalData['cc_type'])) {
$paymentInfo->setCcType($additionalData['cc_type']);
// json decode state data
$stateData = [];
if (!empty($additionalData[self::STATE_DATA])) {
$stateData = json_decode($additionalData[self::STATE_DATA], true);
}
foreach ($this->additionalInformationList as $additionalInformationKey) {
if (isset($additionalData[$additionalInformationKey])) {
$paymentInfo->setAdditionalInformation(
$additionalInformationKey,
$additionalData[$additionalInformationKey]
// Get validated state data array
if (!empty($stateData)) {
$stateData = $this->checkoutStateDataValidator->getValidatedAdditionalData(
$stateData
);
}
// Replace state data with the decoded and validated state data
$additionalData[self::STATE_DATA] = $stateData;
// Set additional data in the payment
$paymentInfo = $this->readPaymentModelArgument($observer);
foreach ($additionalData as $key => $data) {
$paymentInfo->setAdditionalInformation($key, $data);
}
// set ccType
if (!empty($additionalData[self::CC_TYPE])) {
$paymentInfo->setCcType($additionalData[self::CC_TYPE]);
}
// set storeCc
if (!empty($stateData[self::STORE_PAYMENT_METHOD])) {
$paymentInfo->setAdditionalInformation(self::STORE_CC, $stateData[self::STORE_PAYMENT_METHOD]);
}
}
}
......@@ -15,7 +15,7 @@
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* Copyright (c) 2020 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
......@@ -23,6 +23,8 @@
namespace Adyen\Payment\Observer;
use Adyen\Service\Validator\CheckoutStateDataValidator;
use Adyen\Service\Validator\DataArrayValidator;
use Magento\Framework\Event\Observer;
use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface;
......@@ -30,62 +32,84 @@ use Magento\Quote\Api\Data\PaymentInterface;
class AdyenHppDataAssignObserver extends AbstractDataAssignObserver
{
const BRAND_CODE = 'brand_code';
const ISSUER_ID = 'issuer_id';
const GENDER = 'gender';
const DOB = 'dob';
const TELEPHONE = 'telephone';
const DF_VALUE = 'df_value';
const SSN = 'ssn';
const OWNER_NAME = 'ownerName';
const BANK_ACCOUNT_OWNER_NAME = 'bankAccountOwnerName';
const IBAN_NUMBER = 'ibanNumber';
const BANK_ACCOUNT_NUMBER = 'bankAccountNumber';
const BANK_LOCATIONID = 'bankLocationId';
const GUEST_EMAIL = 'guestEmail';
const STATE_DATA = 'stateData';
/**
* Approved root level keys from additional data array
*
* @var array
*/
protected $additionalInformationList = [
private static $approvedAdditionalDataKeys = [
self::BRAND_CODE,
self::ISSUER_ID,
self::GENDER,
self::DOB,
self::TELEPHONE,
self::DF_VALUE,
self::SSN,
self::OWNER_NAME,
self::BANK_ACCOUNT_OWNER_NAME,
self::IBAN_NUMBER,
self::BANK_ACCOUNT_NUMBER,
self::BANK_LOCATIONID
self::GUEST_EMAIL,
self::STATE_DATA
];
/**
* @var CheckoutStateDataValidator
*/
protected $checkoutStateDataValidator;
/**
* AdyenHppDataAssignObserver constructor.
*
* @param CheckoutStateDataValidator $checkoutStateDataValidator
*/
public function __construct(
CheckoutStateDataValidator $checkoutStateDataValidator
) {
$this->checkoutStateDataValidator = $checkoutStateDataValidator;
}
/**
* @param Observer $observer
* @return void
*/
public function execute(Observer $observer)
{
// Get request fields
$data = $this->readDataArgument($observer);
// Get additional data array
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
if (!is_array($additionalData)) {
return;
}
$paymentInfo = $this->readPaymentModelArgument($observer);
// Get a validated additional data array
$additionalData = DataArrayValidator::getArrayOnlyWithApprovedKeys(
$additionalData,
self::$approvedAdditionalDataKeys
);
if (isset($additionalData[self::BRAND_CODE])) {
$paymentInfo->setCcType($additionalData[self::BRAND_CODE]);
// json decode state data
$stateData = [];
if (!empty($additionalData[self::STATE_DATA])) {
$stateData = json_decode($additionalData[self::STATE_DATA], true);
}
foreach ($this->additionalInformationList as $additionalInformationKey) {
if (isset($additionalData[$additionalInformationKey])) {
$paymentInfo->setAdditionalInformation(
$additionalInformationKey,
$additionalData[$additionalInformationKey]
// Get validated state data array
if (!empty($stateData)) {
$stateData = $this->checkoutStateDataValidator->getValidatedAdditionalData(
$stateData
);
}
// Replace state data with the decoded and validated state data
$additionalData[self::STATE_DATA] = $stateData;
// Set additional data in the payment
$paymentInfo = $this->readPaymentModelArgument($observer);
foreach ($additionalData as $key => $data) {
$paymentInfo->setAdditionalInformation($key, $data);
}
// set ccType
if (!empty($additionalData[self::BRAND_CODE])) {
$paymentInfo->setCcType($additionalData[self::BRAND_CODE]);
}
}
}
......@@ -23,39 +23,34 @@
namespace Adyen\Payment\Observer;
use Adyen\Service\Validator\CheckoutStateDataValidator;
use Adyen\Service\Validator\DataArrayValidator;
use Magento\Framework\Event\Observer;
use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface;
class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
{
const RECURRING_DETAIL_REFERENCE = 'recurring_detail_reference';
const ENCRYPTED_SECURITY_CODE = 'cvc';
const CC_TYPE = 'cc_type';
const BRAND = 'brand';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
const VARIANT = 'variant';
const JAVA_ENABLED = 'java_enabled';
const SCREEN_COLOR_DEPTH = 'screen_color_depth';
const SCREEN_WIDTH = 'screen_width';
const SCREEN_HEIGHT = 'screen_height';
const TIMEZONE_OFFSET = 'timezone_offset';
const LANGUAGE = 'language';
const STATE_DATA = 'stateData';
/**
* Approved root level keys from additional data array
*
* @var array
*/
protected $additionalInformationList = [
self::RECURRING_DETAIL_REFERENCE,
self::ENCRYPTED_SECURITY_CODE,
private static $approvedAdditionalDataKeys = [
self::STATE_DATA,
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
*/
......@@ -72,9 +67,11 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
* @param \Adyen\Payment\Helper\Data $adyenHelper
*/
public function __construct(
CheckoutStateDataValidator $checkoutStateDataValidator,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Model\Context $context
) {
$this->checkoutStateDataValidator = $checkoutStateDataValidator;
$this->adyenHelper = $adyenHelper;
$this->appState = $context->getAppState();
}
......@@ -85,27 +82,47 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
*/
public function execute(Observer $observer)
{
// Get request fields
$data = $this->readDataArgument($observer);
// Get additional data array
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
if (!is_array($additionalData)) {
return;
}
$paymentInfo = $this->readPaymentModelArgument($observer);
// Get a validated additional data array
$additionalData = DataArrayValidator::getArrayOnlyWithApprovedKeys(
$additionalData,
self::$approvedAdditionalDataKeys
);
// set ccType
$variant = $additionalData['variant'];
$ccType = $this->adyenHelper->getMagentoCreditCartType($variant);
$paymentInfo->setCcType($ccType);
// json decode state data
$stateData = [];
if (!empty($additionalData[self::STATE_DATA])) {
$stateData = json_decode($additionalData[self::STATE_DATA], true);
}
foreach ($this->additionalInformationList as $additionalInformationKey) {
if (isset($additionalData[$additionalInformationKey])) {
$paymentInfo->setAdditionalInformation(
$additionalInformationKey,
$additionalData[$additionalInformationKey]
// Get validated state data array
if (!empty($stateData)) {
$stateData = $this->checkoutStateDataValidator->getValidatedAdditionalData(
$stateData
);
}
// 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
......@@ -115,11 +132,6 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
} else {
$paymentInfo->setAdditionalInformation('customer_interaction', false);
}
// set ccType
$variant = $additionalData['variant'];
$ccType = $this->adyenHelper->getMagentoCreditCartType($variant);
$paymentInfo->setAdditionalInformation('cc_type', $ccType);
}
/**
......
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment Module
*
* Copyright (c) 2020 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\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Adyen\Payment\Helper\Config;
class AdyenSalesOrderChargedCurrencyObserver implements ObserverInterface
{
/**
* @var Config $config
*/
private $config;
public function __construct(
Config $config
) {
$this->config = $config;
}
public function execute(Observer $observer)
{
/** @var \Magento\Sales\Model\Order $order */
$order = $observer->getEvent()->getOrder();
$paymentMethod = $order->getPayment()->getMethod();
if (strpos($paymentMethod, 'adyen_') !== false) {
$order->setAdyenChargedCurrency($this->config->getChargedCurrency($order->getStoreId()));
}
}
}
......@@ -71,6 +71,10 @@ class UpgradeSchema implements UpgradeSchemaInterface
$this->updateSchemaVersion540($setup);
}
if (version_compare($context->getVersion(), '7.0.0', '<')) {
$this->updateSchemaVersion700($setup);
}
$setup->endSetup();
}
......@@ -402,4 +406,33 @@ class UpgradeSchema implements UpgradeSchemaInterface
$adyenNotificationErrorMessageColumn
);
}
/**
* Upgrade to 7.0.0
*
* New sales_order column for the currency charged based on the Adyen config option (base or display)
*
* @param SchemaSetupInterface $setup
* @return void
*/
public function updateSchemaVersion700(SchemaSetupInterface $setup)
{
$connection = $setup->getConnection();
$tableName = $setup->getTable('sales_order');
$adyenChargedCurrencyColumn = [
'type' => Table::TYPE_TEXT,
'length' => 255,
'nullable' => true,
'default' => null,
'comment' => 'Charged currency depending on Adyen config option',
'after' => 'adyen_notification_event_code_success'
];
$connection->addColumn(
$tableName,
'adyen_charged_currency',
$adyenChargedCurrencyColumn
);
}
}
......@@ -50,6 +50,7 @@ class AdyenInitiateTerminalApiTest extends \PHPUnit\Framework\TestCase
$checkoutSession = $this->getSimpleMock(\Magento\Checkout\Model\Session::class);
$storeManager = $this->getSimpleMock(\Magento\Store\Model\StoreManagerInterface::class);
$productMetadata = $this->getSimpleMock(\Magento\Framework\App\ProductMetadataInterface::class);
$chargedCurrency = $this->getSimpleMock(\Adyen\Payment\Helper\ChargedCurrency::class);
$store = $this->getSimpleMock(\Magento\Store\Api\Data\StoreInterface::class);
$storeManager->method('getStore')
......@@ -82,7 +83,8 @@ class AdyenInitiateTerminalApiTest extends \PHPUnit\Framework\TestCase
$adyenLogger,
$checkoutSession,
$storeManager,
$productMetadata
$productMetadata,
$chargedCurrency
);
}
......
......@@ -2,7 +2,7 @@
"name": "adyen/module-payment",
"description": "Official Magento2 Plugin to connect to Payment Service Provider Adyen.",
"type": "magento2-module",
"version": "6.6.8",
"version": "7.0.0-rc.1",
"license": [
"OSL-3.0",
"AFL-3.0"
......@@ -14,10 +14,11 @@
}
],
"require": {
"adyen/php-api-library": "^7.0",
"adyen/php-api-library": "^8",
"magento/framework": ">=101.0.8 <102 || >=102.0.1",
"magento/module-vault": "101.*",
"magento/module-paypal": ">=100.2.6"
"magento/module-paypal": ">=100.2.6",
"ext-json": "*"
},
"require-dev": {
"phpunit/phpunit": "~6.5.0",
......
......@@ -69,7 +69,12 @@
<comment><![CDATA[Provide the unique live url prefix: <strong>[random]-[company name]</strong> from the "API URLs and Response" menu in the Adyen Customer Area. For more information, please check <a href="https://docs.adyen.com/developers/development-resources/live-endpoints#checkoutendpoints"> our documentation</a>.]]></comment>
<config_path>payment/adyen_abstract/live_endpoint_url_prefix</config_path>
</field>
<field id="charged_currency" translate="label" type="hidden" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Charged currency</label>
<comment><![CDATA[Currency used for Adyen payment processing. This setting is hidden to ensure processing of payments in the expected currency (Display by default), see <a target="_blank" href="https://docs.adyen.com/developers/plugins/magento-2/set-up-the-plugin-in-magento#selecting-charged-currency">Adyen docs</a> for more information.]]></comment>
<source_model>Adyen\Payment\Model\Config\Source\ChargedCurrency</source_model>
<config_path>payment/adyen_abstract/charged_currency</config_path>
</field>
<field id="capture_mode" translate="label" type="select" sortOrder="90" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Capture Delay</label>
<tooltip>Immediate is the default. Set to manual if you want to perform the capture of funds manually later (only affects credit cards and a few alternative payment methods). You need to change this setting as well in Adyen Customer Area => Settings => Merchant Settings => Capture Delay. If you have selected a capture delay of a couple of days in Adyen keep it here on immediate</tooltip>
......
......@@ -39,6 +39,7 @@
<enable_recurring>0</enable_recurring>
<group>adyen</group>
<notifications_can_cancel>1</notifications_can_cancel>
<charged_currency>display</charged_currency>
</adyen_abstract>
<adyen_cc>
<active>1</active>
......
......@@ -367,7 +367,7 @@
<argument name="transferFactory" xsi:type="object">Adyen\Payment\Gateway\Http\TransferFactory</argument>
<argument name="client" xsi:type="object">Adyen\Payment\Gateway\Http\Client\TransactionAuthorization
</argument>
<argument name="validator" xsi:type="object">GeneralResponseValidator</argument>
<argument name="validator" xsi:type="object">CheckoutResponseValidator</argument>
<argument name="handler" xsi:type="object">AdyenPaymentCcVaultResponseHandlerComposite</argument>
</arguments>
</virtualType>
......@@ -557,9 +557,8 @@
<item name="payment" xsi:type="string">Adyen\Payment\Gateway\Request\PaymentDataBuilder</item>
<item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item>
<item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item>
<item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcAuthorizationDataBuilder</item>
<item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CheckoutDataBuilder</item>
<item name="vault" xsi:type="string">Adyen\Payment\Gateway\Request\VaultDataBuilder</item>
<item name="threeds2" xsi:type="string">Adyen\Payment\Gateway\Request\ThreeDS2DataBuilder</item>
</argument>
</arguments>
</virtualType>
......@@ -606,7 +605,7 @@
<item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item>
<item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item>
<item name="oneclick" xsi:type="string">Adyen\Payment\Gateway\Request\OneclickAuthorizationDataBuilder</item>
<item name="threeds2" xsi:type="string">Adyen\Payment\Gateway\Request\ThreeDS2DataBuilder</item>
<item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CheckoutDataBuilder</item>
</argument>
</arguments>
</virtualType>
......@@ -885,14 +884,6 @@
</arguments>
</virtualType>
<!--General Response validator-->
<virtualType name="GeneralResponseValidator" type="Adyen\Payment\Gateway\Validator\GeneralResponseValidator">
<arguments>
<argument name="loggerInterface" xsi:type="object">Adyen\Payment\Logger\AdyenLogger</argument>
</arguments>
</virtualType>
<!--Checkout Response validator-->
<virtualType name="CheckoutResponseValidator" type="Adyen\Payment\Gateway\Validator\CheckoutResponseValidator">
<arguments>
......@@ -1017,8 +1008,8 @@
type="Adyen\Payment\Model\AdyenRequestMerchantSession"/>
<preference for="Adyen\Payment\Api\AdyenInitiateTerminalApiInterface"
type="Adyen\Payment\Model\AdyenInitiateTerminalApi"/>
<preference for="Adyen\Payment\Api\AdyenThreeDS2ProcessInterface"
type="Adyen\Payment\Model\AdyenThreeDS2Process"/>
<preference for="Adyen\Payment\Api\AdyenPaymentDetailsInterface"
type="Adyen\Payment\Model\AdyenPaymentDetails"/>
<preference for="Adyen\Payment\Api\AdyenOriginKeyInterface"
type="Adyen\Payment\Model\AdyenOriginKey"/>
<preference for="Adyen\Payment\Api\AdyenOrderPaymentStatusInterface"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
!function(e,n){"object"===typeof exports&&"object"===typeof module?module.exports=n():"function"===typeof define&&define.amd?define([],n):"object"===typeof exports?exports.ThreedDS2Utils=n():e.ThreedDS2Utils=n()}(this,function(){return function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){"use strict";t.r(n);var r={container:void 0},o={"01":["250px","400px"],"02":["390px","400px"],"03":["500px","600px"],"04":["600px","400px"],"05":["100%","100%"]};function a(e){return o.hasOwnProperty(e)?e:"01"}var i={createIframe:function(e,n){var t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"0",o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"0",a=arguments.length>4?arguments[4]:void 0;if(!n||0===n.length)throw new Error("Name parameter missing for iframe");e instanceof HTMLElement?r.container=e:r.container=document.body;var i=document.createElement("iframe");i.classList.add(n+"Class"),i.width=t,i.height=o,i.name=n,i.setAttribute("frameborder","0"),i.setAttribute("border","0");var d=document.createTextNode("<p>Your browser does not support iframes.</p>");return i.appendChild(d),r.container.appendChild(i),function(e,n){e.attachEvent?e.attachEvent("onload",function(){n&&"function"===typeof n&&n(e.contentWindow)}):e.onload=function(){n&&"function"===typeof n&&n(e.contentWindow)}}(i,a),i},createForm:function(e,n,t,r,o){if(!e||!n||!t||!r||!o)throw new Error("Not all required parameters provided for form creation");if(0===e.length||0===n.length||0===t.length||0===r.length||0===o.length)throw new Error("Not all required parameters have suitable values");var a=document.createElement("form");a.style.display="none",a.name=e,a.action=n,a.method="POST",a.target=t;var i=document.createElement("input");return i.name=r,i.value=o,a.appendChild(i),a},getBrowserInfo:function(){var e=window&&window.screen?window.screen.width:"",n=window&&window.screen?window.screen.height:"",t=window&&window.screen?window.screen.colorDepth:"",r=window&&window.navigator?window.navigator.userAgent:"",o=!(!window||!window.navigator)&&navigator.javaEnabled(),a="";return window&&window.navigator&&(a=window.navigator.language?window.navigator.language:window.navigator.browserLanguage),{screenWidth:e,screenHeight:n,colorDepth:t,userAgent:r,timeZoneOffset:(new Date).getTimezoneOffset(),language:a,javaEnabled:o}},base64Url:{encode:function(e){var n=window.btoa(e).split("=")[0];return n=(n=n.replace("/+/g","-")).replace("///g","_")},decode:function(e){var n=e;switch((n=(n=n.replace("/-/g","+")).replace("/_/g","/")).length%4){case 0:break;case 2:n+="==";break;case 3:n+="=";break;default:window.console&&window.console.log&&window.console.log("### base64url::decodeBase64URL:: Illegal base64url string!")}try{return window.atob(n)}catch(e){throw new Error(e)}}},config:{challengeWindowSizes:o,validateChallengeWindowSize:a,getChallengeWindowSize:function(e){return o[a(e)]},THREEDS_METHOD_TIMEOUT:1e4,CHALLENGE_TIMEOUT:6e5}};n.default=i}]).default});
\ No newline at end of file
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