We will be off from 27/1 (Monday) to 31/1 (Friday) (GMT +7) for our Tet Holiday (Lunar New Year) in our country

Commit 2bbf8fd0 authored by Alexandros Moraitis's avatar Alexandros Moraitis Committed by GitHub

[PW-2858] SEPA tokenization for recurring payments (#795)

* First commit

* remove the storepayment methods from front end

* move the config to store payment methods

* request is complete

* Add the save token logic for alternative paymentmethods to Cron class

* Remove unused logger from Checkout builder class

* Remove rest od the logger

* remove more unused code

* remove commas

* remove space

* Working on adding the public_hash

* Alternative payment method is displayed in Stored Payment Methods page

* add adyen_hpp for alternative payment methods

* add the TokenHppUiProvider class

* [PW-2858] Moving HPP vault config to default Magento PM location

* [PW-2858] HPP vault virtual types

* [PW-2858] Extra configs and account constant usage

* Fix code smell 2/5

* fix suggestions

* Replace date time format

* [PW-2858] Missing virtualtypes

* [PW-2858] Extra virtualtypes and configs

* [PW-2858] Token formatter for HPP

* [PW-2858] Check if PM is adyen_hpp before saving recurring token

* [PW-2858] Using Vault helper for the expDate

* Restoring config label

* [PW-2858] Adjusting VaultDetailsHandler.php to use vault helper

* [PW-2858] Fix code smells

* Update Helper/Requests.php
Co-authored-by: default avatarMarcos Garcia <marcos.asgarcia@gmail.com>

* [PW-2858] phpcs fix

* [PW-2858] getExpirationDate made private and using Vault consts from Cron.php

* [PW-2858] Adding Date use statements

* [PW-2858] Adding cron messages

* Removing duplicated virtualtype

* [PW-2858] phpcs fix
Co-authored-by: default avatarAttila Kiss <42297201+cyattilakiss@users.noreply.github.com>
Co-authored-by: default avataracampos1916 <angel.campos@adyen.com>
Co-authored-by: default avatarMarcos Garcia <marcos.asgarcia@gmail.com>
parent 4891d651
......@@ -24,6 +24,7 @@
namespace Adyen\Payment\Block\Customer;
use Adyen\Payment\Model\Ui\AdyenCcConfigProvider;
use Adyen\Payment\Model\Ui\AdyenHppConfigProvider;
use Adyen\Payment\Helper\Data;
use Magento\Framework\View\Element\Template;
use Magento\Vault\Api\Data\PaymentTokenInterface;
......@@ -55,7 +56,7 @@ class CardRenderer extends AbstractCardRenderer
*/
public function canRender(PaymentTokenInterface $token)
{
return $token->getPaymentMethodCode() === AdyenCcConfigProvider::CODE;
return $token->getPaymentMethodCode() === AdyenCcConfigProvider::CODE ||$token->getPaymentMethodCode() === AdyenHppConfigProvider::CODE;
}
/**
......@@ -63,7 +64,7 @@ class CardRenderer extends AbstractCardRenderer
*/
public function getNumberLast4Digits()
{
return $this->getTokenDetails()['maskedCC'];
return !empty($this->getTokenDetails()['maskedCC']) ? $this->getTokenDetails()['maskedCC'] : "";
}
/**
......
......@@ -141,7 +141,18 @@ class Config
}
return $this->encryptor->decrypt(trim($key));
}
/**
* Check if alternative payment methods vault is enabled
*
* @param null|int|string $storeId
* @return mixed
*/
public function isStoreAlternativePaymentMethodEnabled($storeId = null)
{
return $this->adyenHelper->getAdyenHppVaultConfigDataFlag('active', $storeId);
}
/**
* Retrieve information from payment configuration
*
......
......@@ -525,6 +525,18 @@ class Data extends AbstractHelper
return $this->getConfigData($field, 'adyen_hpp', $storeId, true);
}
/**
* Gives back adyen_hpp_vault configuration values as flag
*
* @param $field
* @param null|int|string $storeId
* @return mixed
*/
public function getAdyenHppVaultConfigDataFlag($field, $storeId = null)
{
return $this->getConfigData($field, 'adyen_hpp_vault', $storeId, true);
}
/**
* Gives back adyen_oneclick configuration values
*
......@@ -1785,6 +1797,17 @@ class Data extends AbstractHelper
return $this->getAdyenCcVaultConfigDataFlag('active', $storeId);
}
/**
* Check if HPP vault is enabled
*
* @param null|int|string $storeId
* @return mixed
*/
public function isHppVaultEnabled($storeId = null)
{
return $this->getAdyenHppVaultConfigDataFlag('active', $storeId);
}
/**
* Checks if the house number needs to be sent to the Adyen API separately or as it is in the street field
*
......
......@@ -38,16 +38,24 @@ class Requests extends AbstractHelper
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* @var \Adyen\Payment\Helper\Config
*/
private $adyenConfig;
/**
* Requests constructor.
*
* @param Data $adyenHelper
* @param Config $adyenConfig ;
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper
\Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Helper\Config $adyenConfig
) {
$this->adyenHelper = $adyenHelper;
$this->adyenConfig = $adyenConfig;
}
/**
......@@ -366,7 +374,10 @@ class Requests extends AbstractHelper
if ($customerId > 0) {
$isGuestUser = false;
}
//active
if ( $this->adyenConfig->isStoreAlternativePaymentMethodEnabled($storeId)) {
$request['storePaymentMethod'] = true;
}
// If the vault feature is on this logic is handled in the VaultDataBuilder
if (!$this->adyenHelper->isCreditCardVaultEnabled()) {
if ($areaCode !== \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE) {
......@@ -375,17 +386,9 @@ class Requests extends AbstractHelper
$enableOneclick = $this->adyenHelper->getAdyenAbstractConfigData('enable_oneclick', $storeId);
$enableRecurring = $this->adyenHelper->getAdyenAbstractConfigData('enable_recurring', $storeId);
if ($enableOneclick && !$isGuestUser) {
$request['enableOneClick'] = true;
} else {
$request['enableOneClick'] = false;
}
if ($enableRecurring) {
$request['enableRecurring'] = true;
} else {
$request['enableRecurring'] = false;
}
$request['enableOneClick'] = $enableOneclick && !$isGuestUser;
$request['enableRecurring'] = (bool)$enableRecurring;
// value can be 0,1 or true
if (!empty($additionalData[AdyenCcDataAssignObserver::STORE_CC]) || ($isGuestUser && $this->adyenHelper->isGuestTokenizationEnabled($storeId))) {
......
......@@ -92,11 +92,12 @@ class Vault
public function saveRecurringDetails($payment, array $additionalData)
{
if (!$this->adyenHelper->isCreditCardVaultEnabled($payment->getOrder()->getStoreId())) {
if (!$this->adyenHelper->isCreditCardVaultEnabled($payment->getOrder()->getStoreId()) &&
!$this->adyenHelper->isHppVaultEnabled($payment->getOrder()->getStoreId())) {
return;
}
if(!$this->validateAdditionalData($additionalData)) {
if (!$this->validateAdditionalData($additionalData)) {
return;
}
......@@ -156,11 +157,15 @@ class Vault
$paymentToken->setExpiresAt($this->getExpirationDate($additionalData[self::EXPIRY_DATE]));
$details = [
'type' => $additionalData[self::PAYMENT_METHOD],
'maskedCC' => $additionalData[self::CARD_SUMMARY],
'expirationDate' => $additionalData[self::EXPIRY_DATE]
];
$details = ['type' => $additionalData[self::PAYMENT_METHOD]];
if (!empty($additionalData[self::CARD_SUMMARY])) {
$details['maskedCC'] = $additionalData[self::CARD_SUMMARY];
}
if (!empty($additionalData[self::EXPIRY_DATE])) {
$details['expirationDate'] = $additionalData[self::EXPIRY_DATE];
}
$paymentToken->setTokenDetails(json_encode($details));
......@@ -201,7 +206,7 @@ class Vault
$expirationDate = explode('/', $expirationDate);
$expDate = new DateTime(
//add leading zero to month
//add leading zero to month
sprintf("%s-%02d-01 00:00:00", $expirationDate[1], $expirationDate[0]),
new DateTimeZone('UTC')
);
......
This diff is collapsed.
<?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\Model\InstantPurchase\Hpp;
use Magento\InstantPurchase\PaymentMethodIntegration\PaymentTokenFormatterInterface;
use Magento\Vault\Api\Data\PaymentTokenInterface;
/**
* Adyen stored credit card formatter.
*/
class TokenFormatter implements PaymentTokenFormatterInterface
{
/**
* Most used HPP types
*
* @var array
*/
public static $baseHppTypes = [
'sepadirectdebit' => 'SEPA Direct Debit'
];
/**
* @inheritdoc
*/
public function formatPaymentToken(PaymentTokenInterface $paymentToken): string
{
$details = json_decode($paymentToken->getTokenDetails() ?: '{}', true);
if (!isset($details['type'], $details['maskedCC'], $details['expirationDate'])) {
throw new \InvalidArgumentException('Invalid Adyen HPP token details.');
}
if (isset(self::$baseCardTypes[$details['type']])) {
$hppType = self::$baseCardTypes[$details['type']];
} else {
$hppType = $details['type'];
}
return sprintf(
'%s: %s, %s: %s (%s: %s)',
__('SEPA'),
$hppType,
__('number'),
$details['maskedCC'],
__('expires'),
$details['expirationDate']
);
}
}
......@@ -30,6 +30,7 @@ use Magento\Directory\Helper\Data;
class AdyenHppConfigProvider implements ConfigProviderInterface
{
const CODE = 'adyen_hpp';
const HPP_VAULT_CODE = 'adyen_hpp_vault';
/**
* @var PaymentHelper
......
<?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\Model\Ui;
use Adyen\Payment\Helper\Data;
use Magento\Vault\Api\Data\PaymentTokenInterface;
use Magento\Vault\Model\Ui\TokenUiComponentInterface;
use Magento\Vault\Model\Ui\TokenUiComponentProviderInterface;
use Magento\Vault\Model\Ui\TokenUiComponentInterfaceFactory;
use Magento\Framework\UrlInterface;
class TokenHppUiComponentProvider implements TokenUiComponentProviderInterface
{
/**
* @var TokenUiComponentInterfaceFactory
*/
private $componentFactory;
/**
* @var Data
*/
private $adyenHelper;
/**
* @param TokenUiComponentInterfaceFactory $componentFactory
* @param UrlInterface $urlBuilder
*/
public function __construct(
TokenUiComponentInterfaceFactory $componentFactory,
Data $adyenHelper
) {
$this->componentFactory = $componentFactory;
$this->adyenHelper = $adyenHelper;
}
/**
* Get UI component for token
*
* @param PaymentTokenInterface $paymentToken
* @return TokenUiComponentInterface
*/
public function getComponentForToken(PaymentTokenInterface $paymentToken)
{
$details = json_decode($paymentToken->getTokenDetails() ?: '{}', true);
$details['icon'] = $this->adyenHelper->getVariantIcon($details['type']);
return $this->componentFactory->create(
[
'config' => [
'code' => AdyenHppConfigProvider::HPP_VAULT_CODE,
TokenUiComponentProviderInterface::COMPONENT_DETAILS => $details,
TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH => $paymentToken->getPublicHash()
],
'name' => 'Adyen_Payment/js/view/payment/method-renderer/vault'
]
);
}
}
......@@ -33,11 +33,16 @@
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_hpp/active</config_path>
</field>
<field id="sort_order" translate="label" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="0">
<field id="sort_order" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Sort Order</label>
<frontend_class>validate-number</frontend_class>
<config_path>payment/adyen_hpp/sort_order</config_path>
</field>
<field id="adyen_hpp_vault_active" translate="label" type="select" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Store alternative payment methods</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_hpp_vault/active</config_path>
</field>
<group id="adyen_hpp_openinvoice_settings" translate="label" showInDefault="1" showInWebsite="1" showInStore="1" sortOrder="100">
<label>Klarna\RatePay\Afterpay Settings</label>
<frontend_model>Magento\Config\Block\System\Config\Form\Fieldset</frontend_model>
......@@ -81,4 +86,4 @@
</field>
</group>
</group>
</include>
\ No newline at end of file
</include>
......@@ -73,6 +73,14 @@
<tokenFormat>Adyen\Payment\Model\InstantPurchase\CreditCard\TokenFormatter</tokenFormat>
</instant_purchase>
</adyen_cc_vault>
<adyen_hpp_vault>
<model>AdyenPaymentHppVaultFacade</model>
<title>Alternative Payment Methods (Adyen)</title>
<instant_purchase>
<available>Adyen\Payment\Model\InstantPurchase\CreditCard\AvailabilityChecker</available>
<tokenFormat>Adyen\Payment\Model\InstantPurchase\Hpp\TokenFormatter</tokenFormat>
</instant_purchase>
</adyen_hpp_vault>
<adyen_google_pay_vault>
<model>AdyenPaymentGooglePayVaultFacade</model>
<title>Stored Cards (Adyen)</title>
......@@ -113,7 +121,7 @@
<ratepay_id>oj9GsQ</ratepay_id>
<sort_order>3</sort_order>
<payment_action>authorize</payment_action>
<can_initialize>1</can_initialize>
<can_initialize>0</can_initialize>
<is_gateway>1</is_gateway>
<can_use_checkout>1</can_use_checkout>
<can_capture>1</can_capture>
......@@ -123,6 +131,8 @@
<can_refund>1</can_refund>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_authorize_vault>1</can_authorize_vault>
<can_capture_vault>1</can_capture_vault>
<group>adyen</group>
</adyen_hpp>
<adyen_pos_cloud>
......
......@@ -53,6 +53,15 @@
<argument name="vaultProvider" xsi:type="object">AdyenPaymentCcFacade</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentHppVaultFacade" type="Magento\Vault\Model\Method\Vault">
<arguments>
<argument name="code" xsi:type="const">Adyen\Payment\Model\Ui\AdyenHppConfigProvider::HPP_VAULT_CODE
</argument>
<argument name="config" xsi:type="object">AdyenPaymentHppVaultConfig</argument>
<argument name="valueHandlerPool" xsi:type="object">AdyenPaymentHppVaultPaymentValueHandlerPool</argument>
<argument name="vaultProvider" xsi:type="object">AdyenPaymentHppFacade</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentGooglePayVaultFacade" type="Magento\Vault\Model\Method\Vault">
<arguments>
<argument name="code" xsi:type="const">Adyen\Payment\Model\Ui\AdyenGooglePayConfigProvider::GOOGLE_PAY_VAULT_CODE
......@@ -147,6 +156,18 @@
</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentHppVaultPaymentValueHandler" type="VaultPaymentDefaultValueHandler">
<arguments>
<argument name="configInterface" xsi:type="object">AdyenPaymentHppVaultConfig</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentHppVaultPaymentValueHandlerPool" type="VaultPaymentValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">AdyenPaymentHppVaultPaymentValueHandler</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentGenericValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
......@@ -283,6 +304,12 @@
</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentHppVaultConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Adyen\Payment\Model\Ui\AdyenHppConfigProvider::HPP_VAULT_CODE
</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentOneclickConfig" type="Magento\Payment\Gateway\Config\Config">
<arguments>
<argument name="methodCode" xsi:type="const">Adyen\Payment\Model\Ui\AdyenOneclickConfigProvider::CODE</argument>
......@@ -344,11 +371,18 @@
<arguments>
<argument name="executors" xsi:type="array">
<item name="adyen_cc" xsi:type="string">AdyenPaymentCcCommandManager</item>
<item name="adyen_hpp" xsi:type="string">AdyenPaymentHppCommandManager</item>
<item name="adyen_google_pay" xsi:type="string">AdyenPaymentCcCommandManager</item>
</argument>
</arguments>
</type>
<virtualType name="AdyenPaymentHppCommandManager" type="Magento\Payment\Gateway\Command\CommandManager">
<arguments>
<argument name="commandPool" xsi:type="object">AdyenPaymentHppCommandPool</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentOneclickCommandPool" type="Magento\Payment\Gateway\Command\CommandPool">
<arguments>
<argument name="commands" xsi:type="array">
......@@ -372,6 +406,18 @@
</arguments>
</virtualType>
<virtualType name="AdyenPaymentHppVaultAuthorizeCommand" type="Magento\Payment\Gateway\Command\GatewayCommand">
<arguments>
<argument name="requestBuilder" xsi:type="object">AdyenPaymentHppVaultAuthorizeRequest</argument>
<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="handler" xsi:type="object">AdyenPaymentHppVaultResponseHandlerComposite</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentHppCommandPool" type="Magento\Payment\Gateway\Command\CommandPool">
<arguments>
<argument name="commands" xsi:type="array">
......@@ -380,6 +426,7 @@
<item name="void" xsi:type="string">AdyenPaymentCancelCommand</item>
<item name="refund" xsi:type="string">AdyenPaymentRefundCommand</item>
<item name="cancel" xsi:type="string">AdyenPaymentCancelCommand</item>
<item name="vault_authorize" xsi:type="string">AdyenPaymentHppVaultAuthorizeCommand</item>
</argument>
</arguments>
</virtualType>
......@@ -596,6 +643,21 @@
</arguments>
</virtualType>
<virtualType name="AdyenPaymentHppVaultResponseHandlerComposite"
type="Magento\Payment\Gateway\Response\HandlerChain">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="payment_details" xsi:type="string">
Adyen\Payment\Gateway\Response\PaymentAuthorisationDetailsHandler
</item>
<item name="payment_comments" xsi:type="string">
Adyen\Payment\Gateway\Response\PaymentCommentHistoryHandler
</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentOneclickAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite">
<arguments>
<argument name="builders" xsi:type="array">
......@@ -628,6 +690,22 @@
</arguments>
</virtualType>
<virtualType name="AdyenPaymentHppVaultAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite">
<arguments>
<argument name="builders" xsi:type="array">
<item name="merchantaccount" xsi:type="string">
Adyen\Payment\Gateway\Request\MerchantAccountDataBuilder
</item>
<item name="customer" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerDataBuilder</item>
<item name="customerip" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerIpDataBuilder</item>
<item name="address" xsi:type="string">Adyen\Payment\Gateway\Request\AddressDataBuilder</item>
<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\RecurringVaultDataBuilder</item>
</argument>
</arguments>
</virtualType>
<virtualType name="AdyenPaymentBoletoAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite">
<arguments>
<argument name="builders" xsi:type="array">
......
......@@ -42,8 +42,9 @@
<arguments>
<argument name="tokenUiComponentProviders" xsi:type="array">
<item name="adyen_cc" xsi:type="object">Adyen\Payment\Model\Ui\TokenUiComponentProvider</item>
<item name="adyen_hpp" xsi:type="object">Adyen\Payment\Model\Ui\TokenHppUiComponentProvider</item>
<item name="adyen_google_pay" xsi:type="object">Adyen\Payment\Model\Ui\TokenGooglePayUiComponentProvider</item>
</argument>
</arguments>
</type>
</config>
\ No newline at end of file
</config>
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