<?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\Helper; use Magento\Framework\App\Helper\AbstractHelper; /** * @SuppressWarnings(PHPMD.LongVariable) */ class Data extends AbstractHelper { const MODULE_NAME = 'adyen-magento2'; const TEST = 'test'; const LIVE = 'live'; const CHECKOUT_COMPONENT_JS_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/3.0.0/adyen.js'; const CHECKOUT_COMPONENT_JS_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.0.0/adyen.js'; /** * @var \Magento\Framework\Encryption\EncryptorInterface */ protected $_encryptor; /** * @var \Magento\Framework\Config\DataInterface */ protected $_dataStorage; /** * @var \Magento\Directory\Model\Config\Source\Country */ protected $_country; /** * @var \Magento\Framework\Module\ModuleListInterface */ protected $_moduleList; /** * @var \Adyen\Payment\Model\ResourceModel\Billing\Agreement\CollectionFactory */ protected $_billingAgreementCollectionFactory; /** * @var \Magento\Framework\View\Asset\Repository */ protected $_assetRepo; /** * @var \Magento\Framework\View\Asset\Source */ protected $_assetSource; /** * @var \Adyen\Payment\Model\ResourceModel\Notification\CollectionFactory */ protected $_notificationFactory; /** * @var \Magento\Tax\Model\Config */ protected $_taxConfig; /** * @var \Magento\Tax\Model\Calculation */ protected $_taxCalculation; /** * @var \Magento\Framework\App\ProductMetadataInterface */ protected $productMetadata; /** * @var \Adyen\Payment\Logger\AdyenLogger */ protected $adyenLogger; /** * @var \Magento\Store\Model\StoreManagerInterface */ protected $storeManager; /** * @var \Magento\Framework\App\CacheInterface */ protected $cache; /** * @var \Adyen\Payment\Model\Billing\AgreementFactory */ protected $billingAgreementFactory; /** * @var ResourceModel\Billing\Agreement */ private $agreementResourceModel; /** * @var \Magento\Framework\Locale\ResolverInterface */ private $localeResolver; /** * @var \Magento\Framework\App\Config\ScopeConfigInterface */ private $config; /** * Data constructor. * @param \Magento\Framework\App\Helper\Context $context * @param \Magento\Framework\Encryption\EncryptorInterface $encryptor * @param \Magento\Framework\Config\DataInterface $dataStorage * @param \Magento\Directory\Model\Config\Source\Country $country * @param \Magento\Framework\Module\ModuleListInterface $moduleList * @param \Adyen\Payment\Model\ResourceModel\Billing\Agreement\CollectionFactory $billingAgreementCollectionFactory * @param \Magento\Framework\View\Asset\Repository $assetRepo * @param \Magento\Framework\View\Asset\Source $assetSource * @param \Adyen\Payment\Model\ResourceModel\Notification\CollectionFactory $notificationFactory * @param \Magento\Tax\Model\Config $taxConfig * @param \Magento\Tax\Model\Calculation $taxCalculation * @param \Magento\Framework\App\ProductMetadataInterface $productMetadata * @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Framework\App\CacheInterface $cache * @param \Adyen\Payment\Model\Billing\AgreementFactory $billingAgreementFactory * @param \Adyen\Payment\Model\ResourceModel\Billing\Agreement $agreementResourceModel */ public function __construct( \Magento\Framework\App\Helper\Context $context, \Magento\Framework\Encryption\EncryptorInterface $encryptor, \Magento\Framework\Config\DataInterface $dataStorage, \Magento\Directory\Model\Config\Source\Country $country, \Magento\Framework\Module\ModuleListInterface $moduleList, \Adyen\Payment\Model\ResourceModel\Billing\Agreement\CollectionFactory $billingAgreementCollectionFactory, \Magento\Framework\View\Asset\Repository $assetRepo, \Magento\Framework\View\Asset\Source $assetSource, \Adyen\Payment\Model\ResourceModel\Notification\CollectionFactory $notificationFactory, \Magento\Tax\Model\Config $taxConfig, \Magento\Tax\Model\Calculation $taxCalculation, \Magento\Framework\App\ProductMetadataInterface $productMetadata, \Adyen\Payment\Logger\AdyenLogger $adyenLogger, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\App\CacheInterface $cache, \Adyen\Payment\Model\Billing\AgreementFactory $billingAgreementFactory, \Adyen\Payment\Model\ResourceModel\Billing\Agreement $agreementResourceModel, \Magento\Framework\Locale\ResolverInterface $localeResolver, \Magento\Framework\App\Config\ScopeConfigInterface $config ) { parent::__construct($context); $this->_encryptor = $encryptor; $this->_dataStorage = $dataStorage; $this->_country = $country; $this->_moduleList = $moduleList; $this->_billingAgreementCollectionFactory = $billingAgreementCollectionFactory; $this->_assetRepo = $assetRepo; $this->_assetSource = $assetSource; $this->_notificationFactory = $notificationFactory; $this->_taxConfig = $taxConfig; $this->_taxCalculation = $taxCalculation; $this->productMetadata = $productMetadata; $this->adyenLogger = $adyenLogger; $this->storeManager = $storeManager; $this->cache = $cache; $this->billingAgreementFactory = $billingAgreementFactory; $this->agreementResourceModel = $agreementResourceModel; $this->localeResolver = $localeResolver; $this->config = $config; } /** * return recurring types for configuration setting * @return array */ public function getRecurringTypes() { return [ \Adyen\Payment\Model\RecurringType::ONECLICK => 'ONECLICK', \Adyen\Payment\Model\RecurringType::ONECLICK_RECURRING => 'ONECLICK,RECURRING', \Adyen\Payment\Model\RecurringType::RECURRING => 'RECURRING' ]; } /** * return recurring types for configuration setting * @return array */ public function getModes() { return [ '1' => 'Test Mode', '0' => 'Production Mode' ]; } /** * return recurring types for configuration setting * @return array */ public function getCaptureModes() { return [ 'auto' => 'immediate', 'manual' => 'manual' ]; } /** * return recurring types for configuration setting * @return array */ public function getPaymentRoutines() { return [ 'single' => 'Single Page Payment Routine', 'multi' => 'Multi-page Payment Routine' ]; } /** * Return the formatted currency. Adyen accepts the currency in multiple formats. * @param $amount * @param $currency * @return string */ public function formatAmount($amount, $currency) { switch ($currency) { case "JPY": case "IDR": case "KRW": case "BYR": case "VND": case "CVE": case "DJF": case "GNF": case "PYG": case "RWF": case "UGX": case "VUV": case "XAF": case "XOF": case "XPF": case "GHC": case "KMF": $format = 0; break; case "MRO": $format = 1; break; case "BHD": case "JOD": case "KWD": case "OMR": case "LYD": case "TND": $format = 3; break; default: $format = 2; break; } return (int)number_format($amount, $format, '', ''); } /** * Tax Percentage needs to be in minor units for Adyen * * @param float $taxPercent * @return int */ public function getMinorUnitTaxPercent($taxPercent) { $taxPercent = $taxPercent * 100; return (int)$taxPercent; } /** * @param $amount * @param $currency * @return float */ public function originalAmount($amount, $currency) { // check the format switch ($currency) { case "JPY": case "IDR": case "KRW": case "BYR": case "VND": case "CVE": case "DJF": case "GNF": case "PYG": case "RWF": case "UGX": case "VUV": case "XAF": case "XOF": case "XPF": case "GHC": case "KMF": $format = 1; break; case "MRO": $format = 10; break; case "BHD": case "JOD": case "KWD": case "OMR": case "LYD": case "TND": $format = 1000; break; default: $format = 100; break; } return ($amount / $format); } /** * Street format * @param type $address * @return array */ public function getStreet($address) { if (empty($address)) { return false; } $street = self::formatStreet($address->getStreet()); $streetName = $street['0']; unset($street['0']); $streetNr = implode(' ', $street); return (['name' => trim($streetName), 'house_number' => $streetNr]); } /** * Street format * @param string $streetLine * @return array */ public function getStreetFromString($streetLine) { $street = self::formatStreet([$streetLine]); $streetName = $street['0']; unset($street['0']); $streetNr = implode(' ', $street); return (['name' => trim($streetName), 'house_number' => $streetNr]); } /** * Fix this one string street + number * @example street + number * @param array $street * @return array $street */ public static function formatStreet($street) { if (count($street) != 1) { return $street; } preg_match('/((\s\d{0,10})|(\s\d{0,10}\w{1,3}))$/i', $street['0'], $houseNumber, PREG_OFFSET_CAPTURE); if (!empty($houseNumber['0'])) { $_houseNumber = trim($houseNumber['0']['0']); $position = $houseNumber['0']['1']; $streetName = trim(substr($street['0'], 0, $position)); $street = [$streetName, $_houseNumber]; } return $street; } /** * gives back global configuration values * * @param $field * @param null $storeId * @return mixed */ public function getAdyenAbstractConfigData($field, $storeId = null) { return $this->getConfigData($field, 'adyen_abstract', $storeId); } /** * gives back global configuration values as boolean * * @param $field * @param null $storeId * @return mixed */ public function getAdyenAbstractConfigDataFlag($field, $storeId = null) { return $this->getConfigData($field, 'adyen_abstract', $storeId, true); } /** * Gives back adyen_cc configuration values * * @param $field * @param null $storeId * @return mixed */ public function getAdyenCcConfigData($field, $storeId = null) { return $this->getConfigData($field, 'adyen_cc', $storeId); } /** * Gives back adyen_cc configuration values as flag * * @param $field * @param null $storeId * @return mixed */ public function getAdyenCcConfigDataFlag($field, $storeId = null) { return $this->getConfigData($field, 'adyen_cc', $storeId, true); } /** * Gives back adyen_cc_vault configuration values as flag * * @param $field * @param int|null $storeId * @return mixed */ public function getAdyenCcVaultConfigDataFlag($field, $storeId = null) { return $this->getConfigData($field, 'adyen_cc_vault', $storeId, true); } /** * Gives back adyen_cc_threeds2 configuration values as flag * * @param $field * @param null $storeId * @return mixed */ public function getAdyenCcThreeDS2ConfigDataFlag($field, $storeId = null) { return $this->getConfigData($field, 'adyen_cc_threeds2', $storeId, true); } /** * Gives back adyen_hpp configuration values * * @param $field * @param null $storeId * @return mixed */ public function getAdyenHppConfigData($field, $storeId = null) { return $this->getConfigData($field, 'adyen_hpp', $storeId); } /** * Gives back adyen_hpp configuration values as flag * * @param $field * @param null $storeId * @return mixed */ public function getAdyenHppConfigDataFlag($field, $storeId = null) { return $this->getConfigData($field, 'adyen_hpp', $storeId, true); } /** * Gives back adyen_oneclick configuration values * * @param $field * @param null $storeId * @return mixed */ public function getAdyenOneclickConfigData($field, $storeId = null) { return $this->getConfigData($field, 'adyen_oneclick', $storeId); } /** * Gives back adyen_oneclick configuration values as flag * * @param $field * @param null $storeId * @return mixed */ public function getAdyenOneclickConfigDataFlag($field, $storeId = null) { return $this->getConfigData($field, 'adyen_oneclick', $storeId, true); } /** * @param $field * @param int|null $storeId * @return bool|mixed */ public function getAdyenPosCloudConfigData($field, $storeId = null) { return $this->getConfigData($field, 'adyen_pos_cloud', $storeId); } /** * @param $field * @param int|null $storeId * @return bool|mixed */ public function getAdyenPosCloudConfigDataFlag($field, $storeId = null) { return $this->getConfigData($field, 'adyen_pos_cloud', $storeId, true); } /** * Gives back adyen_pay_by_mail configuration values * * @param $field * @param int|null $storeId * @return mixed */ public function getAdyenPayByMailConfigData($field, $storeId = null) { return $this->getConfigData($field, 'adyen_pay_by_mail', $storeId); } /** * Gives back adyen_pay_by_mail configuration values as flag * * @param $field * @param int|null $storeId * @return mixed */ public function getAdyenPayByMailConfigDataFlag($field, $storeId = null) { return $this->getConfigData($field, 'adyen_pay_by_mail', $storeId, true); } /** * Gives back adyen_boleto configuration values * * @param $field * @param null $storeId * @return mixed */ public function getAdyenBoletoConfigData($field, $storeId = null) { return $this->getConfigData($field, 'adyen_boleto', $storeId); } /** * Gives back adyen_boleto configuration values as flag * * @param $field * @param null $storeId * @return mixed */ public function getAdyenBoletoConfigDataFlag($field, $storeId = null) { return $this->getConfigData($field, 'adyen_boleto', $storeId, true); } /** * Gives back adyen_apple_pay configuration values * * @param $field * @param null $storeId * @return mixed */ public function getAdyenApplePayConfigData($field, $storeId = null) { return $this->getConfigData($field, 'adyen_apple_pay', $storeId); } /** * @param null $storeId * @return mixed */ public function getAdyenApplePayMerchantIdentifier($storeId = null) { $demoMode = $this->getAdyenAbstractConfigDataFlag('demo_mode'); if ($demoMode) { return $this->getAdyenApplePayConfigData('merchant_identifier_test', $storeId); } else { return $this->getAdyenApplePayConfigData('merchant_identifier_live', $storeId); } } /** * @param null $storeId * @return mixed */ public function getAdyenApplePayPemFileLocation($storeId = null) { $demoMode = $this->getAdyenAbstractConfigDataFlag('demo_mode'); if ($demoMode) { return $this->getAdyenApplePayConfigData('full_path_location_pem_file_test', $storeId); } else { return $this->getAdyenApplePayConfigData('full_path_location_pem_file_live', $storeId); } } /** * Retrieve decrypted hmac key * * @return string */ public function getHmac() { switch ($this->isDemoMode()) { case true: $secretWord = $this->_encryptor->decrypt(trim($this->getAdyenHppConfigData('hmac_test'))); break; default: $secretWord = $this->_encryptor->decrypt(trim($this->getAdyenHppConfigData('hmac_live'))); break; } return $secretWord; } public function getHmacPayByMail() { switch ($this->isDemoMode()) { case true: $secretWord = $this->_encryptor->decrypt(trim($this->getAdyenPayByMailConfigData('hmac_test'))); break; default: $secretWord = $this->_encryptor->decrypt(trim($this->getAdyenPayByMailConfigData('hmac_live'))); break; } return $secretWord; } /** * Check if configuration is set to demo mode * * @param int|null $storeId * @return mixed */ public function isDemoMode($storeId = null) { return $this->getAdyenAbstractConfigDataFlag('demo_mode', $storeId); } /** * Retrieve the decrypted notification password * * @return string */ public function getNotificationPassword() { return $this->_encryptor->decrypt(trim($this->getAdyenAbstractConfigData('notification_password'))); } /** * Retrieve the API key * * @param int|null $storeId * @return string */ public function getAPIKey($storeId = null) { if ($this->isDemoMode($storeId)) { $apiKey = $this->_encryptor->decrypt(trim($this->getAdyenAbstractConfigData('api_key_test', $storeId))); } else { $apiKey = $this->_encryptor->decrypt(trim($this->getAdyenAbstractConfigData('api_key_live', $storeId))); } return $apiKey; } /** * Retrieve the webserver username * * @param int|null $storeId * @return string */ public function getWsUsername($storeId = null) { if ($this->isDemoMode($storeId)) { $wsUsername = trim($this->getAdyenAbstractConfigData('ws_username_test', $storeId)); } else { $wsUsername = trim($this->getAdyenAbstractConfigData('ws_username_live', $storeId)); } return $wsUsername; } /** * Retrieve the Live endpoint prefix key * * @param int|null $storeId * @return string */ public function getLiveEndpointPrefix($storeId = null) { $prefix = trim($this->getAdyenAbstractConfigData('live_endpoint_url_prefix', $storeId)); return $prefix; } /** * Cancels the order * * @param $order */ public function cancelOrder($order) { $orderStatus = $this->getAdyenAbstractConfigData('payment_cancelled'); $order->setActionFlag($orderStatus, true); switch ($orderStatus) { case \Magento\Sales\Model\Order::STATE_HOLDED: if ($order->canHold()) { $order->hold()->save(); } break; default: if ($order->canCancel()) { $order->cancel()->save(); } break; } } /** * Creditcard type that is selected is different from creditcard type that we get back from the request this * function get the magento creditcard type this is needed for getting settings like installments * @param $ccType * @return mixed */ public function getMagentoCreditCartType($ccType) { $ccTypesMapper = $this->getCcTypesAltData(); if (isset($ccTypesMapper[$ccType])) { $ccType = $ccTypesMapper[$ccType]['code']; } return $ccType; } /** * @return array */ public function getCcTypesAltData() { $adyenCcTypes = $this->getAdyenCcTypes(); $types = []; foreach ($adyenCcTypes as $key => $data) { $types[$data['code_alt']] = $data; $types[$data['code_alt']]['code'] = $key; } return $types; } /** * @return mixed */ public function getAdyenCcTypes() { return $this->_dataStorage->get('adyen_credit_cards'); } /** * Retrieve information from payment configuration * * @param $field * @param $paymentMethodCode * @param $storeId * @param bool|false $flag * @return bool|mixed */ public function getConfigData($field, $paymentMethodCode, $storeId, $flag = false) { $path = 'payment/' . $paymentMethodCode . '/' . $field; if (!$flag) { return $this->scopeConfig->getValue($path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeId); } else { return $this->scopeConfig->isSetFlag($path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeId); } } /** * Get adyen magento module's name sent to Adyen * * @return string */ public function getModuleName() { return (string)self::MODULE_NAME; } /** * Get adyen magento module's version * * @return string */ public function getModuleVersion() { return (string)$this->_moduleList->getOne("Adyen_Payment")['setup_version']; } public function getBoletoTypes() { return [ [ 'value' => 'boletobancario_itau', 'label' => __('boletobancario_itau'), ], [ 'value' => 'boletobancario_santander', 'label' => __('boletobancario_santander'), ], [ 'value' => 'primeiropay_boleto', 'label' => __('primeiropay_boleto'), ] ]; } /** * @param $customerId * @param $storeId * @param $grandTotal * @param $recurringType * @return array */ public function getOneClickPaymentMethods($customerId, $storeId, $grandTotal, $recurringType) { $billingAgreements = []; $baCollection = $this->_billingAgreementCollectionFactory->create(); $baCollection->addFieldToFilter('customer_id', $customerId); if ($this->isPerStoreBillingAgreement($storeId)) { $baCollection->addFieldToFilter('store_id', $storeId); } $baCollection->addFieldToFilter('method_code', 'adyen_oneclick'); $baCollection->addActiveFilter(); foreach ($baCollection as $billingAgreement) { $agreementData = $billingAgreement->getAgreementData(); // no agreementData and contractType then ignore if ((!is_array($agreementData)) || (!isset($agreementData['contractTypes']))) { continue; } // check if contractType is supporting the selected contractType for OneClick payments $allowedContractTypes = $agreementData['contractTypes']; if (in_array($recurringType, $allowedContractTypes)) { // check if AgreementLabel is set and if contract has an recurringType if ($billingAgreement->getAgreementLabel()) { // for Ideal use sepadirectdebit because it is if ($agreementData['variant'] == 'ideal') { $agreementData['variant'] = 'sepadirectdebit'; } $data = [ 'reference_id' => $billingAgreement->getReferenceId(), 'agreement_label' => $billingAgreement->getAgreementLabel(), 'agreement_data' => $agreementData ]; if ($this->showLogos()) { $logoName = $agreementData['variant']; $asset = $this->createAsset( 'Adyen_Payment::images/logos/' . $logoName . '.png' ); $icon = null; $placeholder = $this->_assetSource->findSource($asset); if ($placeholder) { list($width, $height) = getimagesize($asset->getSourceFile()); $icon = [ 'url' => $asset->getUrl(), 'width' => $width, 'height' => $height ]; } $data['logo'] = $icon; } /** * Check if there are installments for this creditcard type defined */ $data['number_of_installments'] = 0; $ccType = $this->getMagentoCreditCartType($agreementData['variant']); $installments = null; $installmentsValue = $this->getAdyenCcConfigData('installments'); if ($installmentsValue) { $installments = unserialize($installmentsValue); } if ($installments) { $numberOfInstallments = []; foreach ($installments as $ccTypeInstallment => $installment) { if ($ccTypeInstallment == $ccType) { foreach ($installment as $amount => $installments) { if ($grandTotal >= $amount) { array_push($numberOfInstallments, $installments); } } } } if ($numberOfInstallments) { sort($numberOfInstallments); $data['number_of_installments'] = $numberOfInstallments; } } $billingAgreements[] = $data; } } } return $billingAgreements; } public function isPerStoreBillingAgreement($storeId) { return !$this->getAdyenOneclickConfigDataFlag('share_billing_agreement', $storeId); } /** * @param $paymentMethod * @return bool */ public function isPaymentMethodOpenInvoiceMethod($paymentMethod) { if (strpos($paymentMethod, 'afterpay') !== false || strpos($paymentMethod, 'klarna') !== false || strpos($paymentMethod, 'ratepay') !== false ) { return true; } return false; } /** * @param $paymentMethod * @return bool */ public function isPaymentMethodAfterpayTouchMethod($paymentMethod) { if (strpos($paymentMethod, 'afterpaytouch') !== false) { return true; } return false; } /** * @param $paymentMethod * @return bool */ public function isPaymentMethodMolpayMethod($paymentMethod) { if (strpos($paymentMethod, 'molpay_') !== false) { return true; } return false; } /** * @param $paymentMethod * @return bool */ public function isPaymentMethodOneyMethod($paymentMethod) { if (strpos($paymentMethod, 'facilypay_') !== false) { return true; } return false; } /** * @param $paymentMethod * @return bool */ public function doesPaymentMethodSkipDetails($paymentMethod) { if ($this->isPaymentMethodOpenInvoiceMethod($paymentMethod) || $this->isPaymentMethodMolpayMethod($paymentMethod) || $this->isPaymentMethodOneyMethod($paymentMethod) ) { return true; } return false; } /** * @return mixed */ /** * @param $paymentMethod * @return bool */ public function isPaymentMethodBcmcMobileQRMethod($paymentMethod) { if (strpos($paymentMethod, 'bcmc_mobile_QR') !== false) { return true; } return false; } /** * The payment method for wechat should be only wechatweb until we support the others too. * * @param $paymentMethod * @return bool */ public function isPaymentMethodWechatpayExceptWeb($paymentMethod) { if (strpos($paymentMethod, 'wechatpay') !== false) { if (strpos($paymentMethod, 'wechatpayWeb') !== false) { return false; } return true; } return false; } public function getRatePayId() { return $this->getAdyenHppConfigData("ratepay_id"); } /** * For Klarna And AfterPay use VatCategory High others use none * * @param $paymentMethod * @return bool */ public function isVatCategoryHigh($paymentMethod) { if ($paymentMethod == "klarna" || strlen($paymentMethod) >= 9 && substr($paymentMethod, 0, 9) == 'afterpay_' ) { return true; } return false; } /** * @param $paymentMethod * @return bool */ public function isPaymentMethodBoletoMethod($paymentMethod) { if (strpos($paymentMethod, 'boleto') !== false) { return true; } return false; } /** * @return bool */ public function showLogos() { $showLogos = $this->getAdyenAbstractConfigData('title_renderer'); if ($showLogos == \Adyen\Payment\Model\Config\Source\RenderMode::MODE_TITLE_IMAGE) { return true; } return false; } /** * Create a file asset that's subject of fallback system * * @param string $fileId * @param array $params * @return \Magento\Framework\View\Asset\File */ public function createAsset($fileId, array $params = []) { $params = array_merge(['_secure' => $this->_request->isSecure()], $params); return $this->_assetRepo->createAsset($fileId, $params); } public function getStoreLocale($storeId) { $path = \Magento\Directory\Helper\Data::XML_PATH_DEFAULT_LOCALE; return $this->scopeConfig->getValue($path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeId); } /** * Format Magento locale codes with undersocre to ISO locale codes with dash * @param $localeCode */ public function formatLocaleCode($localeCode) { return str_replace("_", "-", $localeCode); } public function getApplePayShippingTypes() { return [ [ 'value' => 'shipping', 'label' => __('Shipping Method') ], [ 'value' => 'delivery', 'label' => __('Delivery Method') ], [ 'value' => 'storePickup', 'label' => __('Store Pickup Method') ], [ 'value' => 'servicePickup', 'label' => __('Service Pickup Method') ] ]; } public function getUnprocessedNotifications() { $notifications = $this->_notificationFactory->create(); $notifications->unprocessedNotificationsFilter(); return $notifications->getSize(); } /** * @param $formFields * @param $count * @param $name * @param $price * @param $currency * @param $taxAmount * @param $priceInclTax * @param $taxPercent * @param $numberOfItems * @param $payment * @param null $itemId * @return mixed */ public function createOpenInvoiceLineItem( $formFields, $count, $name, $price, $currency, $taxAmount, $priceInclTax, $taxPercent, $numberOfItems, $payment, $itemId = null ) { $description = str_replace("\n", '', trim($name)); $itemAmount = $this->formatAmount($price, $currency); $itemVatAmount = $this->getItemVatAmount( $taxAmount, $priceInclTax, $price, $currency ); // Calculate vat percentage $itemVatPercentage = $this->getMinorUnitTaxPercent($taxPercent); return $this->getOpenInvoiceLineData( $formFields, $count, $currency, $description, $itemAmount, $itemVatAmount, $itemVatPercentage, $numberOfItems, $payment, $itemId ); } /** * @param $formFields * @param $count * @param $order * @param $shippingAmount * @param $shippingTaxAmount * @param $currency * @param $payment * @return mixed */ public function createOpenInvoiceLineShipping( $formFields, $count, $order, $shippingAmount, $shippingTaxAmount, $currency, $payment ) { $description = $order->getShippingDescription(); $itemAmount = $this->formatAmount($shippingAmount, $currency); $itemVatAmount = $this->formatAmount($shippingTaxAmount, $currency); // Create RateRequest to calculate the Tax class rate for the shipping method $rateRequest = $this->_taxCalculation->getRateRequest( $order->getShippingAddress(), $order->getBillingAddress(), null, $order->getStoreId(), $order->getCustomerId() ); $taxClassId = $this->_taxConfig->getShippingTaxClass($order->getStoreId()); $rateRequest->setProductClassId($taxClassId); $rate = $this->_taxCalculation->getRate($rateRequest); $itemVatPercentage = $this->getMinorUnitTaxPercent($rate); $numberOfItems = 1; return $this->getOpenInvoiceLineData( $formFields, $count, $currency, $description, $itemAmount, $itemVatAmount, $itemVatPercentage, $numberOfItems, $payment, "shippingCost" ); } /** * @param $taxAmount * @param $priceInclTax * @param $price * @param $currency * @return string */ public function getItemVatAmount( $taxAmount, $priceInclTax, $price, $currency ) { if ($taxAmount > 0 && $priceInclTax > 0) { return $this->formatAmount($priceInclTax, $currency) - $this->formatAmount($price, $currency); } return $this->formatAmount($taxAmount, $currency); } /** * Set the openinvoice line * * @param $formFields * @param $count * @param $currencyCode * @param $description * @param $itemAmount * @param $itemVatAmount * @param $itemVatPercentage * @param $numberOfItems * @param $payment * @param null|int $itemId optional * @return mixed */ public function getOpenInvoiceLineData( $formFields, $count, $currencyCode, $description, $itemAmount, $itemVatAmount, $itemVatPercentage, $numberOfItems, $payment, $itemId = null ) { $linename = "line" . $count; // item id is optional if ($itemId) { $formFields['openinvoicedata.' . $linename . '.itemId'] = $itemId; } $formFields['openinvoicedata.' . $linename . '.currencyCode'] = $currencyCode; $formFields['openinvoicedata.' . $linename . '.description'] = $description; $formFields['openinvoicedata.' . $linename . '.itemAmount'] = $itemAmount; $formFields['openinvoicedata.' . $linename . '.itemVatAmount'] = $itemVatAmount; $formFields['openinvoicedata.' . $linename . '.itemVatPercentage'] = $itemVatPercentage; $formFields['openinvoicedata.' . $linename . '.numberOfItems'] = $numberOfItems; if ($this->isVatCategoryHigh($payment->getAdditionalInformation( \Adyen\Payment\Observer\AdyenHppDataAssignObserver::BRAND_CODE )) ) { $formFields['openinvoicedata.' . $linename . '.vatCategory'] = "High"; } else { $formFields['openinvoicedata.' . $linename . '.vatCategory'] = "None"; } return $formFields; } /** * @param int|null $storeId * @return string the X API Key for the specified or current store */ public function getPosApiKey($storeId = null) { if ($this->isDemoMode($storeId)) { $apiKey = $this->_encryptor->decrypt(trim($this->getAdyenPosCloudConfigData('api_key_test', $storeId))); } else { $apiKey = $this->_encryptor->decrypt(trim($this->getAdyenPosCloudConfigData('api_key_live', $storeId))); } return $apiKey; } /** * Return the Store ID for the current store/mode * * @param int|null $storeId * @return mixed */ public function getPosStoreId($storeId = null) { return $this->getAdyenPosCloudConfigData('pos_store_id', $storeId); } /** * Return the merchant account name configured for the proper payment method. * If it is not configured for the specific payment method, * return the merchant account name defined in required settings. * * @param $paymentMethod * @param int|null $storeId * @return string */ public function getAdyenMerchantAccount($paymentMethod, $storeId = null) { if (!$storeId) { $storeId = $this->storeManager->getStore()->getId(); } $merchantAccount = $this->getAdyenAbstractConfigData("merchant_account", $storeId); $merchantAccountPos = $this->getAdyenPosCloudConfigData('pos_merchant_account', $storeId); if ($paymentMethod == 'adyen_pos_cloud' && !empty($merchantAccountPos)) { return $merchantAccountPos; } return $merchantAccount; } /** * Format the Receipt sent in the Terminal API response in HTML * so that it can be easily shown to the shopper * * @param $paymentReceipt * @return string */ public function formatTerminalAPIReceipt($paymentReceipt) { $formattedHtml = "<table class='terminal-api-receipt'>"; foreach ($paymentReceipt as $receipt) { if ($receipt['DocumentQualifier'] == "CustomerReceipt") { foreach ($receipt['OutputContent']['OutputText'] as $item) { parse_str($item['Text'], $textParts); $formattedHtml .= "<tr class='terminal-api-receipt'>"; if (!empty($textParts['name'])) { $formattedHtml .= "<td class='terminal-api-receipt-name'>" . $textParts['name'] . "</td>"; } else { $formattedHtml .= "<td class='terminal-api-receipt-name'> </td>"; } if (!empty($textParts['value'])) { $formattedHtml .= "<td class='terminal-api-receipt-value' align='right'>" . $textParts['value'] . "</td>"; } else { $formattedHtml .= "<td class='terminal-api-receipt-value' align='right'> </td>"; } $formattedHtml .= "</tr>"; } } } $formattedHtml .= "</table>"; return $formattedHtml; } /** * Initializes and returns Adyen Client and sets the required parameters of it * * @param int|null $storeId * @param string|null $apiKey * @return \Adyen\Client * @throws \Adyen\AdyenException */ public function initializeAdyenClient($storeId = null, $apiKey = null) { // initialize client if ($storeId === null) { $storeId = $this->storeManager->getStore()->getId(); } if (empty($apiKey)) { $apiKey = $this->getAPIKey($storeId); } $client = $this->createAdyenClient(); $client->setApplicationName("Magento 2 plugin"); $client->setXApiKey($apiKey); $client->setAdyenPaymentSource($this->getModuleName(), $this->getModuleVersion()); $client->setExternalPlatform($this->productMetadata->getName(), $this->productMetadata->getVersion()); if ($this->isDemoMode($storeId)) { $client->setEnvironment(\Adyen\Environment::TEST); } else { $client->setEnvironment(\Adyen\Environment::LIVE, $this->getLiveEndpointPrefix($storeId)); } $client->setLogger($this->adyenLogger); return $client; } /** * @param \Adyen\Client $client * @return \Adyen\Service\PosPayment * @throws \Adyen\AdyenException */ public function createAdyenPosPaymentService($client) { return new \Adyen\Service\PosPayment($client); } /** * @return \Adyen\Client * @throws \Adyen\AdyenException */ private function createAdyenClient() { return new \Adyen\Client(); } /** * @return string */ public function getOrigin() { $baseUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_WEB); $parsed = parse_url($baseUrl); $origin = $parsed['scheme'] . "://" . $parsed['host']; if (!empty($parsed['port'])) { $origin .= ":" . $parsed['port']; } return $origin; } /** * Retrieve origin keys for platform's base url * * @return string * @throws \Adyen\AdyenException */ public function getOriginKeyForBaseUrl() { $origin = $this->getOrigin(); $storeId = $this->storeManager->getStore()->getId(); $cacheKey = 'Adyen_origin_key_for_' . $origin . '_' . $storeId; if (!$originKey = $this->cache->load($cacheKey)) { if ($originKey = $this->getOriginKeyForOrigin($origin, $storeId)) { $this->cache->save($originKey, $cacheKey, [], 60 * 60 * 24); } } return $originKey; } /** * Get origin key for a specific origin using the adyen api library client * * @param $origin * @param int|null $storeId * @return string * @throws \Adyen\AdyenException */ private function getOriginKeyForOrigin($origin, $storeId = null) { $params = [ "originDomains" => [ $origin ] ]; $client = $this->initializeAdyenClient($storeId); try { $service = $this->createAdyenCheckoutUtilityService($client); $response = $service->originKeys($params); } catch (\Exception $e) { $this->adyenLogger->error($e->getMessage()); } $originKey = ""; if (!empty($response['originKeys'][$origin])) { $originKey = $response['originKeys'][$origin]; } return $originKey; } /** * @param int|null $storeId * @return string */ public function getCheckoutEnvironment($storeId = null) { if ($this->isDemoMode($storeId)) { return self::TEST; } return self::LIVE; } /** * @param \Adyen\Client $client * @return \Adyen\Service\CheckoutUtility * @throws \Adyen\AdyenException */ private function createAdyenCheckoutUtilityService($client) { return new \Adyen\Service\CheckoutUtility($client); } /** * @param int|null $storeId * @return string */ public function getCheckoutCardComponentJs($storeId = null) { if ($this->isDemoMode($storeId)) { return self::CHECKOUT_COMPONENT_JS_TEST; } return self::CHECKOUT_COMPONENT_JS_LIVE; } /** * @param $order * @param $additionalData */ public function createAdyenBillingAgreement($order, $additionalData) { if (!empty($additionalData['recurring.recurringDetailReference'])) { $listRecurringContracts = null; try { // Get or create billing agreement /** @var \Adyen\Payment\Model\Billing\Agreement $billingAgreement */ $billingAgreement = $this->billingAgreementFactory->create(); $billingAgreement->load($additionalData['recurring.recurringDetailReference'], 'reference_id'); // check if BA exists if (!($billingAgreement && $billingAgreement->getAgreementId() > 0 && $billingAgreement->isValid())) { // create new BA $billingAgreement = $this->billingAgreementFactory->create(); $billingAgreement->setStoreId($order->getStoreId()); $billingAgreement->importOrderPayment($order->getPayment()); if ($billingAgreement->getCustomerId() === null) { $billingAgreement->setCustomerId($this->getCustomerId($order)); } $message = __('Created billing agreement #%1.', $additionalData['recurring.recurringDetailReference']); } else { $billingAgreement->setIsObjectChanged(true); $message = __('Updated billing agreement #%1.', $additionalData['recurring.recurringDetailReference']); } // Populate billing agreement data $storeOneClick = $order->getPayment()->getAdditionalInformation('store_cc'); $billingAgreement->setCcBillingAgreement($additionalData, $storeOneClick, $order->getStoreId()); $billingAgreementErrors = $billingAgreement->getErrors(); if ($billingAgreement->isValid() && empty($billingAgreementErrors)) { if (!$this->agreementResourceModel->getOrderRelation($billingAgreement->getAgreementId(), $order->getId())) { // save into sales_billing_agreement_order $billingAgreement->addOrderRelation($order); } // add to order to save agreement $order->addRelatedObject($billingAgreement); } else { $message = __('Failed to create billing agreement for this order. Reason(s): ') . join(', ', $billingAgreementErrors); throw new \Exception($message); } } catch (\Exception $exception) { $message = $exception->getMessage(); $this->adyenLogger->error("exception: " . $message); } $comment = $order->addStatusHistoryComment($message); $order->addRelatedObject($comment); } } /** * Method can be used by interceptors to provide the customer ID in a different way. * @param \Magento\Sales\Model\Order $order * @return int|null */ public function getCustomerId(\Magento\Sales\Model\Order $order) { return $order->getCustomerId(); } /** * For backwards compatibility get the recurringType used for HPP + current billing agreements * * @param null $storeId * @return null|string */ public function getRecurringTypeFromOneclickRecurringSetting($storeId = null) { $enableOneclick = $this->getAdyenAbstractConfigData('enable_oneclick', $storeId); $enableRecurring = $this->getAdyenAbstractConfigData('enable_recurring', $storeId); if ($enableOneclick && $enableRecurring) { return \Adyen\Payment\Model\RecurringType::ONECLICK_RECURRING; } elseif ($enableOneclick && !$enableRecurring) { return \Adyen\Payment\Model\RecurringType::ONECLICK; } elseif (!$enableOneclick && $enableRecurring) { return \Adyen\Payment\Model\RecurringType::RECURRING; } else { return \Adyen\Payment\Model\RecurringType::NONE; } } /** * Get icon from variant * * @param $variant * @return array */ public function getVariantIcon($variant) { $asset = $this->createAsset(sprintf("Adyen_Payment::images/logos/%s_small.png", $variant)); list($width, $height) = getimagesize($asset->getSourceFile()); $icon = [ 'url' => $asset->getUrl(), 'width' => $width, 'height' => $height ]; return $icon; } /** * Check if CreditCard vault is enabled * * @param int|null $storeId * @return mixed */ public function isCreditCardVaultEnabled($storeId = null) { return $this->getAdyenCcVaultConfigDataFlag('active', $storeId); } /** * Checks if the house number needs to be sent to the Adyen API separately or as it is in the street field * * @param $country * @return bool */ public function isSeparateHouseNumberRequired($country) { $countryList = ["nl", "de", "se", "no", "at", "fi", "dk"]; return in_array(strtolower($country), $countryList); } /** * Check if 3DS2.0 is enabled for credit cards * * @param int|null $storeId * @return mixed */ public function isCreditCardThreeDS2Enabled($storeId = null) { return $this->getAdyenCcThreeDS2ConfigDataFlag('active', $storeId); } /** * @param $client * @return \Adyen\Service\Checkout */ public function createAdyenCheckoutService($client) { return new \Adyen\Service\Checkout($client); } /** * @param $client * @return \Adyen\Service\Recurring * @throws \Adyen\AdyenException */ public function createAdyenRecurringService($client) { return new \Adyen\Service\Recurring($client); } /** * @param string $date * @param string $format * @return mixed */ public function formatDate($date = null, $format = 'Y-m-d H:i:s') { if (strlen($date) < 0) { $date = date('d-m-Y H:i:s'); } $timeStamp = new \DateTime($date); return $timeStamp->format($format); } /** * @param string|null $type * @param string|null $token * @return string */ public function buildThreeDS2ProcessResponseJson($type = null, $token = null) { $response = ['threeDS2' => false]; if ($type && $token) { $response = [ "threeDS2" => true, "type" => $type, "token" => $token ]; } return json_encode($response); } /** * @param int $storeId * @return mixed|string */ public function getCurrentLocaleCode($storeId) { $localeCode = $this->getAdyenAbstractConfigData('shopper_locale', $storeId); if ($localeCode != "") { return $localeCode; } $locale = $this->localeResolver->getLocale(); if ($locale) { return $locale; } // should have the value if not fall back to default $localeCode = $this->config->getValue( \Magento\Directory\Helper\Data::XML_PATH_DEFAULT_LOCALE, \Magento\Store\Model\ScopeInterface::SCOPE_STORES, $this->storeManager->getStore($storeId)->getCode() ); return $localeCode; } }