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

Commit 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