From 741b3d1684ddb7b29986970af3623985a9d9df3f Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Wed, 25 Oct 2023 15:45:34 +0200 Subject: [PATCH 001/147] CHECMAG2003-188: remove KNet from unavailable alternative payments --- Model/Methods/AlternativePaymentMethod.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Model/Methods/AlternativePaymentMethod.php b/Model/Methods/AlternativePaymentMethod.php index 424c52a1..737951fa 100755 --- a/Model/Methods/AlternativePaymentMethod.php +++ b/Model/Methods/AlternativePaymentMethod.php @@ -105,7 +105,6 @@ class AlternativePaymentMethod extends AbstractMethod 'boleto', 'giropay', 'klarna', - 'knet', 'poli', 'sepa', ]; From f273ef7d1899d6a6124ed8f5619a46380b62f4b1 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Fri, 27 Oct 2023 15:31:14 +0200 Subject: [PATCH 002/147] Bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7dcf15ed..edc52062 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "5.5.0", + "version": "5.6.0", "autoload": { "files": [ "registration.php" From dac02c2586626dadd41c43d974978b914e1b322e Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 14 Nov 2023 16:24:13 +0100 Subject: [PATCH 003/147] CHECMAG2003-192: add payment declined webhook handler --- Model/Service/OrderStatusHandlerService.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Model/Service/OrderStatusHandlerService.php b/Model/Service/OrderStatusHandlerService.php index 3e5b9490..7c91a7c0 100644 --- a/Model/Service/OrderStatusHandlerService.php +++ b/Model/Service/OrderStatusHandlerService.php @@ -159,6 +159,9 @@ public function setOrderStatus(OrderInterface $order, array $webhook): void case 'payment_expired': $this->paymentExpired(); break; + case 'payment_declined': + $this->declined(); + break; case 'payment_authentication_failed': $this->paymentAuthenticationFailed(); break; @@ -331,4 +334,18 @@ protected function paymentAuthenticationFailed(): void $this->order->addStatusHistoryComment(__('3DS authentication failed/expired.')); $this->handleFailedPayment($this->order); } + + /** + * Set the order status for a payment authorization failed webhook. + * + * @return void + * @throws NoSuchEntityException + */ + protected function declined(): void + { + $this->state = Order::STATE_CANCELED; + $this->status = $this->order->getConfig()->getStateDefaultStatus($this->state); + $this->order->addStatusHistoryComment(__('Failed payment authorization')); + $this->handleFailedPayment($this->order); + } } From b4743e63beb5fbec11c1ad85f68fa4626f54737b Mon Sep 17 00:00:00 2001 From: DnD-Nibra Date: Tue, 28 Nov 2023 16:45:24 +0100 Subject: [PATCH 004/147] CHECMAG2003-193: Add config fields - see above --- etc/adminhtml/system.xml | 33 +++++++++++++++++++++++++++++++++ etc/config.xml | 1 + 2 files changed, 34 insertions(+) diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 5258c5e7..159e3402 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -258,6 +258,39 @@ settings/checkoutcom_configuration/gateway_responses + + + + + Magento\Config\Model\Config\Source\Yesno + settings/checkoutcom_configuration/abc_refund_enable + + + + + + + + + + Magento\Config\Model\Config\Backend\Encrypted + settings/checkoutcom_configuration/abc_refund_secret_key + required-entry + + + + + settings/checkoutcom_configuration/abc_refund_public_key + required-entry + + + + + Magento\Config\Model\Config\Backend\Encrypted + settings/checkoutcom_configuration/abc_refund_private_shared_key + required-entry + + diff --git a/etc/config.xml b/etc/config.xml index 7b9e4f70..926c7e23 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -53,6 +53,7 @@ BHD,LYD,JOD,KWD,OMR,TND checkoutcom_card_payment https://api.github.com/repos/checkout/checkout-magento2-plugin/releases + 0 From 7b5d98cb3c1a35cc5af24196e9df202aa555485b Mon Sep 17 00:00:00 2001 From: DnD-Nibra Date: Tue, 28 Nov 2023 17:34:46 +0100 Subject: [PATCH 005/147] CHECMAG2003-193: Retrieve ABC refund configuration - see above --- Gateway/Config/Config.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index 3e095947..79920bda 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -524,4 +524,28 @@ public function needsRiskRules($methodId): bool { return (!$this->getValue('risk_rules_enabled', $methodId) === true); } + + /** + * Check ABC refund after NAS migration + * + * @return bool + */ + public function isAbcRefundToNasActive(): bool + { + return $this->getValue('abc_refund_enable'); + } + + /** + * Get Abc refund keys + * + * @return array + */ + public function getAbcRefundKeys(): array + { + return [ + 'public_key' => $this->getValue('abc_refund_secret_key'), + 'secretKey' => $this->getValue('abc_refund_public_key'), + 'privateSharedKey' => $this->getValue('abc_refund_private_shared_key'), + ]; + } } From 4a62e83ee138a6b01d45a58a06c360fb3f1bb692 Mon Sep 17 00:00:00 2001 From: DnD-Nibra Date: Tue, 28 Nov 2023 17:59:22 +0100 Subject: [PATCH 006/147] CHECMAG2003-193: Fix required entries - see above --- etc/adminhtml/system.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 159e3402..0fb29c8b 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -275,20 +275,17 @@ Magento\Config\Model\Config\Backend\Encrypted settings/checkoutcom_configuration/abc_refund_secret_key - required-entry settings/checkoutcom_configuration/abc_refund_public_key - required-entry Magento\Config\Model\Config\Backend\Encrypted settings/checkoutcom_configuration/abc_refund_private_shared_key - required-entry From 8ddf4313e96bfaeb25261cd4a0f9867d17f14534 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 5 Dec 2023 12:05:00 +0100 Subject: [PATCH 007/147] feature/CHECMAG2003-193: add auto refund feature from ABC after NAS migration --- Gateway/Config/Config.php | 20 ++++---------------- Model/Service/ApiHandlerService.php | 17 +++++++++++++++++ Plugin/Api/RefundInvoice.php | 12 ++++++++++++ 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index 79920bda..5c397a08 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -530,22 +530,10 @@ public function needsRiskRules($methodId): bool * * @return bool */ - public function isAbcRefundToNasActive(): bool + public function isAbcRefundAfterNasMigrationActive(): bool { - return $this->getValue('abc_refund_enable'); - } - - /** - * Get Abc refund keys - * - * @return array - */ - public function getAbcRefundKeys(): array - { - return [ - 'public_key' => $this->getValue('abc_refund_secret_key'), - 'secretKey' => $this->getValue('abc_refund_public_key'), - 'privateSharedKey' => $this->getValue('abc_refund_private_shared_key'), - ]; + return (bool) $this->getValue('abc_refund_enable') + && $this->getValue('abc_refund_secret_key') + && $this->getValue('abc_refund_public_key'); } } diff --git a/Model/Service/ApiHandlerService.php b/Model/Service/ApiHandlerService.php index 8eb8a044..39fb54a3 100644 --- a/Model/Service/ApiHandlerService.php +++ b/Model/Service/ApiHandlerService.php @@ -178,6 +178,23 @@ public function init( return $this; } + public function initABCForRefund( + $storeCode = null, + string $scope = ScopeInterface::SCOPE_WEBSITE + ): ApiHandlerService + { + $secretKey = $this->config->getValue('abc_refund_secret_key', null, $storeCode, $scope); + $publicKey = $this->config->getValue('abc_refund_public_key', null, $storeCode, $scope); + + $this->checkoutApi = new CheckoutApi( + $secretKey, + $this->config->getValue('environment', null, $storeCode, $scope), + $publicKey + ); + + return $this; + } + /** * Get CheckoutApi * diff --git a/Plugin/Api/RefundInvoice.php b/Plugin/Api/RefundInvoice.php index 9804d64d..50cee901 100644 --- a/Plugin/Api/RefundInvoice.php +++ b/Plugin/Api/RefundInvoice.php @@ -140,6 +140,18 @@ public function beforeRefund( ); } + // Try to process the refund with ABC API + if (!$api->isValidResponse($response) && $this->config->isAbcRefundAfterNasMigrationActive()) { + // Initialize ABC API handler + $apiABC = $this->apiHandler->initABCForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $response = $apiABC->refundOrder($payment, $amount); + if (!$apiABC->isValidResponse($response)) { + throw new LocalizedException( + __('The refund request could not be processed.') + ); + } + } + if ($this->statusNeedsCorrection($order)) { $order->setStatus($this->config->getValue('order_status_refunded')); } From 7d162da972d11cf19720efc532d2141f8eeae644 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 5 Dec 2023 13:30:46 +0100 Subject: [PATCH 008/147] feature/CHECMAG2003-193: fix function naming --- Model/Service/ApiHandlerService.php | 2 +- Plugin/Api/RefundInvoice.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Model/Service/ApiHandlerService.php b/Model/Service/ApiHandlerService.php index 980ad65e..71e529f7 100644 --- a/Model/Service/ApiHandlerService.php +++ b/Model/Service/ApiHandlerService.php @@ -199,7 +199,7 @@ public function init( return $this; } - public function initABCForRefund( + public function initAbcForRefund( $storeCode = null, string $scope = ScopeInterface::SCOPE_WEBSITE ): ApiHandlerService diff --git a/Plugin/Api/RefundInvoice.php b/Plugin/Api/RefundInvoice.php index 50cee901..e9922aeb 100644 --- a/Plugin/Api/RefundInvoice.php +++ b/Plugin/Api/RefundInvoice.php @@ -143,7 +143,7 @@ public function beforeRefund( // Try to process the refund with ABC API if (!$api->isValidResponse($response) && $this->config->isAbcRefundAfterNasMigrationActive()) { // Initialize ABC API handler - $apiABC = $this->apiHandler->initABCForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $apiABC = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); $response = $apiABC->refundOrder($payment, $amount); if (!$apiABC->isValidResponse($response)) { throw new LocalizedException( From 356d208dba30f58796a5f9ede527a0a123d703bf Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Fri, 8 Dec 2023 16:41:58 +0100 Subject: [PATCH 009/147] CHECMAG2003-195: change cc error messages on single form --- view/frontend/web/css/frames/single.css | 1 + view/frontend/web/css/frames/single.min.css | 2 +- view/frontend/web/js/frames/single.js | 48 +++++++++++++++++-- view/frontend/web/js/frames/single.min.js | 7 +-- .../payment/checkoutcom_card_payment.html | 6 ++- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/view/frontend/web/css/frames/single.css b/view/frontend/web/css/frames/single.css index 68e6cb26..949f147c 100644 --- a/view/frontend/web/css/frames/single.css +++ b/view/frontend/web/css/frames/single.css @@ -61,6 +61,7 @@ } #checkoutcom_card_payment_frm .error-message { + display: block; color: #C9501C; font-size: 1.2rem; margin: 8px 0 0 1px; diff --git a/view/frontend/web/css/frames/single.min.css b/view/frontend/web/css/frames/single.min.css index f5ddf687..d7053b63 100644 --- a/view/frontend/web/css/frames/single.min.css +++ b/view/frontend/web/css/frames/single.min.css @@ -13,4 +13,4 @@ * @link https://docs.checkout.com/ */ -#checkoutcom_card_payment_frm *,#checkoutcom_card_payment_frm ::after,#checkoutcom_card_payment_frm ::before{box-sizing:border-box}#checkoutcom_card_payment_frm html{padding:1rem;background-color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}#checkoutcom_card_payment_frm iframe{width:100%}#checkoutcom_card_payment_frm .one-liner{display:flex;flex-direction:column}#checkoutcom_card_payment_frm .card-frame{border:solid 1px #13395e;border-radius:3px;width:100%;margin-bottom:8px;height:40px;box-shadow:0 1px 3px 0 rgba(19,57,94,.2)}#checkoutcom_card_payment_frm .card-frame.frame--rendered{opacity:1}#checkoutcom_card_payment_frm .card-frame.frame--rendered.frame--focus{border:solid 1px #13395e;box-shadow:0 2px 5px 0 rgba(19,57,94,.15)}#checkoutcom_card_payment_frm .card-frame.frame--rendered.frame--invalid{border:solid 1px #d96830;box-shadow:0 2px 5px 0 rgba(217,104,48,.15)}#checkoutcom_card_payment_frm .error-message{color:#c9501c;font-size:1.2rem;margin:8px 0 0 1px;font-weight:300}#checkoutcom_card_payment_frm .success-payment-message{color:#13395e;line-height:1.4}#checkoutcom_card_payment_frm .token{color:#b35e14;font-size:.9rem;font-family:monospace}@media screen and (min-width:31rem){#checkoutcom_card_payment_frm .one-liner{flex-direction:row}#checkoutcom_card_payment_frm .card-frame{margin-bottom:0}} +#checkoutcom_card_payment_frm *,#checkoutcom_card_payment_frm ::after,#checkoutcom_card_payment_frm ::before{box-sizing:border-box}#checkoutcom_card_payment_frm html{padding:1rem;background-color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}#checkoutcom_card_payment_frm iframe{width:100%}#checkoutcom_card_payment_frm .one-liner{display:flex;flex-direction:column}#checkoutcom_card_payment_frm .card-frame{border:1px solid #13395e;border-radius:3px;width:100%;margin-bottom:8px;height:40px;box-shadow:0 1px 3px 0 rgba(19,57,94,.2)}#checkoutcom_card_payment_frm .card-frame.frame--rendered{opacity:1}#checkoutcom_card_payment_frm .card-frame.frame--rendered.frame--focus{border:1px solid #13395e;box-shadow:0 2px 5px 0 rgba(19,57,94,.15)}#checkoutcom_card_payment_frm .card-frame.frame--rendered.frame--invalid{border:1px solid #d96830;box-shadow:0 2px 5px 0 rgba(217,104,48,.15)}#checkoutcom_card_payment_frm .error-message{display:block;color:#c9501c;font-size:1.2rem;margin:8px 0 0 1px;font-weight:300}#checkoutcom_card_payment_frm .success-payment-message{color:#13395e;line-height:1.4}#checkoutcom_card_payment_frm .token{color:#b35e14;font-size:.9rem;font-family:monospace}@media screen and (min-width:31rem){#checkoutcom_card_payment_frm .one-liner{flex-direction:row}#checkoutcom_card_payment_frm .card-frame{margin-bottom:0}} diff --git a/view/frontend/web/js/frames/single.js b/view/frontend/web/js/frames/single.js index 26011c9e..3f79ecda 100755 --- a/view/frontend/web/js/frames/single.js +++ b/view/frontend/web/js/frames/single.js @@ -36,6 +36,27 @@ define( return this.F; }, + getLogos: function () { + var logos = {}; + + logos['card-number'] = { + src: 'card', + alt: __('Card number logo') + }; + + logos['expiry-date'] = { + src: 'exp-date', + alt: __('Expiry date logo') + }; + + logos['cvv'] = { + src: 'cvv', + alt: __('CVV logo') + }; + + return logos; + }, + getErrors: function () { var errors = { 'card-number': __('Please enter a valid card number'), @@ -55,10 +76,29 @@ define( }, onValidationChanged: function (event) { - var targetSelector = '.error-message'; - var errorMessage = document.querySelector(targetSelector); - errorMessage.textContent = this.getErrorMessage(event); - } + var e = event.element; + var pm = event.paymentMethod; + var targetSelector = '#' + this.formId + ' .icon-container.payment-method'; + let container = document.querySelector(targetSelector); + + if (event.isValid || event.isEmpty) { + this.clearErrorMessage(e); + } else { + this.setErrorMessage(e); + } + }, + + clearErrorMessage: function (el) { + var targetSelector = '#' + this.formId + ' .error-message__' + el; + var message = document.querySelector(targetSelector); + message.textContent = ''; + }, + + setErrorMessage: function (el) { + var targetSelector = '#' + this.formId + ' .error-message__' + el; + var message = document.querySelector(targetSelector); + message.textContent = this.getErrors()[el]; + }, }; } ); diff --git a/view/frontend/web/js/frames/single.min.js b/view/frontend/web/js/frames/single.min.js index d8981181..668c8b19 100755 --- a/view/frontend/web/js/frames/single.min.js +++ b/view/frontend/web/js/frames/single.min.js @@ -14,9 +14,4 @@ * @link https://docs.checkout.com/ */ -define(["jquery","mage/translate"],function (e,t) { - "use strict";return{load:function (e,t) { - return this.F=e,this.formId=t,this.F.addEventHandler(this.F.Events.FRAME_VALIDATION_CHANGED,this.onValidationChanged.bind(this)),this.F},getErrors:function () { - return{"card-number":t("Please enter a valid card number"),"expiry-date":t("Please enter a valid expiry date"),cvv:t("Please enter a valid CVV code")}},getErrorMessage:function (e) { - return e.isValid||e.isEmpty?"":this.getErrors()[e.element]},onValidationChanged:function (e) { - document.querySelector(".error-message").textContent=this.getErrorMessage(e)}}}); +define(["jquery","mage/translate"],function(e,r){return{load:function(e,r){return this.F=e,this.formId=r,this.F.addEventHandler(this.F.Events.FRAME_VALIDATION_CHANGED,this.onValidationChanged.bind(this)),this.F},getLogos:function(){var e={};return e["card-number"]={src:"card",alt:r("Card number logo")},e["expiry-date"]={src:"exp-date",alt:r("Expiry date logo")},e.cvv={src:"cvv",alt:r("CVV logo")},e},getErrors:function(){return{"card-number":r("Please enter a valid card number"),"expiry-date":r("Please enter a valid expiry date"),cvv:r("Please enter a valid CVV code")}},getErrorMessage:function(e){return e.isValid||e.isEmpty?"":this.getErrors()[e.element]},onValidationChanged:function(e){var r=e.element;e.paymentMethod;var t="#"+this.formId+" .icon-container.payment-method";document.querySelector(t),e.isValid||e.isEmpty?this.clearErrorMessage(r):this.setErrorMessage(r)},clearErrorMessage:function(e){var r="#"+this.formId+" .error-message__"+e;document.querySelector(r).textContent=""},setErrorMessage:function(e){var r="#"+this.formId+" .error-message__"+e;document.querySelector(r).textContent=this.getErrors()[e]}}}); diff --git a/view/frontend/web/template/payment/checkoutcom_card_payment.html b/view/frontend/web/template/payment/checkoutcom_card_payment.html index 7f9c0edf..3d80221f 100755 --- a/view/frontend/web/template/payment/checkoutcom_card_payment.html +++ b/view/frontend/web/template/payment/checkoutcom_card_payment.html @@ -61,7 +61,11 @@
-

+
+ + + +
From 7263f2d07927e2a669197c734cb3be1cf500976e Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Fri, 8 Dec 2023 16:43:17 +0100 Subject: [PATCH 010/147] CHECMAG2003-195: remove unused func --- view/frontend/web/js/frames/single.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/view/frontend/web/js/frames/single.js b/view/frontend/web/js/frames/single.js index 3f79ecda..e8c423d1 100755 --- a/view/frontend/web/js/frames/single.js +++ b/view/frontend/web/js/frames/single.js @@ -67,19 +67,8 @@ define( return errors; }, - getErrorMessage: function (event) { - if (event.isValid || event.isEmpty) { - return ''; - } - - return this.getErrors()[event.element]; - }, - onValidationChanged: function (event) { var e = event.element; - var pm = event.paymentMethod; - var targetSelector = '#' + this.formId + ' .icon-container.payment-method'; - let container = document.querySelector(targetSelector); if (event.isValid || event.isEmpty) { this.clearErrorMessage(e); From 9be3271d77b1fb24843d28cf54a64ec0ddb97f53 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 11 Dec 2023 16:08:31 +0100 Subject: [PATCH 011/147] CHECMAG2003-193: init ABC on catching exception in refund --- Plugin/Api/RefundInvoice.php | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Plugin/Api/RefundInvoice.php b/Plugin/Api/RefundInvoice.php index e9922aeb..b40edc05 100644 --- a/Plugin/Api/RefundInvoice.php +++ b/Plugin/Api/RefundInvoice.php @@ -18,9 +18,11 @@ namespace CheckoutCom\Magento2\Plugin\Api; +use Checkout\CheckoutArgumentException; use CheckoutCom\Magento2\Gateway\Config\Config; use CheckoutCom\Magento2\Model\Service\ApiHandlerService; use CheckoutCom\Magento2\Model\Service\MethodHandlerService; +use GraphQL\Exception\InvalidArgument; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Sales\Api\Data\CreditmemoInterface; @@ -113,7 +115,14 @@ public function beforeRefund( $storeCode = $this->storeManager->getStore()->getCode(); // Initialize the API handler - $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive()) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } // Get the method and method id $methodId = $order->getPayment()->getMethodInstance()->getCode(); @@ -140,18 +149,6 @@ public function beforeRefund( ); } - // Try to process the refund with ABC API - if (!$api->isValidResponse($response) && $this->config->isAbcRefundAfterNasMigrationActive()) { - // Initialize ABC API handler - $apiABC = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); - $response = $apiABC->refundOrder($payment, $amount); - if (!$apiABC->isValidResponse($response)) { - throw new LocalizedException( - __('The refund request could not be processed.') - ); - } - } - if ($this->statusNeedsCorrection($order)) { $order->setStatus($this->config->getValue('order_status_refunded')); } From acbfeac88256662d03af7fb80b9a579d28faf620 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 11 Dec 2023 16:09:57 +0100 Subject: [PATCH 012/147] CHECMAG2003-193: remove useless use --- Plugin/Api/RefundInvoice.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Plugin/Api/RefundInvoice.php b/Plugin/Api/RefundInvoice.php index b40edc05..484c5844 100644 --- a/Plugin/Api/RefundInvoice.php +++ b/Plugin/Api/RefundInvoice.php @@ -22,7 +22,6 @@ use CheckoutCom\Magento2\Gateway\Config\Config; use CheckoutCom\Magento2\Model\Service\ApiHandlerService; use CheckoutCom\Magento2\Model\Service\MethodHandlerService; -use GraphQL\Exception\InvalidArgument; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Sales\Api\Data\CreditmemoInterface; From a86a8c73bb2b04f3da62832a9a88e36352c32a3b Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 11 Dec 2023 16:50:00 +0100 Subject: [PATCH 013/147] CHECMAG2003-193: handle config load by store --- Gateway/Config/Config.php | 8 ++++---- Plugin/Api/RefundInvoice.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index 4a0a980b..696c9ea9 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -562,11 +562,11 @@ public function needsRiskRules($methodId): bool * * @return bool */ - public function isAbcRefundAfterNasMigrationActive(): bool + public function isAbcRefundAfterNasMigrationActive($storeCode = null): bool { - return (bool) $this->getValue('abc_refund_enable') - && $this->getValue('abc_refund_secret_key') - && $this->getValue('abc_refund_public_key'); + return (bool) $this->getValue('abc_refund_enable', null, $storeCode) + && $this->getValue('abc_refund_secret_key', null, $storeCode) + && $this->getValue('abc_refund_public_key', null, $storeCode); } /** diff --git a/Plugin/Api/RefundInvoice.php b/Plugin/Api/RefundInvoice.php index 484c5844..11c875f0 100644 --- a/Plugin/Api/RefundInvoice.php +++ b/Plugin/Api/RefundInvoice.php @@ -117,7 +117,7 @@ public function beforeRefund( try { $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); } catch (CheckoutArgumentException $e) { - if (!$this->config->isAbcRefundAfterNasMigrationActive()) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { throw new LocalizedException(__($e->getMessage())); } $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); From 05ea9746db7518039bfb06f7cab6b8a5b71679ba Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 11 Dec 2023 16:59:12 +0100 Subject: [PATCH 014/147] CHECMAG2003-193: handle config load by store with store of the order not store default --- Plugin/Api/RefundInvoice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugin/Api/RefundInvoice.php b/Plugin/Api/RefundInvoice.php index 11c875f0..83b909f2 100644 --- a/Plugin/Api/RefundInvoice.php +++ b/Plugin/Api/RefundInvoice.php @@ -111,7 +111,7 @@ public function beforeRefund( bool $isOnline = false ): array { // Get the store code - $storeCode = $this->storeManager->getStore()->getCode(); + $storeCode = $this->storeManager->getStore($order->getStoreId())->getCode(); // Initialize the API handler try { From 534899a1403fecc0e649b792dd72921f1c1f8b79 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 11 Dec 2023 17:30:16 +0100 Subject: [PATCH 015/147] CHECMAG2003-193: handle API call with correct version of sdk --- Gateway/Config/Config.php | 4 +--- Model/Service/ApiHandlerService.php | 14 +++++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index 696c9ea9..c7ef2144 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -564,9 +564,7 @@ public function needsRiskRules($methodId): bool */ public function isAbcRefundAfterNasMigrationActive($storeCode = null): bool { - return (bool) $this->getValue('abc_refund_enable', null, $storeCode) - && $this->getValue('abc_refund_secret_key', null, $storeCode) - && $this->getValue('abc_refund_public_key', null, $storeCode); + return (bool) $this->getValue('abc_refund_enable', null, $storeCode); } /** diff --git a/Model/Service/ApiHandlerService.php b/Model/Service/ApiHandlerService.php index 71e529f7..40c46044 100644 --- a/Model/Service/ApiHandlerService.php +++ b/Model/Service/ApiHandlerService.php @@ -207,11 +207,15 @@ public function initAbcForRefund( $secretKey = $this->config->getValue('abc_refund_secret_key', null, $storeCode, $scope); $publicKey = $this->config->getValue('abc_refund_public_key', null, $storeCode, $scope); - $this->checkoutApi = new CheckoutApi( - $secretKey, - $this->config->getValue('environment', null, $storeCode, $scope), - $publicKey - ); + $api = CheckoutSdk::builder(); + $environment = $this->config->getEnvironment((int)$storeCode, $scope); + + $this->checkoutApi = $api + ->previous()->staticKeys() + ->publicKey($publicKey) + ->secretKey($secretKey) + ->environment($environment) + ->build(); return $this; } From 82f96d8917b4b3e8f693ab49004f48cf2a380cad Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 12 Dec 2023 10:40:12 +0100 Subject: [PATCH 016/147] CHECMAG2003-193: remove useless key and add debug --- Plugin/Api/RefundInvoice.php | 6 +++++- etc/adminhtml/system.xml | 9 +-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Plugin/Api/RefundInvoice.php b/Plugin/Api/RefundInvoice.php index 83b909f2..c9da0f56 100644 --- a/Plugin/Api/RefundInvoice.php +++ b/Plugin/Api/RefundInvoice.php @@ -112,13 +112,17 @@ public function beforeRefund( ): array { // Get the store code $storeCode = $this->storeManager->getStore($order->getStoreId())->getCode(); + error_log("enable. ".$this->config->isAbcRefundAfterNasMigrationActive($storeCode) . PHP_EOL, 3, "/bitnami/magento/var/log/behou.log"); + error_log("public key. ".$this->config->getValue('abc_refund_public_key', null, $storeCode) . PHP_EOL, 3, "/bitnami/magento/var/log/behou.log"); + error_log("secret key ".$this->config->getValue('abc_refund_secret_key', null, $storeCode) . PHP_EOL, 3, "/bitnami/magento/var/log/behou.log"); + // Initialize the API handler try { $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); } catch (CheckoutArgumentException $e) { if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { - throw new LocalizedException(__($e->getMessage())); + throw new LocalizedException(__('Localized '.$e->getMessage())); } $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); } diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 7b556225..eebd9b65 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -279,13 +279,12 @@ - + Magento\Config\Model\Config\Source\Yesno settings/checkoutcom_configuration/abc_refund_enable - @@ -299,12 +298,6 @@ settings/checkoutcom_configuration/abc_refund_public_key - - - - Magento\Config\Model\Config\Backend\Encrypted - settings/checkoutcom_configuration/abc_refund_private_shared_key - From 646bf2752e5cd958814dc2f940ba7bc4763e4ab2 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 12 Dec 2023 11:29:27 +0100 Subject: [PATCH 017/147] CHECMAG2003-193: add ABC refund fallback on all payment methods --- Model/Methods/AlternativePaymentMethod.php | 9 ++++++++- Model/Methods/ApplePayMethod.php | 9 ++++++++- Model/Methods/CardPaymentMethod.php | 9 ++++++++- Model/Methods/GooglePayMethod.php | 9 ++++++++- Model/Methods/MotoMethod.php | 9 ++++++++- Model/Methods/VaultMethod.php | 9 ++++++++- Plugin/Api/RefundInvoice.php | 8 ++------ 7 files changed, 50 insertions(+), 12 deletions(-) diff --git a/Model/Methods/AlternativePaymentMethod.php b/Model/Methods/AlternativePaymentMethod.php index 737951fa..4c769b9e 100755 --- a/Model/Methods/AlternativePaymentMethod.php +++ b/Model/Methods/AlternativePaymentMethod.php @@ -1059,7 +1059,14 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod $storeCode = $payment->getOrder()->getStore()->getCode(); // Initialize the API handler - $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } // Check the status if (!$this->canRefund()) { diff --git a/Model/Methods/ApplePayMethod.php b/Model/Methods/ApplePayMethod.php index 99bd777b..68551e91 100755 --- a/Model/Methods/ApplePayMethod.php +++ b/Model/Methods/ApplePayMethod.php @@ -494,7 +494,14 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod $storeCode = $payment->getOrder()->getStore()->getCode(); // Initialize the API handler - $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } // Check the status if (!$this->canRefund()) { diff --git a/Model/Methods/CardPaymentMethod.php b/Model/Methods/CardPaymentMethod.php index c1649c6d..99ea8894 100755 --- a/Model/Methods/CardPaymentMethod.php +++ b/Model/Methods/CardPaymentMethod.php @@ -558,7 +558,14 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod $storeCode = $payment->getOrder()->getStore()->getCode(); // Initialize the API handler - $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } // Check the status if (!$this->canRefund()) { diff --git a/Model/Methods/GooglePayMethod.php b/Model/Methods/GooglePayMethod.php index 594bf748..9bdaaac7 100755 --- a/Model/Methods/GooglePayMethod.php +++ b/Model/Methods/GooglePayMethod.php @@ -490,7 +490,14 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod $storeCode = $payment->getOrder()->getStore()->getCode(); // Initialize the API handler - $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } // Check the status if (!$this->canRefund()) { diff --git a/Model/Methods/MotoMethod.php b/Model/Methods/MotoMethod.php index 5d435ebc..4a825647 100755 --- a/Model/Methods/MotoMethod.php +++ b/Model/Methods/MotoMethod.php @@ -331,7 +331,14 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod $storeCode = $payment->getOrder()->getStore()->getCode(); // Initialize the API handler - $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } // Check the status if (!$this->canRefund()) { diff --git a/Model/Methods/VaultMethod.php b/Model/Methods/VaultMethod.php index 90af924e..8ee92dcd 100755 --- a/Model/Methods/VaultMethod.php +++ b/Model/Methods/VaultMethod.php @@ -551,7 +551,14 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod $storeCode = $payment->getOrder()->getStore()->getCode(); // Initialize the API handler - $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } // Check the status if (!$this->canRefund()) { diff --git a/Plugin/Api/RefundInvoice.php b/Plugin/Api/RefundInvoice.php index c9da0f56..11c875f0 100644 --- a/Plugin/Api/RefundInvoice.php +++ b/Plugin/Api/RefundInvoice.php @@ -111,18 +111,14 @@ public function beforeRefund( bool $isOnline = false ): array { // Get the store code - $storeCode = $this->storeManager->getStore($order->getStoreId())->getCode(); - error_log("enable. ".$this->config->isAbcRefundAfterNasMigrationActive($storeCode) . PHP_EOL, 3, "/bitnami/magento/var/log/behou.log"); - error_log("public key. ".$this->config->getValue('abc_refund_public_key', null, $storeCode) . PHP_EOL, 3, "/bitnami/magento/var/log/behou.log"); - error_log("secret key ".$this->config->getValue('abc_refund_secret_key', null, $storeCode) . PHP_EOL, 3, "/bitnami/magento/var/log/behou.log"); - + $storeCode = $this->storeManager->getStore()->getCode(); // Initialize the API handler try { $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); } catch (CheckoutArgumentException $e) { if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { - throw new LocalizedException(__('Localized '.$e->getMessage())); + throw new LocalizedException(__($e->getMessage())); } $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); } From 2a9b2be80f3630e74aca783cd57db3bbe2f1128b Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 12 Dec 2023 11:37:14 +0100 Subject: [PATCH 018/147] CHECMAG2003-193: add ABC refund fallback on Card method --- Model/Methods/CardPaymentMethod.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Model/Methods/CardPaymentMethod.php b/Model/Methods/CardPaymentMethod.php index 99ea8894..0e2338f9 100755 --- a/Model/Methods/CardPaymentMethod.php +++ b/Model/Methods/CardPaymentMethod.php @@ -427,7 +427,14 @@ public function capture(InfoInterface $payment, $amount): AbstractMethod $storeCode = $payment->getOrder()->getStore()->getCode(); // Initialize the API handler - $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } // Check the status if (!$this->canCapture()) { From 0ab23666c8bc548574cf203a5f16f08eda8d0c5c Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 12 Dec 2023 12:05:17 +0100 Subject: [PATCH 019/147] CHECMAG2003-193: fix scope config --- Gateway/Config/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index c7ef2144..2eef81a6 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -564,7 +564,7 @@ public function needsRiskRules($methodId): bool */ public function isAbcRefundAfterNasMigrationActive($storeCode = null): bool { - return (bool) $this->getValue('abc_refund_enable', null, $storeCode); + return (bool) $this->getValue('abc_refund_enable', null, $storeCode, ScopeInterface::SCOPE_STORE); } /** From 27293e800132b6b056eaf1665cd8ad8c87f61433 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 12 Dec 2023 13:40:52 +0100 Subject: [PATCH 020/147] CHECMAG2003-193: add backend model for abc refund key in config --- etc/config.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/config.xml b/etc/config.xml index c57430e5..80635b08 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -55,6 +55,7 @@ checkoutcom_card_payment https://api.github.com/repos/checkout/checkout-magento2-plugin/releases 0 + From 1d081d873fe9115fbddf4ac8b095909b624f31a8 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Wed, 13 Dec 2023 16:17:53 +0100 Subject: [PATCH 021/147] CHECMAG2003-193: add refund fallback on ABC when API exception happens on refund order --- Model/Methods/AlternativePaymentMethod.php | 10 +++++++++- Model/Methods/ApplePayMethod.php | 11 ++++++++++- Model/Methods/CardPaymentMethod.php | 10 +++++++++- Model/Methods/GooglePayMethod.php | 11 ++++++++++- Model/Methods/MotoMethod.php | 11 ++++++++++- Model/Methods/VaultMethod.php | 11 ++++++++++- 6 files changed, 58 insertions(+), 6 deletions(-) diff --git a/Model/Methods/AlternativePaymentMethod.php b/Model/Methods/AlternativePaymentMethod.php index 4c769b9e..77fec72f 100755 --- a/Model/Methods/AlternativePaymentMethod.php +++ b/Model/Methods/AlternativePaymentMethod.php @@ -1076,7 +1076,15 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod } // Process the refund request - $response = $api->refundOrder($payment, $amount); + try { + $response = $api->refundOrder($payment, $amount); + } catch (CheckoutApiException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $response = $api->refundOrder($payment, $amount); + } if (!$api->isValidResponse($response)) { throw new LocalizedException( diff --git a/Model/Methods/ApplePayMethod.php b/Model/Methods/ApplePayMethod.php index 68551e91..8fb31da0 100755 --- a/Model/Methods/ApplePayMethod.php +++ b/Model/Methods/ApplePayMethod.php @@ -511,7 +511,16 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod } // Process the refund request - $response = $api->refundOrder($payment, $amount); + try { + $response = $api->refundOrder($payment, $amount); + } catch (CheckoutApiException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $response = $api->refundOrder($payment, $amount); + } + if (!$api->isValidResponse($response)) { throw new LocalizedException( __('The refund request could not be processed.') diff --git a/Model/Methods/CardPaymentMethod.php b/Model/Methods/CardPaymentMethod.php index 0e2338f9..ea15691c 100755 --- a/Model/Methods/CardPaymentMethod.php +++ b/Model/Methods/CardPaymentMethod.php @@ -582,7 +582,15 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod } // Process the refund request - $response = $api->refundOrder($payment, $amount); + try { + $response = $api->refundOrder($payment, $amount); + } catch (CheckoutApiException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $response = $api->refundOrder($payment, $amount); + } if (!$api->isValidResponse($response)) { throw new LocalizedException( diff --git a/Model/Methods/GooglePayMethod.php b/Model/Methods/GooglePayMethod.php index 9bdaaac7..0a60e174 100755 --- a/Model/Methods/GooglePayMethod.php +++ b/Model/Methods/GooglePayMethod.php @@ -507,7 +507,16 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod } // Process the refund request - $response = $api->refundOrder($payment, $amount); + try { + $response = $api->refundOrder($payment, $amount); + } catch (CheckoutApiException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $response = $api->refundOrder($payment, $amount); + } + if (!$api->isValidResponse($response)) { throw new LocalizedException( __('The refund request could not be processed.') diff --git a/Model/Methods/MotoMethod.php b/Model/Methods/MotoMethod.php index 4a825647..e6d8cacb 100755 --- a/Model/Methods/MotoMethod.php +++ b/Model/Methods/MotoMethod.php @@ -348,7 +348,16 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod } // Process the refund request - $response = $api->refundOrder($payment, $amount); + try { + $response = $api->refundOrder($payment, $amount); + } catch (CheckoutApiException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $response = $api->refundOrder($payment, $amount); + } + if (!$api->isValidResponse($response)) { throw new LocalizedException( __('The refund request could not be processed.') diff --git a/Model/Methods/VaultMethod.php b/Model/Methods/VaultMethod.php index 8ee92dcd..b39bae5c 100755 --- a/Model/Methods/VaultMethod.php +++ b/Model/Methods/VaultMethod.php @@ -568,7 +568,16 @@ public function refund(InfoInterface $payment, $amount): AbstractMethod } // Process the refund request - $response = $api->refundOrder($payment, $amount); + try { + $response = $api->refundOrder($payment, $amount); + } catch (CheckoutApiException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $response = $api->refundOrder($payment, $amount); + } + if (!$api->isValidResponse($response)) { throw new LocalizedException( __('The refund request could not be processed.') From 8d2664eac126581b96a37e635146d85fbddcb467 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Fri, 15 Dec 2023 10:24:42 +0100 Subject: [PATCH 022/147] Bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index edc52062..f971a2e2 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "5.6.0", + "version": "5.7.0", "autoload": { "files": [ "registration.php" From 71ac6803d02d8c0a341e27fe64f69e8681ee6501 Mon Sep 17 00:00:00 2001 From: DnD-Nibra Date: Fri, 15 Dec 2023 11:28:52 +0100 Subject: [PATCH 023/147] CHECMAG2003-198: Add labels configurations - see above --- etc/adminhtml/system.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index eebd9b65..404b4d3d 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -384,6 +384,21 @@ Add add CSS styles in JSON format for the payment form (See Frames.js docs for more information). Ex: {"base":{"color":"blue","fontSize":"18px"}} + + + + payment/checkoutcom_card_payment/card_number_label + + + + + payment/checkoutcom_card_payment/expiration_date_label + + + + + payment/checkoutcom_card_payment/cvv_label + From bf6fe8c219c5c3f9eed25dd51580689c1a094d0d Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Wed, 20 Dec 2023 16:37:42 +0100 Subject: [PATCH 024/147] CHECMAG2003-198: add credit card label & placeholder configurations to frontend form --- etc/adminhtml/system.xml | 39 +++++++++++++- .../checkoutcom_card_payment.js | 5 +- .../frontend/web/js/view/payment/utilities.js | 54 ++++++++----------- .../payment/checkoutcom_card_payment.html | 6 +-- 4 files changed, 65 insertions(+), 39 deletions(-) diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 404b4d3d..3fe8e47f 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -16,7 +16,6 @@
-
]]> @@ -388,16 +387,54 @@ payment/checkoutcom_card_payment/card_number_label + + multi + + + On multi form layout only + + + + + + payment/checkoutcom_card_payment/card_number_placeholder payment/checkoutcom_card_payment/expiration_date_label + + multi + + + On multi form layout only + + + + + + payment/checkoutcom_card_payment/expiration_date_month_placeholder + + + + + payment/checkoutcom_card_payment/expiration_date_year_placeholder payment/checkoutcom_card_payment/cvv_label + + multi + + + On multi form layout only + + + + + + payment/checkoutcom_card_payment/cvv_placeholder diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index 0f4fcea7..70d9e11e 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -48,7 +48,8 @@ define( redirectAfterPlaceOrder: false, allowPlaceOrder: ko.observable(false), isCoBadged: ko.observable(false), - tooltipVisible: ko.observable(false) + tooltipVisible: ko.observable(false), + cardLabels: Utilities.getCardLabels(METHOD_ID) }, /** @@ -215,7 +216,7 @@ define( debug: Boolean(self.getValue('debug') && self.getValue('console_logging')), schemeChoice: true, modes: [ Frames.modes.FEATURE_FLAG_SCHEME_CHOICE], - localization: Utilities.getShopLanguage(), + localization: Utilities.getCardPlaceholders(METHOD_ID), style: (formStyles) ? formStyles : {} } ); diff --git a/view/frontend/web/js/view/payment/utilities.js b/view/frontend/web/js/view/payment/utilities.js index 61e78c8a..edc2148d 100755 --- a/view/frontend/web/js/view/payment/utilities.js +++ b/view/frontend/web/js/view/payment/utilities.js @@ -208,49 +208,37 @@ define( }, /** - * Gets the card form language fallback. + * Get card form labels * * @return {string} */ - getLangageFallback: function () { - return Config[KEY_DATA].user.language_fallback; + getCardLabels: function (KEY) { + return { + cardNumberLabel: Config[KEY].card_number_label ? + Config[KEY].card_number_label : __('Card number'), + expiryDateLabel: Config[KEY].expiration_date_label ? + Config[KEY].expiration_date_label : __('Expiration Date'), + cvvLabel: Config[KEY].cvv_label ? + Config[KEY].cvv_label : __('Card Verification Number') + } }, /** - * Get the card form shop language + * Get card form placeholders * * @return {string} */ - getShopLanguage: function () { - let mageShopLanguage = Config[KEY_DATA].store.language; - let framesLanguage; - switch (mageShopLanguage) { - case 'nl_NL': - framesLanguage = 'NL-NL'; - break; - case 'en_GB': - framesLanguage = 'EN-GB'; - break; - case 'fr_FR': - framesLanguage = 'FR-FR'; - break; - case 'de_DE': - framesLanguage = 'DE-DE'; - break; - case 'it_IT': - framesLanguage = 'IT-IT'; - break; - case 'ko_KR': - framesLanguage = 'KR-KR'; - break; - case 'es_ES': - framesLanguage = 'ES-ES'; - break; - default: - framesLanguage = this.getLangageFallback().toUpperCase().split("_").join('-'); + getCardPlaceholders: function (KEY) { + return { + cardNumberPlaceholder: Config[KEY].card_number_placeholder ? + Config[KEY].card_number_placeholder : __('Card number'), + expiryMonthPlaceholder: Config[KEY].expiration_date_month_placeholder ? + Config[KEY].expiration_date_month_placeholder : __('MM'), + expiryYearPlaceholder: Config[KEY].expiration_date_year_placeholder ? + Config[KEY].expiration_date_year_placeholder : __('YY'), + cvvPlaceholder: Config[KEY].cvv_placeholder ? + Config[KEY].cvv_placeholder : __('CVV') } - - return framesLanguage; }, /** diff --git a/view/frontend/web/template/payment/checkoutcom_card_payment.html b/view/frontend/web/template/payment/checkoutcom_card_payment.html index 7f9c0edf..83383df4 100755 --- a/view/frontend/web/template/payment/checkoutcom_card_payment.html +++ b/view/frontend/web/template/payment/checkoutcom_card_payment.html @@ -67,7 +67,7 @@
@@ -87,7 +87,7 @@
@@ -103,7 +103,7 @@
From 05628485b61140ecbf1de27df92996fce2e96930 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Mon, 8 Jan 2024 17:49:56 +0100 Subject: [PATCH 025/147] CHECMAG2003-200: add disabled btn state change in else condition (only if cc form isn't valid) --- .../view/payment/method-renderer/checkoutcom_card_payment.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index 70d9e11e..a9758a08 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -301,9 +301,9 @@ define( // Submit the payment form Frames.submitCard(); + } else { + self.allowPlaceOrder(false); } - - self.allowPlaceOrder(false); } ); From 21b2cd5660ccffe7dc88aa8f0d14953a06612181 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Fri, 19 Jan 2024 13:27:47 +0100 Subject: [PATCH 026/147] CHECMAG2003-204: Fix authorization check on placing order --- Controller/Payment/PlaceOrder.php | 16 ++++++++++++++-- Model/Service/PaymentErrorHandlerService.php | 7 +++++++ view/frontend/web/js/view/payment/utilities.js | 13 ------------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Controller/Payment/PlaceOrder.php b/Controller/Payment/PlaceOrder.php index 9c601a91..66947428 100644 --- a/Controller/Payment/PlaceOrder.php +++ b/Controller/Payment/PlaceOrder.php @@ -206,7 +206,6 @@ public function execute(): Json $url = ''; $message = ''; $debugMessage = ''; - $responseCode = ''; $success = false; $log = true; @@ -262,8 +261,9 @@ public function execute(): Json $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); $isValidResponse = $api->isValidResponse($response); + $responseCode = isset($response['response_code']) ? $response['response_code'] : ''; - if ($isValidResponse) { + if ($isValidResponse && $this->isAuthorized($responseCode)) { // Create an order if processing is payment first $order = $order === null ? $this->orderHandler->setMethodId($data['methodId'])->handleOrder($quote) : $order; @@ -380,4 +380,16 @@ protected function requestPayment(CartInterface $quote, array $data, float $amou $reference ); } + + /** + * Check if response code is successful + * + * @param string $responseCode + * + * @return bool + */ + protected function isAuthorized(string $responseCode): bool + { + return empty($responseCode) || mb_substr($responseCode, 0, 2) === PaymentErrorHandlerService::TRANSACTION_SUCCESS_DIGITS; + } } diff --git a/Model/Service/PaymentErrorHandlerService.php b/Model/Service/PaymentErrorHandlerService.php index 993d0293..a3a5e673 100755 --- a/Model/Service/PaymentErrorHandlerService.php +++ b/Model/Service/PaymentErrorHandlerService.php @@ -44,6 +44,13 @@ class PaymentErrorHandlerService 'payment_refund_declined' => 'Failed payment refund', 'payment_pending' => 'Failed payment request', ]; + + /** + * TRANSACTION_SUCCESS_DIGITS const + * + * @var string TRANSACTION_SUCCESS_DIGITS + */ + const TRANSACTION_SUCCESS_DIGITS = '10'; /** * $transactionHandler field * diff --git a/view/frontend/web/js/view/payment/utilities.js b/view/frontend/web/js/view/payment/utilities.js index 61e78c8a..31325450 100755 --- a/view/frontend/web/js/view/payment/utilities.js +++ b/view/frontend/web/js/view/payment/utilities.js @@ -369,16 +369,6 @@ define( messageContainer.show(); }, - /** - * Show response code. - */ - showResponseCode: function (type, message, methodId) { - var messageContainer = this.getMethodContainer(methodId).find('.message-response-code'); - messageContainer.addClass('message-' + type + ' ' + type); - messageContainer.append('
Response Code: ' + __(message) + '
'); - messageContainer.show(); - }, - /** * Clear all messages. */ @@ -442,9 +432,6 @@ define( if (data.debugMessage) { self.showDebugMessage('error', data.debugMessage, methodId); } - if (data.responseCode) { - self.showResponseCode('error', data.responseCode, methodId); - } self.allowPlaceOrder(methodId + '_btn', false) } else if (data.success && data.url) { // Handle 3DS redirection From 4927f088b20c583e7ab660f8bcd30d5d8285b5fe Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Wed, 24 Jan 2024 15:06:33 +0100 Subject: [PATCH 027/147] CHECMAG2003-200: add timer around submit card promise for testing --- .../payment/method-renderer/checkoutcom_card_payment.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index a9758a08..cbb617e4 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -299,8 +299,13 @@ define( }; } + // @DND debug : Timer for submit card promise execution time + console.time('Submit Card'); // Submit the payment form - Frames.submitCard(); + Frames.submitCard().then(() => { + console.timeEnd('Submit Card'); + }); + // / @DND debug : Timer for submit card promise execution time } else { self.allowPlaceOrder(false); } From 1b35b5ef1c0db55fd39b1ea9e36877cadfbda682 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Wed, 24 Jan 2024 17:55:01 +0100 Subject: [PATCH 028/147] CHECMAG2003-199: check applepay supported version before initialize it --- i18n/en_GB.csv | 1 + i18n/en_US.csv | 1 + .../web/js/view/payment/applepay-utilities.js | 18 ++++++++++++++ .../payment/cart/checkoutcom_applepay_cart.js | 24 +++++++++++++------ .../method-renderer/checkoutcom_apple_pay.js | 16 ++++++++++++- .../frontend/web/js/view/payment/utilities.js | 1 + 6 files changed, 53 insertions(+), 8 deletions(-) diff --git a/i18n/en_GB.csv b/i18n/en_GB.csv index 7e43c6ec..49af47a1 100644 --- a/i18n/en_GB.csv +++ b/i18n/en_GB.csv @@ -184,3 +184,4 @@ Debitor,Debitor "Street and Postal Match","Street and Postal Match" "Street and Postal Not Verified","Street and Postal Not Verified" "The issuer has not certified or has not provided the encryption keys to the interchange","The issuer has not certified or has not provided the encryption keys to the interchange" +"Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.","Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers." diff --git a/i18n/en_US.csv b/i18n/en_US.csv index 7e43c6ec..49af47a1 100644 --- a/i18n/en_US.csv +++ b/i18n/en_US.csv @@ -184,3 +184,4 @@ Debitor,Debitor "Street and Postal Match","Street and Postal Match" "Street and Postal Not Verified","Street and Postal Not Verified" "The issuer has not certified or has not provided the encryption keys to the interchange","The issuer has not certified or has not provided the encryption keys to the interchange" +"Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.","Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers." diff --git a/view/frontend/web/js/view/payment/applepay-utilities.js b/view/frontend/web/js/view/payment/applepay-utilities.js index 6b748a2f..98dd2365 100644 --- a/view/frontend/web/js/view/payment/applepay-utilities.js +++ b/view/frontend/web/js/view/payment/applepay-utilities.js @@ -24,6 +24,9 @@ define( 'use strict'; return { + applePayDefaultVersion: 5, + applePayVersion: 14, + /** * Is Virtual. * @@ -200,6 +203,21 @@ define( } else { return ""; } + }, + + /** + * Check if applepay version is supported + */ + initializeApplePaySession (paymentRequest) { + if (!ApplePaySession.supportsVersion(this.applePayVersion) && !ApplePaySession.supportsVersion(this.applePayDefaultVersion)) { + return false; + } + + const versionToUse = ApplePaySession.supportsVersion(this.applePayVersion) + ? this.applePayVersion + : this.applePayDefaultVersion; + + return new ApplePaySession(versionToUse, paymentRequest); } }; } diff --git a/view/frontend/web/js/view/payment/cart/checkoutcom_applepay_cart.js b/view/frontend/web/js/view/payment/cart/checkoutcom_applepay_cart.js index 3478cec1..aa0986bb 100644 --- a/view/frontend/web/js/view/payment/cart/checkoutcom_applepay_cart.js +++ b/view/frontend/web/js/view/payment/cart/checkoutcom_applepay_cart.js @@ -15,6 +15,7 @@ define([ "jquery", + "Magento_Customer/js/customer-data", "Magento_Checkout/js/view/payment/default", "CheckoutCom_Magento2/js/view/payment/utilities", "CheckoutCom_Magento2/js/view/payment/applepay-utilities", @@ -28,6 +29,7 @@ "mage/translate", ], function ( $, + customerData, Component, Utilities, ApplePayUtilities, @@ -120,10 +122,6 @@ "email" ], }; - - // Start the payment session - Utilities.log(paymentRequest); - var session = new ApplePaySession(12, paymentRequest); } else { var paymentRequest = { currencyCode: Utilities.getQuoteCurrency(), @@ -148,10 +146,22 @@ ], shippingMethods: [], }; + } + + // Start the payment session + Utilities.log(paymentRequest); + var session = ApplePayUtilities.initializeApplePaySession(paymentRequest); + + if (!session) { + Utilities.log('Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.'); + customerData.set('messages', { + messages: [{ + type: 'error', + text: __('Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.') + }] + }); - // Start the payment session - Utilities.log(paymentRequest); - var session = new ApplePaySession(12, paymentRequest); + return false; } // Merchant Validation diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js index e0399fe7..1a66d39b 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js @@ -16,6 +16,7 @@ define( [ 'jquery', + 'Magento_Customer/js/customer-data', 'Magento_Checkout/js/view/payment/default', 'CheckoutCom_Magento2/js/view/payment/utilities', "CheckoutCom_Magento2/js/view/payment/applepay-utilities", @@ -26,6 +27,7 @@ define( ], function ( $, + customerData, Component, Utilities, ApplePayUtilities, @@ -285,7 +287,19 @@ define( // Start the payment session Utilities.log(paymentRequest); - var session = new ApplePaySession(14, paymentRequest); + var session = ApplePayUtilities.initializeApplePaySession(paymentRequest); + + if (!session) { + Utilities.log('Your browser is not compatible with the Apple Pay version'); + + Utilities.showMessage( + 'error', + __('Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.'), + METHOD_ID + ); + + return false; + } // Merchant Validation session.onvalidatemerchant = function (event) { diff --git a/view/frontend/web/js/view/payment/utilities.js b/view/frontend/web/js/view/payment/utilities.js index 01637f03..8f47fcc2 100755 --- a/view/frontend/web/js/view/payment/utilities.js +++ b/view/frontend/web/js/view/payment/utilities.js @@ -362,6 +362,7 @@ define( */ clearMessages: function (methodId) { var messageContainer = this.getMethodContainer(methodId).find('.message'); + messageContainer.removeClass('message-warning warning message-error error'); messageContainer.hide(); messageContainer.empty(); }, From 8cc23bd44681aaebcd2398d0e844aa711974ce2b Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 29 Jan 2024 15:57:14 +0100 Subject: [PATCH 029/147] CHECMAG2003-205: Update documentation under frame.js customization field --- etc/adminhtml/system.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 3fe8e47f..c14b56e1 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -380,7 +380,7 @@ payment/checkoutcom_card_payment/payment_form_styles - Add add CSS styles in JSON format for the payment form (See Frames.js docs for more information). Ex: {"base":{"color":"blue","fontSize":"18px"}} + Frames.js docs in the "style" node of javascript example for more information). Ex: {"base":{"color":"blue","fontSize":"18px"}}]]> From c1f1bc6979d35181478252b66da1662c3e105a20 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 30 Jan 2024 09:32:57 +0100 Subject: [PATCH 030/147] CHECMAG2003-204: fix response code when it is not defined --- Controller/Payment/PlaceOrder.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Controller/Payment/PlaceOrder.php b/Controller/Payment/PlaceOrder.php index 66947428..bae6173f 100644 --- a/Controller/Payment/PlaceOrder.php +++ b/Controller/Payment/PlaceOrder.php @@ -206,6 +206,7 @@ public function execute(): Json $url = ''; $message = ''; $debugMessage = ''; + $responseCode = ''; $success = false; $log = true; From 81da63052928359bb994163bf592d17340942700 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Wed, 31 Jan 2024 14:30:49 +0100 Subject: [PATCH 031/147] CHECMAG2003-207: change applepay behavior on checkout --- .../method-renderer/checkoutcom_apple_pay.js | 345 ++++++++---------- .../payment/checkoutcom_apple_pay.html | 27 +- 2 files changed, 175 insertions(+), 197 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js index 1a66d39b..fe9e9c4c 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js @@ -16,7 +16,7 @@ define( [ 'jquery', - 'Magento_Customer/js/customer-data', + 'ko', 'Magento_Checkout/js/view/payment/default', 'CheckoutCom_Magento2/js/view/payment/utilities', "CheckoutCom_Magento2/js/view/payment/applepay-utilities", @@ -27,7 +27,7 @@ define( ], function ( $, - customerData, + ko, Component, Utilities, ApplePayUtilities, @@ -44,8 +44,9 @@ define( { defaults: { template: 'CheckoutCom_Magento2/payment/' + METHOD_ID + '.html', - button_target: '#ckoApplePayButton', - redirectAfterPlaceOrder: false + buttonClass: 'apple-pay-button-', + redirectAfterPlaceOrder: false, + canPayWithApplePay: ko.observable(false) }, /** @@ -55,6 +56,7 @@ define( this._super(); Utilities.setEmail(); Utilities.loadCss('apple-pay', 'apple-pay'); + this.launchApplePay(); return this; }, @@ -101,7 +103,7 @@ define( * * @return {array} */ - processSupportedNetworks: function(networksEnabled) { + processSupportedNetworks: function (networksEnabled) { if (networksEnabled.includes("mada") && !(Utilities.getStoreCountry() === "SA")) { networksEnabled.splice(networksEnabled.indexOf("mada"), 1); } @@ -114,8 +116,8 @@ define( * * @return {string} */ - getCountryCode: function() { - return Utilities.getStoreCountry() === "SA" ? "SA" : window.checkoutConfig.defaultCountryId; + getCountryCode: function () { + return Utilities.getStoreCountry() === "SA" ? "SA" : window.checkoutConfig.defaultCountryId; }, /** @@ -177,7 +179,7 @@ define( ); }, - setBilling: function(shippingDetails, billingDetails) { + setBilling: function (shippingDetails, billingDetails) { let requestBody = { address: { country_id: billingDetails.countryCode.toUpperCase(), @@ -204,213 +206,188 @@ define( // Prepare the parameters var self = this; - // Apply the button style - $(self.button_target) - .addClass('apple-pay-button-' + self.getValue('button_style')); + this.buttonClass = `${this.buttonClass}${this.getValue('button_style')}`; // Check if the session is available if (window.ApplePaySession) { - var merchantIdentifier = self.getValue('merchant_id'); - var promise = ApplePaySession.canMakePaymentsWithActiveCard(merchantIdentifier); - promise.then( - function (canMakePayments) { - if (canMakePayments) { - $(self.button_target).css('display', 'block'); - } else { - Utilities.showMessage( - 'warning', - __('Apple Pay is available but not currently active.'), - METHOD_ID - ); - } - } - ).catch( - function (error) { - Utilities.log(error); - } - ); + const merchantIdentifier = self.getValue('merchant_id'); + const canMakePayments = ApplePaySession.canMakePayments(merchantIdentifier); + + this.canPayWithApplePay(canMakePayments); + if (!canMakePayments) { + Utilities.showMessage( + 'warning', + __('Apple Pay is available but not currently active.'), + METHOD_ID + ); + } } else { - $(self.button_target).css('display', 'none'); + this.canPayWithApplePay(false); Utilities.showMessage( 'warning', __('Apple Pay is not available for this browser.'), METHOD_ID ); } + }, - // Handle the events - $(self.button_target).click( - function (evt) { - if (Utilities.methodIsSelected(METHOD_ID)) { - // Validate T&C submission - if (!AdditionalValidators.validate()) { - return; - } - - // Prepare the parameters - var runningTotal = Utilities.getQuoteValue(); - - // Build the payment request - if (ApplePayUtilities.getIsVirtual()) { - var paymentRequest = { - currencyCode: Utilities.getQuoteCurrency(), - countryCode: self.getCountryCode(), - total: { - label: Utilities.getStoreName(), - amount: runningTotal - }, - supportedNetworks: self.getSupportedNetworks(), - merchantCapabilities: self.getMerchantCapabilities(), - requiredBillingContactFields: [ - "postalAddress", - "name", - "phone", - "email" - ], - requiredShippingContactFields: [ - "phone", - "email" - ], - }; - } else { - var paymentRequest = { - currencyCode: Utilities.getQuoteCurrency(), - countryCode: self.getCountryCode(), - total: { - label: Utilities.getStoreName(), - amount: runningTotal - }, - supportedNetworks: self.getSupportedNetworks(), - merchantCapabilities: self.getMerchantCapabilities() - }; - } - - // Start the payment session - Utilities.log(paymentRequest); - var session = ApplePayUtilities.initializeApplePaySession(paymentRequest); + placeOrder: function () { + if (Utilities.methodIsSelected(METHOD_ID)) { + // Validate T&C submission + if (!AdditionalValidators.validate()) { + return; + } - if (!session) { - Utilities.log('Your browser is not compatible with the Apple Pay version'); + // Prepare the parameters + var runningTotal = Utilities.getQuoteValue(); + + // Build the payment request + if (ApplePayUtilities.getIsVirtual()) { + var paymentRequest = { + currencyCode: Utilities.getQuoteCurrency(), + countryCode: this.getCountryCode(), + total: { + label: Utilities.getStoreName(), + amount: runningTotal + }, + supportedNetworks: this.getSupportedNetworks(), + merchantCapabilities: this.getMerchantCapabilities(), + requiredBillingContactFields: [ + "postalAddress", + "name", + "phone", + "email" + ], + requiredShippingContactFields: [ + "phone", + "email" + ], + }; + } else { + var paymentRequest = { + currencyCode: Utilities.getQuoteCurrency(), + countryCode: this.getCountryCode(), + total: { + label: Utilities.getStoreName(), + amount: runningTotal + }, + supportedNetworks: this.getSupportedNetworks(), + merchantCapabilities: this.getMerchantCapabilities() + }; + } - Utilities.showMessage( - 'error', - __('Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.'), - METHOD_ID - ); + // Start the payment session + Utilities.log(paymentRequest); + var session = new ApplePaySession(14, paymentRequest); - return false; + // Merchant Validation + session.onvalidatemerchant = function (event) { + var promise = this.performValidation(event.validationURL); + promise.then( + function (merchantSession) { + session.completeMerchantValidation(merchantSession); } - - // Merchant Validation - session.onvalidatemerchant = function (event) { - var promise = self.performValidation(event.validationURL); - promise.then( - function (merchantSession) { - session.completeMerchantValidation(merchantSession); - } - ).catch( - function (error) { - Utilities.log(error); - } - ); + ).catch( + function (error) { + Utilities.log(error); } + ); + } - // Shipping contact - session.onshippingcontactselected = function (event) { - var status = ApplePaySession.STATUS_SUCCESS; + // Shipping contact + session.onshippingcontactselected = function (event) { + var status = ApplePaySession.STATUS_SUCCESS; - // Shipping info - var shippingOptions = []; + // Shipping info + var shippingOptions = []; - var newTotal = { - type: 'final', - label: ap['storeName'], - amount: runningTotal - }; + var newTotal = { + type: 'final', + label: ap['storeName'], + amount: runningTotal + }; - session.completeShippingContactSelection(status, shippingOptions, newTotal, self.getLineItems()); - } + session.completeShippingContactSelection(status, shippingOptions, newTotal, this.getLineItems()); + } - // Shipping method selection - session.onshippingmethodselected = function (event) { - var status = ApplePaySession.STATUS_SUCCESS; - var newTotal = { - type: 'final', - label: ap['storeName'], - amount: runningTotal - }; + // Shipping method selection + session.onshippingmethodselected = function (event) { + var status = ApplePaySession.STATUS_SUCCESS; + var newTotal = { + type: 'final', + label: ap['storeName'], + amount: runningTotal + }; - session.completeShippingMethodSelection(status, newTotal, self.getLineItems()); - } + session.completeShippingMethodSelection(status, newTotal, this.getLineItems()); + } - // Payment method selection - session.onpaymentmethodselected = function (event) { - var newTotal = { - type: 'final', - label: Utilities.getStoreName(), - amount: runningTotal - }; + // Payment method selection + session.onpaymentmethodselected = function (event) { + var newTotal = { + type: 'final', + label: Utilities.getStoreName(), + amount: runningTotal + }; - session.completePaymentMethodSelection(newTotal, self.getLineItems()); - } + session.completePaymentMethodSelection(newTotal, this.getLineItems()); + } - // Payment method authorization - session.onpaymentauthorized = function (event) { - // Prepare the payload - var payload = { - methodId: METHOD_ID, - cardToken: event.payment.token, - source: METHOD_ID - }; - - if (ApplePayUtilities.getIsVirtual()) { - self.setBilling( - event.payment.shippingContact, - event.payment.billingContact - ); + // Payment method authorization + session.onpaymentauthorized = function (event) { + // Prepare the payload + var payload = { + methodId: METHOD_ID, + cardToken: event.payment.token, + source: METHOD_ID + }; + + if (ApplePayUtilities.getIsVirtual()) { + this.setBilling( + event.payment.shippingContact, + event.payment.billingContact + ); + } + + // Send the request + var promise = this.sendPaymentRequest(payload); + promise.then( + function (data) { + var status; + if (data.success) { + status = ApplePaySession.STATUS_SUCCESS; + } else { + status = ApplePaySession.STATUS_FAILURE; } - // Send the request - var promise = self.sendPaymentRequest(payload); - promise.then( - function (data) { - var status; - if (data.success) { - status = ApplePaySession.STATUS_SUCCESS; - } else { - status = ApplePaySession.STATUS_FAILURE; - } - - session.completePayment(status); - - if (data.success && data.url) { - // Redirect to success page - FullScreenLoader.startLoader(); - // Handle 3DS redirection - window.location.href = data.url; - } else { - // Normal redirection - RedirectOnSuccessAction.execute(); - } - Utilities.cleanCustomerShippingAddress(); - } - ).catch( - function (error) { - Utilities.log(error); - } - ); - } + session.completePayment(status); - // Session cancellation - session.oncancel = function (event) { - Utilities.log(event); + if (data.success && data.url) { + // Redirect to success page + FullScreenLoader.startLoader(); + // Handle 3DS redirection + window.location.href = data.url; + } else { + // Normal redirection + RedirectOnSuccessAction.execute(); + } + Utilities.cleanCustomerShippingAddress(); + } + ).catch( + function (error) { + Utilities.log(error); } + ); + } - // Begin session - session.begin(); - } + // Session cancellation + session.oncancel = function (event) { + Utilities.log(event); } - ); + + // Begin session + session.begin(); + } } } ); diff --git a/view/frontend/web/template/payment/checkoutcom_apple_pay.html b/view/frontend/web/template/payment/checkoutcom_apple_pay.html index e78e0e28..4d33d841 100755 --- a/view/frontend/web/template/payment/checkoutcom_apple_pay.html +++ b/view/frontend/web/template/payment/checkoutcom_apple_pay.html @@ -14,10 +14,10 @@ -->
+ data-bind="css: {'_active': (getCode() == isChecked())}, attr: {'id': getCode() + '_container'}">
+ data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()" /> @@ -34,20 +34,21 @@
-
- - - - -
+
+ + + + +
-
-
- -
-
+
From 3cb76acea1992dfe180dbe87f1d2e7fccebf2299 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Wed, 31 Jan 2024 15:56:35 +0100 Subject: [PATCH 032/147] CHECMAG2003-200: launch submit card promise after place order button click --- .../checkoutcom_card_payment.js | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index cbb617e4..77752806 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -24,9 +24,10 @@ define( 'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Customer/js/model/customer', 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/model/full-screen-loader', 'framesjs' ], - function ($, ko, Component, Utilities, FramesMulti, FramesSingle, AdditionalValidators, Customer, Quote) { + function ($, ko, Component, Utilities, FramesMulti, FramesSingle, AdditionalValidators, Customer, Quote, FullScreenLoader) { 'use strict'; window.checkoutConfig.reloadOnBillingAddress = true; const METHOD_ID = 'checkoutcom_card_payment'; @@ -284,8 +285,8 @@ define( // Card validation changed event Frames.addEventHandler( Frames.Events.CARD_VALIDATION_CHANGED, - function (event) { - var valid = Frames.isCardValid() + function () { + const valid = Frames.isCardValid() if (valid) { if(cardholderName.length === 0) { if(Utilities.getBillingAddress()) { @@ -298,17 +299,9 @@ define( name: cardholderName }; } - - // @DND debug : Timer for submit card promise execution time - console.time('Submit Card'); - // Submit the payment form - Frames.submitCard().then(() => { - console.timeEnd('Submit Card'); - }); - // / @DND debug : Timer for submit card promise execution time - } else { - self.allowPlaceOrder(false); } + + self.allowPlaceOrder(valid); } ); @@ -323,9 +316,6 @@ define( // Enable the submit form Frames.enableSubmitForm(); - - // Set allowPlaceOrder to true only when tokenized. - self.allowPlaceOrder(true); } ); @@ -346,19 +336,26 @@ define( if (Utilities.methodIsSelected(METHOD_ID)) { // Validate the order placement if (AdditionalValidators.validate() && Frames.isCardValid()) { - // Prepare the payload - var payload = { - methodId: METHOD_ID, - cardToken: this.cardToken, - cardBin: this.cardBin, - saveCard: this.saveCard, - preferredScheme: this.preferredScheme, - source: METHOD_ID - }; - - // Place the order - Utilities.placeOrder(payload, METHOD_ID); - Utilities.cleanCustomerShippingAddress(); + // Start the loader + FullScreenLoader.startLoader(); + // Submit the payment form + Frames.submitCard().then((response) => { + // Prepare the payload + const payload = { + methodId: METHOD_ID, + cardToken: response.token, + cardBin: response.bin, + saveCard: this.saveCard, + preferredScheme: response.preferred_scheme, + source: METHOD_ID + }; + + // Place the order + Utilities.placeOrder(payload, METHOD_ID); + Utilities.cleanCustomerShippingAddress(); + }).catch(function () { + FullScreenLoader.stopLoader(); + }); } } }, From 4575a41eb8ad8f0d8ce8889d3292a1a7592a11f4 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Wed, 14 Feb 2024 14:58:10 +0100 Subject: [PATCH 033/147] CHECMAG2003-207: use self instead of this on sessions functions --- .../method-renderer/checkoutcom_apple_pay.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js index fe9e9c4c..5f876527 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js @@ -210,7 +210,7 @@ define( // Check if the session is available if (window.ApplePaySession) { - const merchantIdentifier = self.getValue('merchant_id'); + const merchantIdentifier = this.getValue('merchant_id'); const canMakePayments = ApplePaySession.canMakePayments(merchantIdentifier); this.canPayWithApplePay(canMakePayments); @@ -232,6 +232,8 @@ define( }, placeOrder: function () { + let self = this; + if (Utilities.methodIsSelected(METHOD_ID)) { // Validate T&C submission if (!AdditionalValidators.validate()) { @@ -282,7 +284,7 @@ define( // Merchant Validation session.onvalidatemerchant = function (event) { - var promise = this.performValidation(event.validationURL); + var promise = self.performValidation(event.validationURL); promise.then( function (merchantSession) { session.completeMerchantValidation(merchantSession); @@ -307,7 +309,7 @@ define( amount: runningTotal }; - session.completeShippingContactSelection(status, shippingOptions, newTotal, this.getLineItems()); + session.completeShippingContactSelection(status, shippingOptions, newTotal, self.getLineItems()); } // Shipping method selection @@ -319,7 +321,7 @@ define( amount: runningTotal }; - session.completeShippingMethodSelection(status, newTotal, this.getLineItems()); + session.completeShippingMethodSelection(status, newTotal, self.getLineItems()); } // Payment method selection @@ -330,7 +332,7 @@ define( amount: runningTotal }; - session.completePaymentMethodSelection(newTotal, this.getLineItems()); + session.completePaymentMethodSelection(newTotal, self.getLineItems()); } // Payment method authorization @@ -343,14 +345,14 @@ define( }; if (ApplePayUtilities.getIsVirtual()) { - this.setBilling( + self.setBilling( event.payment.shippingContact, event.payment.billingContact ); } // Send the request - var promise = this.sendPaymentRequest(payload); + var promise = self.sendPaymentRequest(payload); promise.then( function (data) { var status; From 2983e94a46e7a7007032a775efc024eec2875f5e Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Wed, 14 Feb 2024 14:59:15 +0100 Subject: [PATCH 034/147] CHECMAG2003-207: remove useless self var --- .../js/view/payment/method-renderer/checkoutcom_apple_pay.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js index 5f876527..45db58ac 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js @@ -203,9 +203,6 @@ define( * @return {bool} */ launchApplePay: function () { - // Prepare the parameters - var self = this; - this.buttonClass = `${this.buttonClass}${this.getValue('button_style')}`; // Check if the session is available From 4eb892c1cbc0a047d193366bfbcb4646bd27530c Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Fri, 16 Feb 2024 10:42:13 +0100 Subject: [PATCH 035/147] bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f971a2e2..6fa20def 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "5.7.0", + "version": "5.8.0", "autoload": { "files": [ "registration.php" From 717657d78f2fd50f4cddcd4f30e0ff61359a4700 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 19 Feb 2024 16:55:14 +0100 Subject: [PATCH 036/147] CHECMAG2003-210: fixed preferred scheme value --- .../view/payment/method-renderer/checkoutcom_card_payment.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index 77752806..9a4c018a 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -312,7 +312,7 @@ define( // Store the card token and the card bin self.cardToken = event.token; self.cardBin = event.bin; - self.preferredScheme = event.preferred_scheme; + self.preferredScheme = event.scheme; // Enable the submit form Frames.enableSubmitForm(); @@ -346,7 +346,7 @@ define( cardToken: response.token, cardBin: response.bin, saveCard: this.saveCard, - preferredScheme: response.preferred_scheme, + preferredScheme: response.scheme, source: METHOD_ID }; From 7afdadda5c63dc37dd78b1d78e2b328768a1990e Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Tue, 20 Feb 2024 12:23:01 +0100 Subject: [PATCH 037/147] CHECMAG2003-212: manage error case on payment ajax request --- .../payment/method-renderer/checkoutcom_card_payment.js | 2 +- view/frontend/web/js/view/payment/utilities.js | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index 77752806..a4af302d 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -351,7 +351,7 @@ define( }; // Place the order - Utilities.placeOrder(payload, METHOD_ID); + Utilities.placeOrder(payload, METHOD_ID, false); Utilities.cleanCustomerShippingAddress(); }).catch(function () { FullScreenLoader.stopLoader(); diff --git a/view/frontend/web/js/view/payment/utilities.js b/view/frontend/web/js/view/payment/utilities.js index 8f47fcc2..9bd7c3cc 100755 --- a/view/frontend/web/js/view/payment/utilities.js +++ b/view/frontend/web/js/view/payment/utilities.js @@ -403,11 +403,13 @@ define( * * @return {void} */ - placeOrder: function (payload, methodId) { + placeOrder: function (payload, methodId, startLoader = true) { var self = this; - // Start the loader - FullScreenLoader.startLoader(); + if (startLoader) { + // Start the loader + FullScreenLoader.startLoader(); + } // Send the request $.ajax({ @@ -421,7 +423,6 @@ define( if (data.debugMessage) { self.showDebugMessage('error', data.debugMessage, methodId); } - self.allowPlaceOrder(methodId + '_btn', false) } else if (data.success && data.url) { // Handle 3DS redirection window.location.href = data.url; From 64b96932a4845db4e527b17c26895b33734ecc2b Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 20 Feb 2024 13:43:43 +0100 Subject: [PATCH 038/147] CHECMAG2003-210: fix check back on preferred scheme --- Model/Methods/CardPaymentMethod.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Model/Methods/CardPaymentMethod.php b/Model/Methods/CardPaymentMethod.php index ea15691c..696d5205 100755 --- a/Model/Methods/CardPaymentMethod.php +++ b/Model/Methods/CardPaymentMethod.php @@ -66,6 +66,9 @@ class CardPaymentMethod extends AbstractMethod * @var string CODE */ const CODE = 'checkoutcom_card_payment'; + + const PREFERRED_SCHEMES = ['VISA','MASTERCARD','CARTES_BANCAIRES']; + /** * $_code field * @@ -357,7 +360,7 @@ public function sendPaymentRequest( } // Preferred scheme - if (isset($data['preferredScheme']) && $data['preferredScheme'] !== '') { + if (isset($data['preferredScheme']) && in_array((string) $data['preferredScheme'], self::PREFERRED_SCHEMES) { $request->processing = ['preferred_scheme' => strtolower($data['preferredScheme'])]; } From c6eabe39aabc9c8bffe871ef86eda7a122bbe6c0 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 20 Feb 2024 13:50:37 +0100 Subject: [PATCH 039/147] CHECMAG2003-210: fix syntax error --- Model/Methods/CardPaymentMethod.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Model/Methods/CardPaymentMethod.php b/Model/Methods/CardPaymentMethod.php index 696d5205..6da889b2 100755 --- a/Model/Methods/CardPaymentMethod.php +++ b/Model/Methods/CardPaymentMethod.php @@ -360,7 +360,7 @@ public function sendPaymentRequest( } // Preferred scheme - if (isset($data['preferredScheme']) && in_array((string) $data['preferredScheme'], self::PREFERRED_SCHEMES) { + if (isset($data['preferredScheme']) && in_array((string) $data['preferredScheme'], self::PREFERRED_SCHEMES)) { $request->processing = ['preferred_scheme' => strtolower($data['preferredScheme'])]; } From dd42962f050aa147c6c3d3bfbb9f6def527ec226 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 20 Feb 2024 14:38:25 +0100 Subject: [PATCH 040/147] bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6fa20def..50e8115b 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "5.8.0", + "version": "5.8.1", "autoload": { "files": [ "registration.php" From c08377d69e4881c861386f858311ea60b2db3a87 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Tue, 27 Feb 2024 16:07:01 +0100 Subject: [PATCH 041/147] CHECMAG2003-206 - First step of paypal method --- Block/Paypal/Script.php | 52 ++ Controller/Paypal/Context.php | 54 ++ Model/Methods/PaypalMethod.php | 562 ++++++++++++++++++ .../Service/PaymentContextRequestService.php | 128 ++++ composer.json | 2 +- etc/adminhtml/system.xml | 60 ++ etc/config.xml | 25 + etc/payment.xml | 3 + view/frontend/layout/checkout_index_index.xml | 10 + .../templates/script/paypal-script.phtml | 27 + view/frontend/web/css/paypal/paypal.css | 0 .../method-renderer/checkoutcom_paypal.js | 229 +++++++ .../template/payment/checkoutcom_paypal.html | 58 ++ 13 files changed, 1209 insertions(+), 1 deletion(-) create mode 100644 Block/Paypal/Script.php create mode 100644 Controller/Paypal/Context.php create mode 100755 Model/Methods/PaypalMethod.php create mode 100644 Model/Service/PaymentContextRequestService.php create mode 100644 view/frontend/templates/script/paypal-script.phtml create mode 100644 view/frontend/web/css/paypal/paypal.css create mode 100755 view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js create mode 100755 view/frontend/web/template/payment/checkoutcom_paypal.html diff --git a/Block/Paypal/Script.php b/Block/Paypal/Script.php new file mode 100644 index 00000000..bd8fa0d8 --- /dev/null +++ b/Block/Paypal/Script.php @@ -0,0 +1,52 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +namespace CheckoutCom\Magento2\Block\Paypal; + +use CheckoutCom\Magento2\Model\Methods\PaypalMethod; +use Magento\Framework\View\Element\Template; + +class Script extends Template +{ + private PaypalMethod $paypalMethod; + + public function __construct( + Template\Context $context, + PaypalMethod $paypalMethod, + array $data = [] + ) { + parent::__construct($context, $data); + $this->paypalMethod = $paypalMethod; + } + + public function getPaypalMerchantId(): string + { + return (string)$this->paypalMethod->getConfigData('merchant_id'); + } + + public function getClientId(): string + { + return (string)$this->paypalMethod->getConfigData('checkout_client_id'); + } + + public function getPartnerAttributionId(): string + { + return (string)$this->paypalMethod->getConfigData('checkout_partner_attribution_id'); + } +} diff --git a/Controller/Paypal/Context.php b/Controller/Paypal/Context.php new file mode 100644 index 00000000..c2736bf1 --- /dev/null +++ b/Controller/Paypal/Context.php @@ -0,0 +1,54 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +declare(strict_types=1); + +namespace CheckoutCom\Magento2\Controller\Paypal; + +use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\App\Action\Action; +use Magento\Framework\App\ResponseInterface; +use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\Controller\ResultInterface; + +class Context extends Action +{ + protected JsonFactory $jsonFactory; + protected PaymentContextRequestService $paymentContextRequestService; + + public function __construct( + JsonFactory $jsonFactory, + PaymentContextRequestService $paymentContextRequestService + ) { + $this->jsonFactory = $jsonFactory; + $this->paymentContextRequestService = $paymentContextRequestService; + } + + public function execute(): ResponseInterface | ResultInterface + { + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'content' => $this->paymentContextRequestService->makePaymentContextRequests('paypal') + ] + ); + + return $resultJson; + } +} diff --git a/Model/Methods/PaypalMethod.php b/Model/Methods/PaypalMethod.php new file mode 100755 index 00000000..a43aaa79 --- /dev/null +++ b/Model/Methods/PaypalMethod.php @@ -0,0 +1,562 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +declare(strict_types=1); + +namespace CheckoutCom\Magento2\Model\Methods; + +use Checkout\CheckoutApiException; +use Checkout\CheckoutArgumentException; +use Checkout\Payments\BillingDescriptor; +use Checkout\Payments\Previous\PaymentRequest as PreviousPaymentRequest; +use Checkout\Payments\Previous\Source\RequestTokenSource as PreviousRequestTokenSource; +use Checkout\Payments\Request\PaymentRequest; +use Checkout\Payments\Request\Source\RequestTokenSource; +use Checkout\Payments\ThreeDsRequest; +use Checkout\Tokens\GooglePayTokenData; +use Checkout\Tokens\GooglePayTokenRequest; +use CheckoutCom\Magento2\Gateway\Config\Config; +use CheckoutCom\Magento2\Helper\Logger as LoggerHelper; +use CheckoutCom\Magento2\Helper\Utilities; +use CheckoutCom\Magento2\Model\Service\ApiHandlerService; +use CheckoutCom\Magento2\Model\Service\QuoteHandlerService; +use Magento\Backend\Model\Auth\Session; +use Magento\Directory\Helper\Data as DirectoryHelper; +use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\Api\ExtensionAttributesFactory; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Data\Collection\AbstractDb; +use Magento\Framework\DataObjectFactory; +use Magento\Framework\Exception\FileSystemException; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Model\Context; +use Magento\Framework\Model\ResourceModel\AbstractResource; +use Magento\Framework\Registry; +use Magento\Framework\Serialize\Serializer\Json; +use Magento\Payment\Helper\Data; +use Magento\Payment\Model\InfoInterface; +use Magento\Payment\Model\Method\Logger; +use Magento\Quote\Api\Data\CartInterface; +use Magento\Store\Model\ScopeInterface; +use Magento\Store\Model\StoreManagerInterface; + +/** + * Class GooglePayMethod + */ +class PaypalMethod extends AbstractMethod +{ + /** + * CODE constant + * + * @var string CODE + */ + const CODE = 'checkoutcom_paypal'; + /** + * $_code field + * + * @var string $_code + */ + protected $_code = self::CODE; + /** + * $_canAuthorize field + * + * @var bool $_canAuthorize + */ + protected $_canAuthorize = true; + /** + * $_canCapture field + * + * @var bool $_canCapture + */ + protected $_canCapture = true; + /** + * $_canCapturePartial field + * + * @var bool $_canCapturePartial + */ + protected $_canCapturePartial = true; + /** + * $_canVoid field + * + * @var bool $_canVoid + */ + protected $_canVoid = true; + /** + * $_canUseInternal field + * + * @var bool $_canUseInternal + */ + protected $_canUseInternal = false; + /** + * $_canUseCheckout field + * + * @var bool $_canUseCheckout + */ + protected $_canUseCheckout = true; + /** + * $_canRefund field + * + * @var bool $_canRefund + */ + protected $_canRefund = true; + /** + * $_canRefundInvoicePartial field + * + * @var bool $_canRefundInvoicePartial + */ + protected $_canRefundInvoicePartial = true; + /** + * @var Json + */ + private $json; + /** + * $config field + * + * @var Config $config + */ + private $config; + /** + * $apiHandler field + * + * @var ApiHandlerService $apiHandler + */ + private $apiHandler; + /** + * $utilities field + * + * @var Utilities $utilities + */ + private $utilities; + /** + * $quoteHandler field + * + * @var QuoteHandlerService $quoteHandler + */ + private $quoteHandler; + /** + * $ckoLogger field + * + * @var Logger $ckoLogger + */ + private $ckoLogger; + /** + * $storeManager field + * + * @var StoreManagerInterface $storeManager + */ + private $storeManager; + /** + * $backendAuthSession field + * + * @var Session $backendAuthSession + */ + private $backendAuthSession; + + /** + * GooglePayMethod constructor + * + * @param Context $context + * @param Registry $registry + * @param ExtensionAttributesFactory $extensionFactory + * @param AttributeValueFactory $customAttributeFactory + * @param Data $paymentData + * @param ScopeConfigInterface $scopeConfig + * @param Logger $logger + * @param Config $config + * @param ApiHandlerService $apiHandler + * @param Utilities $utilities + * @param StoreManagerInterface $storeManager + * @param QuoteHandlerService $quoteHandler + * @param LoggerHelper $ckoLogger + * @param Session $backendAuthSession + * @param DirectoryHelper $directoryHelper + * @param DataObjectFactory $dataObjectFactory + * @param Json $json + * @param AbstractResource|null $resource + * @param AbstractDb|null $resourceCollection + * @param array $data + */ + public function __construct( + Context $context, + Registry $registry, + ExtensionAttributesFactory $extensionFactory, + AttributeValueFactory $customAttributeFactory, + Data $paymentData, + ScopeConfigInterface $scopeConfig, + Logger $logger, + Config $config, + ApiHandlerService $apiHandler, + Utilities $utilities, + StoreManagerInterface $storeManager, + QuoteHandlerService $quoteHandler, + LoggerHelper $ckoLogger, + Session $backendAuthSession, + DirectoryHelper $directoryHelper, + DataObjectFactory $dataObjectFactory, + Json $json, + AbstractResource $resource = null, + AbstractDb $resourceCollection = null, + array $data = [] + ) { + parent::__construct( + $config, + $context, + $registry, + $extensionFactory, + $customAttributeFactory, + $paymentData, + $scopeConfig, + $logger, + $directoryHelper, + $dataObjectFactory, + $resource, + $resourceCollection, + $data + ); + + $this->config = $config; + $this->apiHandler = $apiHandler; + $this->utilities = $utilities; + $this->storeManager = $storeManager; + $this->quoteHandler = $quoteHandler; + $this->ckoLogger = $ckoLogger; + $this->backendAuthSession = $backendAuthSession; + $this->json = $json; + } + + /** + * @param array $data + * @param float $amount + * @param string $currency + * @param string $reference + * + * @return array + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws FileSystemException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function sendPaymentRequest(array $data, float $amount, string $currency, string $reference = ''): array + { + // Get the store code + $storeCode = $this->storeManager->getStore()->getCode(); + + // Initialize the API handler + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + + // Get the quote + $quote = $this->quoteHandler->getQuote(); + + // Create the Google Pay data + $googlePayData = new GooglePayTokenData(); + $googlePayData->signature = $data['cardToken']['signature']; + $googlePayData->protocolVersion = $data['cardToken']['protocolVersion']; + $googlePayData->signedMessage = $data['cardToken']['signedMessage']; + + // Get the token data + $tokenData = new GooglePayTokenRequest(); + $tokenData->token_data = $googlePayData; + + // Create the Apple Pay token source + $response = $api->getCheckoutApi()->getTokensClient()->requestWalletToken($tokenData); + + if ($this->apiHandler->isPreviousMode()) { + $tokenSource = new PreviousRequestTokenSource(); + } else { + $tokenSource = new RequestTokenSource(); + } + + $tokenSource->token = $response['token']; + $tokenSource->billing_address = $api->createBillingAddress($quote); + + // Set the payment + if ($this->apiHandler->isPreviousMode()) { + $request = new PreviousPaymentRequest(); + } else { + $request = new PaymentRequest(); + } + + $request->source = $tokenSource; + $request->currency = $currency; + $request->processing_channel_id = $this->config->getValue('channel_id'); + + // Prepare the metadata array + $request->metadata['methodId'] = $this->_code; + + // Prepare the capture setting + $needsAutoCapture = $this->config->needsAutoCapture(); + $request->capture = $needsAutoCapture; + if ($needsAutoCapture) { + $request->capture_on = $this->config->getCaptureTime(); + } + + // Set the request parameters + $request->amount = $this->quoteHandler->amountToGateway( + $this->utilities->formatDecimals($amount), + $quote + ); + + $request->reference = $reference; + $request->success_url = $this->config->getStoreUrl() . 'checkout_com/payment/verify'; + $request->failure_url = $this->config->getStoreUrl() . 'checkout_com/payment/fail'; + + $theeDsRequest = new ThreeDsRequest(); + $theeDsRequest->enabled = $this->config->needs3ds($this->_code); + $request->three_ds = $theeDsRequest; + + $request->description = __('Payment request from %1', $this->config->getStoreName())->render(); + $request->customer = $api->createCustomer($quote); + $request->payment_type = 'Regular'; + $request->shipping = $api->createShippingAddress($quote); + + // Billing descriptor + if ($this->config->needsDynamicDescriptor()) { + $billingDescriptor = new BillingDescriptor(); + $billingDescriptor->city = $this->config->getValue('descriptor_city'); + $billingDescriptor->name = $this->config->getValue('descriptor_name', null, null, ScopeInterface::SCOPE_STORE); + $request->billing_descriptor = $billingDescriptor; + } + + // Add the quote metadata + $request->metadata['quoteData'] = $this->json->serialize($this->quoteHandler->getQuoteRequestData($quote)); + + // Add the base metadata + $request->metadata = array_merge( + $request->metadata, + $this->apiHandler->getBaseMetadata() + ); + + $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); + + // Send the charge request + return $api->getCheckoutApi()->getPaymentsClient()->requestPayment($request); + } + + /** + * @param InfoInterface $payment + * @param $amount + * + * @return AbstractMethod + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function capture(InfoInterface $payment, $amount): AbstractMethod + { + if ($this->backendAuthSession->isLoggedIn()) { + // Get the store code + $storeCode = $payment->getOrder()->getStore()->getCode(); + + // Initialize the API handler + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + + // Check the status + if (!$this->canCapture()) { + throw new LocalizedException( + __('The capture action is not available.') + ); + } + + // Process the capture request + $response = $api->captureOrder($payment, (float)$amount); + if (!$api->isValidResponse($response)) { + throw new LocalizedException( + __('The capture request could not be processed.') + ); + } + + // Set the transaction id from response + $payment->setTransactionId($response['action_id']); + } + + return $this; + } + + /** + * @param InfoInterface $payment + * + * @return AbstractMethod + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws LocalizedException + */ + public function void(InfoInterface $payment): AbstractMethod + { + if ($this->backendAuthSession->isLoggedIn()) { + // Get the store code + $storeCode = $payment->getOrder()->getStore()->getCode(); + + // Initialize the API handler + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + + // Check the status + if (!$this->canVoid()) { + throw new LocalizedException( + __('The void action is not available.') + ); + } + + // Process the void request + $response = $api->voidOrder($payment); + if (!$api->isValidResponse($response)) { + throw new LocalizedException( + __('The void request could not be processed.') + ); + } + + // Set the transaction id from response + $payment->setTransactionId($response['action_id']); + } + + return $this; + } + + /** + * @param InfoInterface $payment + * + * @return AbstractMethod + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws LocalizedException + */ + public function cancel(InfoInterface $payment): AbstractMethod + { + if ($this->backendAuthSession->isLoggedIn()) { + $order = $payment->getOrder(); + // Get the store code + $storeCode = $order->getStore()->getCode(); + + // Initialize the API handler + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + + // Check the status + if (!$this->canVoid()) { + throw new LocalizedException( + __('The void action is not available.') + ); + } + + // Process the void request + $response = $api->voidOrder($payment); + if (!$api->isValidResponse($response)) { + throw new LocalizedException( + __('The void request could not be processed.') + ); + } + + $comment = __( + 'Canceled order online, the voided amount is %1.', + $order->formatPriceTxt($order->getGrandTotal()) + ); + $payment->setMessage($comment); + // Set the transaction id from response + $payment->setTransactionId($response['action_id']); + } + + return $this; + } + + /** + * @param InfoInterface $payment + * @param $amount + * + * @return AbstractMethod + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function refund(InfoInterface $payment, $amount): AbstractMethod + { + if ($this->backendAuthSession->isLoggedIn()) { + // Get the store code + $storeCode = $payment->getOrder()->getStore()->getCode(); + + // Initialize the API handler + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } + + // Check the status + if (!$this->canRefund()) { + throw new LocalizedException( + __('The refund action is not available.') + ); + } + + // Process the refund request + try { + $response = $api->refundOrder($payment, $amount); + } catch (CheckoutApiException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $response = $api->refundOrder($payment, $amount); + } + + if (!$api->isValidResponse($response)) { + throw new LocalizedException( + __('The refund request could not be processed.') + ); + } + + // Set the transaction id from response + $payment->setTransactionId($response['action_id']); + } + + return $this; + } + + /** + * Check whether method is available + * + * @param CartInterface|null $quote + * + * @return bool + * @throws LocalizedException + */ + public function isAvailable(CartInterface $quote = null): bool + { + if ($this->isModuleActive() && parent::isAvailable($quote) && null !== $quote) { + return $this->config->getValue('active', $this->_code) && !$this->backendAuthSession->isLoggedIn(); + } + + return false; + } + + /** + * @inheritDoc + */ + public function canUseForCurrency($currencyCode): bool + { + $availableCurrencies = array_filter(explode(',', $this->getConfigData('specificcurrencies') ?? '')); + if (!empty($availableCountries) && !in_array($currencyCode, $availableCurrencies)) { + return false; + } + + return true; + } +} diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php new file mode 100644 index 00000000..66303f4c --- /dev/null +++ b/Model/Service/PaymentContextRequestService.php @@ -0,0 +1,128 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +declare(strict_types=1); + +namespace CheckoutCom\Magento2\Model\Service; + +use Checkout\Payments\AuthorizationType; +use Checkout\Payments\Contexts\PaymentContextsItems; +use Checkout\Payments\Contexts\PaymentContextsRequest; +use Checkout\Payments\PaymentType; +use CheckoutCom\Magento2\Gateway\Config\Config; +use CheckoutCom\Magento2\Helper\Logger as MagentoLoggerHelper; +use CheckoutCom\Magento2\Helper\Utilities; +use Magento\Checkout\Model\Session; +use Magento\Framework\UrlInterface; +use Magento\Quote\Api\Data\CartInterface; +use Magento\Quote\Model\Quote; +use Magento\Store\Model\StoreManagerInterface; + +class PaymentContextRequestService +{ + protected StoreManagerInterface $storeManager; + protected ApiHandlerService $apiHandlerService; + protected Session $checkoutSession; + protected Config $checkoutConfigProvider; + protected UrlInterface $urlBuilder; + protected MagentoLoggerHelper $ckoLogger; + protected Utilities $utilities; + + public function __construct( + StoreManagerInterface $storeManager, + ApiHandlerService $apiHandler, + Session $checkoutSession, + Config $checkoutConfigProvider, + UrlInterface $urlBuilder, + ApiHandlerService $apiHandlerService, + MagentoLoggerHelper $ckoLogger, + Utilities $utilities + ) { + $this->storeManager = $storeManager; + $this->apiHandlerService = $apiHandler; + $this->checkoutConfigProvider = $checkoutConfigProvider; + $this->checkoutSession = $checkoutSession; + $this->urlBuilder = $urlBuilder; + $this->ckoLogger = $ckoLogger; + $this->utilities = $utilities; + } + + public function makePaymentContextRequests(string $sourceType, ?string $paymentType = null, ?string $authorizationType = null): array + { + $quote = $this->getQuote(); + if (!$quote->getId()) { + return []; + } + + $request = $this->getContextRequest($quote, $sourceType, $paymentType, $authorizationType); + + $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); + + return $this->apiHandlerService->getCheckoutApi()->getPaymentContextsClient()->createPaymentContexts($request); + } + + private function getContextRequest( + Quote | CartInterface $quote, + string $sourceType, + ?string $paymentType = null, + ?string $authorizationType = null + ): PaymentContextsRequest { + // Set Default values + if (!$paymentType) { + $paymentType = PaymentType::$regular; + } + if (!$authorizationType) { + $authorizationType = AuthorizationType::$final; + } + + // Global informations + $request = new PaymentContextsRequest(); + $request->amount = $quote->getGrandTotal(); + $request->payment_type = $paymentType; + $request->currency = $quote->getCurrency()->getQuoteCurrencyCode(); + $request->capture = $this->checkoutConfigProvider->needsAutoCapture(); + $request->processing_channel_id = $this->checkoutConfigProvider->getValue('channel_id'); + + // Source Type + $request->source = new AbstractRequestSource($sourceType); + + // Items + $items = []; + /** @var Quote\Item $item */ + foreach ($quote->getAllItems() as $item) { + $contextItem = new PaymentContextsItems(); + $contextItem->reference = $item->getSku(); + $contextItem->quantity = $item->getQty(); + $contextItem->name = $item->getName(); + $contextItem->unit_price = $item->getPrice(); + $items[] = $contextItem; + } + $request->items = $items; + + // Urls + $request->success_url = $this->urlBuilder->getUrl('checkout/onepage/success'); + $request->failure_url = $this->urlBuilder->getUrl('checkout/onepage/failure'); + + return $request; + } + + private function getQuote(): Quote | CartInterface + { + return $this->checkoutSession->getQuote(); + } + +} diff --git a/composer.json b/composer.json index 50e8115b..c2e11aa7 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "checkoutcom/magento2", "description": "Checkout.com Payment Gateway for Magento 2", "require": { - "checkout/checkout-sdk-php": "3.0.6", + "checkout/checkout-sdk-php": "3.0.21", "php": "~7.3.0||~7.4.0||~8.1.0||~8.2.0", "magento/framework": ">=100.0.1" }, diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index c14b56e1..564bd452 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -628,6 +628,66 @@ + + + + + payment/checkoutcom_paypal/title + + + + + Magento\Config\Model\Config\Source\Yesno + payment/checkoutcom_paypal/active + + + + + + + + + payment/checkoutcom_paypal/client_id + Provide your Client ID + + + + + payment/checkoutcom_paypal/merchant_id + Provide your Merchant ID + + + + + payment/checkoutcom_paypal/checkout_client_id + sdk documentation]]> + + + + + payment/checkoutcom_paypal/checkout_partner_attribution_id + sdk documentation]]> + + + + + Magento\Config\Model\Config\Source\Yesno + payment/checkoutcom_paypal/express_cart + + + + + Magento\Config\Model\Config\Source\Yesno + payment/checkoutcom_paypal/express_minicart + + + + + validate-number + payment/checkoutcom_paypal/sort_order + + + diff --git a/etc/config.xml b/etc/config.xml index 80635b08..5b9efd0c 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -173,6 +173,31 @@ TEST white + + CheckoutCom\Magento2\Model\Methods\PaypalMethod + Paypal with Checkout.com + 0 + 0 + 0 + 0 + ASLqLf4pnWuBshW8Qh8z_DRUbIv2Cgs3Ft8aauLm9Z-MO9FZx1INSo38nW109o_Xvu88P3tly88XbJMR + CheckoutLtd_PSP + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + 1 + AF,AX,AL,DZ,AS,AD,AO,AI,AQ,AG,AR,AM,AW,AU,AT,AZ,BS,BH,BD,BB,BY,BE,BZ,BJ,BM,BT,BO,BA,BW,BV,BR,IO,VG,BN,BG,BF,BI,KH,CM,CA,CV,KY,CF,TD,CL,CN,CX,CC,CO,KM,CG,CD,CK,CR,CI,HR,CU,CY,CZ,DK,DJ,DM,DO,EC,EG,SV,GQ,ER,EE,ET,FK,FO,FJ,FI,FR,GF,PF,TF,GA,GM,GE,DE,GH,GI,GR,GL,GD,GP,GU,GT,GG,GN,GW,GY,HT,HM,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IM,IL,IT,JM,JP,JE,JO,KZ,KE,KI,KW,KG,LA,LV,LB,LS,LR,LY,LI,LT,LU,MO,MK,MG,MW,MY,MV,ML,MT,MH,MQ,MR,MU,YT,MX,FM,MD,MC,MN,ME,MS,MA,MZ,MM,NA,NR,NP,NL,AN,NC,NZ,NI,NE,NG,NU,NF,MP,KP,NO,OM,PK,PW,PS,PA,PG,PY,PE,PH,PN,PL,PT,QA,RE,RO,RU,RW,WS,SM,ST,SA,SN,RS,SC,SL,SG,SK,SI,SB,SO,ZA,GS,KR,ES,LK,BL,SH,KN,LC,MF,PM,VC,SD,SR,SJ,SZ,SE,CH,SY,TW,TJ,TZ,TH,TL,TG,TK,TO,TT,TN,TR,TM,TC,TV,UG,UA,AE,GB,US,UY,UM,VI,UZ,VU,VA,VE,VN,WF,EH,YE,ZM,ZW + AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,INR,ILS,JPY,MXN,TWD,NZD,NOK,PHP,PLN,GBP,RUB,SGD,SEK,CHF,THB,USD + CheckoutCom\Magento2\Model\Methods\ApplePayMethod Apple Pay with Checkout.com diff --git a/etc/payment.xml b/etc/payment.xml index 47d9b592..01f7769c 100644 --- a/etc/payment.xml +++ b/etc/payment.xml @@ -26,6 +26,9 @@ 0 + + 0 + 0 diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml index fec3e168..70579f92 100755 --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -19,6 +19,13 @@ + + + + @@ -38,6 +45,9 @@ CheckoutCom_Magento2/js/view/payment/method-renderer + + true + true diff --git a/view/frontend/templates/script/paypal-script.phtml b/view/frontend/templates/script/paypal-script.phtml new file mode 100644 index 00000000..7fba7222 --- /dev/null +++ b/view/frontend/templates/script/paypal-script.phtml @@ -0,0 +1,27 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +use CheckoutCom\Magento2\Block\Paypal\Script; +use Magento\Framework\Escaper; +/** @var Escaper $escaper */ +/** @var Script $block */ +$clientId = $block->getClientId(); +$partnerId = $block->getPartnerAttributionId(); +$paypalMerchantId = $block->getPaypalMerchantId(); +if ($clientId && $partnerId && $paypalMerchantId): +?> + + diff --git a/view/frontend/web/css/paypal/paypal.css b/view/frontend/web/css/paypal/paypal.css new file mode 100644 index 00000000..e69de29b diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js new file mode 100755 index 00000000..58c8c108 --- /dev/null +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js @@ -0,0 +1,229 @@ +/** + * Checkout.com + * Authorized and regulated as an electronic money institution + * by the UK Financial Conduct Authority (FCA) under number 900816. + * + * PHP version 7 + * + * @category Magento2 + * @package Checkout.com + * @author Platforms Development Team + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +define( + [ + 'jquery', + 'Magento_Checkout/js/view/payment/default', + 'CheckoutCom_Magento2/js/view/payment/utilities', + 'Magento_Checkout/js/model/full-screen-loader', + 'Magento_Checkout/js/model/payment/additional-validators', + 'Magento_Checkout/js/model/quote', + 'mage/translate', + 'jquery/ui', + ], + function( + $, Component, Utilities, FullScreenLoader, AdditionalValidators, Quote, + __) { + + 'use strict'; + window.checkoutConfig.reloadOnBillingAddress = true; + const METHOD_ID = 'checkoutcom_paypal'; + let loadEvents = true; + let loaded = false; + + return Component.extend( + { + defaults: { + template: 'CheckoutCom_Magento2/payment/' + METHOD_ID + + '.html', + buttonId: METHOD_ID + '_btn', + redirectAfterPlaceOrder: false, + orderId: null + }, + + /** + * @return {exports} + */ + initialize: function() { + this._super(); + Utilities.loadCss('paypal', 'paypal'); + }, + + initPaypalButton: function() { + + let self = this; + + // Obtain Checkout context OrderId + $.ajax( + { + type: "POST", + url: Utilities.getUrl('paypal/context'), + data: { + }, + success: function (data) { + alert('success'); + }, + error: function (request, status, error) { + alert('passuccess'); + } + } + ); + + + paypal.Buttons({ + createOrder() { + + return self.defaults.orderId; + }, + onApprove: async function(data) { + alert( + 'Transaction approved, PLEASE MAKE something'); + }, + }).render('#paypal-button-container'); + }, + + /** + * @return {string} + */ + getCode: function() { + return METHOD_ID; + }, + + /** + * @return {string} + */ + getValue: function(field) { + return Utilities.getValue(METHOD_ID, field); + }, + + /** + * @return {void} + */ + checkLastPaymentMethod: function() { + return Utilities.checkLastPaymentMethod(); + }, + + /** + * @return {void} + */ + initWidget: function() { + // Start the loader + FullScreenLoader.startLoader(); + + let self = this; + alert('inipaypal'); + // Send the AJAX request + /*$.ajax( + { + type: "POST", + url: Utilities.getUrl('apm/display'), + data: { + country_id: Utilities.getBillingAddress() ? Utilities.getBillingAddress().country_id : null + }, + success: function (data) { + self.animateRender(data); + self.initEvents(); + self.checkLastPaymentMethod(); + }, + error: function (request, status, error) { + Utilities.log(error); + + // Stop the loader + FullScreenLoader.stopLoader(); + } + } + );*/ + }, + + /** + * @return {void} + */ + initEvents: function() { + alert('ça init les events'); + if (loadEvents) { + let self = this; + let prevAddress; + + /*Quote.billingAddress.subscribe( + function (newAddress) { + if (!newAddress || !prevAddress || newAddress.getKey() !== prevAddress.getKey()) { + prevAddress = newAddress; + if (newAddress) { + self.reloadApms(Quote.billingAddress().countryId); + } + } + } + );*/ + + loadEvents = false; + } + }, + + /** + * @return {void} + */ + placeOrder: function() { + alert('place paypal order'); + + let id = $('#apm-container div[aria-selected=true]'). + attr('id'); + + if (Utilities.methodIsSelected(METHOD_ID) && id) { + let form = $('#cko-apm-form-' + id), + data = {methodId: METHOD_ID}; + + // Start the loader + FullScreenLoader.startLoader(); + + // Serialize data + form.serializeArray().forEach( + function(e) { + data[e.name] = e.value; + }, + ); + + // Place the order + if (AdditionalValidators.validate() && form.valid() && + this.custom(data)) { + Utilities.placeOrder( + data, + METHOD_ID, + function() { + Utilities.log(__('Success')); + }, + function() { + Utilities.log(__('Fail')); + }, + ); + Utilities.cleanCustomerShippingAddress(); + } + + FullScreenLoader.stopLoader(); + } + }, + + /** + * Custom "before place order" flows. + */ + + /** + * Dynamic function handler. + * + * @param {String} id The identifier + * @return {boolean} + */ + custom: function(data) { + var result = true; + if (typeof this[data.source] == 'function') { + result = this[data.source](data); + } + + return result; + }, + }, + ); + }, +); diff --git a/view/frontend/web/template/payment/checkoutcom_paypal.html b/view/frontend/web/template/payment/checkoutcom_paypal.html new file mode 100755 index 00000000..3dfc7bda --- /dev/null +++ b/view/frontend/web/template/payment/checkoutcom_paypal.html @@ -0,0 +1,58 @@ + + +
+
+ + +
+ +
+ + + + + + +
+
+
+ + +
+ + + +
+ + +
+ + + +
+ + +
+
+
+ + +
+
+
+
From 796d3ebdd63d312dc209905da34ac7617e9a77dc Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Wed, 28 Feb 2024 09:04:27 +0100 Subject: [PATCH 042/147] CHECMAG2003-206 - First Working Paypal Process --- Controller/Paypal/Context.php | 10 +- Model/Methods/PaypalMethod.php | 77 +--------- .../Service/PaymentContextRequestService.php | 26 +++- etc/di.xml | 1 + .../method-renderer/checkoutcom_paypal.js | 135 ++++++------------ .../template/payment/checkoutcom_paypal.html | 2 - 6 files changed, 71 insertions(+), 180 deletions(-) diff --git a/Controller/Paypal/Context.php b/Controller/Paypal/Context.php index c2736bf1..1367d5d8 100644 --- a/Controller/Paypal/Context.php +++ b/Controller/Paypal/Context.php @@ -27,20 +27,20 @@ use Magento\Framework\Controller\Result\JsonFactory; use Magento\Framework\Controller\ResultInterface; -class Context extends Action +class Context implements HttpGetActionInterface,HttpPostActionInterface { - protected JsonFactory $jsonFactory; + protected JsonFactory $resultJsonFactory; protected PaymentContextRequestService $paymentContextRequestService; public function __construct( - JsonFactory $jsonFactory, + JsonFactory $resultJsonFactory, PaymentContextRequestService $paymentContextRequestService ) { - $this->jsonFactory = $jsonFactory; + $this->resultJsonFactory = $resultJsonFactory; $this->paymentContextRequestService = $paymentContextRequestService; } - public function execute(): ResponseInterface | ResultInterface + public function execute() { $resultJson = $this->resultJsonFactory->create(); $resultJson->setData( diff --git a/Model/Methods/PaypalMethod.php b/Model/Methods/PaypalMethod.php index a43aaa79..f20dd86a 100755 --- a/Model/Methods/PaypalMethod.php +++ b/Model/Methods/PaypalMethod.php @@ -21,14 +21,8 @@ use Checkout\CheckoutApiException; use Checkout\CheckoutArgumentException; -use Checkout\Payments\BillingDescriptor; use Checkout\Payments\Previous\PaymentRequest as PreviousPaymentRequest; -use Checkout\Payments\Previous\Source\RequestTokenSource as PreviousRequestTokenSource; use Checkout\Payments\Request\PaymentRequest; -use Checkout\Payments\Request\Source\RequestTokenSource; -use Checkout\Payments\ThreeDsRequest; -use Checkout\Tokens\GooglePayTokenData; -use Checkout\Tokens\GooglePayTokenRequest; use CheckoutCom\Magento2\Gateway\Config\Config; use CheckoutCom\Magento2\Helper\Logger as LoggerHelper; use CheckoutCom\Magento2\Helper\Utilities; @@ -263,28 +257,6 @@ public function sendPaymentRequest(array $data, float $amount, string $currency, // Get the quote $quote = $this->quoteHandler->getQuote(); - // Create the Google Pay data - $googlePayData = new GooglePayTokenData(); - $googlePayData->signature = $data['cardToken']['signature']; - $googlePayData->protocolVersion = $data['cardToken']['protocolVersion']; - $googlePayData->signedMessage = $data['cardToken']['signedMessage']; - - // Get the token data - $tokenData = new GooglePayTokenRequest(); - $tokenData->token_data = $googlePayData; - - // Create the Apple Pay token source - $response = $api->getCheckoutApi()->getTokensClient()->requestWalletToken($tokenData); - - if ($this->apiHandler->isPreviousMode()) { - $tokenSource = new PreviousRequestTokenSource(); - } else { - $tokenSource = new RequestTokenSource(); - } - - $tokenSource->token = $response['token']; - $tokenSource->billing_address = $api->createBillingAddress($quote); - // Set the payment if ($this->apiHandler->isPreviousMode()) { $request = new PreviousPaymentRequest(); @@ -292,56 +264,9 @@ public function sendPaymentRequest(array $data, float $amount, string $currency, $request = new PaymentRequest(); } - $request->source = $tokenSource; - $request->currency = $currency; + $request->payment_context_id = $data['contextPaymentId']; $request->processing_channel_id = $this->config->getValue('channel_id'); - // Prepare the metadata array - $request->metadata['methodId'] = $this->_code; - - // Prepare the capture setting - $needsAutoCapture = $this->config->needsAutoCapture(); - $request->capture = $needsAutoCapture; - if ($needsAutoCapture) { - $request->capture_on = $this->config->getCaptureTime(); - } - - // Set the request parameters - $request->amount = $this->quoteHandler->amountToGateway( - $this->utilities->formatDecimals($amount), - $quote - ); - - $request->reference = $reference; - $request->success_url = $this->config->getStoreUrl() . 'checkout_com/payment/verify'; - $request->failure_url = $this->config->getStoreUrl() . 'checkout_com/payment/fail'; - - $theeDsRequest = new ThreeDsRequest(); - $theeDsRequest->enabled = $this->config->needs3ds($this->_code); - $request->three_ds = $theeDsRequest; - - $request->description = __('Payment request from %1', $this->config->getStoreName())->render(); - $request->customer = $api->createCustomer($quote); - $request->payment_type = 'Regular'; - $request->shipping = $api->createShippingAddress($quote); - - // Billing descriptor - if ($this->config->needsDynamicDescriptor()) { - $billingDescriptor = new BillingDescriptor(); - $billingDescriptor->city = $this->config->getValue('descriptor_city'); - $billingDescriptor->name = $this->config->getValue('descriptor_name', null, null, ScopeInterface::SCOPE_STORE); - $request->billing_descriptor = $billingDescriptor; - } - - // Add the quote metadata - $request->metadata['quoteData'] = $this->json->serialize($this->quoteHandler->getQuoteRequestData($quote)); - - // Add the base metadata - $request->metadata = array_merge( - $request->metadata, - $this->apiHandler->getBaseMetadata() - ); - $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); // Send the charge request diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index 66303f4c..86a4ad51 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -23,6 +23,7 @@ use Checkout\Payments\Contexts\PaymentContextsItems; use Checkout\Payments\Contexts\PaymentContextsRequest; use Checkout\Payments\PaymentType; +use Checkout\Payments\Request\Source\AbstractRequestSource; use CheckoutCom\Magento2\Gateway\Config\Config; use CheckoutCom\Magento2\Helper\Logger as MagentoLoggerHelper; use CheckoutCom\Magento2\Helper\Utilities; @@ -30,6 +31,7 @@ use Magento\Framework\UrlInterface; use Magento\Quote\Api\Data\CartInterface; use Magento\Quote\Model\Quote; +use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; class PaymentContextRequestService @@ -72,7 +74,12 @@ public function makePaymentContextRequests(string $sourceType, ?string $paymentT $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); - return $this->apiHandlerService->getCheckoutApi()->getPaymentContextsClient()->createPaymentContexts($request); + $storeCode = $this->storeManager->getStore($quote->getStoreId())->getCode(); + $api = $this->apiHandlerService->init($storeCode, ScopeInterface::SCOPE_STORE); + + return $api->getCheckoutApi() + ->getPaymentContextsClient() + ->createPaymentContexts($request); } private function getContextRequest( @@ -91,7 +98,7 @@ private function getContextRequest( // Global informations $request = new PaymentContextsRequest(); - $request->amount = $quote->getGrandTotal(); + $request->amount = $this->utilities->formatDecimals($quote->getGrandTotal() * 100); $request->payment_type = $paymentType; $request->currency = $quote->getCurrency()->getQuoteCurrencyCode(); $request->capture = $this->checkoutConfigProvider->needsAutoCapture(); @@ -108,9 +115,22 @@ private function getContextRequest( $contextItem->reference = $item->getSku(); $contextItem->quantity = $item->getQty(); $contextItem->name = $item->getName(); - $contextItem->unit_price = $item->getPrice(); + $contextItem->unit_price = $this->utilities->formatDecimals($item->getRowTotalInclTax() / $item->getQty()) * 100; + $items[] = $contextItem; } + + // Shipping fee + $shipping = $quote->getShippingAddress(); + + if ($shipping->getShippingDescription()) { + $product = new PaymentContextsItems(); + $product->name = $shipping->getShippingDescription(); + $product->quantity = 1; + $product->unit_price = $shipping->getShippingInclTax() * 100; + + $items[] = $product; + } $request->items = $items; // Urls diff --git a/etc/di.xml b/etc/di.xml index 3bac7ff9..ffc6eb2c 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -41,6 +41,7 @@ CheckoutCom\Magento2\Model\Methods\AlternativePaymentMethod CheckoutCom\Magento2\Model\Methods\ApplePayMethod CheckoutCom\Magento2\Model\Methods\GooglePayMethod + CheckoutCom\Magento2\Model\Methods\PaypalMethod CheckoutCom\Magento2\Model\Methods\VaultMethod diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js index 58c8c108..47b2dd7d 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js @@ -41,7 +41,8 @@ define( '.html', buttonId: METHOD_ID + '_btn', redirectAfterPlaceOrder: false, - orderId: null + chkPayPalOrderid: null, + chkPayPalContextId: null }, /** @@ -50,39 +51,50 @@ define( initialize: function() { this._super(); Utilities.loadCss('paypal', 'paypal'); + let self = this; + + //Todo: proper way to init, the paypal button must be loaded when + // #paypal-button-container is on the dom + setTimeout(function(){ + self.initPaypalButton(); + },1000); }, initPaypalButton: function() { let self = this; - // Obtain Checkout context OrderId + // Prepare Context $.ajax( { - type: "POST", + type: 'POST', url: Utilities.getUrl('paypal/context'), - data: { + showLoader: true, + data: {}, + success: function(data) { + if (typeof data.content !== 'undefined') { + self.chkPayPalOrderid = data.content.partner_metadata.order_id; + self.chkPayPalContextId = data.content.id; + + // Init paypal button after getting context order id + paypal.Buttons({ + createOrder() { + return self.chkPayPalOrderid; + }, + onApprove: async function(data) { + self.placeOrder(); + }, + }).render('#paypal-button-container'); + + } + // Todo else message manager error }, - success: function (data) { - alert('success'); + error: function(request, status, error) { + // Todo message manager error }, - error: function (request, status, error) { - alert('passuccess'); - } - } + }, ); - - paypal.Buttons({ - createOrder() { - - return self.defaults.orderId; - }, - onApprove: async function(data) { - alert( - 'Transaction approved, PLEASE MAKE something'); - }, - }).render('#paypal-button-container'); }, /** @@ -114,50 +126,16 @@ define( FullScreenLoader.startLoader(); let self = this; - alert('inipaypal'); - // Send the AJAX request - /*$.ajax( - { - type: "POST", - url: Utilities.getUrl('apm/display'), - data: { - country_id: Utilities.getBillingAddress() ? Utilities.getBillingAddress().country_id : null - }, - success: function (data) { - self.animateRender(data); - self.initEvents(); - self.checkLastPaymentMethod(); - }, - error: function (request, status, error) { - Utilities.log(error); - - // Stop the loader - FullScreenLoader.stopLoader(); - } - } - );*/ }, /** * @return {void} */ initEvents: function() { - alert('ça init les events'); if (loadEvents) { let self = this; let prevAddress; - /*Quote.billingAddress.subscribe( - function (newAddress) { - if (!newAddress || !prevAddress || newAddress.getKey() !== prevAddress.getKey()) { - prevAddress = newAddress; - if (newAddress) { - self.reloadApms(Quote.billingAddress().countryId); - } - } - } - );*/ - loadEvents = false; } }, @@ -166,28 +144,16 @@ define( * @return {void} */ placeOrder: function() { - alert('place paypal order'); - - let id = $('#apm-container div[aria-selected=true]'). - attr('id'); - - if (Utilities.methodIsSelected(METHOD_ID) && id) { - let form = $('#cko-apm-form-' + id), - data = {methodId: METHOD_ID}; - - // Start the loader - FullScreenLoader.startLoader(); - - // Serialize data - form.serializeArray().forEach( - function(e) { - data[e.name] = e.value; - }, - ); + FullScreenLoader.startLoader(); + + if (Utilities.methodIsSelected(METHOD_ID) && this.chkPayPalContextId) { + let data = { + methodId: METHOD_ID, + contextPaymentId: this.chkPayPalContextId, + }; // Place the order - if (AdditionalValidators.validate() && form.valid() && - this.custom(data)) { + if (AdditionalValidators.validate()) { Utilities.placeOrder( data, METHOD_ID, @@ -204,25 +170,6 @@ define( FullScreenLoader.stopLoader(); } }, - - /** - * Custom "before place order" flows. - */ - - /** - * Dynamic function handler. - * - * @param {String} id The identifier - * @return {boolean} - */ - custom: function(data) { - var result = true; - if (typeof this[data.source] == 'function') { - result = this[data.source](data); - } - - return result; - }, }, ); }, diff --git a/view/frontend/web/template/payment/checkoutcom_paypal.html b/view/frontend/web/template/payment/checkoutcom_paypal.html index 3dfc7bda..6758a0b0 100755 --- a/view/frontend/web/template/payment/checkoutcom_paypal.html +++ b/view/frontend/web/template/payment/checkoutcom_paypal.html @@ -50,8 +50,6 @@
- -
From 8075e714fb0fddfbbb5a1cf75126fb8911f44178 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Wed, 28 Feb 2024 09:49:15 +0100 Subject: [PATCH 043/147] CHECMAG2003-206 - Allow non capture mode in paypal widget --- Block/Paypal/Script.php | 9 +++++++ Controller/Paypal/Context.php | 11 +++++---- .../templates/script/paypal-script.phtml | 2 +- .../method-renderer/checkoutcom_paypal.js | 24 +------------------ 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/Block/Paypal/Script.php b/Block/Paypal/Script.php index bd8fa0d8..379c6b22 100644 --- a/Block/Paypal/Script.php +++ b/Block/Paypal/Script.php @@ -19,20 +19,24 @@ namespace CheckoutCom\Magento2\Block\Paypal; +use CheckoutCom\Magento2\Gateway\Config\Config; use CheckoutCom\Magento2\Model\Methods\PaypalMethod; use Magento\Framework\View\Element\Template; class Script extends Template { private PaypalMethod $paypalMethod; + private Config $checkoutConfig; public function __construct( Template\Context $context, PaypalMethod $paypalMethod, + Config $checkoutConfig, array $data = [] ) { parent::__construct($context, $data); $this->paypalMethod = $paypalMethod; + $this->checkoutConfig = $checkoutConfig; } public function getPaypalMerchantId(): string @@ -49,4 +53,9 @@ public function getPartnerAttributionId(): string { return (string)$this->paypalMethod->getConfigData('checkout_partner_attribution_id'); } + + public function getIntent(): string + { + return $this->checkoutConfig->needsAutoCapture() ? 'capture' : 'authorize'; + } } diff --git a/Controller/Paypal/Context.php b/Controller/Paypal/Context.php index 1367d5d8..91701e23 100644 --- a/Controller/Paypal/Context.php +++ b/Controller/Paypal/Context.php @@ -22,12 +22,10 @@ use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\App\Action\Action; -use Magento\Framework\App\ResponseInterface; +use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; -use Magento\Framework\Controller\ResultInterface; -class Context implements HttpGetActionInterface,HttpPostActionInterface +class Context implements HttpPostActionInterface { protected JsonFactory $resultJsonFactory; protected PaymentContextRequestService $paymentContextRequestService; @@ -40,7 +38,10 @@ public function __construct( $this->paymentContextRequestService = $paymentContextRequestService; } - public function execute() + /** + * @inheritDoc + */ + public function execute(): Json { $resultJson = $this->resultJsonFactory->create(); $resultJson->setData( diff --git a/view/frontend/templates/script/paypal-script.phtml b/view/frontend/templates/script/paypal-script.phtml index 7fba7222..bb521c91 100644 --- a/view/frontend/templates/script/paypal-script.phtml +++ b/view/frontend/templates/script/paypal-script.phtml @@ -23,5 +23,5 @@ $partnerId = $block->getPartnerAttributionId(); $paypalMerchantId = $block->getPaypalMerchantId(); if ($clientId && $partnerId && $paypalMerchantId): ?> - + diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js index 47b2dd7d..a24af923 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js @@ -118,34 +118,12 @@ define( return Utilities.checkLastPaymentMethod(); }, - /** - * @return {void} - */ - initWidget: function() { - // Start the loader - FullScreenLoader.startLoader(); - - let self = this; - }, - - /** - * @return {void} - */ - initEvents: function() { - if (loadEvents) { - let self = this; - let prevAddress; - - loadEvents = false; - } - }, - /** * @return {void} */ placeOrder: function() { FullScreenLoader.startLoader(); - + if (Utilities.methodIsSelected(METHOD_ID) && this.chkPayPalContextId) { let data = { methodId: METHOD_ID, From 6e38289eed32cff1fe1946442ef1e22201e91ece Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Wed, 28 Feb 2024 15:12:17 +0100 Subject: [PATCH 044/147] CHECMAG2003-206 - Add express buttons --- Block/Paypal/Script.php | 19 +++ Controller/Paypal/Context.php | 12 +- Model/Methods/PaypalMethod.php | 3 + .../Service/PaymentContextRequestService.php | 14 ++- view/frontend/layout/checkout_cart_index.xml | 11 ++ view/frontend/layout/checkout_index_index.xml | 12 +- view/frontend/layout/default.xml | 19 +++ view/frontend/templates/cart/paypal.phtml | 27 +++++ .../templates/script/paypal-script.phtml | 2 +- .../web/js/view/minicart/paypalbutton.js | 114 ++++++++++++++++++ .../payment/cart/checkoutcom_paypal_cart.js | 113 +++++++++++++++++ .../method-renderer/checkoutcom_paypal.js | 71 ++++++----- .../checkout/minicart/paypalbutton.html | 16 +++ 13 files changed, 389 insertions(+), 44 deletions(-) create mode 100644 view/frontend/templates/cart/paypal.phtml create mode 100644 view/frontend/web/js/view/minicart/paypalbutton.js create mode 100644 view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js create mode 100644 view/frontend/web/template/checkout/minicart/paypalbutton.html diff --git a/Block/Paypal/Script.php b/Block/Paypal/Script.php index 379c6b22..e3f30f27 100644 --- a/Block/Paypal/Script.php +++ b/Block/Paypal/Script.php @@ -56,6 +56,25 @@ public function getPartnerAttributionId(): string public function getIntent(): string { + if ($this->isExpressButton()) { + return 'authorize'; + } + return $this->checkoutConfig->needsAutoCapture() ? 'capture' : 'authorize'; } + + public function getCommit(): string + { + return $this->isExpressButton() ? 'false' : 'true'; + } + + public function getPageType(): string + { + return $this->getScriptType() ?? 'checkout'; + } + + private function isExpressButton(): bool + { + return $this->getMode() === 'express'; + } } diff --git a/Controller/Paypal/Context.php b/Controller/Paypal/Context.php index 91701e23..38feb470 100644 --- a/Controller/Paypal/Context.php +++ b/Controller/Paypal/Context.php @@ -20,8 +20,8 @@ namespace CheckoutCom\Magento2\Controller\Paypal; use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; -use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; @@ -29,13 +29,16 @@ class Context implements HttpPostActionInterface { protected JsonFactory $resultJsonFactory; protected PaymentContextRequestService $paymentContextRequestService; + protected RequestInterface $request; public function __construct( JsonFactory $resultJsonFactory, - PaymentContextRequestService $paymentContextRequestService + PaymentContextRequestService $paymentContextRequestService, + RequestInterface $request ) { $this->resultJsonFactory = $resultJsonFactory; $this->paymentContextRequestService = $paymentContextRequestService; + $this->request = $request; } /** @@ -46,7 +49,10 @@ public function execute(): Json $resultJson = $this->resultJsonFactory->create(); $resultJson->setData( [ - 'content' => $this->paymentContextRequestService->makePaymentContextRequests('paypal') + 'content' => $this->paymentContextRequestService->makePaymentContextRequests( + 'paypal', + (bool)$this->request->getParam('forceAuthorizeMode') + ) ] ); diff --git a/Model/Methods/PaypalMethod.php b/Model/Methods/PaypalMethod.php index f20dd86a..445779da 100755 --- a/Model/Methods/PaypalMethod.php +++ b/Model/Methods/PaypalMethod.php @@ -264,6 +264,9 @@ public function sendPaymentRequest(array $data, float $amount, string $currency, $request = new PaymentRequest(); } + // Set parameters + $payment->capture = $this->config->needsAutoCapture(); + $payment->amount = $this->utilities->formatDecimals($amount * 100); $request->payment_context_id = $data['contextPaymentId']; $request->processing_channel_id = $this->config->getValue('channel_id'); diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index 86a4ad51..ddf8bc90 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -63,14 +63,18 @@ public function __construct( $this->utilities = $utilities; } - public function makePaymentContextRequests(string $sourceType, ?string $paymentType = null, ?string $authorizationType = null): array - { + public function makePaymentContextRequests( + string $sourceType, + ?bool $forceAuthorize = false, + ?string $paymentType = null, + ?string $authorizationType = null + ): array { $quote = $this->getQuote(); if (!$quote->getId()) { return []; } - $request = $this->getContextRequest($quote, $sourceType, $paymentType, $authorizationType); + $request = $this->getContextRequest($quote, $sourceType, $forceAuthorize, $paymentType, $authorizationType); $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); @@ -85,6 +89,7 @@ public function makePaymentContextRequests(string $sourceType, ?string $paymentT private function getContextRequest( Quote | CartInterface $quote, string $sourceType, + ?bool $forceAuthorize = false, ?string $paymentType = null, ?string $authorizationType = null ): PaymentContextsRequest { @@ -95,13 +100,14 @@ private function getContextRequest( if (!$authorizationType) { $authorizationType = AuthorizationType::$final; } + $capture = $forceAuthorize ? false : $this->checkoutConfigProvider->needsAutoCapture(); // Global informations $request = new PaymentContextsRequest(); $request->amount = $this->utilities->formatDecimals($quote->getGrandTotal() * 100); $request->payment_type = $paymentType; $request->currency = $quote->getCurrency()->getQuoteCurrencyCode(); - $request->capture = $this->checkoutConfigProvider->needsAutoCapture(); + $request->capture = $capture; $request->processing_channel_id = $this->checkoutConfigProvider->getValue('channel_id'); // Source Type diff --git a/view/frontend/layout/checkout_cart_index.xml b/view/frontend/layout/checkout_cart_index.xml index dea6da35..4ac23588 100644 --- a/view/frontend/layout/checkout_cart_index.xml +++ b/view/frontend/layout/checkout_cart_index.xml @@ -6,6 +6,17 @@ + + + + + express + cart + + diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml index 70579f92..fee7da2b 100755 --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -19,12 +19,18 @@ - + + + name="checkout.paypal.checkout.script" + template="CheckoutCom_Magento2::script/paypal-script.phtml" > + + checkout + checkout + + diff --git a/view/frontend/layout/default.xml b/view/frontend/layout/default.xml index 5d705221..24d55bf8 100644 --- a/view/frontend/layout/default.xml +++ b/view/frontend/layout/default.xml @@ -25,6 +25,12 @@ CheckoutCom_Magento2/checkout/minicart/applepaybutton + + CheckoutCom_Magento2/js/view/minicart/paypalbutton + + CheckoutCom_Magento2/checkout/minicart/paypalbutton + + @@ -37,5 +43,18 @@ + + + + + + express + mini-cart + + + diff --git a/view/frontend/templates/cart/paypal.phtml b/view/frontend/templates/cart/paypal.phtml new file mode 100644 index 00000000..740b7fd5 --- /dev/null +++ b/view/frontend/templates/cart/paypal.phtml @@ -0,0 +1,27 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ +?> + +
+
+
diff --git a/view/frontend/templates/script/paypal-script.phtml b/view/frontend/templates/script/paypal-script.phtml index bb521c91..3eda8058 100644 --- a/view/frontend/templates/script/paypal-script.phtml +++ b/view/frontend/templates/script/paypal-script.phtml @@ -23,5 +23,5 @@ $partnerId = $block->getPartnerAttributionId(); $paypalMerchantId = $block->getPaypalMerchantId(); if ($clientId && $partnerId && $paypalMerchantId): ?> - + diff --git a/view/frontend/web/js/view/minicart/paypalbutton.js b/view/frontend/web/js/view/minicart/paypalbutton.js new file mode 100644 index 00000000..81fd8db9 --- /dev/null +++ b/view/frontend/web/js/view/minicart/paypalbutton.js @@ -0,0 +1,114 @@ +/** + * @author Agence Dn'D + * @copyright 2004-present Agence Dn'D + * @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @link https://www.dnd.fr/ + */ + +define([ + 'jquery', + 'ko', + 'uiComponent', + 'Magento_Customer/js/customer-data', + 'Magento_Customer/js/model/customer', + 'mage/url', +], function($, ko, Component, customerData, customer, Url) { + 'use strict'; + + return Component.extend({ + isVisible: ko.observable(false), + chkPayPalOrderid: null, + chkPayPalContextId: null, + + initialize: function() { + this._super(); + let cartData = customerData.get('cart'); + + this.isVisible(cartData()['summary_count'] > 0 + && ((cartData()['isGuestCheckoutAllowed']) || + (!cartData()['isGuestCheckoutAllowed'] && + customer.isLoggedIn())) + && cartData()['checkoutcom_paypal'] + && cartData()['checkoutcom_paypal']['express_minicart'] === '1' + && cartData()['checkoutcom_paypal']['active'] === '1', + ); + + if (this.isVisible) { + this.setCkcContext(); + } + + cartData.subscribe((updatedCart) => { + if (typeof window.checkoutConfig !== 'undefined' + && typeof window.checkoutConfig.quoteId === 'undefined') { + window.checkoutConfig = {...updatedCart['checkoutConfigProvider']}; + } + + this.isVisible(updatedCart['summary_count'] > 0 + && ((cartData()['isGuestCheckoutAllowed']) || + (!cartData()['isGuestCheckoutAllowed'] && + customer.isLoggedIn())) + && updatedCart['checkoutcom_paypal'] + && updatedCart['checkoutcom_paypal']['express_minicart'] === + '1' + && updatedCart['checkoutcom_paypal']['active'] === '1'); + + if (this.isVisible) { + this.setCkcContext(); + } + }); + }, + + setCkcContext: function() { + let self = this; + // THIS SCRIPT (Utilities.getUrl('paypal/context')) HAS TO BE CALLED ON THE 'createOrder' event of the paypal button + // The call must not be async and the 'createOrder' should return the order id + //Todo: proper way to init, the paypal button must be loaded when + // #paypal-button-container is on the dom + setTimeout(function() { + self.initPaypalButton(); + }, 1500); + }, + + // Has to be factored, it's used 3 times on the whole code + initPaypalButton: function() { + + let self = this; + + // Prepare Context + let containerSelector = '#minicart-paypal-button-container'; + let datas = {forceAuthorizeMode: true}; + + if($(containerSelector).length > 0) { + $.ajax( + { + type: 'POST', + url: Url.build('checkout_com/paypal/context'), + showLoader: false, + data: datas, + success: function(data) { + if (typeof data.content !== 'undefined') { + self.chkPayPalOrderid = data.content.partner_metadata.order_id; + self.chkPayPalContextId = data.content.id; + + // Init paypal button after getting context order id + paypal.Buttons({ + createOrder() { + return self.chkPayPalOrderid; + }, + onApprove: async function(data) { + alert('APPROVED MOZERFUCKER'); + }, + }).render(containerSelector); + + } + // Todo else message manager error + }, + error: function(request, status, error) { + // Todo message manager error + }, + }, + ); + } + }, + }); +}); diff --git a/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js b/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js new file mode 100644 index 00000000..69c78b4e --- /dev/null +++ b/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js @@ -0,0 +1,113 @@ +/** + * @author Agence Dn'D + * @copyright 2004-present Agence Dn'D + * @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + * @link https://www.dnd.fr/ + */ + +define([ + 'jquery', + 'ko', + 'uiComponent', + 'Magento_Customer/js/customer-data', + 'Magento_Customer/js/model/customer', + 'mage/url', +], function($, ko, Component, customerData, customer, Url) { + 'use strict'; + + return Component.extend({ + isVisible: ko.observable(false), + chkPayPalOrderid: null, + chkPayPalContextId: null, + + initialize: function() { + this._super(); + let cartData = customerData.get('cart'); + + this.isVisible(cartData()['summary_count'] > 0 + && ((cartData()['isGuestCheckoutAllowed']) || + (!cartData()['isGuestCheckoutAllowed'] && + customer.isLoggedIn())) + && cartData()['checkoutcom_paypal'] + && cartData()['checkoutcom_paypal']['express_cart'] === '1' + && cartData()['checkoutcom_paypal']['active'] === '1', + ); + + if (this.isVisible) { + this.setCkcContext(); + } + + cartData.subscribe((updatedCart) => { + if (typeof window.checkoutConfig !== 'undefined' + && typeof window.checkoutConfig.quoteId === 'undefined') { + window.checkoutConfig = {...updatedCart['checkoutConfigProvider']}; + } + + this.isVisible(updatedCart['summary_count'] > 0 + && ((cartData()['isGuestCheckoutAllowed']) || + (!cartData()['isGuestCheckoutAllowed'] && + customer.isLoggedIn())) + && updatedCart['checkoutcom_paypal'] + && updatedCart['checkoutcom_paypal']['express_cart'] === + '1' + && updatedCart['checkoutcom_paypal']['active'] === '1'); + + if (this.isVisible) { + this.setCkcContext(); + } + }); + }, + + setCkcContext: function() { + let self = this; + // THIS SCRIPT (Utilities.getUrl('paypal/context')) HAS TO BE CALLED ON THE 'createOrder' event of the paypal button + // The call must not be async and the 'createOrder' should return the order id + //Todo: proper way to init, the paypal button must be loaded when + // #paypal-button-container is on the dom + setTimeout(function() { + self.initPaypalButton(); + }, 1500); + }, + + // Has to be factored, it's used 3 times on the whole code + initPaypalButton: function() { + + let self = this; + + // Prepare Context + let containerSelector = '#cart-paypal-button-container'; + let datas = {forceAuthorizeMode: true}; + if($(containerSelector).length > 0) { + $.ajax( + { + type: 'POST', + url: Url.build('checkout_com/paypal/context'), + showLoader: false, + data: datas, + success: function(data) { + if (typeof data.content !== 'undefined') { + self.chkPayPalOrderid = data.content.partner_metadata.order_id; + self.chkPayPalContextId = data.content.id; + + // Init paypal button after getting context order id + paypal.Buttons({ + createOrder() { + return self.chkPayPalOrderid; + }, + onApprove: async function(data) { + alert('APPROVED MOZERFUCKER'); + }, + }).render(containerSelector); + + } + // Todo else message manager error + }, + error: function(request, status, error) { + // Todo message manager error + }, + }, + ); + } + }, + }); +}); diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js index a24af923..2912416f 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js @@ -42,7 +42,7 @@ define( buttonId: METHOD_ID + '_btn', redirectAfterPlaceOrder: false, chkPayPalOrderid: null, - chkPayPalContextId: null + chkPayPalContextId: null, }, /** @@ -55,46 +55,50 @@ define( //Todo: proper way to init, the paypal button must be loaded when // #paypal-button-container is on the dom - setTimeout(function(){ + setTimeout(function() { self.initPaypalButton(); - },1000); + }, 1000); }, initPaypalButton: function() { let self = this; + let containerSelector = '#paypal-button-container'; + let datas = {}; + // Prepare Context - $.ajax( - { - type: 'POST', - url: Utilities.getUrl('paypal/context'), - showLoader: true, - data: {}, - success: function(data) { - if (typeof data.content !== 'undefined') { - self.chkPayPalOrderid = data.content.partner_metadata.order_id; - self.chkPayPalContextId = data.content.id; - - // Init paypal button after getting context order id - paypal.Buttons({ - createOrder() { - return self.chkPayPalOrderid; - }, - onApprove: async function(data) { - self.placeOrder(); - }, - }).render('#paypal-button-container'); - - } - // Todo else message manager error - }, - error: function(request, status, error) { - // Todo message manager error + if ($(containerSelector).length > 0) { + $.ajax( + { + type: 'POST', + url: Utilities.getUrl('paypal/context'), + showLoader: true, + data: datas, + success: function(data) { + if (typeof data.content !== 'undefined') { + self.chkPayPalOrderid = data.content.partner_metadata.order_id; + self.chkPayPalContextId = data.content.id; + + // Init paypal button after getting context order id + paypal.Buttons({ + createOrder() { + return self.chkPayPalOrderid; + }, + onApprove: async function(data) { + self.placeOrder(); + }, + }).render(containerSelector); + + } + // Todo else message manager error + }, + error: function(request, status, error) { + // Todo message manager error + }, }, - }, - ); - + ); + } }, /** @@ -124,7 +128,8 @@ define( placeOrder: function() { FullScreenLoader.startLoader(); - if (Utilities.methodIsSelected(METHOD_ID) && this.chkPayPalContextId) { + if (Utilities.methodIsSelected(METHOD_ID) && + this.chkPayPalContextId) { let data = { methodId: METHOD_ID, contextPaymentId: this.chkPayPalContextId, diff --git a/view/frontend/web/template/checkout/minicart/paypalbutton.html b/view/frontend/web/template/checkout/minicart/paypalbutton.html new file mode 100644 index 00000000..2dbae2bc --- /dev/null +++ b/view/frontend/web/template/checkout/minicart/paypalbutton.html @@ -0,0 +1,16 @@ + + + +
+
+
+
+
+ From d5c18c8b0c69e8f45070a7a4256ea17b298d523d Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Thu, 29 Feb 2024 16:00:48 +0100 Subject: [PATCH 045/147] CHECMAG2003-206 - Introducing paypal express review --- .../Cart/{ApplePay.php => CheckoutConfig.php} | 2 +- Block/Paypal/Review/PaymentMethod.php | 47 +++++++ Block/Paypal/Review/PlaceOrderButton.php | 62 +++++++++ Block/Paypal/Review/ShippinAddress.php | 52 ++++++++ Block/Paypal/Review/ShippingMethod.php | 88 +++++++++++++ Controller/Paypal/Review.php | 118 +++++++++++++++++ Controller/Paypal/SaveExpressShipping.php | 124 ++++++++++++++++++ Model/Methods/PaypalMethod.php | 10 +- .../Service/PaymentContextRequestService.php | 94 ++++++++++++- .../layout/checkoutcom_paypal_review.xml | 72 ++++++++++ view/frontend/layout/default.xml | 2 +- .../paypal/review/payment-method.phtml | 17 +++ .../payment/paypal/review/place-order.phtml | 46 +++++++ .../paypal/review/shipping-address.phtml | 24 ++++ .../paypal/review/shipping-method.phtml | 45 +++++++ .../web/js/view/minicart/paypalbutton.js | 11 +- .../payment/cart/checkoutcom_paypal_cart.js | 9 +- .../checkoutcom_paypal_review.js | 66 ++++++++++ 18 files changed, 873 insertions(+), 16 deletions(-) rename Block/Cart/{ApplePay.php => CheckoutConfig.php} (98%) create mode 100644 Block/Paypal/Review/PaymentMethod.php create mode 100644 Block/Paypal/Review/PlaceOrderButton.php create mode 100644 Block/Paypal/Review/ShippinAddress.php create mode 100644 Block/Paypal/Review/ShippingMethod.php create mode 100644 Controller/Paypal/Review.php create mode 100644 Controller/Paypal/SaveExpressShipping.php create mode 100644 view/frontend/layout/checkoutcom_paypal_review.xml create mode 100644 view/frontend/templates/payment/paypal/review/payment-method.phtml create mode 100644 view/frontend/templates/payment/paypal/review/place-order.phtml create mode 100644 view/frontend/templates/payment/paypal/review/shipping-address.phtml create mode 100644 view/frontend/templates/payment/paypal/review/shipping-method.phtml create mode 100755 view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js diff --git a/Block/Cart/ApplePay.php b/Block/Cart/CheckoutConfig.php similarity index 98% rename from Block/Cart/ApplePay.php rename to Block/Cart/CheckoutConfig.php index 8b1ea55d..9f81182a 100644 --- a/Block/Cart/ApplePay.php +++ b/Block/Cart/CheckoutConfig.php @@ -33,7 +33,7 @@ use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\View\Element\Template\Context; -class ApplePay extends Onepage +class CheckoutConfig extends Onepage { private Cart $cart; private ConfigProvider $checkoutComConfigProvider; diff --git a/Block/Paypal/Review/PaymentMethod.php b/Block/Paypal/Review/PaymentMethod.php new file mode 100644 index 00000000..ca05ec31 --- /dev/null +++ b/Block/Paypal/Review/PaymentMethod.php @@ -0,0 +1,47 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +namespace CheckoutCom\Magento2\Block\Paypal\Review; + +use Magento\Checkout\Model\Session; +use Magento\Framework\View\Element\Template; + +class PaymentMethod extends Template +{ + protected Session $checkoutSession; + + public function __construct( + Template\Context $context, + Session $checkoutSession, + array $data = [] + ) { + parent::__construct($context, $data); + $this->checkoutSession = $checkoutSession; + } + + public function getEmail(): string + { + return (string)$this->checkoutSession->getQuote()->getCustomerEmail(); + } + + public function getPaymentMethod(): string + { + return (string)$this->checkoutSession->getQuote()->getPayment()->getMethodInstance()->getTitle(); + } +} diff --git a/Block/Paypal/Review/PlaceOrderButton.php b/Block/Paypal/Review/PlaceOrderButton.php new file mode 100644 index 00000000..42e2d29f --- /dev/null +++ b/Block/Paypal/Review/PlaceOrderButton.php @@ -0,0 +1,62 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +namespace CheckoutCom\Magento2\Block\Paypal\Review; + +use CheckoutCom\Magento2\Controller\Paypal\Review; +use Magento\Checkout\Model\Session; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\View\Element\Template; + +class PlaceOrderButton extends Template +{ + protected Session $checkoutSession; + protected RequestInterface $request; + + public function __construct( + Template\Context $context, + Session $checkoutSession, + RequestInterface $request, + array $data = [] + ) { + parent::__construct($context, $data); + $this->checkoutSession = $checkoutSession; + $this->request = $request; + } + + public function getEmail(): string + { + return (string)$this->checkoutSession->getQuote()->getCustomerEmail(); + } + + public function canPlaceOrder(): bool + { + return (bool)$this->checkoutSession->getQuote()->getShippingAddress()->getShippingMethod(); + } + + public function getPaymentMethod(): string + { + return (string)$this->checkoutSession->getQuote()->getPayment()->getMethodInstance()->getCode(); + } + + public function getContextId(): string + { + return (string)$this->request->getParam(Review::PAYMENT_CONTEXT_ID_PARAMETER); + } +} diff --git a/Block/Paypal/Review/ShippinAddress.php b/Block/Paypal/Review/ShippinAddress.php new file mode 100644 index 00000000..31636f3b --- /dev/null +++ b/Block/Paypal/Review/ShippinAddress.php @@ -0,0 +1,52 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +namespace CheckoutCom\Magento2\Block\Paypal\Review; + +use Magento\Checkout\Model\Session; +use Magento\Customer\Block\Address\Renderer\RendererInterface; +use Magento\Customer\Model\Address\Config as AddressConfig; +use Magento\Framework\Convert\ConvertArray; +use Magento\Framework\View\Element\Template; + +class ShippinAddress extends Template +{ + protected Session $checkoutSession; + protected AddressConfig $addressConfig; + + public function __construct( + Template\Context $context, + Session $checkoutSession, + AddressConfig $addressConfig, + array $data = [] + ) { + parent::__construct($context, $data); + $this->addressConfig = $addressConfig; + $this->checkoutSession = $checkoutSession; + } + + public function renderAddress(): string + { + /** @var RendererInterface $renderer */ + $renderer = $this->addressConfig->getFormatByCode('html')->getRenderer(); + $addressData = ConvertArray::toFlatArray($this->checkoutSession->getQuote()->getShippingAddress()->getData()); + + return $renderer->renderArray($addressData); + } +} diff --git a/Block/Paypal/Review/ShippingMethod.php b/Block/Paypal/Review/ShippingMethod.php new file mode 100644 index 00000000..be6b22fc --- /dev/null +++ b/Block/Paypal/Review/ShippingMethod.php @@ -0,0 +1,88 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +namespace CheckoutCom\Magento2\Block\Paypal\Review; + +use CheckoutCom\Magento2\Controller\Paypal\Review; +use Magento\Checkout\Model\Session; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Pricing\PriceCurrencyInterface; +use Magento\Framework\UrlInterface; +use Magento\Framework\View\Element\Template; +use Magento\Quote\Model\Quote\Address as QuoteAddresss; +use Magento\Quote\Model\Quote\Address\Rate as QuoteRate; + +class ShippingMethod extends Template +{ + protected Session $checkoutSession; + protected UrlInterface $url; + protected RequestInterface $request; + protected PriceCurrencyInterface $priceCurrency; + + public function __construct( + Template\Context $context, + Session $checkoutSession, + RequestInterface $request, + UrlInterface $url, + PriceCurrencyInterface $priceCurrency, + array $data = [] + ) { + parent::__construct($context, $data); + $this->checkoutSession = $checkoutSession; + $this->url = $url; + $this->request = $request; + $this->priceCurrency = $priceCurrency; + } + + public function getRates() + { + $shippingAddress = $this->getShippingAddress(); + $shippingAddress->collectShippingRates(); + + return $shippingAddress->getGroupedAllShippingRates(); + } + + public function getShippingMethodUpdateUrl(QuoteRate $carrierRate): string + { + return $this->url->getUrl('checkoutcom/paypal/saveExpressShipping', [ + Review::PAYMENT_CONTEXT_ID_PARAMETER => $this->request->getParam(Review::PAYMENT_CONTEXT_ID_PARAMETER), + Review::SHIPPING_METHOD_PARAMETER => $carrierRate->getCode() + ]); + } + + public function isCurrentShippingRate(QuoteRate $carrierRate): bool + { + return $carrierRate->getCode() === $this->getShippingAddress()->getShippingMethod(); + } + + public function getFormatedPrice($price) + { + return $this->priceCurrency->convertAndFormat( + $price, + false, + PriceCurrencyInterface::DEFAULT_PRECISION, + $this->checkoutSession->getQuote()->getStore() + ); + } + + private function getShippingAddress(): QuoteAddresss + { + return $this->checkoutSession->getQuote()->getShippingAddress(); + } +} diff --git a/Controller/Paypal/Review.php b/Controller/Paypal/Review.php new file mode 100644 index 00000000..f4b8695b --- /dev/null +++ b/Controller/Paypal/Review.php @@ -0,0 +1,118 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +declare(strict_types=1); + +namespace CheckoutCom\Magento2\Controller\Paypal; + +use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; +use Magento\Checkout\Model\Session; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Controller\Result\RedirectFactory; +use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Message\ManagerInterface; +use Magento\Framework\UrlInterface; +use \Magento\Quote\Api\Data\PaymentInterface; +use \Magento\Quote\Api\Data\PaymentInterfaceFactory; +use \CheckoutCom\Magento2\Model\Methods\PaypalMethod; + +class Review implements HttpGetActionInterface +{ + public const PAYMENT_CONTEXT_ID_PARAMETER = 'contextId'; + public const SHIPPING_METHOD_PARAMETER = 'method_code'; + + protected ResultFactory $resultFactory; + protected ManagerInterface $messageManager; + protected RequestInterface $request; + protected Session $checkoutSession; + protected PaymentContextRequestService $paymentContextRequestService; + protected RedirectFactory $redirectFactory; + protected UrlInterface $urlInterface; + protected PaymentInterfaceFactory $paymentInterfaceFactory; + protected PaypalMethod $paypalMethod; + + public function __construct( + ResultFactory $resultFactory, + ManagerInterface $messageManager, + RequestInterface $request, + Session $checkoutSession, + PaymentContextRequestService $paymentContextRequestService, + RedirectFactory $redirectFactory, + UrlInterface $urlInterface, + PaymentInterfaceFactory $paymentInterfaceFactory, + PaypalMethod $paypalMethod + ) { + $this->resultFactory = $resultFactory; + $this->request = $request; + $this->messageManager = $messageManager; + $this->checkoutSession = $checkoutSession; + $this->paymentContextRequestService = $paymentContextRequestService; + $this->redirectFactory = $redirectFactory; + $this->urlInterface = $urlInterface; + $this->paymentInterfaceFactory = $paymentInterfaceFactory; + $this->paypalMethod = $paypalMethod; + } + + /** + * @inheritDoc + */ + public function execute() + { + $resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE); + //$reviewBlock = $resultPage->getLayout()->getBlock('braintree.paypal.review'); + + $quote = $this->checkoutSession->getQuote(); + $redirectToCart = false; + $paymentContextId = $this->request->getParam(self::PAYMENT_CONTEXT_ID_PARAMETER); + + // Check quote + if (!$quote || ($quote && !$quote->getId())) { + $this->messageManager->addErrorMessage(__('Your Cart is empty')); + $redirectToCart = true; + } + + // Check if context is given + if (!$redirectToCart && !$paymentContextId) { + $this->messageManager->addErrorMessage(__('We cannot find your payment informations, please try again')); + $redirectToCart = true; + } + + // Check if context exists + if (!$redirectToCart) { + /** @var PaymentInterface $paymentMethod */ + $paymentMethod = $this->paymentInterfaceFactory->create(); + $paymentMethod->setMethod($this->paypalMethod->getCode()); + + $contextDatas = $this->paymentContextRequestService->getPaymentContextById($paymentContextId, (int)$quote->getStoreId(), true,$paymentMethod); + + if (empty($contextDatas)) { + $this->messageManager->addErrorMessage(__('We cannot find your payment informations, please try again')); + $redirectToCart = true; + } + } + + if ($redirectToCart) { + return $this->redirectFactory->create()->setUrl($this->urlInterface->getUrl('checkout/cart')); + } + + /*$reviewBlock->setQuote($quote); + $reviewBlock->getChildBlock('shipping_method')->setData('quote', $quote);*/ + + return $resultPage; + } +} diff --git a/Controller/Paypal/SaveExpressShipping.php b/Controller/Paypal/SaveExpressShipping.php new file mode 100644 index 00000000..42adad79 --- /dev/null +++ b/Controller/Paypal/SaveExpressShipping.php @@ -0,0 +1,124 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +declare(strict_types=1); + +namespace CheckoutCom\Magento2\Controller\Paypal; + +use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; +use Magento\Checkout\Model\Session; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Controller\Result\RedirectFactory; +use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Message\ManagerInterface; +use Magento\Framework\UrlInterface; +use Magento\Quote\Api\CartRepositoryInterface; + +class SaveExpressShipping implements HttpGetActionInterface +{ + protected ResultFactory $resultFactory; + protected ManagerInterface $messageManager; + protected RequestInterface $request; + protected Session $checkoutSession; + protected PaymentContextRequestService $paymentContextRequestService; + protected RedirectFactory $redirectFactory; + protected UrlInterface $urlInterface; + protected CartRepositoryInterface $cartRepository; + + public function __construct( + ResultFactory $resultFactory, + ManagerInterface $messageManager, + RequestInterface $request, + Session $checkoutSession, + PaymentContextRequestService $paymentContextRequestService, + RedirectFactory $redirectFactory, + UrlInterface $urlInterface, + CartRepositoryInterface $cartRepository + ) { + $this->resultFactory = $resultFactory; + $this->request = $request; + $this->messageManager = $messageManager; + $this->checkoutSession = $checkoutSession; + $this->paymentContextRequestService = $paymentContextRequestService; + $this->redirectFactory = $redirectFactory; + $this->urlInterface = $urlInterface; + $this->cartRepository = $cartRepository; + } + + /** + * @inheritDoc + */ + public function execute() + { + $quote = $this->checkoutSession->getQuote(); + $redirectToCart = false; + $paymentContextId = $this->request->getParam(Review::PAYMENT_CONTEXT_ID_PARAMETER); + $methodCode = $this->request->getParam(Review::SHIPPING_METHOD_PARAMETER); + + // Check quote + if (!$quote || ($quote && !$quote->getId())) { + $this->messageManager->addErrorMessage(__('Your Cart is empty')); + $redirectToCart = true; + } + + // Check if method is given + if (!$quote || ($quote && !$quote->getId())) { + $this->messageManager->addErrorMessage(__('Your Cart is empty')); + $redirectToCart = true; + } + + // Check if context is given + if (!$redirectToCart && !$paymentContextId) { + $this->messageManager->addErrorMessage(__('We cannot find your payment informations, please try again')); + $redirectToCart = true; + } + + // Check if context exists + if (!$redirectToCart) { + $contextDatas = $this->paymentContextRequestService->getPaymentContextById($paymentContextId, (int)$quote->getStoreId(), false); + + if (empty($contextDatas)) { + $this->messageManager->addErrorMessage(__('We cannot find your payment informations, please try again')); + $redirectToCart = true; + } + } + + if ($redirectToCart) { + return $this->redirectFactory->create()->setUrl($this->urlInterface->getUrl('checkout/cart')); + } + + // Save Shipping address + try { + $shippingAddress = $quote->getShippingAddress(); + $shippingAddress->setShippingMethod($methodCode)->setCollectShippingRates(true); + $cartExtension = $quote->getExtensionAttributes(); + if ($cartExtension && $cartExtension->getShippingAssignments()) { + $cartExtension->getShippingAssignments()[0] + ->getShipping() + ->setMethod($methodCode); + } + $quote->collectTotals(); + + $this->cartRepository->save($quote); + } catch (Exception $e) { + $this->messageManager->addErrorMessage(__($e->getMessage())); + } + + return $this->redirectFactory->create()->setRefererUrl(); + } +} diff --git a/Model/Methods/PaypalMethod.php b/Model/Methods/PaypalMethod.php index 445779da..46e7f036 100755 --- a/Model/Methods/PaypalMethod.php +++ b/Model/Methods/PaypalMethod.php @@ -27,6 +27,7 @@ use CheckoutCom\Magento2\Helper\Logger as LoggerHelper; use CheckoutCom\Magento2\Helper\Utilities; use CheckoutCom\Magento2\Model\Service\ApiHandlerService; +use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; use CheckoutCom\Magento2\Model\Service\QuoteHandlerService; use Magento\Backend\Model\Auth\Session; use Magento\Directory\Helper\Data as DirectoryHelper; @@ -161,6 +162,8 @@ class PaypalMethod extends AbstractMethod */ private $backendAuthSession; + private PaymentContextRequestService $contextService; + /** * GooglePayMethod constructor * @@ -203,6 +206,7 @@ public function __construct( DirectoryHelper $directoryHelper, DataObjectFactory $dataObjectFactory, Json $json, + PaymentContextRequestService $contextService, AbstractResource $resource = null, AbstractDb $resourceCollection = null, array $data = [] @@ -231,6 +235,7 @@ public function __construct( $this->ckoLogger = $ckoLogger; $this->backendAuthSession = $backendAuthSession; $this->json = $json; + $this->contextService = $contextService; } /** @@ -265,8 +270,9 @@ public function sendPaymentRequest(array $data, float $amount, string $currency, } // Set parameters - $payment->capture = $this->config->needsAutoCapture(); - $payment->amount = $this->utilities->formatDecimals($amount * 100); + $request->capture = $this->config->needsAutoCapture(); + $request->amount = $this->utilities->formatDecimals($amount * 100); + $request->items = $this->contextService->getRequestItems($quote); $request->payment_context_id = $data['contextPaymentId']; $request->processing_channel_id = $this->config->getValue('channel_id'); diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index ddf8bc90..96a2be9a 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -27,9 +27,14 @@ use CheckoutCom\Magento2\Gateway\Config\Config; use CheckoutCom\Magento2\Helper\Logger as MagentoLoggerHelper; use CheckoutCom\Magento2\Helper\Utilities; +use Exception; use Magento\Checkout\Model\Session; use Magento\Framework\UrlInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\AddressInterface; +use Magento\Quote\Api\Data\AddressInterfaceFactory; use Magento\Quote\Api\Data\CartInterface; +use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Model\Quote; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; @@ -43,6 +48,8 @@ class PaymentContextRequestService protected UrlInterface $urlBuilder; protected MagentoLoggerHelper $ckoLogger; protected Utilities $utilities; + protected AddressInterfaceFactory $addressInterfaceFactory; + protected CartRepositoryInterface $cartRepository; public function __construct( StoreManagerInterface $storeManager, @@ -52,7 +59,9 @@ public function __construct( UrlInterface $urlBuilder, ApiHandlerService $apiHandlerService, MagentoLoggerHelper $ckoLogger, - Utilities $utilities + Utilities $utilities, + AddressInterfaceFactory $addressInterfaceFactory, + CartRepositoryInterface $cartRepository ) { $this->storeManager = $storeManager; $this->apiHandlerService = $apiHandler; @@ -61,6 +70,8 @@ public function __construct( $this->urlBuilder = $urlBuilder; $this->ckoLogger = $ckoLogger; $this->utilities = $utilities; + $this->addressInterfaceFactory = $addressInterfaceFactory; + $this->cartRepository = $cartRepository; } public function makePaymentContextRequests( @@ -86,6 +97,69 @@ public function makePaymentContextRequests( ->createPaymentContexts($request); } + public function getPaymentContextById(string $paymentContextId, int $storeId, ?bool $refreshQuote = false, ?PaymentInterface $paymentMethod = null): array + { + $storeCode = $this->storeManager->getStore($storeId)->getCode(); + $api = $this->apiHandlerService->init($storeCode, ScopeInterface::SCOPE_STORE); + try { + $contextDatas = $api->getCheckoutApi()->getPaymentContextsClient()->getPaymentContextDetails($paymentContextId); + if ($refreshQuote) { + $this->refreshQuoteWithPaymentContext($contextDatas, $paymentMethod); + } + + return $contextDatas; + } catch (Exception $e) { + return []; + } + } + + public function refreshQuoteWithPaymentContext(array $contextDatas, ?PaymentInterface $paymentMethod = null): void + { + if (empty($contextDatas)) { + return; + } + + $quote = $this->getQuote(); + + $paymentRequestsDatas = $contextDatas['payment_request']; + $splittedName = explode(' ', $paymentRequestsDatas['customer']['name'], 2); + $lastNameIndex = count($splittedName) === 2 ? 1 : 0; + $quote->setCustomerFirstname($splittedName[0]); + $quote->setCustomerLastname($splittedName[1]); + $quote->setCustomerEmail($paymentRequestsDatas['customer']['email']); + + /** @var AddressInterface $quoteAddress */ + $quoteAddress = $this->addressInterfaceFactory->create(); + $shippingAddressRequesDatas = $paymentRequestsDatas['shipping']['address']; + $splittedName = explode(' ', $paymentRequestsDatas['shipping']['first_name'], 2); + $lastNameIndex = count($splittedName) === 2 ? 1 : 0; + $quoteAddress->setFirstname($splittedName[0]); + $quoteAddress->setLastname($splittedName[1]); + + $quoteAddress->setCity($shippingAddressRequesDatas['city']); + $quoteAddress->setCountryId($shippingAddressRequesDatas['country']); + $quoteAddress->setPostcode($shippingAddressRequesDatas['zip']); + $quoteAddress->setTelephone('0000000000'); + $streets = []; + $i = 1; + while ($i < 4) { + if (!empty($shippingAddressRequesDatas['address_line' . $i])) { + $streets[] = $shippingAddressRequesDatas['address_line' . $i]; + } + $i++; + } + $quoteAddress->setStreet($streets); + + // Set Payment method if given + if ($paymentMethod) { + $quote->setPayment($paymentMethod); + } + + //Assign addresse and save quote + $quote->setBillingAddress($quoteAddress)->setShippingAddress($quoteAddress); + $this->cartRepository->save($quote); + } + private function getContextRequest( Quote | CartInterface $quote, string $sourceType, @@ -114,6 +188,17 @@ private function getContextRequest( $request->source = new AbstractRequestSource($sourceType); // Items + $request->items = $this->getRequestItems($quote); + + // Urls + $request->success_url = $this->urlBuilder->getUrl('checkout/onepage/success'); + $request->failure_url = $this->urlBuilder->getUrl('checkout/onepage/failure'); + + return $request; + } + + public function getRequestItems(Quote | CartInterface $quote): array + { $items = []; /** @var Quote\Item $item */ foreach ($quote->getAllItems() as $item) { @@ -137,13 +222,8 @@ private function getContextRequest( $items[] = $product; } - $request->items = $items; - // Urls - $request->success_url = $this->urlBuilder->getUrl('checkout/onepage/success'); - $request->failure_url = $this->urlBuilder->getUrl('checkout/onepage/failure'); - - return $request; + return $items; } private function getQuote(): Quote | CartInterface diff --git a/view/frontend/layout/checkoutcom_paypal_review.xml b/view/frontend/layout/checkoutcom_paypal_review.xml new file mode 100644 index 00000000..526e820e --- /dev/null +++ b/view/frontend/layout/checkoutcom_paypal_review.xml @@ -0,0 +1,72 @@ + + + + + Review Order + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/view/frontend/layout/default.xml b/view/frontend/layout/default.xml index 24d55bf8..3e6dd44c 100644 --- a/view/frontend/layout/default.xml +++ b/view/frontend/layout/default.xml @@ -41,7 +41,7 @@
- + diff --git a/view/frontend/templates/payment/paypal/review/payment-method.phtml b/view/frontend/templates/payment/paypal/review/payment-method.phtml new file mode 100644 index 00000000..e6f50e44 --- /dev/null +++ b/view/frontend/templates/payment/paypal/review/payment-method.phtml @@ -0,0 +1,17 @@ + +
+ escapeHtml(__('Payment Method')) ?> +
+ escapeHtml($block->getPaymentMethod()); ?>
+ escapeHtml($block->getEmail()); ?> +
+
diff --git a/view/frontend/templates/payment/paypal/review/place-order.phtml b/view/frontend/templates/payment/paypal/review/place-order.phtml new file mode 100644 index 00000000..be2eef80 --- /dev/null +++ b/view/frontend/templates/payment/paypal/review/place-order.phtml @@ -0,0 +1,46 @@ + + +
+
+
+
+ getChildHtml('agreements') ?> +
+
+ +
+ + escapeHtml(__('Submitting order information...')) ?> + + renderStyleAsTag("display: none;", 'span#review-please-wait') ?> +
+
+ diff --git a/view/frontend/templates/payment/paypal/review/shipping-address.phtml b/view/frontend/templates/payment/paypal/review/shipping-address.phtml new file mode 100644 index 00000000..c0c0314f --- /dev/null +++ b/view/frontend/templates/payment/paypal/review/shipping-address.phtml @@ -0,0 +1,24 @@ + + +
+ + escapeHtml(__('Shipping Address')) ?> + +
+
+ escapeHtml( + $block->renderAddress(), + ['br'] + ); ?> +
+
+
diff --git a/view/frontend/templates/payment/paypal/review/shipping-method.phtml b/view/frontend/templates/payment/paypal/review/shipping-method.phtml new file mode 100644 index 00000000..8a6b769e --- /dev/null +++ b/view/frontend/templates/payment/paypal/review/shipping-method.phtml @@ -0,0 +1,45 @@ +getRates(); +?> +
+ escapeHtml(__('Shipping Method')) ?> +
+ + + + isCurrentShippingRate($carrierMethod); ?> + + + + + + escapeHtml($carrierMethod->getCarrierTitle()) ?> - + escapeHtml($carrierMethod->getMethodTitle()) ?> - + getFormatedPrice($carrierMethod->getPrice()) ?> + + + + + + + + +

+ escapeHtml( + __( + 'Sorry, no quotes are available for this order right now.' + ) + ); ?> +

+ +
+
diff --git a/view/frontend/web/js/view/minicart/paypalbutton.js b/view/frontend/web/js/view/minicart/paypalbutton.js index 81fd8db9..d9ccb2ea 100644 --- a/view/frontend/web/js/view/minicart/paypalbutton.js +++ b/view/frontend/web/js/view/minicart/paypalbutton.js @@ -12,7 +12,8 @@ define([ 'Magento_Customer/js/customer-data', 'Magento_Customer/js/model/customer', 'mage/url', -], function($, ko, Component, customerData, customer, Url) { + 'Magento_Checkout/js/model/full-screen-loader', +], function($, ko, Component, customerData, customer, Url, FullScreenLoader) { 'use strict'; return Component.extend({ @@ -78,7 +79,7 @@ define([ let containerSelector = '#minicart-paypal-button-container'; let datas = {forceAuthorizeMode: true}; - if($(containerSelector).length > 0) { + if ($(containerSelector).length > 0) { $.ajax( { type: 'POST', @@ -96,7 +97,11 @@ define([ return self.chkPayPalOrderid; }, onApprove: async function(data) { - alert('APPROVED MOZERFUCKER'); + // Redirect on paypal reviex page (express checkout) + FullScreenLoader.startLoader(); + window.location.href = Url.build( + 'checkout_com/paypal/review/contextId/' + + self.chkPayPalContextId); }, }).render(containerSelector); diff --git a/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js b/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js index 69c78b4e..d8ce725c 100644 --- a/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js +++ b/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js @@ -12,7 +12,8 @@ define([ 'Magento_Customer/js/customer-data', 'Magento_Customer/js/model/customer', 'mage/url', -], function($, ko, Component, customerData, customer, Url) { + 'Magento_Checkout/js/model/full-screen-loader', +], function($, ko, Component, customerData, customer, Url,FullScreenLoader) { 'use strict'; return Component.extend({ @@ -95,7 +96,11 @@ define([ return self.chkPayPalOrderid; }, onApprove: async function(data) { - alert('APPROVED MOZERFUCKER'); + // Redirect on paypal reviex page (express checkout) + FullScreenLoader.startLoader(); + window.location.href = Url.build( + 'checkout_com/paypal/review/contextId/' + + self.chkPayPalContextId); }, }).render(containerSelector); diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js new file mode 100755 index 00000000..f9e4b5c5 --- /dev/null +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js @@ -0,0 +1,66 @@ +/** + * Checkout.com + * Authorized and regulated as an electronic money institution + * by the UK Financial Conduct Authority (FCA) under number 900816. + * + * PHP version 7 + * + * @category Magento2 + * @package Checkout.com + * @author Platforms Development Team + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +define( + [ + 'jquery', + 'CheckoutCom_Magento2/js/view/payment/utilities', + 'Magento_Checkout/js/model/full-screen-loader', + ], + function($, Utilities, FullScreenLoader) { + 'use strict'; + + $.widget('checkoutcom.paypalreviewplaceorder', { + + _create: function(config, element) { + let self = this; + + $(this.options.buttonSelector).click(function() { + self.placeOrder(); + }); + }, + + /** + * @return {void} + */ + placeOrder: function() { + FullScreenLoader.startLoader(); + let self = this; + + if (this.options.chkPayPalContextId) { + $(this.options.buttonSelector).attr('disabled', 'disabled'); + setTimeout(function(){ + $(self.options.buttonSelector).removeAttr('disabled'); + },1500); + + let data = { + methodId: this.options.methodId, + contextPaymentId: this.options.chkPayPalContextId, + }; + + // Place the order + Utilities.placeOrder( + data, + this.options.methodId, + true + ); + Utilities.cleanCustomerShippingAddress(); + + FullScreenLoader.stopLoader(); + } + }, + }); + return $.checkoutcom.paypalreviewplaceorder; + }); From c68b885fe3694331b5fdbbefdbe0ac5aa0f12c4e Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Fri, 1 Mar 2024 12:09:08 +0100 Subject: [PATCH 046/147] CHECMAG2003-206 - Managing address edit + display items on review page --- Block/Paypal/Review/PaymentMethod.php | 6 +- Block/Paypal/Review/PlaceOrderButton.php | 6 +- Block/Paypal/Review/ShippinAddress.php | 52 ------ Block/Paypal/Review/ShippingAddress.php | 155 ++++++++++++++++++ Block/Paypal/Review/ShippingMethod.php | 2 +- Controller/Paypal/Review.php | 8 +- .../{SaveExpressShipping.php => SaveData.php} | 43 ++--- .../Paypal/SaveExpressShippingAddress.php | 83 ++++++++++ .../Paypal/SaveExpressShippingMethod.php | 65 ++++++++ .../Service/PaymentContextRequestService.php | 19 ++- etc/adminhtml/system.xml | 6 + etc/config.xml | 1 + .../layout/checkoutcom_paypal_review.xml | 40 ++--- .../payment/paypal/review/details.phtml | 29 ++++ .../paypal/review/shipping-address.phtml | 111 +++++++++++++ 15 files changed, 523 insertions(+), 103 deletions(-) delete mode 100644 Block/Paypal/Review/ShippinAddress.php create mode 100644 Block/Paypal/Review/ShippingAddress.php rename Controller/Paypal/{SaveExpressShipping.php => SaveData.php} (82%) create mode 100644 Controller/Paypal/SaveExpressShippingAddress.php create mode 100644 Controller/Paypal/SaveExpressShippingMethod.php create mode 100644 view/frontend/templates/payment/paypal/review/details.phtml diff --git a/Block/Paypal/Review/PaymentMethod.php b/Block/Paypal/Review/PaymentMethod.php index ca05ec31..9e026697 100644 --- a/Block/Paypal/Review/PaymentMethod.php +++ b/Block/Paypal/Review/PaymentMethod.php @@ -19,20 +19,24 @@ namespace CheckoutCom\Magento2\Block\Paypal\Review; +use CheckoutCom\Magento2\Model\Methods\PaypalMethod; use Magento\Checkout\Model\Session; use Magento\Framework\View\Element\Template; class PaymentMethod extends Template { protected Session $checkoutSession; + protected PaypalMethod $paypalMethod; public function __construct( Template\Context $context, Session $checkoutSession, + PaypalMethod $paypalMethod, array $data = [] ) { parent::__construct($context, $data); $this->checkoutSession = $checkoutSession; + $this->paypalMethod = $paypalMethod; } public function getEmail(): string @@ -42,6 +46,6 @@ public function getEmail(): string public function getPaymentMethod(): string { - return (string)$this->checkoutSession->getQuote()->getPayment()->getMethodInstance()->getTitle(); + return (string)$this->paypalMethod->getTitle(); } } diff --git a/Block/Paypal/Review/PlaceOrderButton.php b/Block/Paypal/Review/PlaceOrderButton.php index 42e2d29f..b8fb1cbc 100644 --- a/Block/Paypal/Review/PlaceOrderButton.php +++ b/Block/Paypal/Review/PlaceOrderButton.php @@ -20,6 +20,7 @@ namespace CheckoutCom\Magento2\Block\Paypal\Review; use CheckoutCom\Magento2\Controller\Paypal\Review; +use CheckoutCom\Magento2\Model\Methods\PaypalMethod; use Magento\Checkout\Model\Session; use Magento\Framework\App\RequestInterface; use Magento\Framework\View\Element\Template; @@ -28,16 +29,19 @@ class PlaceOrderButton extends Template { protected Session $checkoutSession; protected RequestInterface $request; + protected PaypalMethod $paypalMethod; public function __construct( Template\Context $context, Session $checkoutSession, RequestInterface $request, + PaypalMethod $paypalMethod, array $data = [] ) { parent::__construct($context, $data); $this->checkoutSession = $checkoutSession; $this->request = $request; + $this->paypalMethod = $paypalMethod; } public function getEmail(): string @@ -52,7 +56,7 @@ public function canPlaceOrder(): bool public function getPaymentMethod(): string { - return (string)$this->checkoutSession->getQuote()->getPayment()->getMethodInstance()->getCode(); + return (string)$this->paypalMethod->getCode(); } public function getContextId(): string diff --git a/Block/Paypal/Review/ShippinAddress.php b/Block/Paypal/Review/ShippinAddress.php deleted file mode 100644 index 31636f3b..00000000 --- a/Block/Paypal/Review/ShippinAddress.php +++ /dev/null @@ -1,52 +0,0 @@ - - * @copyright 2010-present Checkout.com - * @license https://opensource.org/licenses/mit-license.html MIT License - * @link https://docs.checkout.com/ - */ - -namespace CheckoutCom\Magento2\Block\Paypal\Review; - -use Magento\Checkout\Model\Session; -use Magento\Customer\Block\Address\Renderer\RendererInterface; -use Magento\Customer\Model\Address\Config as AddressConfig; -use Magento\Framework\Convert\ConvertArray; -use Magento\Framework\View\Element\Template; - -class ShippinAddress extends Template -{ - protected Session $checkoutSession; - protected AddressConfig $addressConfig; - - public function __construct( - Template\Context $context, - Session $checkoutSession, - AddressConfig $addressConfig, - array $data = [] - ) { - parent::__construct($context, $data); - $this->addressConfig = $addressConfig; - $this->checkoutSession = $checkoutSession; - } - - public function renderAddress(): string - { - /** @var RendererInterface $renderer */ - $renderer = $this->addressConfig->getFormatByCode('html')->getRenderer(); - $addressData = ConvertArray::toFlatArray($this->checkoutSession->getQuote()->getShippingAddress()->getData()); - - return $renderer->renderArray($addressData); - } -} diff --git a/Block/Paypal/Review/ShippingAddress.php b/Block/Paypal/Review/ShippingAddress.php new file mode 100644 index 00000000..6a80926e --- /dev/null +++ b/Block/Paypal/Review/ShippingAddress.php @@ -0,0 +1,155 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +namespace CheckoutCom\Magento2\Block\Paypal\Review; + +use CheckoutCom\Magento2\Controller\Paypal\Review; +use Magento\Checkout\Model\Session as CheckoutSession; +use Magento\Customer\Api\AddressMetadataInterface; +use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\Customer\Api\Data\AddressInterfaceFactory; +use Magento\Customer\Api\Data\CustomerInterfaceFactory; +use Magento\Customer\Block\Address\Edit as CustomerAddressEdit; +use Magento\Customer\Helper\Address; +use Magento\Customer\Helper\Session\CurrentCustomer; +use Magento\Customer\Model\Address\Config as AddressConfig; +use Magento\Customer\Model\Session; +use Magento\Directory\Helper\Data; +use Magento\Directory\Model\ResourceModel\Country\CollectionFactory as CountryCollectionFactory; +use Magento\Directory\Model\ResourceModel\Region\CollectionFactory; +use Magento\Framework\Api\DataObjectHelper; +use Magento\Framework\App\Cache\Type\Config; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Json\EncoderInterface; +use Magento\Framework\Phrase; +use Magento\Framework\UrlInterface; +use Magento\Framework\View\Element\Template\Context; + +class ShippingAddress extends CustomerAddressEdit +{ + protected CheckoutSession $checkoutSession; + protected AddressConfig $addressConfig; + protected CustomerInterfaceFactory $customerInterfaceFactory; + protected UrlInterface $url; + protected RequestInterface $request; + + public function __construct( + Context $context, + Data $directoryHelper, + EncoderInterface $jsonEncoder, + Config $configCacheType, + CollectionFactory $regionCollectionFactory, + CountryCollectionFactory $countryCollectionFactory, + Session $customerSession, + AddressRepositoryInterface $addressRepository, + AddressInterfaceFactory $addressDataFactory, + CurrentCustomer $currentCustomer, + DataObjectHelper $dataObjectHelper, + CheckoutSession $checkoutSession, + AddressConfig $addressConfig, + CustomerInterfaceFactory $customerInterfaceFactory, + UrlInterface $url, + RequestInterface $request, + array $data = [], + AddressMetadataInterface $addressMetadata = null, + Address $addressHelper = null + ) { + parent::__construct( + $context, + $directoryHelper, + $jsonEncoder, + $configCacheType, + $regionCollectionFactory, + $countryCollectionFactory, + $customerSession, + $addressRepository, + $addressDataFactory, + $currentCustomer, + $dataObjectHelper, + $data, + $addressMetadata, + $addressHelper + ); + + $this->addressConfig = $addressConfig; + $this->checkoutSession = $checkoutSession; + $this->customerInterfaceFactory = $customerInterfaceFactory; + $this->url = $url; + $this->request = $request; + + $this->_address = $this->checkoutSession->getQuote()->getShippingAddress(); + } + + public function getAddress() + { + return $this->checkoutSession->getQuote()->getShippingAddress(); + } + + public function getCustomer() + { + return $this->customerInterfaceFactory->create(); + } + + public function isDefaultBilling() + { + return false; + } + + public function isDefaultShipping() + { + return false; + } + + public function canSetAsDefaultBilling() + { + return false; + } + + public function canSetAsDefaultShipping() + { + return false; + } + + public function getCustomerAddressCount() + { + return 1; + } + + public function getRegion() + { + return (string)$this->getAddress()->getRegion(); + } + + public function getRegionId() + { + return $this->getAddress()->getRegionId() ?? 0; + } + + public function getTitle(): Phrase + { + return __('Review Order'); + } + + public function getSaveUrl() + { + return $this->url->getUrl('checkoutcom/paypal/saveExpressShippingAddress', [ + Review::PAYMENT_CONTEXT_ID_PARAMETER => $this->request->getParam(Review::PAYMENT_CONTEXT_ID_PARAMETER) + ]); + } +} diff --git a/Block/Paypal/Review/ShippingMethod.php b/Block/Paypal/Review/ShippingMethod.php index be6b22fc..a10a063b 100644 --- a/Block/Paypal/Review/ShippingMethod.php +++ b/Block/Paypal/Review/ShippingMethod.php @@ -60,7 +60,7 @@ public function getRates() public function getShippingMethodUpdateUrl(QuoteRate $carrierRate): string { - return $this->url->getUrl('checkoutcom/paypal/saveExpressShipping', [ + return $this->url->getUrl('checkoutcom/paypal/saveExpressShippingMethod', [ Review::PAYMENT_CONTEXT_ID_PARAMETER => $this->request->getParam(Review::PAYMENT_CONTEXT_ID_PARAMETER), Review::SHIPPING_METHOD_PARAMETER => $carrierRate->getCode() ]); diff --git a/Controller/Paypal/Review.php b/Controller/Paypal/Review.php index f4b8695b..d9230ab1 100644 --- a/Controller/Paypal/Review.php +++ b/Controller/Paypal/Review.php @@ -19,6 +19,7 @@ namespace CheckoutCom\Magento2\Controller\Paypal; +use CheckoutCom\Magento2\Model\Methods\PaypalMethod; use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; use Magento\Checkout\Model\Session; use Magento\Framework\App\Action\HttpGetActionInterface; @@ -27,9 +28,8 @@ use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Message\ManagerInterface; use Magento\Framework\UrlInterface; -use \Magento\Quote\Api\Data\PaymentInterface; -use \Magento\Quote\Api\Data\PaymentInterfaceFactory; -use \CheckoutCom\Magento2\Model\Methods\PaypalMethod; +use Magento\Quote\Api\Data\PaymentInterface; +use Magento\Quote\Api\Data\PaymentInterfaceFactory; class Review implements HttpGetActionInterface { @@ -98,7 +98,7 @@ public function execute() $paymentMethod = $this->paymentInterfaceFactory->create(); $paymentMethod->setMethod($this->paypalMethod->getCode()); - $contextDatas = $this->paymentContextRequestService->getPaymentContextById($paymentContextId, (int)$quote->getStoreId(), true,$paymentMethod); + $contextDatas = $this->paymentContextRequestService->getPaymentContextById($paymentContextId, (int)$quote->getStoreId(), true, $paymentMethod); if (empty($contextDatas)) { $this->messageManager->addErrorMessage(__('We cannot find your payment informations, please try again')); diff --git a/Controller/Paypal/SaveExpressShipping.php b/Controller/Paypal/SaveData.php similarity index 82% rename from Controller/Paypal/SaveExpressShipping.php rename to Controller/Paypal/SaveData.php index 42adad79..e7ed12fa 100644 --- a/Controller/Paypal/SaveExpressShipping.php +++ b/Controller/Paypal/SaveData.php @@ -21,15 +21,18 @@ use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; use Magento\Checkout\Model\Session; -use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\Result\RedirectFactory; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Message\ManagerInterface; use Magento\Framework\UrlInterface; use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\AddressInterfaceFactory; +use Magento\Quote\Api\Data\CartInterface; +use Magento\Quote\Model\Quote; +use \CheckoutCom\Magento2\Model\Methods\PaypalMethod; -class SaveExpressShipping implements HttpGetActionInterface +class SaveData { protected ResultFactory $resultFactory; protected ManagerInterface $messageManager; @@ -39,6 +42,8 @@ class SaveExpressShipping implements HttpGetActionInterface protected RedirectFactory $redirectFactory; protected UrlInterface $urlInterface; protected CartRepositoryInterface $cartRepository; + protected AddressInterfaceFactory $addressInterfaceFactory; + protected PaypalMethod $paypalMethod; public function __construct( ResultFactory $resultFactory, @@ -48,7 +53,9 @@ public function __construct( PaymentContextRequestService $paymentContextRequestService, RedirectFactory $redirectFactory, UrlInterface $urlInterface, - CartRepositoryInterface $cartRepository + CartRepositoryInterface $cartRepository, + AddressInterfaceFactory $addressInterfaceFactory, + PaypalMethod $paypalMethod ) { $this->resultFactory = $resultFactory; $this->request = $request; @@ -58,17 +65,16 @@ public function __construct( $this->redirectFactory = $redirectFactory; $this->urlInterface = $urlInterface; $this->cartRepository = $cartRepository; + $this->addressInterfaceFactory = $addressInterfaceFactory; + $this->paypalMethod = $paypalMethod; } - /** - * @inheritDoc - */ - public function execute() + protected function shouldRedirectToCart(): bool { $quote = $this->checkoutSession->getQuote(); $redirectToCart = false; + $paymentContextId = $this->request->getParam(Review::PAYMENT_CONTEXT_ID_PARAMETER); - $methodCode = $this->request->getParam(Review::SHIPPING_METHOD_PARAMETER); // Check quote if (!$quote || ($quote && !$quote->getId())) { @@ -76,12 +82,6 @@ public function execute() $redirectToCart = true; } - // Check if method is given - if (!$quote || ($quote && !$quote->getId())) { - $this->messageManager->addErrorMessage(__('Your Cart is empty')); - $redirectToCart = true; - } - // Check if context is given if (!$redirectToCart && !$paymentContextId) { $this->messageManager->addErrorMessage(__('We cannot find your payment informations, please try again')); @@ -98,11 +98,12 @@ public function execute() } } - if ($redirectToCart) { - return $this->redirectFactory->create()->setUrl($this->urlInterface->getUrl('checkout/cart')); - } + return $redirectToCart; + } - // Save Shipping address + protected function setShippingMethod(string $methodCode, CartInterface | Quote $quote): bool + { + // Save Shipping method try { $shippingAddress = $quote->getShippingAddress(); $shippingAddress->setShippingMethod($methodCode)->setCollectShippingRates(true); @@ -115,10 +116,12 @@ public function execute() $quote->collectTotals(); $this->cartRepository->save($quote); + + return true; } catch (Exception $e) { $this->messageManager->addErrorMessage(__($e->getMessage())); - } - return $this->redirectFactory->create()->setRefererUrl(); + return false; + } } } diff --git a/Controller/Paypal/SaveExpressShippingAddress.php b/Controller/Paypal/SaveExpressShippingAddress.php new file mode 100644 index 00000000..de34fe21 --- /dev/null +++ b/Controller/Paypal/SaveExpressShippingAddress.php @@ -0,0 +1,83 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +declare(strict_types=1); + +namespace CheckoutCom\Magento2\Controller\Paypal; + +use Magento\Customer\Api\Data\AddressInterface as CustomerAddressInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Quote\Api\Data\AddressInterface; + +class SaveExpressShippingAddress extends SaveData implements HttpPostActionInterface +{ + /** + * @inheritDoc + */ + public function execute() + { + $quote = $this->checkoutSession->getQuote(); + + $redirectToCart = $this->shouldRedirectToCart(); + + if ($redirectToCart) { + return $this->redirectFactory->create()->setUrl($this->urlInterface->getUrl('checkout/cart')); + } + + //Assign address and save quote + try { + $quoteAddress = $this->buildAddress(); + $quote->setBillingAddress($quoteAddress)->setShippingAddress($quoteAddress); + $this->cartRepository->save($quote); + + // Auto assign method + $shippingAddress = $quote->getShippingAddress(); + if ($this->paypalMethod->getConfigData('express_auto_method') && !$shippingAddress->getShippingMethod()) { + $shippingAddress->collectShippingRates(); + $rates = $shippingAddress->getGroupedAllShippingRates(); + if (!empty($rates)) { + foreach ($rates as $carrier) { + foreach ($carrier as $carrierMethod) { + $this->setShippingMethod($carrierMethod->getCode(), $quote); + break; + } + } + } + } + } catch (Exception $e) { + $this->messageManager->addErrorMessage(__('Unable to save Address: ' . $e->getMessage())); + } + + return $this->redirectFactory->create()->setRefererUrl(); + } + + public function buildAddress(): AddressInterface + { + $address = $this->addressInterfaceFactory->create(); + $address->setFirstname($this->request->getParam(CustomerAddressInterface::FIRSTNAME)); + $address->setLastName($this->request->getParam(CustomerAddressInterface::LASTNAME)); + $address->setCompany($this->request->getParam(CustomerAddressInterface::COMPANY)); + $address->setCountryId($this->request->getParam(CustomerAddressInterface::COUNTRY_ID)); + $address->setPostCode($this->request->getParam(CustomerAddressInterface::POSTCODE)); + $address->setRegionId($this->request->getParam(CustomerAddressInterface::REGION_ID)); + $address->setCity($this->request->getParam(CustomerAddressInterface::CITY)); + $address->setStreet($this->request->getParam(CustomerAddressInterface::STREET)); + $address->setTelephone($this->request->getParam(CustomerAddressInterface::TELEPHONE)); + + return $address; + } +} diff --git a/Controller/Paypal/SaveExpressShippingMethod.php b/Controller/Paypal/SaveExpressShippingMethod.php new file mode 100644 index 00000000..f4185785 --- /dev/null +++ b/Controller/Paypal/SaveExpressShippingMethod.php @@ -0,0 +1,65 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +declare(strict_types=1); + +namespace CheckoutCom\Magento2\Controller\Paypal; + +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; + +class SaveExpressShippingMethod extends SaveData implements HttpGetActionInterface +{ + /** + * @inheritDoc + */ + public function execute() + { + $quote = $this->checkoutSession->getQuote(); + + $redirectToCart = $this->shouldRedirectToCart(); + $methodCode = $this->request->getParam(Review::SHIPPING_METHOD_PARAMETER); + if (!$redirectToCart && !$methodCode) { + $this->messageManager->addErrorMessage(__('Missing shipping method')); + + return $this->redirectFactory->create()->setRefererUrl(); + } + + if ($redirectToCart) { + return $this->redirectFactory->create()->setUrl($this->urlInterface->getUrl('checkout/cart')); + } + + // Save Shipping address + try { + $shippingAddress = $quote->getShippingAddress(); + $shippingAddress->setShippingMethod($methodCode)->setCollectShippingRates(true); + $cartExtension = $quote->getExtensionAttributes(); + if ($cartExtension && $cartExtension->getShippingAssignments()) { + $cartExtension->getShippingAssignments()[0] + ->getShipping() + ->setMethod($methodCode); + } + $quote->collectTotals(); + + $this->cartRepository->save($quote); + } catch (Exception $e) { + $this->messageManager->addErrorMessage(__($e->getMessage())); + } + + return $this->redirectFactory->create()->setRefererUrl(); + } +} diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index 96a2be9a..b0e4cf15 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -29,6 +29,7 @@ use CheckoutCom\Magento2\Helper\Utilities; use Exception; use Magento\Checkout\Model\Session; +use Magento\Directory\Model\ResourceModel\Region\CollectionFactory as RegionCollectionFactory; use Magento\Framework\UrlInterface; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\AddressInterface; @@ -50,6 +51,7 @@ class PaymentContextRequestService protected Utilities $utilities; protected AddressInterfaceFactory $addressInterfaceFactory; protected CartRepositoryInterface $cartRepository; + protected RegionCollectionFactory $regionCollectionFactory; public function __construct( StoreManagerInterface $storeManager, @@ -61,6 +63,7 @@ public function __construct( MagentoLoggerHelper $ckoLogger, Utilities $utilities, AddressInterfaceFactory $addressInterfaceFactory, + RegionCollectionFactory $regionCollectionFactory, CartRepositoryInterface $cartRepository ) { $this->storeManager = $storeManager; @@ -72,6 +75,7 @@ public function __construct( $this->utilities = $utilities; $this->addressInterfaceFactory = $addressInterfaceFactory; $this->cartRepository = $cartRepository; + $this->regionCollectionFactory = $regionCollectionFactory; } public function makePaymentContextRequests( @@ -81,7 +85,7 @@ public function makePaymentContextRequests( ?string $authorizationType = null ): array { $quote = $this->getQuote(); - if (!$quote->getId()) { + if (!$quote->getId() || ($quote->getId() && !$quote->getItemsQty())) { return []; } @@ -139,7 +143,7 @@ public function refreshQuoteWithPaymentContext(array $contextDatas, ?PaymentInte $quoteAddress->setCity($shippingAddressRequesDatas['city']); $quoteAddress->setCountryId($shippingAddressRequesDatas['country']); $quoteAddress->setPostcode($shippingAddressRequesDatas['zip']); - $quoteAddress->setTelephone('0000000000'); + $streets = []; $i = 1; while ($i < 4) { @@ -150,6 +154,17 @@ public function refreshQuoteWithPaymentContext(array $contextDatas, ?PaymentInte } $quoteAddress->setStreet($streets); + // Manage region + $stateName = $shippingAddressRequesDatas['state']; + if ($stateName) { + $regionCollection = $this->regionCollectionFactory->create(); + $region = $regionCollection->addFieldToFilter('default_name', ['eq' => $stateName])->getFirstItem(); + if ($region->getId()) { + $quoteAddress->setRegionCode($region->getCode()); + $quoteAddress->setRegionId($region->getRegionId()); + } + } + // Set Payment method if given if ($paymentMethod) { $quote->setPayment($paymentMethod); diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 564bd452..bbee0d68 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -681,6 +681,12 @@ payment/checkoutcom_paypal/express_minicart + + + Magento\Config\Model\Config\Source\Yesno + payment/checkoutcom_paypal/express_auto_method + + validate-number diff --git a/etc/config.xml b/etc/config.xml index 5b9efd0c..1e8822d2 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -180,6 +180,7 @@ 0 0 0 + 1 ASLqLf4pnWuBshW8Qh8z_DRUbIv2Cgs3Ft8aauLm9Z-MO9FZx1INSo38nW109o_Xvu88P3tly88XbJMR CheckoutLtd_PSP 1 diff --git a/view/frontend/layout/checkoutcom_paypal_review.xml b/view/frontend/layout/checkoutcom_paypal_review.xml index 526e820e..07872c84 100644 --- a/view/frontend/layout/checkoutcom_paypal_review.xml +++ b/view/frontend/layout/checkoutcom_paypal_review.xml @@ -14,34 +14,46 @@ */ --> + Review Order - - + + + + Magento\Customer\Block\DataProviders\AddressAttributeData + Magento\Customer\Block\DataProviders\PostCodesPatternsAttributeData + Magento\Customer\ViewModel\Address + Magento\Customer\ViewModel\Address\RegionProvider + + - - + + + + + @@ -50,23 +62,7 @@ as="agreements" template="Magento_CheckoutAgreements::additional_agreements.phtml"/> - - - - diff --git a/view/frontend/templates/payment/paypal/review/details.phtml b/view/frontend/templates/payment/paypal/review/details.phtml new file mode 100644 index 00000000..3ac79073 --- /dev/null +++ b/view/frontend/templates/payment/paypal/review/details.phtml @@ -0,0 +1,29 @@ + +
+ + + + + + + + + + + getItems() as $item) : ?> + getItemHtml($item) ?> + + + getChildHtml('totals') ?> + +
escapeHtml(__('Items in Your Shopping Cart')) ?>
escapeHtml(__('Item')) ?>escapeHtml(__('Price')) ?>escapeHtml(__('Qty')) ?>escapeHtml(__('Subtotal')) ?>
+
diff --git a/view/frontend/templates/payment/paypal/review/shipping-address.phtml b/view/frontend/templates/payment/paypal/review/shipping-address.phtml index c0c0314f..4032aeac 100644 --- a/view/frontend/templates/payment/paypal/review/shipping-address.phtml +++ b/view/frontend/templates/payment/paypal/review/shipping-address.phtml @@ -14,6 +14,117 @@ use \CheckoutCom\Magento2\Block\Paypal\Review\ShippinAddress; escapeHtml(__('Shipping Address')) ?>
+
+
+ Contact Information
+ + + +
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+
+ Address
+
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ +
+ +
+ +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+
+
+ + + +
+
+
+ +
+
+
+
escapeHtml( $block->renderAddress(), From ada442bb219cb6ba39090373ca54ff6de402291b Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Fri, 1 Mar 2024 12:48:00 +0100 Subject: [PATCH 047/147] CHECMAG2003-206 - Manage Discount amount --- Model/Service/PaymentContextRequestService.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index b0e4cf15..86612a0f 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -217,11 +217,13 @@ public function getRequestItems(Quote | CartInterface $quote): array $items = []; /** @var Quote\Item $item */ foreach ($quote->getAllItems() as $item) { + $discount = $this->utilities->formatDecimals($item->getDiscountAmount()) * 100; $contextItem = new PaymentContextsItems(); $contextItem->reference = $item->getSku(); $contextItem->quantity = $item->getQty(); $contextItem->name = $item->getName(); - $contextItem->unit_price = $this->utilities->formatDecimals($item->getRowTotalInclTax() / $item->getQty()) * 100; + $contextItem->discount_amount = $discount; + $contextItem->unit_price = ($this->utilities->formatDecimals($item->getRowTotalInclTax() / $item->getQty()) * 100) - $discount; $items[] = $contextItem; } @@ -245,5 +247,4 @@ private function getQuote(): Quote | CartInterface { return $this->checkoutSession->getQuote(); } - } From 2f90e43a221b8a79e56ecafd8b1a80b9e45ff59a Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Fri, 1 Mar 2024 13:09:38 +0100 Subject: [PATCH 048/147] CHECMAG2003-206 - Better way to calculate discount when requesting payment --- Model/Service/PaymentContextRequestService.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index 86612a0f..a4d66bb3 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -223,7 +223,9 @@ public function getRequestItems(Quote | CartInterface $quote): array $contextItem->quantity = $item->getQty(); $contextItem->name = $item->getName(); $contextItem->discount_amount = $discount; - $contextItem->unit_price = ($this->utilities->formatDecimals($item->getRowTotalInclTax() / $item->getQty()) * 100) - $discount; + $contextItem->unit_price = + ($this->utilities->formatDecimals($item->getRowTotalInclTax() / $item->getQty()) * 100) - + ($this->utilities->formatDecimals($discount / $item->getQty())); $items[] = $contextItem; } From 4799c30182ded00e1ebf0a36b8f72bd22fadd1a0 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Fri, 1 Mar 2024 13:37:05 +0100 Subject: [PATCH 049/147] CHECMAG2003-206 - Code cleaning --- Controller/Paypal/Review.php | 5 - Controller/Paypal/SaveData.php | 14 +- .../Paypal/SaveExpressShippingAddress.php | 2 +- .../payment/paypal/review/details.phtml | 24 +- .../paypal/review/payment-method.phtml | 17 +- .../payment/paypal/review/place-order.phtml | 18 +- .../paypal/review/shipping-address.phtml | 377 +++++++++++++++++- .../paypal/review/shipping-method.phtml | 18 +- 8 files changed, 444 insertions(+), 31 deletions(-) diff --git a/Controller/Paypal/Review.php b/Controller/Paypal/Review.php index d9230ab1..3132bce6 100644 --- a/Controller/Paypal/Review.php +++ b/Controller/Paypal/Review.php @@ -74,7 +74,6 @@ public function __construct( public function execute() { $resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE); - //$reviewBlock = $resultPage->getLayout()->getBlock('braintree.paypal.review'); $quote = $this->checkoutSession->getQuote(); $redirectToCart = false; @@ -92,7 +91,6 @@ public function execute() $redirectToCart = true; } - // Check if context exists if (!$redirectToCart) { /** @var PaymentInterface $paymentMethod */ $paymentMethod = $this->paymentInterfaceFactory->create(); @@ -110,9 +108,6 @@ public function execute() return $this->redirectFactory->create()->setUrl($this->urlInterface->getUrl('checkout/cart')); } - /*$reviewBlock->setQuote($quote); - $reviewBlock->getChildBlock('shipping_method')->setData('quote', $quote);*/ - return $resultPage; } } diff --git a/Controller/Paypal/SaveData.php b/Controller/Paypal/SaveData.php index e7ed12fa..bbdbcb3a 100644 --- a/Controller/Paypal/SaveData.php +++ b/Controller/Paypal/SaveData.php @@ -19,18 +19,20 @@ namespace CheckoutCom\Magento2\Controller\Paypal; +use CheckoutCom\Magento2\Model\Methods\PaypalMethod; use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; use Magento\Checkout\Model\Session; use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\Result\RedirectFactory; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Message\ManagerInterface; use Magento\Framework\UrlInterface; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\AddressInterfaceFactory; use Magento\Quote\Api\Data\CartInterface; use Magento\Quote\Model\Quote; -use \CheckoutCom\Magento2\Model\Methods\PaypalMethod; class SaveData { @@ -69,6 +71,12 @@ public function __construct( $this->paypalMethod = $paypalMethod; } + /** + * Control about current request + * + * @throws LocalizedException + * @throws NoSuchEntityException + */ protected function shouldRedirectToCart(): bool { $quote = $this->checkoutSession->getQuote(); @@ -101,9 +109,11 @@ protected function shouldRedirectToCart(): bool return $redirectToCart; } + /** + * Assign a shipping method to quote + */ protected function setShippingMethod(string $methodCode, CartInterface | Quote $quote): bool { - // Save Shipping method try { $shippingAddress = $quote->getShippingAddress(); $shippingAddress->setShippingMethod($methodCode)->setCollectShippingRates(true); diff --git a/Controller/Paypal/SaveExpressShippingAddress.php b/Controller/Paypal/SaveExpressShippingAddress.php index de34fe21..97df733b 100644 --- a/Controller/Paypal/SaveExpressShippingAddress.php +++ b/Controller/Paypal/SaveExpressShippingAddress.php @@ -44,7 +44,7 @@ public function execute() $quote->setBillingAddress($quoteAddress)->setShippingAddress($quoteAddress); $this->cartRepository->save($quote); - // Auto assign method + // Auto assign shipping method $shippingAddress = $quote->getShippingAddress(); if ($this->paypalMethod->getConfigData('express_auto_method') && !$shippingAddress->getShippingMethod()) { $shippingAddress->collectShippingRates(); diff --git a/view/frontend/templates/payment/paypal/review/details.phtml b/view/frontend/templates/payment/paypal/review/details.phtml index 3ac79073..1e5e8e4c 100644 --- a/view/frontend/templates/payment/paypal/review/details.phtml +++ b/view/frontend/templates/payment/paypal/review/details.phtml @@ -1,10 +1,24 @@ + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ -use CheckoutCom\Magento2\Block\Paypal\Review\PaymentMethod; +use Magento\Checkout\Block\Cart\Totals; use Magento\Framework\Escaper; /** - * @var PaymentMethod $block + * @var Totals $block * @var Escaper $escaper */ ?> @@ -20,10 +34,12 @@ use Magento\Framework\Escaper; getItems() as $item) : ?> - getItemHtml($item) ?> + getItemHtml($item) ?> - getChildHtml('totals') ?> + getChildHtml('totals') ?>
diff --git a/view/frontend/templates/payment/paypal/review/payment-method.phtml b/view/frontend/templates/payment/paypal/review/payment-method.phtml index e6f50e44..3d6e5f6f 100644 --- a/view/frontend/templates/payment/paypal/review/payment-method.phtml +++ b/view/frontend/templates/payment/paypal/review/payment-method.phtml @@ -1,11 +1,26 @@ + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + /** * @var PaymentMethod $block * @var Escaper $escaper */ +use CheckoutCom\Magento2\Block\Paypal\Review\PaymentMethod; use Magento\Framework\Escaper; -use \CheckoutCom\Magento2\Block\Paypal\Review\PaymentMethod; ?>
diff --git a/view/frontend/templates/payment/paypal/review/place-order.phtml b/view/frontend/templates/payment/paypal/review/place-order.phtml index be2eef80..9c56d10b 100644 --- a/view/frontend/templates/payment/paypal/review/place-order.phtml +++ b/view/frontend/templates/payment/paypal/review/place-order.phtml @@ -1,4 +1,19 @@ + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + /** * @var PlaceOrderButton $block * @var Escaper $escaper @@ -10,7 +25,7 @@ use Magento\Framework\Escaper; ?>
+ class="form order-review-form">
@@ -43,4 +58,5 @@ use Magento\Framework\Escaper; } + diff --git a/view/frontend/templates/payment/paypal/review/shipping-address.phtml b/view/frontend/templates/payment/paypal/review/shipping-address.phtml index 4032aeac..0985cce7 100644 --- a/view/frontend/templates/payment/paypal/review/shipping-address.phtml +++ b/view/frontend/templates/payment/paypal/review/shipping-address.phtml @@ -1,11 +1,26 @@ + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + /** * @var ShippinAddress $block * @var Escaper $escaper */ +use CheckoutCom\Magento2\Block\Paypal\Review\ShippinAddress; use Magento\Framework\Escaper; -use \CheckoutCom\Magento2\Block\Paypal\Review\ShippinAddress; ?> @@ -15,22 +30,26 @@ use \CheckoutCom\Magento2\Block\Paypal\Review\ShippinAddress;
+ action="https://nas.checmag2.dnd.fr/customer/address/formPost/" method="post" id="form-validate" enctype="multipart/form-data" + data-hasrequired="* Required Fields" novalidate="novalidate">
- Contact Information
- + Contact Information +
+
- +
- +
@@ -48,7 +67,8 @@ use \CheckoutCom\Magento2\Block\Paypal\Review\ShippinAddress;
- Address
+ Address +
- +
- +
@@ -87,11 +109,79 @@ use \CheckoutCom\Magento2\Block\Paypal\Review\ShippinAddress; State/Province
- - - + Please select a region, state or province. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -99,18 +189,273 @@ use \CheckoutCom\Magento2\Block\Paypal\Review\ShippinAddress; Zip/Postal Code
- + -
+ +
-
+
diff --git a/view/frontend/templates/payment/paypal/review/shipping-method.phtml b/view/frontend/templates/payment/paypal/review/shipping-method.phtml index 8a6b769e..5c36aaf9 100644 --- a/view/frontend/templates/payment/paypal/review/shipping-method.phtml +++ b/view/frontend/templates/payment/paypal/review/shipping-method.phtml @@ -1,4 +1,19 @@ + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + /** * @var ShippingMethod $block * @var Escaper $escaper @@ -24,7 +39,8 @@ $rates = $block->getRates(); escapeHtml($carrierMethod->getCarrierTitle()) ?> - escapeHtml($carrierMethod->getMethodTitle()) ?> - - getFormatedPrice($carrierMethod->getPrice()) ?> + getFormatedPrice($carrierMethod->getPrice()) ?> From ea5e8a1409f26179154c6cc3cff90ebd1b317eed Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Fri, 1 Mar 2024 13:53:05 +0100 Subject: [PATCH 050/147] CHECMAG2003-206 - Manage Capture mode on express --- Block/Paypal/Script.php | 6 +----- view/frontend/web/js/view/minicart/paypalbutton.js | 2 +- .../web/js/view/payment/cart/checkoutcom_paypal_cart.js | 6 +++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Block/Paypal/Script.php b/Block/Paypal/Script.php index e3f30f27..3863f235 100644 --- a/Block/Paypal/Script.php +++ b/Block/Paypal/Script.php @@ -56,11 +56,7 @@ public function getPartnerAttributionId(): string public function getIntent(): string { - if ($this->isExpressButton()) { - return 'authorize'; - } - - return $this->checkoutConfig->needsAutoCapture() ? 'capture' : 'authorize'; + return $this->checkoutConfig->needsAutoCapture() ? 'capture' : 'authorize'; } public function getCommit(): string diff --git a/view/frontend/web/js/view/minicart/paypalbutton.js b/view/frontend/web/js/view/minicart/paypalbutton.js index d9ccb2ea..80cd3cd3 100644 --- a/view/frontend/web/js/view/minicart/paypalbutton.js +++ b/view/frontend/web/js/view/minicart/paypalbutton.js @@ -77,7 +77,7 @@ define([ // Prepare Context let containerSelector = '#minicart-paypal-button-container'; - let datas = {forceAuthorizeMode: true}; + let datas = {forceAuthorizeMode: 0}; if ($(containerSelector).length > 0) { $.ajax( diff --git a/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js b/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js index d8ce725c..b9531c82 100644 --- a/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js +++ b/view/frontend/web/js/view/payment/cart/checkoutcom_paypal_cart.js @@ -13,7 +13,7 @@ define([ 'Magento_Customer/js/model/customer', 'mage/url', 'Magento_Checkout/js/model/full-screen-loader', -], function($, ko, Component, customerData, customer, Url,FullScreenLoader) { +], function($, ko, Component, customerData, customer, Url, FullScreenLoader) { 'use strict'; return Component.extend({ @@ -77,8 +77,8 @@ define([ // Prepare Context let containerSelector = '#cart-paypal-button-container'; - let datas = {forceAuthorizeMode: true}; - if($(containerSelector).length > 0) { + let datas = {forceAuthorizeMode: 0}; + if ($(containerSelector).length > 0) { $.ajax( { type: 'POST', From 8f39b2d7a7f8e48b3d195bdaae2f576234c56e8e Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Fri, 1 Mar 2024 14:00:21 +0100 Subject: [PATCH 051/147] CHECMAG2003-206 - Remove not used file --- .../paypal/review/shipping-address.phtml | 480 ------------------ 1 file changed, 480 deletions(-) delete mode 100644 view/frontend/templates/payment/paypal/review/shipping-address.phtml diff --git a/view/frontend/templates/payment/paypal/review/shipping-address.phtml b/view/frontend/templates/payment/paypal/review/shipping-address.phtml deleted file mode 100644 index 0985cce7..00000000 --- a/view/frontend/templates/payment/paypal/review/shipping-address.phtml +++ /dev/null @@ -1,480 +0,0 @@ - - * @copyright 2010-present Checkout.com - * @license https://opensource.org/licenses/mit-license.html MIT License - * @link https://docs.checkout.com/ - */ - -/** - * @var ShippinAddress $block - * @var Escaper $escaper - */ - -use CheckoutCom\Magento2\Block\Paypal\Review\ShippinAddress; -use Magento\Framework\Escaper; - -?> - -
- - escapeHtml(__('Shipping Address')) ?> - -
- -
- Contact Information -
- - - -
- -
- -
-
-
- -
- -
-
- -
- -
- -
-
-
- -
- -
-
-
-
- Address -
-
- -
-
- -
- -
-
- -
- -
-
-
-
-
- -
- -
- -
-
-
- -
- - -
-
-
- -
- - - -
-
-
- -
-
-
- - - -
-
-
- -
-
- - -
- escapeHtml( - $block->renderAddress(), - ['br'] - ); ?> -
-
-
From 6e8939acb415a745a6aef7b1c944542e870e722a Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Mon, 4 Mar 2024 16:06:00 +0400 Subject: [PATCH 052/147] CHECMAG2003-206: fix minicart behaviour with configurable products --- Model/Service/PaymentContextRequestService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index a4d66bb3..f4f51e58 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -216,7 +216,7 @@ public function getRequestItems(Quote | CartInterface $quote): array { $items = []; /** @var Quote\Item $item */ - foreach ($quote->getAllItems() as $item) { + foreach ($quote->getAllVisibleItems() as $item) { $discount = $this->utilities->formatDecimals($item->getDiscountAmount()) * 100; $contextItem = new PaymentContextsItems(); $contextItem->reference = $item->getSku(); From 4d4736d7c01f1b942864775de735ef3b2e58d637 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Mon, 4 Mar 2024 13:18:39 +0100 Subject: [PATCH 053/147] CHECMAG2003-206 - Fix issue with price to 0 products --- Model/Service/PaymentContextRequestService.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index f4f51e58..24a4e4d0 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -218,14 +218,19 @@ public function getRequestItems(Quote | CartInterface $quote): array /** @var Quote\Item $item */ foreach ($quote->getAllVisibleItems() as $item) { $discount = $this->utilities->formatDecimals($item->getDiscountAmount()) * 100; + $unitPrice = ($this->utilities->formatDecimals($item->getRowTotalInclTax() / $item->getQty()) * 100) - + ($this->utilities->formatDecimals($discount / $item->getQty())); + // Api does not accept 0 prices + if (!$unitPrice) { + continue; + } + $contextItem = new PaymentContextsItems(); $contextItem->reference = $item->getSku(); $contextItem->quantity = $item->getQty(); $contextItem->name = $item->getName(); $contextItem->discount_amount = $discount; - $contextItem->unit_price = - ($this->utilities->formatDecimals($item->getRowTotalInclTax() / $item->getQty()) * 100) - - ($this->utilities->formatDecimals($discount / $item->getQty())); + $contextItem->unit_price = $unitPrice; $items[] = $contextItem; } From 5ccadfd749c30b6534adc91e83f1f5103dd717ea Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 4 Mar 2024 14:51:05 +0100 Subject: [PATCH 054/147] CHECMAG2003-214: change payment first option processing to keep unique order reference for each payment --- Controller/Api/V1.php | 32 ++++++----------------- Controller/Api/V2.php | 24 +++++++---------- Controller/Payment/PlaceOrder.php | 24 +++++++---------- Model/Api/V3.php | 34 ++++++++++-------------- Model/Service/OrderHandlerService.php | 37 ++++++++++++++++++++++++++- etc/adminhtml/system.xml | 2 +- etc/config.xml | 2 +- 7 files changed, 78 insertions(+), 77 deletions(-) diff --git a/Controller/Api/V1.php b/Controller/Api/V1.php index 21f8804d..8760a259 100644 --- a/Controller/Api/V1.php +++ b/Controller/Api/V1.php @@ -161,30 +161,14 @@ public function execute(): Json if ($this->isValidRequest()) { // Load the quote $quote = $this->loadQuote(); - $order = null; - $reservedOrderId = null; - - if ($this->config->isPaymentWithOrderFirst()) { - // Create an order - $order = $this->orderHandler->setMethodId('checkoutcom_card_payment')->handleOrder($quote); - } - - if ($this->config->isPaymentWithPaymentFirst()) { - // Reserved an order - /** @var string $reservedOrderId */ - $reservedOrderId = $this->quoteHandler->getReference($quote); - } - - + $order = $this->orderHandler->setMethodId('checkoutcom_card_payment')->handleOrder($quote); // Process the payment - if (($this->config->isPaymentWithPaymentFirst() && $this->quoteHandler->isQuote($quote) && $reservedOrderId !== null) - || ($this->config->isPaymentWithOrderFirst() && $this->orderHandler->isOrder($order)) - ) { + if ($this->orderHandler->isOrder($order)) { //Init values to request payment - $amount = (float)$this->config->isPaymentWithPaymentFirst() ? $quote->getGrandTotal() : $order->getGrandTotal(); - $currency = (string)$this->config->isPaymentWithPaymentFirst() ? $quote->getQuoteCurrencyCode() : $order->getOrderCurrencyCode(); - $reference = (string)$this->config->isPaymentWithPaymentFirst() ? $reservedOrderId : $order->getIncrementId(); + $amount = $order->getGrandTotal(); + $currency = $order->getOrderCurrencyCode(); + $reference = $order->getIncrementId(); // Get response and success $response = $this->requestPayment($amount, $currency, $reference); @@ -195,9 +179,6 @@ public function execute(): Json // Process the response $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); if ($api->isValidResponse($response)) { - // Create an order if processing is with payment first - $order = $order === null ? $this->orderHandler->setMethodId('checkoutcom_card_payment')->handleOrder($quote) : $order; - // Get the payment details $paymentDetails = $api->getPaymentDetails($response->id); @@ -211,6 +192,9 @@ public function execute(): Json $success = $response->isSuccessful(); $orderId = $order->getId(); } else { + // Delete the order if payment is first + $this->orderHandler->deleteOrder($order); + $errorMessage = __('The payment request was declined by the gateway.'); } } else { diff --git a/Controller/Api/V2.php b/Controller/Api/V2.php index 702ec144..08421ae0 100644 --- a/Controller/Api/V2.php +++ b/Controller/Api/V2.php @@ -343,29 +343,20 @@ protected function hasValidFields() */ protected function processPayment(): array { - // Try to load a quote - $quote = $this->config->isPaymentWithPaymentFirst() ? $this->loadQuote() : null; - // Reserved an order - $reservedOrderId = $this->config->isPaymentWithPaymentFirst() ? $this->quoteHandler->getReference($quote) : null; - // Create Order if needed before paymen - $orderBeforePayment = $this->config->isPaymentWithOrderFirst() ? $this->createOrder() : null; + // Create Order if needed before payment + $order = $this->createOrder(); // Process the payment - if (($this->config->isPaymentWithPaymentFirst() && $this->quoteHandler->isQuote($quote) && $reservedOrderId !== null) - || ($this->config->isPaymentWithOrderFirst() && $this->orderHandler->isOrder($orderBeforePayment)) - ) { + if ($this->orderHandler->isOrder($order)) { //Init values to request payment - $amount = (float)$this->config->isPaymentWithPaymentFirst() ? $quote->getGrandTotal() : $orderBeforePayment->getGrandTotal(); - $currency = (string)$this->config->isPaymentWithPaymentFirst() ? $quote->getQuoteCurrencyCode() : $orderBeforePayment->getOrderCurrencyCode(); - $reference = (string)$this->config->isPaymentWithPaymentFirst() ? $reservedOrderId : $orderBeforePayment->getIncrementId(); + $amount = $order->getGrandTotal(); + $currency = $order->getOrderCurrencyCode(); + $reference = $order->getIncrementId(); // Get the payment response $response = $this->getPaymentResponse($amount, $currency, $reference); if ($this->api->isValidResponse($response)) { - // Create Order - $this->order = $order = ($orderBeforePayment === null) ? $this->createOrder() : $orderBeforePayment; - // Process the payment response $is3ds = property_exists( $response, @@ -408,6 +399,9 @@ protected function processPayment(): array if (isset($this->data->failure_url)) { $this->result['redirect_url'] = $this->data->failure_url; } + + // Delete the order if payment is first + $this->orderHandler->deleteOrder($order); } // Update the order id diff --git a/Controller/Payment/PlaceOrder.php b/Controller/Payment/PlaceOrder.php index bae6173f..05652945 100644 --- a/Controller/Payment/PlaceOrder.php +++ b/Controller/Payment/PlaceOrder.php @@ -219,18 +219,12 @@ public function execute(): Json if (isset($data['methodId']) && !$this->isEmptyCardToken($data)) { // Process the request if ($this->getRequest()->isAjax() && $quote) { - // Reserved an order - /** @var string $reservedOrderId */ - $reservedOrderId = $this->config->isPaymentWithPaymentFirst() ? $this->quoteHandler->getReference($quote) : null; - //Create order if it is needed before payment - $order = $this->config->isPaymentWithOrderFirst() ? $this->orderHandler->setMethodId($data['methodId'])->handleOrder($quote) : null; + //Create order before payment + $order = $this->orderHandler->setMethodId($data['methodId'])->handleOrder($quote); // Process the payment - if (($this->config->isPaymentWithPaymentFirst() && $this->quoteHandler->isQuote($quote) && $reservedOrderId !== null) - || ($this->config->isPaymentWithOrderFirst() && $this->orderHandler->isOrder($order) - ) - ) { + if ($this->orderHandler->isOrder($order)) { $log = false; // Get the debug config value $debug = $this->scopeConfig->getValue( @@ -245,9 +239,9 @@ public function execute(): Json ); //Init values to request payment - $amount = (float)$this->config->isPaymentWithPaymentFirst() ? $quote->getGrandTotal() : $order->getGrandTotal(); - $currency = (string)$this->config->isPaymentWithPaymentFirst() ? $quote->getQuoteCurrencyCode() : $order->getOrderCurrencyCode(); - $reference = (string)$this->config->isPaymentWithPaymentFirst() ? $reservedOrderId : $order->getIncrementId(); + $amount = (float) $order->getGrandTotal(); + $currency = (string) $order->getOrderCurrencyCode(); + $reference = (string) $order->getIncrementId(); // Get response and success $response = $this->requestPayment($quote, $data, $amount, $currency, $reference); @@ -265,9 +259,6 @@ public function execute(): Json $responseCode = isset($response['response_code']) ? $response['response_code'] : ''; if ($isValidResponse && $this->isAuthorized($responseCode)) { - // Create an order if processing is payment first - $order = $order === null ? $this->orderHandler->setMethodId($data['methodId'])->handleOrder($quote) : $order; - // Add the payment info to the order $order = $this->utilities->setPaymentData($order, $response, $data); @@ -304,6 +295,9 @@ public function execute(): Json if ($this->config->isPaymentWithOrderFirst()) { $this->orderStatusHandler->handleFailedPayment($order); } + + // Delete the order if payment is first + $this->orderHandler->deleteOrder($order); } } else { // Payment failed diff --git a/Model/Api/V3.php b/Model/Api/V3.php index 1cf5b531..f4b255a3 100644 --- a/Model/Api/V3.php +++ b/Model/Api/V3.php @@ -152,12 +152,6 @@ class V3 implements V3Interface * @var Object $api */ private $api; - /** - * $order field - * - * @var Object $order - */ - private $order; /** * $quote field * @@ -295,10 +289,8 @@ private function execute(): PaymentResponseInterface if ($this->isValidPublicKey()) { if ($this->hasValidFields()) { $this->result = $this->processPayment(); - if (!$this->result['success']) { + if (!$this->result['success'] && !$this->result['error_message']) { $this->result['error_message'][] = __('The order could not be created.'); - // Handle order on failed payment - $this->orderStatusHandler->handleFailedPayment($this->order); } } } else { @@ -333,25 +325,19 @@ private function isValidPublicKey(): bool */ private function processPayment(): array { - // Try to load a quote - $quote = $this->config->isPaymentWithPaymentFirst() ? $this->loadQuote() : null; - $reservedOrderId = $this->config->isPaymentWithPaymentFirst() ? $this->quoteHandler->getReference($quote) : null; - // Create order if needed before payment - $orderBeforePayment = $this->config->isPaymentWithOrderFirst() ? $this->createOrder($this->data->getPaymentMethod()) : null; + $order = $this->createOrder($this->data->getPaymentMethod()); - if (($quote !== null && $reservedOrderId !== null) || $this->orderHandler->isOrder($orderBeforePayment)) { + if ($this->orderHandler->isOrder($order)) { //Init values to request payment - $amount = (float)$this->config->isPaymentWithPaymentFirst() ? $quote->getGrandTotal() : $orderBeforePayment->getGrandTotal(); - $currency = (string)$this->config->isPaymentWithPaymentFirst() ? $quote->getQuoteCurrencyCode() : $orderBeforePayment->getOrderCurrencyCode(); - $reference = (string)$this->config->isPaymentWithPaymentFirst() ? $reservedOrderId : $orderBeforePayment->getIncrementId(); + $amount = $order->getGrandTotal(); + $currency = $order->getOrderCurrencyCode(); + $reference = $order->getIncrementId(); // Get the payment $response = $this->getPaymentResponse($amount, $currency, $reference); if ($this->api->isValidResponse($response)) { - $this->order = $order = ($orderBeforePayment === null) ? $this->createOrder($this->data->getPaymentMethod()) : $orderBeforePayment; - // Process the payment response $is3ds = property_exists($response, '_links') && isset($response->_links['redirect']) @@ -380,6 +366,11 @@ private function processPayment(): array ); } + // Handle order on failed payment if payment is order first. + if ($this->config->isPaymentWithOrderFirst()) { + $this->orderStatusHandler->handleFailedPayment($order); + } + // Token invalid/expired if (method_exists($response, 'getErrors')) { $this->result['error_message'] = array_merge( @@ -391,6 +382,9 @@ private function processPayment(): array if ($this->data->getFailureUrl()) { $this->result['redirect_url'] = $this->data->getFailureUrl(); } + + // Delete the order if payment is first + $this->orderHandler->deleteOrder($order); } // Update the order id diff --git a/Model/Service/OrderHandlerService.php b/Model/Service/OrderHandlerService.php index 75607649..c43479f0 100644 --- a/Model/Service/OrderHandlerService.php +++ b/Model/Service/OrderHandlerService.php @@ -29,10 +29,12 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Model\AbstractExtensibleModel; +use Magento\Framework\Registry; use Magento\Quote\Api\Data\CartInterface; use Magento\Quote\Model\Quote; use Magento\Quote\Model\QuoteManagement; use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\OrderManagementInterface; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Status\History as OrderStatusHistory; @@ -108,6 +110,20 @@ class OrderHandlerService */ private $transactionHandler; + /** + * $orderManagement field + * + * @var OrderManagementInterface $orderManagement + */ + private $orderManagement; + + /** + * $registry field + * + * @var Registry $registry + */ + private $registry; + /** * OrderHandlerService constructor * @@ -121,6 +137,7 @@ class OrderHandlerService * @param Logger $logger * @param TransactionHandlerService $transactionHandler * @param SortOrderBuilderFactory $sortOrderBuilderFactory + * @param OrderManagementInterface $orderManagement */ public function __construct( Session $checkoutSession, @@ -132,7 +149,9 @@ public function __construct( StoreManagerInterface $storeManager, Logger $logger, TransactionHandlerService $transactionHandler, - SortOrderBuilderFactory $sortOrderBuilderFactory + SortOrderBuilderFactory $sortOrderBuilderFactory, + OrderManagementInterface $orderManagement, + Registry $registry ) { $this->checkoutSession = $checkoutSession; $this->quoteManagement = $quoteManagement; @@ -144,6 +163,8 @@ public function __construct( $this->logger = $logger; $this->transactionHandler = $transactionHandler; $this->sortOrderBuilderFactory = $sortOrderBuilderFactory; + $this->orderManagement = $orderManagement; + $this->registry = $registry; } /** @@ -386,4 +407,18 @@ public function getOrderDetails(OrderInterface $order): array 'transactions' => $this->transactionHandler->getTransactionDetails($order), ]; } + + /** + * Delete order if order processing is Payment first. + * Temporary function before removing completely the feature. + */ + public function deleteOrder(OrderInterface $order): void + { + if ($this->config->isPaymentWithPaymentFirst()) { + $this->orderManagement->cancel($order->getEntityId()); + $this->registry->register('isSecureArea', true); + $this->orderRepository->delete($order); + $this->registry->unregister('isSecureArea'); + } + } } diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index c14b56e1..15a6d309 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -56,7 +56,7 @@ CheckoutCom\Magento2\Model\Config\Backend\Source\ConfigPaymentProcesing settings/checkoutcom_configuration/payment_processing - Specify if payment should be processed before order creation (default) or after order creation (respectful of native Magento and Adobe Commerce processing). + - Payment first: order will not appear in orders list if payment is failed]]> diff --git a/etc/config.xml b/etc/config.xml index 80635b08..f7538ead 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -20,7 +20,7 @@ secret_key,private_shared_key 1 - payment_first + order_first 0 0 0 From edbde7e3a4a25922f413548a0f906563f6675b9d Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 5 Mar 2024 14:32:36 +0100 Subject: [PATCH 055/147] CHECMAG2003-214: handle delete of order if payment first with 3DS --- Controller/Payment/Fail.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Controller/Payment/Fail.php b/Controller/Payment/Fail.php index 775a2ab5..43a45c27 100644 --- a/Controller/Payment/Fail.php +++ b/Controller/Payment/Fail.php @@ -191,6 +191,9 @@ public function execute(): ResponseInterface // Handle the failed order $this->orderStatusHandler->handleFailedPayment($order); + //Delete order if payment first + $this->orderHandler->deleteOrder($order); + $errorMessage = null; if (isset($response['actions'][0]['response_code'])) { $errorMessage = $this->paymentErrorHandlerService->getErrorMessage( From ca6ad95c8af52083228acdb2e9d0e2d5930ff649 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Thu, 7 Mar 2024 09:05:36 +0100 Subject: [PATCH 056/147] Bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 50e8115b..0327fe18 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "5.8.1", + "version": "5.8.2", "autoload": { "files": [ "registration.php" From 1dbe34b2af6df8ca461d523c4e61abe611075a39 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Thu, 7 Mar 2024 10:26:07 +0100 Subject: [PATCH 057/147] CHECMAG2003-206: manage paypal express component on minicart and cart --- view/frontend/layout/checkout_cart_index.xml | 48 +++++- view/frontend/layout/default.xml | 7 +- view/frontend/templates/cart/paypal.phtml | 10 +- .../templates/script/paypal-script.phtml | 8 +- .../checkoutcom_paypal_express.js | 152 ++++++++++++++++++ .../web/js/view/payment/paypal-utilities.js | 64 ++++++++ .../frontend/web/js/view/payment/utilities.js | 4 +- .../template/payment/checkoutcom_paypal.html | 13 +- .../payment/checkoutcom_paypal_express.html | 24 +++ 9 files changed, 305 insertions(+), 25 deletions(-) create mode 100755 view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js create mode 100644 view/frontend/web/js/view/payment/paypal-utilities.js create mode 100644 view/frontend/web/template/payment/checkoutcom_paypal_express.html diff --git a/view/frontend/layout/checkout_cart_index.xml b/view/frontend/layout/checkout_cart_index.xml index 4ac23588..a761e5be 100644 --- a/view/frontend/layout/checkout_cart_index.xml +++ b/view/frontend/layout/checkout_cart_index.xml @@ -6,19 +6,51 @@ - - - + - express - cart + + + + CheckoutCom_Magento2/js/view/payment/method-renderer/checkoutcom_paypal_express + + CheckoutCom_Magento2/payment/checkoutcom_paypal_express + express_cart + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + cart + + + diff --git a/view/frontend/layout/default.xml b/view/frontend/layout/default.xml index 3e6dd44c..5131eaf0 100644 --- a/view/frontend/layout/default.xml +++ b/view/frontend/layout/default.xml @@ -26,9 +26,10 @@ - CheckoutCom_Magento2/js/view/minicart/paypalbutton + CheckoutCom_Magento2/js/view/payment/method-renderer/checkoutcom_paypal_express - CheckoutCom_Magento2/checkout/minicart/paypalbutton + CheckoutCom_Magento2/payment/checkoutcom_paypal_express + express_minicart @@ -48,7 +49,7 @@ express diff --git a/view/frontend/templates/cart/paypal.phtml b/view/frontend/templates/cart/paypal.phtml index 740b7fd5..212f3ddb 100644 --- a/view/frontend/templates/cart/paypal.phtml +++ b/view/frontend/templates/cart/paypal.phtml @@ -16,12 +16,12 @@ ?> -
-
+
+
diff --git a/view/frontend/templates/script/paypal-script.phtml b/view/frontend/templates/script/paypal-script.phtml index 3eda8058..17807763 100644 --- a/view/frontend/templates/script/paypal-script.phtml +++ b/view/frontend/templates/script/paypal-script.phtml @@ -23,5 +23,11 @@ $partnerId = $block->getPartnerAttributionId(); $paypalMerchantId = $block->getPaypalMerchantId(); if ($clientId && $partnerId && $paypalMerchantId): ?> - + diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js new file mode 100755 index 00000000..0e43989a --- /dev/null +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js @@ -0,0 +1,152 @@ +/** + * Checkout.com + * Authorized and regulated as an electronic money institution + * by the UK Financial Conduct Authority (FCA) under number 900816. + * + * PHP version 7 + * + * @category Magento2 + * @package Checkout.com + * @author Platforms Development Team + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +define([ + 'jquery', + 'ko', + 'uiComponent', + 'CheckoutCom_Magento2/js/view/payment/paypal-utilities', + 'Magento_Customer/js/customer-data', + 'mage/url', +], function ($, ko, Component, PaypalUtilities, CustomerData, Url) { + 'use strict'; + + return Component.extend({ + isVisible: ko.observable(false), + chkPayPalOrderid: null, + chkPayPalContextId: null, + paypalScriptUrl: 'https://www.paypal.com/sdk/js', + paypalExpressInitialized: false, + + /** + * @return {void} + */ + initialize: function () { + this._super(); + this.cartData = CustomerData.get('cart'); + this.customer = CustomerData.get('customer'); + + this._loadPaypalScript(); + this._dataListeners(); + }, + + /** + * @return {void} + */ + _loadPaypalScript: function () { + if (this._canUsePaypalExpress() && !this.paypalExpressInitialized) { + const { + checkout_client_id, + merchant_id, + checkout_partner_attribution_id + } = this.cartData().checkoutcom_paypal; + + this.paypalCheckoutConfig = { + paypalScriptUrl: this.paypalScriptUrl, + clientId: checkout_client_id, + merchantId: merchant_id, + partnerAttributionId: checkout_partner_attribution_id, + ...window.paypalCheckoutConfig + } + + const scriptPromise = PaypalUtilities.paypalScriptLoader(this.paypalCheckoutConfig); + + scriptPromise.then(() => { + this._initializePaypalExpressButton(); + }).catch((error) => { + console.log(error); + }); + } + }, + + /** + * @return {void} + */ + _dataListeners: function () { + this.cartData.subscribe((newCartData) => { + this._loadPaypalScript(); + }); + }, + + /** + * @return {void} + */ + _initializePaypalExpressButton: function () { + this.isVisible(this.cartData().summary_count > 0); + + this.cartData.subscribe((newCartData) => { + this.isVisible(newCartData.summary_count > 0); + }); + + this.paypalExpressInitialized = true; + }, + + /** + * @param {HTMLDivElement} $el + * @return {void} + */ + renderPaypalButton: async function ($el) { + paypal.Buttons({ + createOrder: async () => { + return await this._getPaypalOrderId(); + }, + onApprove: async (data) => { + // Redirect on paypal reviex page (express checkout) + window.location.href = Url.build( + 'checkout_com/paypal/review/contextId/' + + this.chkPayPalContextId); + }, + }).render($el); + }, + + /** + * @return {void} + */ + _canUsePaypalExpress: function () { + const checkoutPaypalConfig = this.cartData().hasOwnProperty('checkoutcom_paypal') ? + this.cartData().checkoutcom_paypal : + null; + + return checkoutPaypalConfig + && (this.cartData().isGuestCheckoutAllowed || this.customer.fullname) + && checkoutPaypalConfig['active'] === '1' + && checkoutPaypalConfig[this.context] === '1'; + }, + + /** + * @private + * @return {Promise} + */ + _getPaypalOrderId: function () { + return fetch(Url.build('checkout_com/paypal/context'), { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest' + }, + body: JSON.stringify({ + forceAuthorizeMode: 0 + }), + }) + .then(response => response.json()) + .then(response => { + this.chkPayPalContextId = response.content.id; + this.chkPayPalOrderid = response.content.partner_metadata.order_id; + + return this.chkPayPalOrderid; + }); + } + }); +}); diff --git a/view/frontend/web/js/view/payment/paypal-utilities.js b/view/frontend/web/js/view/payment/paypal-utilities.js new file mode 100644 index 00000000..27e0f227 --- /dev/null +++ b/view/frontend/web/js/view/payment/paypal-utilities.js @@ -0,0 +1,64 @@ +/** + * Checkout.com + * Authorized and regulated as an electronic money institution + * by the UK Financial Conduct Authority (FCA) under number 900816. + * + * PHP version 7 + * + * @category Magento2 + * @package Checkout.com + * @author Platforms Development Team + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +define([ + 'jquery' +], function ($) { + 'use strict'; + + return { + + /** + * @public + * @param {Object} config + * @return {Promise} + */ + paypalScriptLoader: function (config) { + return new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.addEventListener('load', () => { + resolve(); + }); + + script.addEventListener('error', () => { + reject('Something wrong happened with paypal script load'); + }); + + this.buildScript(script, config); + }); + }, + + /** + * @public + * @param {HTMLScriptElement} script + * @param {Object} config + */ + buildScript: function (script, config) { + const scriptUrl = new URL(config.paypalScriptUrl); + scriptUrl.searchParams.append('client-id', config.clientId); + scriptUrl.searchParams.append('merchant-id', config.merchantId); + scriptUrl.searchParams.append('intent', config.intent); + scriptUrl.searchParams.append('commit', config.commit); + scriptUrl.searchParams.append('disable-funding', 'credit,card,sepa'); + + script.type = 'text/javascript'; + script.src = scriptUrl; + script.dataset.pageType = config.pageType; + script.dataset.partnerAttributionId = config.partnerAttributionId; + + document.head.appendChild(script); + } + }; +}); diff --git a/view/frontend/web/js/view/payment/utilities.js b/view/frontend/web/js/view/payment/utilities.js index 9bd7c3cc..d68f732e 100755 --- a/view/frontend/web/js/view/payment/utilities.js +++ b/view/frontend/web/js/view/payment/utilities.js @@ -401,7 +401,7 @@ define( /** * Place a new order. * - * @return {void} + * @return {JQuery.ajax} */ placeOrder: function (payload, methodId, startLoader = true) { var self = this; @@ -412,7 +412,7 @@ define( } // Send the request - $.ajax({ + return $.ajax({ type: 'POST', url: self.getUrl('payment/placeorder'), data: payload, diff --git a/view/frontend/web/template/payment/checkoutcom_paypal.html b/view/frontend/web/template/payment/checkoutcom_paypal.html index 6758a0b0..1de1e6dc 100755 --- a/view/frontend/web/template/payment/checkoutcom_paypal.html +++ b/view/frontend/web/template/payment/checkoutcom_paypal.html @@ -13,9 +13,11 @@ */ --> -
+
- + @@ -46,11 +48,10 @@
- +
-
-
-
+
+
diff --git a/view/frontend/web/template/payment/checkoutcom_paypal_express.html b/view/frontend/web/template/payment/checkoutcom_paypal_express.html new file mode 100644 index 00000000..8fa31163 --- /dev/null +++ b/view/frontend/web/template/payment/checkoutcom_paypal_express.html @@ -0,0 +1,24 @@ + + + +
+
+
+
+
+ From 41f71b7d4e6353ff5360ac18204fdc7081919e01 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Thu, 7 Mar 2024 10:44:54 +0100 Subject: [PATCH 058/147] CHECMAG2003-206 - Code cleaning --- Block/Paypal/Review/PaymentMethod.php | 4 +-- Block/Paypal/Review/PlaceOrderButton.php | 4 +-- Block/Paypal/Review/ShippingAddress.php | 26 ++++++++++++------- Block/Paypal/Review/ShippingMethod.php | 7 ++--- Block/Paypal/Script.php | 6 ++--- Controller/Paypal/Context.php | 4 +-- Controller/Paypal/Review.php | 5 ++-- Controller/Paypal/SaveData.php | 4 +-- .../Paypal/SaveExpressShippingAddress.php | 1 - .../Paypal/SaveExpressShippingMethod.php | 1 - Model/Methods/PaypalMethod.php | 22 ---------------- 11 files changed, 32 insertions(+), 52 deletions(-) diff --git a/Block/Paypal/Review/PaymentMethod.php b/Block/Paypal/Review/PaymentMethod.php index 9e026697..3d06a43f 100644 --- a/Block/Paypal/Review/PaymentMethod.php +++ b/Block/Paypal/Review/PaymentMethod.php @@ -16,12 +16,12 @@ * @license https://opensource.org/licenses/mit-license.html MIT License * @link https://docs.checkout.com/ */ - namespace CheckoutCom\Magento2\Block\Paypal\Review; use CheckoutCom\Magento2\Model\Methods\PaypalMethod; use Magento\Checkout\Model\Session; use Magento\Framework\View\Element\Template; +use \Magento\Framework\View\Element\Template\Context as TemplateContext; class PaymentMethod extends Template { @@ -29,7 +29,7 @@ class PaymentMethod extends Template protected PaypalMethod $paypalMethod; public function __construct( - Template\Context $context, + TemplateContext $context, Session $checkoutSession, PaypalMethod $paypalMethod, array $data = [] diff --git a/Block/Paypal/Review/PlaceOrderButton.php b/Block/Paypal/Review/PlaceOrderButton.php index b8fb1cbc..75cc32c0 100644 --- a/Block/Paypal/Review/PlaceOrderButton.php +++ b/Block/Paypal/Review/PlaceOrderButton.php @@ -16,7 +16,6 @@ * @license https://opensource.org/licenses/mit-license.html MIT License * @link https://docs.checkout.com/ */ - namespace CheckoutCom\Magento2\Block\Paypal\Review; use CheckoutCom\Magento2\Controller\Paypal\Review; @@ -24,6 +23,7 @@ use Magento\Checkout\Model\Session; use Magento\Framework\App\RequestInterface; use Magento\Framework\View\Element\Template; +use \Magento\Framework\View\Element\Template\Context as TemplateContext; class PlaceOrderButton extends Template { @@ -32,7 +32,7 @@ class PlaceOrderButton extends Template protected PaypalMethod $paypalMethod; public function __construct( - Template\Context $context, + TemplateContext $context, Session $checkoutSession, RequestInterface $request, PaypalMethod $paypalMethod, diff --git a/Block/Paypal/Review/ShippingAddress.php b/Block/Paypal/Review/ShippingAddress.php index 6a80926e..6e4a352d 100644 --- a/Block/Paypal/Review/ShippingAddress.php +++ b/Block/Paypal/Review/ShippingAddress.php @@ -24,6 +24,7 @@ use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Api\AddressRepositoryInterface; use Magento\Customer\Api\Data\AddressInterfaceFactory; +use Magento\Customer\Api\Data\CustomerInterface; use Magento\Customer\Api\Data\CustomerInterfaceFactory; use Magento\Customer\Block\Address\Edit as CustomerAddressEdit; use Magento\Customer\Helper\Address; @@ -36,10 +37,13 @@ use Magento\Framework\Api\DataObjectHelper; use Magento\Framework\App\Cache\Type\Config; use Magento\Framework\App\RequestInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Json\EncoderInterface; use Magento\Framework\Phrase; use Magento\Framework\UrlInterface; use Magento\Framework\View\Element\Template\Context; +use Magento\Quote\Model\Quote\Address as QuoteAddress; class ShippingAddress extends CustomerAddressEdit { @@ -96,42 +100,46 @@ public function __construct( $this->_address = $this->checkoutSession->getQuote()->getShippingAddress(); } - public function getAddress() + /** + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function getAddress(): ?QuoteAddress { return $this->checkoutSession->getQuote()->getShippingAddress(); } - public function getCustomer() + public function getCustomer(): CustomerInterface { return $this->customerInterfaceFactory->create(); } - public function isDefaultBilling() + public function isDefaultBilling(): bool { return false; } - public function isDefaultShipping() + public function isDefaultShipping(): bool { return false; } - public function canSetAsDefaultBilling() + public function canSetAsDefaultBilling(): bool { return false; } - public function canSetAsDefaultShipping() + public function canSetAsDefaultShipping(): bool { return false; } - public function getCustomerAddressCount() + public function getCustomerAddressCount(): int { return 1; } - public function getRegion() + public function getRegion(): string { return (string)$this->getAddress()->getRegion(); } @@ -146,7 +154,7 @@ public function getTitle(): Phrase return __('Review Order'); } - public function getSaveUrl() + public function getSaveUrl(): string { return $this->url->getUrl('checkoutcom/paypal/saveExpressShippingAddress', [ Review::PAYMENT_CONTEXT_ID_PARAMETER => $this->request->getParam(Review::PAYMENT_CONTEXT_ID_PARAMETER) diff --git a/Block/Paypal/Review/ShippingMethod.php b/Block/Paypal/Review/ShippingMethod.php index a10a063b..97fcb5be 100644 --- a/Block/Paypal/Review/ShippingMethod.php +++ b/Block/Paypal/Review/ShippingMethod.php @@ -25,6 +25,7 @@ use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Framework\UrlInterface; use Magento\Framework\View\Element\Template; +use Magento\Framework\View\Element\Template\Context as TemplateContext; use Magento\Quote\Model\Quote\Address as QuoteAddresss; use Magento\Quote\Model\Quote\Address\Rate as QuoteRate; @@ -36,7 +37,7 @@ class ShippingMethod extends Template protected PriceCurrencyInterface $priceCurrency; public function __construct( - Template\Context $context, + TemplateContext $context, Session $checkoutSession, RequestInterface $request, UrlInterface $url, @@ -50,7 +51,7 @@ public function __construct( $this->priceCurrency = $priceCurrency; } - public function getRates() + public function getRates(): array { $shippingAddress = $this->getShippingAddress(); $shippingAddress->collectShippingRates(); @@ -71,7 +72,7 @@ public function isCurrentShippingRate(QuoteRate $carrierRate): bool return $carrierRate->getCode() === $this->getShippingAddress()->getShippingMethod(); } - public function getFormatedPrice($price) + public function getFormatedPrice($price): string { return $this->priceCurrency->convertAndFormat( $price, diff --git a/Block/Paypal/Script.php b/Block/Paypal/Script.php index 3863f235..64570cea 100644 --- a/Block/Paypal/Script.php +++ b/Block/Paypal/Script.php @@ -16,12 +16,12 @@ * @license https://opensource.org/licenses/mit-license.html MIT License * @link https://docs.checkout.com/ */ - namespace CheckoutCom\Magento2\Block\Paypal; use CheckoutCom\Magento2\Gateway\Config\Config; use CheckoutCom\Magento2\Model\Methods\PaypalMethod; use Magento\Framework\View\Element\Template; +use Magento\Framework\View\Element\Template\Context as TemplateContext; class Script extends Template { @@ -29,7 +29,7 @@ class Script extends Template private Config $checkoutConfig; public function __construct( - Template\Context $context, + TemplateContext $context, PaypalMethod $paypalMethod, Config $checkoutConfig, array $data = [] @@ -56,7 +56,7 @@ public function getPartnerAttributionId(): string public function getIntent(): string { - return $this->checkoutConfig->needsAutoCapture() ? 'capture' : 'authorize'; + return $this->checkoutConfig->needsAutoCapture() ? 'capture' : 'authorize'; } public function getCommit(): string diff --git a/Controller/Paypal/Context.php b/Controller/Paypal/Context.php index 38feb470..4659c3fb 100644 --- a/Controller/Paypal/Context.php +++ b/Controller/Paypal/Context.php @@ -1,5 +1,6 @@ Date: Thu, 7 Mar 2024 10:47:11 +0100 Subject: [PATCH 059/147] CHECMAG2003-206 - Code cleaning --- Block/Paypal/Review/ShippingMethod.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Block/Paypal/Review/ShippingMethod.php b/Block/Paypal/Review/ShippingMethod.php index 97fcb5be..4b900317 100644 --- a/Block/Paypal/Review/ShippingMethod.php +++ b/Block/Paypal/Review/ShippingMethod.php @@ -16,7 +16,6 @@ * @license https://opensource.org/licenses/mit-license.html MIT License * @link https://docs.checkout.com/ */ - namespace CheckoutCom\Magento2\Block\Paypal\Review; use CheckoutCom\Magento2\Controller\Paypal\Review; From 19b47ccfa963e51fda423994fcf62a2bf9b7c696 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Thu, 7 Mar 2024 10:54:44 +0100 Subject: [PATCH 060/147] CHECMAG2003-206 - Code cleaning --- Controller/Paypal/Review.php | 4 +++- Controller/Paypal/SaveExpressShippingAddress.php | 6 +++--- Controller/Paypal/SaveExpressShippingMethod.php | 7 +++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Controller/Paypal/Review.php b/Controller/Paypal/Review.php index 24cd4b0d..e87f03f0 100644 --- a/Controller/Paypal/Review.php +++ b/Controller/Paypal/Review.php @@ -23,8 +23,10 @@ use Magento\Checkout\Model\Session; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\RequestInterface; +use Magento\Framework\Controller\Result\Redirect; use Magento\Framework\Controller\Result\RedirectFactory; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Controller\ResultInterface; use Magento\Framework\Message\ManagerInterface; use Magento\Framework\UrlInterface; use Magento\Quote\Api\Data\PaymentInterface; @@ -70,7 +72,7 @@ public function __construct( /** * @inheritDoc */ - public function execute() + public function execute(): Redirect | ResultInterface { $resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE); diff --git a/Controller/Paypal/SaveExpressShippingAddress.php b/Controller/Paypal/SaveExpressShippingAddress.php index 888bac31..20754637 100644 --- a/Controller/Paypal/SaveExpressShippingAddress.php +++ b/Controller/Paypal/SaveExpressShippingAddress.php @@ -1,5 +1,6 @@ checkoutSession->getQuote(); diff --git a/Controller/Paypal/SaveExpressShippingMethod.php b/Controller/Paypal/SaveExpressShippingMethod.php index 92704a62..007ccb1c 100644 --- a/Controller/Paypal/SaveExpressShippingMethod.php +++ b/Controller/Paypal/SaveExpressShippingMethod.php @@ -1,5 +1,6 @@ checkoutSession->getQuote(); From 42bb2e3acdaf0d20a63abaca556b3e9cd319e788 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Thu, 7 Mar 2024 11:43:03 +0100 Subject: [PATCH 061/147] CHECMAG2003-206: paypal checkout payment method implementation and review page reformat --- .../layout/checkoutcom_paypal_review.xml | 2 +- .../method-renderer/checkoutcom_paypal.js | 281 +++++++++--------- .../checkoutcom_paypal_express.js | 6 +- .../checkoutcom_paypal_review.js | 90 +++--- 4 files changed, 192 insertions(+), 187 deletions(-) diff --git a/view/frontend/layout/checkoutcom_paypal_review.xml b/view/frontend/layout/checkoutcom_paypal_review.xml index 07872c84..907161e7 100644 --- a/view/frontend/layout/checkoutcom_paypal_review.xml +++ b/view/frontend/layout/checkoutcom_paypal_review.xml @@ -26,7 +26,7 @@ - + { + this.placeOrderEnable(true); + }).catch((error) => { + Utilities.log(error); + }); + }, + + /** + * @param {HTMLDivElement} element + * @return {void} + */ + renderPaypalButton: function (element) { + paypal.Buttons({ + createOrder: async () => { + return await this._getPaypalOrderId(); }, - - /** - * @return {exports} - */ - initialize: function() { - this._super(); - Utilities.loadCss('paypal', 'paypal'); - let self = this; - - //Todo: proper way to init, the paypal button must be loaded when - // #paypal-button-container is on the dom - setTimeout(function() { - self.initPaypalButton(); - }, 1000); - }, - - initPaypalButton: function() { - - let self = this; - - let containerSelector = '#paypal-button-container'; - let datas = {}; - - // Prepare Context - if ($(containerSelector).length > 0) { - $.ajax( - { - type: 'POST', - url: Utilities.getUrl('paypal/context'), - showLoader: true, - data: datas, - success: function(data) { - if (typeof data.content !== 'undefined') { - self.chkPayPalOrderid = data.content.partner_metadata.order_id; - self.chkPayPalContextId = data.content.id; - - // Init paypal button after getting context order id - paypal.Buttons({ - createOrder() { - return self.chkPayPalOrderid; - }, - onApprove: async function(data) { - self.placeOrder(); - }, - }).render(containerSelector); - - } - // Todo else message manager error - }, - error: function(request, status, error) { - // Todo message manager error - }, - }, - ); - } - }, - - /** - * @return {string} - */ - getCode: function() { - return METHOD_ID; + onApprove: async (data) => { + this.placeOrder(); }, - - /** - * @return {string} - */ - getValue: function(field) { - return Utilities.getValue(METHOD_ID, field); - }, - - /** - * @return {void} - */ - checkLastPaymentMethod: function() { - return Utilities.checkLastPaymentMethod(); - }, - - /** - * @return {void} - */ - placeOrder: function() { - FullScreenLoader.startLoader(); - - if (Utilities.methodIsSelected(METHOD_ID) && - this.chkPayPalContextId) { - let data = { - methodId: METHOD_ID, - contextPaymentId: this.chkPayPalContextId, - }; - - // Place the order - if (AdditionalValidators.validate()) { - Utilities.placeOrder( - data, - METHOD_ID, - function() { - Utilities.log(__('Success')); - }, - function() { - Utilities.log(__('Fail')); - }, - ); - Utilities.cleanCustomerShippingAddress(); - } - - FullScreenLoader.stopLoader(); - } + }).render(element); + }, + + /** + * @return {string} + */ + getCode: function () { + return METHOD_ID; + }, + + /** + * @param {string} field + * @return {string} + */ + getValue: function (field) { + return Utilities.getValue(METHOD_ID, field); + }, + + /** + * @return {void} + */ + checkLastPaymentMethod: function () { + return Utilities.checkLastPaymentMethod(); + }, + + /** + * @return {Promise} + */ + _getPaypalOrderId: function () { + return fetch(Url.build('checkout_com/paypal/context'), { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest' }, - }, - ); - }, -); + }) + .then(response => response.json()) + .then(response => { + this.chkPayPalContextId = response.content.id; + this.chkPayPalOrderid = response.content.partner_metadata.order_id; + + return this.chkPayPalOrderid; + }); + }, + + /** + * @return {void} + */ + placeOrder: function () { + FullScreenLoader.startLoader(); + + if (Utilities.methodIsSelected(METHOD_ID) && + this.chkPayPalContextId) { + let data = { + methodId: METHOD_ID, + contextPaymentId: this.chkPayPalContextId, + }; + + // Place the order + if (AdditionalValidators.validate()) { + Utilities.placeOrder( + data, + METHOD_ID, + function () { + Utilities.log(__('Success')); + }, + function () { + Utilities.log(__('Fail')); + }, + ); + Utilities.cleanCustomerShippingAddress(); + } + + FullScreenLoader.stopLoader(); + } + }, + }); +}); diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js index 0e43989a..86e6ba1e 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js @@ -17,10 +17,11 @@ define([ 'jquery', 'ko', 'uiComponent', + 'CheckoutCom_Magento2/js/view/payment/utilities', 'CheckoutCom_Magento2/js/view/payment/paypal-utilities', 'Magento_Customer/js/customer-data', 'mage/url', -], function ($, ko, Component, PaypalUtilities, CustomerData, Url) { +], function ($, ko, Component, Utilities, PaypalUtilities, CustomerData, Url) { 'use strict'; return Component.extend({ @@ -66,7 +67,7 @@ define([ scriptPromise.then(() => { this._initializePaypalExpressButton(); }).catch((error) => { - console.log(error); + Utilities.log(error); }); } }, @@ -126,7 +127,6 @@ define([ }, /** - * @private * @return {Promise} */ _getPaypalOrderId: function () { diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js index f9e4b5c5..abdd28cd 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js @@ -13,54 +13,60 @@ * @link https://docs.checkout.com/ */ -define( - [ - 'jquery', - 'CheckoutCom_Magento2/js/view/payment/utilities', - 'Magento_Checkout/js/model/full-screen-loader', - ], - function($, Utilities, FullScreenLoader) { - 'use strict'; +define([ + 'jquery', + 'CheckoutCom_Magento2/js/view/payment/utilities', +], function ($, Utilities) { + 'use strict'; - $.widget('checkoutcom.paypalreviewplaceorder', { + $.widget('checkoutCom.paypalReviewPlaceorder', { - _create: function(config, element) { - let self = this; + /** + * @return {void} + */ + _create: function () { + this._eventListeners() + }, - $(this.options.buttonSelector).click(function() { - self.placeOrder(); - }); - }, + /** + * @return {void} + */ + _eventListeners () { + $(this.options.buttonSelector).on('click', (event) => { + this.placeOrder(event); + }); + }, - /** - * @return {void} - */ - placeOrder: function() { - FullScreenLoader.startLoader(); - let self = this; + /** + * @param {jQuery.Event} event + * @return {void} + */ + placeOrder: function (event) { + $('body').trigger('processStart'); - if (this.options.chkPayPalContextId) { - $(this.options.buttonSelector).attr('disabled', 'disabled'); - setTimeout(function(){ - $(self.options.buttonSelector).removeAttr('disabled'); - },1500); + if (this.options.chkPayPalContextId) { + const submitButton = $(event.currentTarget); + const data = { + methodId: this.options.methodId, + contextPaymentId: this.options.chkPayPalContextId, + }; - let data = { - methodId: this.options.methodId, - contextPaymentId: this.options.chkPayPalContextId, - }; + submitButton.attr('disabled', 'disabled'); - // Place the order - Utilities.placeOrder( - data, - this.options.methodId, - true - ); - Utilities.cleanCustomerShippingAddress(); + // Place the order + Utilities.placeOrder( + data, + this.options.methodId, + true + ) + .catch((data) => { + $('body').trigger('processStop'); + }); - FullScreenLoader.stopLoader(); - } - }, - }); - return $.checkoutcom.paypalreviewplaceorder; + Utilities.cleanCustomerShippingAddress(); + } + }, }); + + return $.checkoutCom.paypalReviewPlaceorder; +}); From fd7a0645005400ebcba7b08537efe1e58f6073f1 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Thu, 7 Mar 2024 11:49:08 +0100 Subject: [PATCH 062/147] CHECMAG2003-206 - Log technical message and display generic messages --- Controller/Paypal/SaveData.php | 4 ++++ Controller/Paypal/SaveExpressShippingAddress.php | 3 ++- Controller/Paypal/SaveExpressShippingMethod.php | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Controller/Paypal/SaveData.php b/Controller/Paypal/SaveData.php index 1fed7546..a5c275bd 100644 --- a/Controller/Paypal/SaveData.php +++ b/Controller/Paypal/SaveData.php @@ -17,6 +17,7 @@ */ namespace CheckoutCom\Magento2\Controller\Paypal; +use CheckoutCom\Magento2\Helper\Logger as LoggerHelper; use CheckoutCom\Magento2\Model\Methods\PaypalMethod; use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; use Magento\Checkout\Model\Session; @@ -44,8 +45,10 @@ class SaveData protected CartRepositoryInterface $cartRepository; protected AddressInterfaceFactory $addressInterfaceFactory; protected PaypalMethod $paypalMethod; + protected LoggerHelper $logger; public function __construct( + LoggerHelper $loggerHelper, ResultFactory $resultFactory, ManagerInterface $messageManager, RequestInterface $request, @@ -67,6 +70,7 @@ public function __construct( $this->cartRepository = $cartRepository; $this->addressInterfaceFactory = $addressInterfaceFactory; $this->paypalMethod = $paypalMethod; + $this->logger = $loggerHelper; } /** diff --git a/Controller/Paypal/SaveExpressShippingAddress.php b/Controller/Paypal/SaveExpressShippingAddress.php index 20754637..87b70bce 100644 --- a/Controller/Paypal/SaveExpressShippingAddress.php +++ b/Controller/Paypal/SaveExpressShippingAddress.php @@ -58,7 +58,8 @@ public function execute(): Redirect } } } catch (Exception $e) { - $this->messageManager->addErrorMessage(__('Unable to save Address: ' . $e->getMessage())); + $this->logger->write(__('Error occured while saving paypal express shipping address: %1', $e->getMessage())); + $this->messageManager->addErrorMessage(__('Unable to save Addres')); } return $this->redirectFactory->create()->setRefererUrl(); diff --git a/Controller/Paypal/SaveExpressShippingMethod.php b/Controller/Paypal/SaveExpressShippingMethod.php index 007ccb1c..a44b6ad0 100644 --- a/Controller/Paypal/SaveExpressShippingMethod.php +++ b/Controller/Paypal/SaveExpressShippingMethod.php @@ -55,7 +55,8 @@ public function execute(): Redirect $this->cartRepository->save($quote); } catch (Exception $e) { - $this->messageManager->addErrorMessage(__($e->getMessage())); + $this->logger->write(__('Error occured while saving paypal express shipping method: %1', $e->getMessage())); + $this->messageManager->addErrorMessage(__('An error occurred while saving shipping method')); } return $this->redirectFactory->create()->setRefererUrl(); From 810fd83a8ff3d1cd4d848c96fe5eee01d5b84064 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Thu, 7 Mar 2024 14:29:17 +0100 Subject: [PATCH 063/147] CHECMAG2003-206: remove Utilities use on express paypal method --- .../payment/method-renderer/checkoutcom_paypal_express.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js index 86e6ba1e..282e17d1 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_express.js @@ -17,11 +17,10 @@ define([ 'jquery', 'ko', 'uiComponent', - 'CheckoutCom_Magento2/js/view/payment/utilities', 'CheckoutCom_Magento2/js/view/payment/paypal-utilities', 'Magento_Customer/js/customer-data', 'mage/url', -], function ($, ko, Component, Utilities, PaypalUtilities, CustomerData, Url) { +], function ($, ko, Component, PaypalUtilities, CustomerData, Url) { 'use strict'; return Component.extend({ @@ -67,7 +66,7 @@ define([ scriptPromise.then(() => { this._initializePaypalExpressButton(); }).catch((error) => { - Utilities.log(error); + }); } }, From f2633a94a2cecc771d5612ee620b8e333b73a646 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Thu, 7 Mar 2024 18:01:02 +0100 Subject: [PATCH 064/147] CHECMAG2003-206: paypal express review page integration --- .../layout/checkoutcom_paypal_review.xml | 4 +- .../templates/cart/minicart-config.phtml | 7 ++- .../templates/payment/paypal/review.phtml | 53 +++++++++++++++++++ .../paypal/review/payment-method.phtml | 2 +- .../payment/paypal/review/place-order.phtml | 16 +++--- .../paypal/review/shipping-method.phtml | 9 ++-- view/frontend/web/css/paypal/paypal.css | 29 ++++++++++ .../method-renderer/checkoutcom_apple_pay.js | 1 + .../checkoutcom_paypal_review.js | 20 ++++--- .../frontend/web/js/view/payment/utilities.js | 8 ++- 10 files changed, 122 insertions(+), 27 deletions(-) create mode 100644 view/frontend/templates/payment/paypal/review.phtml diff --git a/view/frontend/layout/checkoutcom_paypal_review.xml b/view/frontend/layout/checkoutcom_paypal_review.xml index 907161e7..3dca2021 100644 --- a/view/frontend/layout/checkoutcom_paypal_review.xml +++ b/view/frontend/layout/checkoutcom_paypal_review.xml @@ -26,7 +26,7 @@ - + - + diff --git a/view/frontend/templates/cart/minicart-config.phtml b/view/frontend/templates/cart/minicart-config.phtml index 2c43de4f..20d44f73 100644 --- a/view/frontend/templates/cart/minicart-config.phtml +++ b/view/frontend/templates/cart/minicart-config.phtml @@ -6,8 +6,11 @@ * @link https://www.dnd.fr/ */ -/** @var \CheckoutCom\Magento2\Block\Cart\ApplePay $block */ -/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */ +use CheckoutCom\Magento2\Block\Cart\CheckoutConfig; +use Magento\Framework\View\Helper\SecureHtmlRenderer; + +/** @var CheckoutConfig $block */ +/** @var SecureHtmlRenderer $secureRenderer */ ?> getProductCount() > 0 ? $block->getSerializedCheckoutConfig() : $block->getSerializedCheckoutComConfig(); $scriptString = << diff --git a/view/frontend/templates/payment/paypal/review/shipping-method.phtml b/view/frontend/templates/payment/paypal/review/shipping-method.phtml index 5c36aaf9..1a67bd1d 100644 --- a/view/frontend/templates/payment/paypal/review/shipping-method.phtml +++ b/view/frontend/templates/payment/paypal/review/shipping-method.phtml @@ -24,7 +24,7 @@ use Magento\Framework\Escaper; $rates = $block->getRates(); ?> -
+
escapeHtml(__('Shipping Method')) ?>
@@ -33,14 +33,15 @@ $rates = $block->getRates(); isCurrentShippingRate($carrierMethod); ?> + class="item" + href="escapeHtmlAttr($block->getShippingMethodUpdateUrl($carrierMethod)); ?>"> - + escapeHtml($carrierMethod->getCarrierTitle()) ?> - escapeHtml($carrierMethod->getMethodTitle()) ?> - getFormatedPrice($carrierMethod->getPrice()) ?> + $block->getFormatedPrice($carrierMethod->getPrice()) ?> diff --git a/view/frontend/web/css/paypal/paypal.css b/view/frontend/web/css/paypal/paypal.css index e69de29b..f7efe4b0 100644 --- a/view/frontend/web/css/paypal/paypal.css +++ b/view/frontend/web/css/paypal/paypal.css @@ -0,0 +1,29 @@ +.checkoutcom-paypal-review .box .box-title { + display: block; + margin: 0 0 20px; + padding: 0 0 10px; + width: 100%; + box-sizing: border-box; +} + +.checkoutcom-paypal-review .box .box-title span { + font-weight: 300; + line-height: 1.2; + font-size: 18px; +} + +.checkoutcom-paypal-review .box-order-shipping-method .item { + display: block; +} + +@media screen and (min-width: 769px) { + .checkoutcom-paypal-review .boxes { + display: grid; + gap: 4%; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .checkoutcom-paypal-review .box .box-title { + border-bottom: 1px solid #C5C5C5; + } +} diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js index 45db58ac..25636cd0 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js @@ -30,6 +30,7 @@ define( ko, Component, Utilities, + Utilities, ApplePayUtilities, FullScreenLoader, AdditionalValidators, diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js index abdd28cd..b8d1c92b 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal_review.js @@ -25,14 +25,22 @@ define([ * @return {void} */ _create: function () { - this._eventListeners() + this.editAddressForm = this.element.find('.form-address-edit'); + this.submitButton = this.element.find(this.options.buttonSelector); + + Utilities.loadCss('paypal', 'paypal'); + this._eventListeners(); + + if (!this.editAddressForm.validation('isValid')) { + this.submitButton.attr('disabled', 'true'); + } }, /** * @return {void} */ _eventListeners () { - $(this.options.buttonSelector).on('click', (event) => { + this.submitButton.on('click', (event) => { this.placeOrder(event); }); }, @@ -51,19 +59,19 @@ define([ contextPaymentId: this.options.chkPayPalContextId, }; - submitButton.attr('disabled', 'disabled'); - // Place the order Utilities.placeOrder( data, this.options.methodId, - true + false ) - .catch((data) => { + .then(() => { $('body').trigger('processStop'); }); Utilities.cleanCustomerShippingAddress(); + } else { + $('body').trigger('processStop'); } }, }); diff --git a/view/frontend/web/js/view/payment/utilities.js b/view/frontend/web/js/view/payment/utilities.js index d68f732e..fd955f1c 100755 --- a/view/frontend/web/js/view/payment/utilities.js +++ b/view/frontend/web/js/view/payment/utilities.js @@ -70,8 +70,12 @@ define( var cssPath = window.checkoutConfig.payment.checkoutcom_magento2.checkoutcom_data.css_path; cssPath += folderPath + '/' + fileName + ext; - // Append the CSS file - $('head').append(''); + const css = document.createElement('link'); + css.rel = 'stylesheet'; + css.media = 'all'; + css.href = cssPath; + + document.head.appendChild(css); }, /** From 11741db55586e3c4cb900074d5f7ee20f3e3522b Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Fri, 8 Mar 2024 11:53:43 +0100 Subject: [PATCH 065/147] CHECMAG2003-206: remove old javascript file --- .../web/js/view/minicart/paypalbutton.js | 119 ------------------ 1 file changed, 119 deletions(-) delete mode 100644 view/frontend/web/js/view/minicart/paypalbutton.js diff --git a/view/frontend/web/js/view/minicart/paypalbutton.js b/view/frontend/web/js/view/minicart/paypalbutton.js deleted file mode 100644 index 80cd3cd3..00000000 --- a/view/frontend/web/js/view/minicart/paypalbutton.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @author Agence Dn'D - * @copyright 2004-present Agence Dn'D - * @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * @link https://www.dnd.fr/ - */ - -define([ - 'jquery', - 'ko', - 'uiComponent', - 'Magento_Customer/js/customer-data', - 'Magento_Customer/js/model/customer', - 'mage/url', - 'Magento_Checkout/js/model/full-screen-loader', -], function($, ko, Component, customerData, customer, Url, FullScreenLoader) { - 'use strict'; - - return Component.extend({ - isVisible: ko.observable(false), - chkPayPalOrderid: null, - chkPayPalContextId: null, - - initialize: function() { - this._super(); - let cartData = customerData.get('cart'); - - this.isVisible(cartData()['summary_count'] > 0 - && ((cartData()['isGuestCheckoutAllowed']) || - (!cartData()['isGuestCheckoutAllowed'] && - customer.isLoggedIn())) - && cartData()['checkoutcom_paypal'] - && cartData()['checkoutcom_paypal']['express_minicart'] === '1' - && cartData()['checkoutcom_paypal']['active'] === '1', - ); - - if (this.isVisible) { - this.setCkcContext(); - } - - cartData.subscribe((updatedCart) => { - if (typeof window.checkoutConfig !== 'undefined' - && typeof window.checkoutConfig.quoteId === 'undefined') { - window.checkoutConfig = {...updatedCart['checkoutConfigProvider']}; - } - - this.isVisible(updatedCart['summary_count'] > 0 - && ((cartData()['isGuestCheckoutAllowed']) || - (!cartData()['isGuestCheckoutAllowed'] && - customer.isLoggedIn())) - && updatedCart['checkoutcom_paypal'] - && updatedCart['checkoutcom_paypal']['express_minicart'] === - '1' - && updatedCart['checkoutcom_paypal']['active'] === '1'); - - if (this.isVisible) { - this.setCkcContext(); - } - }); - }, - - setCkcContext: function() { - let self = this; - // THIS SCRIPT (Utilities.getUrl('paypal/context')) HAS TO BE CALLED ON THE 'createOrder' event of the paypal button - // The call must not be async and the 'createOrder' should return the order id - //Todo: proper way to init, the paypal button must be loaded when - // #paypal-button-container is on the dom - setTimeout(function() { - self.initPaypalButton(); - }, 1500); - }, - - // Has to be factored, it's used 3 times on the whole code - initPaypalButton: function() { - - let self = this; - - // Prepare Context - let containerSelector = '#minicart-paypal-button-container'; - let datas = {forceAuthorizeMode: 0}; - - if ($(containerSelector).length > 0) { - $.ajax( - { - type: 'POST', - url: Url.build('checkout_com/paypal/context'), - showLoader: false, - data: datas, - success: function(data) { - if (typeof data.content !== 'undefined') { - self.chkPayPalOrderid = data.content.partner_metadata.order_id; - self.chkPayPalContextId = data.content.id; - - // Init paypal button after getting context order id - paypal.Buttons({ - createOrder() { - return self.chkPayPalOrderid; - }, - onApprove: async function(data) { - // Redirect on paypal reviex page (express checkout) - FullScreenLoader.startLoader(); - window.location.href = Url.build( - 'checkout_com/paypal/review/contextId/' + - self.chkPayPalContextId); - }, - }).render(containerSelector); - - } - // Todo else message manager error - }, - error: function(request, status, error) { - // Todo message manager error - }, - }, - ); - } - }, - }); -}); From 26f0f33f3967b6d5f3335fc4506166d9ceeeab28 Mon Sep 17 00:00:00 2001 From: Arnaud Savoye Date: Fri, 8 Mar 2024 16:46:31 +0100 Subject: [PATCH 066/147] CHECMAG2003-215 Modify giropay nas and abc --- Model/Methods/AlternativePaymentMethod.php | 27 ++++++++++------------ 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Model/Methods/AlternativePaymentMethod.php b/Model/Methods/AlternativePaymentMethod.php index 77fec72f..30e81147 100755 --- a/Model/Methods/AlternativePaymentMethod.php +++ b/Model/Methods/AlternativePaymentMethod.php @@ -27,7 +27,8 @@ use Checkout\Payments\Previous\Source\Apm\RequestBoletoSource; use Checkout\Payments\Previous\Source\Apm\RequestEpsSource as PreviousRequestEpsSource; use Checkout\Payments\Previous\Source\Apm\RequestFawrySource as PreviousRequestFawrySource; -use Checkout\Payments\Previous\Source\Apm\RequestGiropaySource; +use Checkout\Payments\Previous\Source\Apm\RequestGiropaySource as PreviousRequestGiropaySource; +use Checkout\Payments\Request\Source\Apm\RequestGiropaySource; use Checkout\Payments\Previous\Source\Apm\RequestIdealSource as PreviousRequestIdealSource; use Checkout\Payments\Previous\Source\Apm\RequestKlarnaSource; use Checkout\Payments\Previous\Source\Apm\RequestKnetSource; @@ -103,7 +104,6 @@ class AlternativePaymentMethod extends AbstractMethod const NAS_UNAVAILABLE_APM = [ 'alipay', 'boleto', - 'giropay', 'klarna', 'poli', 'sepa', @@ -682,22 +682,19 @@ public function boleto(array $data): RequestBoletoSource * * @param array $data * - * @return RequestGiropaySource + * @return RequestGiropaySource|PreviousRequestGiropaySource * @throws NoSuchEntityException */ - public function giropay(array $data): RequestGiropaySource + public function giropay(array $data) { - /** @var string $purpose */ - $purpose = substr( - (string)__('Pay. req. from %1', $this->config->getStoreName()), - 0, - 27 - ); - - $source = new RequestGiropaySource(); - $source->purpose = null; - $source->bic = $this->getValue('bic', $data); - $source->info_fields = null; + if ($this->apiHandler->isPreviousMode()) { + $source = new PreviousRequestGiropaySource(); + $source->purpose = null; + $source->bic = $this->getValue('bic', $data); + $source->info_fields = null; + } else { + $source = new RequestGiropaySource(); + } return $source; } From 8630fde6ef86764e655cdd161a8484b053c0b638 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Mon, 11 Mar 2024 10:20:01 +0100 Subject: [PATCH 067/147] CHECMAG2003-206: add error message logger on checkout --- Controller/Paypal/Review.php | 4 ++-- i18n/en_GB.csv | 1 + i18n/en_US.csv | 1 + .../payment/method-renderer/checkoutcom_paypal.js | 11 ++++------- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Controller/Paypal/Review.php b/Controller/Paypal/Review.php index e87f03f0..5eafb881 100644 --- a/Controller/Paypal/Review.php +++ b/Controller/Paypal/Review.php @@ -70,9 +70,9 @@ public function __construct( } /** - * @inheritDoc + * @return Page|Redirect */ - public function execute(): Redirect | ResultInterface + public function execute() { $resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE); diff --git a/i18n/en_GB.csv b/i18n/en_GB.csv index 49af47a1..eb9bdef6 100644 --- a/i18n/en_GB.csv +++ b/i18n/en_GB.csv @@ -185,3 +185,4 @@ Debitor,Debitor "Street and Postal Not Verified","Street and Postal Not Verified" "The issuer has not certified or has not provided the encryption keys to the interchange","The issuer has not certified or has not provided the encryption keys to the interchange" "Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.","Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers." +"Something went wrong with paypal method. Please choose another method.","Something went wrong with paypal method. Please choose another method." diff --git a/i18n/en_US.csv b/i18n/en_US.csv index 49af47a1..eb9bdef6 100644 --- a/i18n/en_US.csv +++ b/i18n/en_US.csv @@ -185,3 +185,4 @@ Debitor,Debitor "Street and Postal Not Verified","Street and Postal Not Verified" "The issuer has not certified or has not provided the encryption keys to the interchange","The issuer has not certified or has not provided the encryption keys to the interchange" "Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.","Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers." +"Something went wrong with paypal method. Please choose another method.","Something went wrong with paypal method. Please choose another method." diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js index 6319942b..3d3f8240 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js @@ -81,13 +81,6 @@ define([ }).render(element); }, - /** - * @return {string} - */ - getCode: function () { - return METHOD_ID; - }, - /** * @param {string} field * @return {string} @@ -120,6 +113,10 @@ define([ this.chkPayPalOrderid = response.content.partner_metadata.order_id; return this.chkPayPalOrderid; + }) + .catch((response) => { + Utilities.log(response); + Utilities.showMessage('error', __('Something went wrong with paypal method. Please choose another method.'), METHOD_ID); }); }, From 76a65474bbbabfdfd9ff296f1dcc3795d16ecfd9 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Mon, 11 Mar 2024 10:20:20 +0100 Subject: [PATCH 068/147] CHECMAG2003-206 - Do not send free shipping on payment request --- Model/Service/PaymentContextRequestService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index 24a4e4d0..c234f46d 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -238,7 +238,7 @@ public function getRequestItems(Quote | CartInterface $quote): array // Shipping fee $shipping = $quote->getShippingAddress(); - if ($shipping->getShippingDescription()) { + if ($shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { $product = new PaymentContextsItems(); $product->name = $shipping->getShippingDescription(); $product->quantity = 1; From 3770fa93cfbb61ef25d3e01be1ae8902b5ca86a0 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Mon, 11 Mar 2024 10:59:04 +0100 Subject: [PATCH 069/147] CHECMAG2003-206: sort CSV lines --- i18n/en_GB.csv | 298 ++++++++++++++++++++++++------------------------- i18n/en_US.csv | 298 ++++++++++++++++++++++++------------------------- 2 files changed, 294 insertions(+), 302 deletions(-) diff --git a/i18n/en_GB.csv b/i18n/en_GB.csv index eb9bdef6..06f0b4da 100644 --- a/i18n/en_GB.csv +++ b/i18n/en_GB.csv @@ -1,163 +1,37 @@ -"Please keep your website safe! Your checkout plugin (v' . . ') is not the latest version (v' . . '). - Update now to get the latest features and security updates. - See https://github.com/checkout/checkout-magento2-plugin for detailed instructions.","Please keep your website safe! Your checkout plugin (v' . . ') is not the latest version (v' . . '). - Update now to get the latest features and security updates. - See https://github.com/checkout/checkout-magento2-plugin for detailed instructions." -Configure,Configure -Close,Close -"Learn More","Learn More" -"View Demo","View Demo" -"The payment card has been stored successfully.","The payment card has been stored successfully." -"The card could not be saved.","The card could not be saved." -"The payment request was declined by the gateway.","The payment request was declined by the gateway." -"The order could not be created.","The order could not be created." -"The request is invalid.","The request is invalid." -"No quote was found with the provided ID.","No quote was found with the provided ID." -"The quote ID is missing or invalid.","The quote ID is missing or invalid." -"The payment token is missing or invalid.","The payment token is missing or invalid." -"The public key is invalid.","The public key is invalid." -"No quote found with the provided ID","No quote found with the provided ID" -"Payment token provided is not a string","Payment token provided is not a string" -"Payment token provided is empty string","Payment token provided is empty string" -"Payment token is missing from request body","Payment token is missing from request body" -"Quote ID provided must be a positive integer","Quote ID provided must be a positive integer" -"Quote ID is missing from request body","Quote ID is missing from request body" -"Card BIN is empty string","Card BIN is empty string" -"Success URL provided is not a string","Success URL provided is not a string" -"Success URL is empty string","Success URL is empty string" -"Failure URL provided is not a string","Failure URL provided is not a string" -"Failure URL is empty string","Failure URL is empty string" -"An error occurred and the order could not be created.","An error occurred and the order could not be created." -"Your order number %1 has been created successfully.","Your order number %1 has been created successfully." -"The transaction could not be processed.","The transaction could not be processed." -"The order could not be processed.","The order could not be processed." -"The request is invalid or there was no quote found.","The request is invalid or there was no quote found." -"Please enter valid card details.","Please enter valid card details." -"The transaction could not be processed or has been cancelled.","The transaction could not be processed or has been cancelled." -"Invalid request. No order found.","Invalid request. No order found." -"Invalid request. No session ID found.","Invalid request. No session ID found." -"Webhook and order successfully processed.","Webhook and order successfully processed." -"The order creation failed. Please check the error logs.","The order creation failed. Please check the error logs." -"The webhook response is invalid.","The webhook response is invalid." -"The webhook payment response is invalid.","The webhook payment response is invalid." -"Unauthorized request. No matching private shared key.","Unauthorized request. No matching private shared key." -Black,Black -White,White -"White with line","White with line" -"Credit cards","Credit cards" -"Debit cards","Debit cards" -Visa,Visa -Mastercard,Mastercard -"American Express","American Express" -None,None -title,title -Test,Test -Production,Production -Standard,Standard -Simple,Simple -JCB,JCB -Discover,Discover -English,English -Spanish,Spanish -German,German -Korean,Korean -French,French -Italian,Italian -Dutch,Dutch -"Cancel the order","Cancel the order" -"Delete the order","Delete the order" -"Do nothing","Do nothing" -Processing,Processing -Pending,Pending -Authorize,Authorize -"Authorize and Capture","Authorize and Capture" -"Single iframe","Single iframe" -"Multiple iframes","Multiple iframes" -Webhook,Webhook -"Cron Job","Cron Job" -"Payment request from %1","Payment request from %1" -"The capture action is not available.","The capture action is not available." -"The capture request could not be processed.","The capture request could not be processed." -"The void action is not available.","The void action is not available." -"The void request could not be processed.","The void request could not be processed." -"The refund action is not available.","The refund action is not available." -"The refund request could not be processed.","The refund request could not be processed." -"The CVV value is required.","The CVV value is required." -"There is no quote available to place an order.","There is no quote available to place an order." -"A payment method ID is required to place an order.","A payment method ID is required to place an order." " for an amount of %1. Action ID: %2. Event ID: %3. Payment ID: %4. Error: %5 %6"," for an amount of %1. Action ID: %2. Event ID: %3. Payment ID: %4. Error: %5 %6" -"The payment was declined, please try again. If the problem persists, try another card or payment method.","The payment was declined, please try again. If the problem persists, try another card or payment method." -"You have reached the limit allowed for this card/account, please try again with another card or payment method.","You have reached the limit allowed for this card/account, please try again with another card or payment method." -"Something went wrong, please try again later","Something went wrong, please try again later" -"It looks like your card is invalid or blocked, please try with another card","It looks like your card is invalid or blocked, please try with another card" -"It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method","It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method" +"3DS authorization code","3DS authorization code" "3DS has expired or authentication failed, please try again","3DS has expired or authentication failed, please try again" -"The transaction could not be processed","The transaction could not be processed" -"Payment capture initiated, awaiting capture confirmation.","Payment capture initiated, awaiting capture confirmation." "3DS payment expired.","3DS payment expired." -"This card is already saved.","This card is already saved." -ending,ending -expires,expires -"Missing action ID for webhook with payment ID %","Missing action ID for webhook with payment ID %" -"The payment request was successfully processed.","The payment request was successfully processed." -"The transaction could not be processed. Please check the payment details.","The transaction could not be processed. Please check the payment details." -"Please provide the required card information for the MOTO payment.","Please provide the required card information for the MOTO payment." -"Missing required card information for the MOTO payment.","Missing required card information for the MOTO payment." -CVV,CVV -"Get your credentials here.","Get your credentials here." -"Add a card","Add a card" -"Save the card","Save the card" -"Card Number","Card Number" -"Expiration Date","Expiration Date" -Type,Type -Actions,Actions -Delete,Delete -"The card ending with %1 will be deleted.","The card ending with %1 will be deleted." -"Delete a card","Delete a card" -Name,Name -"Cadastro de Pessoas Físicas or Cadastro Nacional da Pessoa Jurídica","Cadastro de Pessoas Físicas or Cadastro Nacional da Pessoa Jurídica" -"Birth date (YYYY-MM-DD)","Birth date (YYYY-MM-DD)" -BIC,BIC -Description,Description -"Could not load the Klarna script.","Could not load the Klarna script." -"Account IBAN","Account IBAN" -Continue,Continue -"SEPA Direct Debit Mandate for single payment","SEPA Direct Debit Mandate for single payment" -Creditor,Creditor -"Creditor ID","Creditor ID" -Debitor,Debitor -"By accepting this mandate form, you authorise (A) b4payment GmbH to send instructions to your bank to debit your account (B) your bank to debit your account in accordance with the instructions from b4payment GmbH.","By accepting this mandate form, you authorise (A) b4payment GmbH to send instructions to your bank to debit your account (B) your bank to debit your account in accordance with the instructions from b4payment GmbH." -"As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited.","As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited." -"I accept the mandate for a single payment","I accept the mandate for a single payment" -"Your rights regarding the above mandate are explained in a statement that you can obtain from your bank.","Your rights regarding the above mandate are explained in a statement that you can obtain from your bank." -"Place Order","Place Order" -"Card number","Card number" -"Save this card for later use.","Save this card for later use." -"Set Webhooks","Set Webhooks" -"Attention, webhook not properly configured!","Attention, webhook not properly configured!" -"Your webhook is all set!","Your webhook is all set!" -"Error! Could not set webhooks. Please check your secret key.","Error! Could not set webhooks. Please check your secret key." -"Attention, secret key incorrect!","Attention, secret key incorrect!" -"Use Risk Rules For MOTO","Use Risk Rules For MOTO" -"3DS authorization code","3DS authorization code" -"Payment Method refunded","Payment Method refunded" -"Mismatched Address (fraud check)","Mismatched Address (fraud check)" -"Alternative payment method","Alternative payment method" -"Transaction Id","Transaction Id" -"Card Country","Card Country" -"Card Bank","Card Bank" -"Card expiry year","Card expiry year" -"Card expiry month","Card expiry month" -"Card 4 last numbers","Card 4 last numbers" -"Card type","Card type" -"Payment Additional Information","Payment Additional Information" "5 Digit Postal Match","5 Digit Postal Match" +"A payment method ID is required to place an order.","A payment method ID is required to place an order." "AVS Not Available","AVS Not Available" +"Account IBAN","Account IBAN" +"Add a card","Add a card" +"Alternative payment method","Alternative payment method" +"American Express","American Express" +"An error occurred and the order could not be created.","An error occurred and the order could not be created." +"As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited.","As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited." "Attempt at processing performed. Not authenticated or verified, but a proof of attempted authentication/verification is provided.","Attempt at processing performed. Not authenticated or verified, but a proof of attempted authentication/verification is provided." +"Attention, secret key incorrect!","Attention, secret key incorrect!" +"Attention, webhook not properly configured!","Attention, webhook not properly configured!" "Authentication or account verification could not be performed. This is due to a technical problem, or another problem as indicated in ARes or RReq.","Authentication or account verification could not be performed. This is due to a technical problem, or another problem as indicated in ARes or RReq." "Authentication or account verification rejected. Issuer is rejecting and requests that authorization not be attempted.","Authentication or account verification rejected. Issuer is rejecting and requests that authorization not be attempted." "Authentication verification successful.","Authentication verification successful." +"Authorize and Capture","Authorize and Capture" "Authorizing entity has not attempted card verification or could not verify the CVD due to a security device error","Authorizing entity has not attempted card verification or could not verify the CVD due to a security device error" +"Birth date (YYYY-MM-DD)","Birth date (YYYY-MM-DD)" +"By accepting this mandate form, you authorise (A) b4payment GmbH to send instructions to your bank to debit your account (B) your bank to debit your account in accordance with the instructions from b4payment GmbH.","By accepting this mandate form, you authorise (A) b4payment GmbH to send instructions to your bank to debit your account (B) your bank to debit your account in accordance with the instructions from b4payment GmbH." +"Cadastro de Pessoas Físicas or Cadastro Nacional da Pessoa Jurídica","Cadastro de Pessoas Físicas or Cadastro Nacional da Pessoa Jurídica" +"Cancel the order","Cancel the order" +"Card 4 last numbers","Card 4 last numbers" +"Card BIN is empty string","Card BIN is empty string" +"Card Bank","Card Bank" +"Card Country","Card Country" +"Card Number","Card Number" +"Card expiry month","Card expiry month" +"Card expiry year","Card expiry year" +"Card number","Card number" +"Card type","Card type" "Card verification not performed, CVD was not on the card. Not all cards have a CVD value encoded","Card verification not performed, CVD was not on the card. Not all cards have a CVD value encoded" "Card verification performed, and CVD was invalid","Card verification performed, and CVD was invalid" "Card verification performed, and CVD was valid","Card verification performed, and CVD was valid" @@ -170,19 +44,141 @@ Debitor,Debitor "Cardholder Name, Street and Postal/ZIP Match","Cardholder Name, Street and Postal/ZIP Match" "Challenge required. Additional authentication is required using the CReq or CRes.","Challenge required. Additional authentication is required using the CReq or CRes." "Challenge required. Decoupled authentication confirmed.","Challenge required. Decoupled authentication confirmed." +"Could not load the Klarna script.","Could not load the Klarna script." +"Credit cards","Credit cards" +"Creditor ID","Creditor ID" +"Cron Job","Cron Job" +"Debit cards","Debit cards" +"Delete a card","Delete a card" +"Delete the order","Delete the order" +"Do nothing","Do nothing" +"Error! Could not set webhooks. Please check your secret key.","Error! Could not set webhooks. Please check your secret key." +"Expiration Date","Expiration Date" +"Failure URL is empty string","Failure URL is empty string" +"Failure URL provided is not a string","Failure URL provided is not a string" +"Get your credentials here.","Get your credentials here." +"I accept the mandate for a single payment","I accept the mandate for a single payment" "Informational only. 3DS requestor challenge preference acknowledged.","Informational only. 3DS requestor challenge preference acknowledged." +"Invalid request. No order found.","Invalid request. No order found." +"Invalid request. No session ID found.","Invalid request. No session ID found." +"It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method","It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method" +"It looks like your card is invalid or blocked, please try with another card","It looks like your card is invalid or blocked, please try with another card" +"Learn More","Learn More" "Match Not Capable","Match Not Capable" +"Mismatched Address (fraud check)","Mismatched Address (fraud check)" +"Missing action ID for webhook with payment ID %","Missing action ID for webhook with payment ID %" +"Missing required card information for the MOTO payment.","Missing required card information for the MOTO payment." +"Multiple iframes","Multiple iframes" "No Address Match","No Address Match" "No CVV2 information is available",,"No CVV2 information is available" +"No quote found with the provided ID","No quote found with the provided ID" +"No quote was found with the provided ID.","No quote was found with the provided ID." "Not Verified or Not Supported","Not Verified or Not Supported" "Not authenticated or account not verified. This means the transaction was denied.","Not authenticated or account not verified. This means the transaction was denied." "Not supported","Not supported" +"Payment Additional Information","Payment Additional Information" +"Payment Method refunded","Payment Method refunded" +"Payment capture initiated, awaiting capture confirmation.","Payment capture initiated, awaiting capture confirmation." +"Payment request from %1","Payment request from %1" +"Payment token is missing from request body","Payment token is missing from request body" +"Payment token provided is empty string","Payment token provided is empty string" +"Payment token provided is not a string","Payment token provided is not a string" +"Place Order","Place Order" +"Please enter valid card details.","Please enter valid card details." +"Please keep your website safe! Your checkout plugin (v' . . ') is not the latest version (v' . . '). Update now to get the latest features and security updates. See https://github.com/checkout/checkout-magento2-plugin for detailed instructions.","Please keep your website safe! Your checkout plugin (v' . . ') is not the latest version (v' . . '). Update now to get the latest features and security updates. See https://github.com/checkout/checkout-magento2-plugin for detailed instructions." +"Please provide the required card information for the MOTO payment.","Please provide the required card information for the MOTO payment." +"Quote ID is missing from request body","Quote ID is missing from request body" +"Quote ID provided must be a positive integer","Quote ID provided must be a positive integer" +"SEPA Direct Debit Mandate for single payment","SEPA Direct Debit Mandate for single payment" +"Save the card","Save the card" +"Save this card for later use.","Save this card for later use." +"Set Webhooks","Set Webhooks" +"Single iframe","Single iframe" +"Something went wrong with paypal method. Please choose another method.","Something went wrong with paypal method. Please choose another method." +"Something went wrong, please try again later","Something went wrong, please try again later" "Street Match Postal Not Verified","Street Match Postal Not Verified" "Street Match","Street Match" "Street Not Verified Postal Match","Street Not Verified Postal Match" "Street and 5 Digit Postal Match","Street and 5 Digit Postal Match" "Street and Postal Match","Street and Postal Match" "Street and Postal Not Verified","Street and Postal Not Verified" +"Success URL is empty string","Success URL is empty string" +"Success URL provided is not a string","Success URL provided is not a string" +"The CVV value is required.","The CVV value is required." +"The capture action is not available.","The capture action is not available." +"The capture request could not be processed.","The capture request could not be processed." +"The card could not be saved.","The card could not be saved." +"The card ending with %1 will be deleted.","The card ending with %1 will be deleted." "The issuer has not certified or has not provided the encryption keys to the interchange","The issuer has not certified or has not provided the encryption keys to the interchange" +"The order could not be created.","The order could not be created." +"The order could not be processed.","The order could not be processed." +"The order creation failed. Please check the error logs.","The order creation failed. Please check the error logs." +"The payment card has been stored successfully.","The payment card has been stored successfully." +"The payment request was declined by the gateway.","The payment request was declined by the gateway." +"The payment request was successfully processed.","The payment request was successfully processed." +"The payment token is missing or invalid.","The payment token is missing or invalid." +"The payment was declined, please try again. If the problem persists, try another card or payment method.","The payment was declined, please try again. If the problem persists, try another card or payment method." +"The public key is invalid.","The public key is invalid." +"The quote ID is missing or invalid.","The quote ID is missing or invalid." +"The refund action is not available.","The refund action is not available." +"The refund request could not be processed.","The refund request could not be processed." +"The request is invalid or there was no quote found.","The request is invalid or there was no quote found." +"The request is invalid.","The request is invalid." +"The transaction could not be processed or has been cancelled.","The transaction could not be processed or has been cancelled." +"The transaction could not be processed","The transaction could not be processed" +"The transaction could not be processed. Please check the payment details.","The transaction could not be processed. Please check the payment details." +"The transaction could not be processed.","The transaction could not be processed." +"The void action is not available.","The void action is not available." +"The void request could not be processed.","The void request could not be processed." +"The webhook payment response is invalid.","The webhook payment response is invalid." +"The webhook response is invalid.","The webhook response is invalid." +"There is no quote available to place an order.","There is no quote available to place an order." +"This card is already saved.","This card is already saved." +"Transaction Id","Transaction Id" +"Unauthorized request. No matching private shared key.","Unauthorized request. No matching private shared key." +"Use Risk Rules For MOTO","Use Risk Rules For MOTO" +"View Demo","View Demo" +"Webhook and order successfully processed.","Webhook and order successfully processed." +"White with line","White with line" +"You have reached the limit allowed for this card/account, please try again with another card or payment method.","You have reached the limit allowed for this card/account, please try again with another card or payment method." "Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.","Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers." -"Something went wrong with paypal method. Please choose another method.","Something went wrong with paypal method. Please choose another method." +"Your order number %1 has been created successfully.","Your order number %1 has been created successfully." +"Your rights regarding the above mandate are explained in a statement that you can obtain from your bank.","Your rights regarding the above mandate are explained in a statement that you can obtain from your bank." +"Your webhook is all set!","Your webhook is all set!" +Actions,Actions +Authorize,Authorize +BIC,BIC +Black,Black +CVV,CVV +Close,Close +Configure,Configure +Continue,Continue +Creditor,Creditor +Debitor,Debitor +Delete,Delete +Description,Description +Discover,Discover +Dutch,Dutch +English,English +French,French +German,German +Italian,Italian +JCB,JCB +Korean,Korean +Mastercard,Mastercard +Name,Name +None,None +Pending,Pending +Processing,Processing +Production,Production +Simple,Simple +Spanish,Spanish +Standard,Standard +Test,Test +Type,Type +Visa,Visa +Webhook,Webhook +White,White +ending,ending +expires,expires +title,title diff --git a/i18n/en_US.csv b/i18n/en_US.csv index eb9bdef6..06f0b4da 100644 --- a/i18n/en_US.csv +++ b/i18n/en_US.csv @@ -1,163 +1,37 @@ -"Please keep your website safe! Your checkout plugin (v' . . ') is not the latest version (v' . . '). - Update now to get the latest features and security updates. - See https://github.com/checkout/checkout-magento2-plugin for detailed instructions.","Please keep your website safe! Your checkout plugin (v' . . ') is not the latest version (v' . . '). - Update now to get the latest features and security updates. - See https://github.com/checkout/checkout-magento2-plugin for detailed instructions." -Configure,Configure -Close,Close -"Learn More","Learn More" -"View Demo","View Demo" -"The payment card has been stored successfully.","The payment card has been stored successfully." -"The card could not be saved.","The card could not be saved." -"The payment request was declined by the gateway.","The payment request was declined by the gateway." -"The order could not be created.","The order could not be created." -"The request is invalid.","The request is invalid." -"No quote was found with the provided ID.","No quote was found with the provided ID." -"The quote ID is missing or invalid.","The quote ID is missing or invalid." -"The payment token is missing or invalid.","The payment token is missing or invalid." -"The public key is invalid.","The public key is invalid." -"No quote found with the provided ID","No quote found with the provided ID" -"Payment token provided is not a string","Payment token provided is not a string" -"Payment token provided is empty string","Payment token provided is empty string" -"Payment token is missing from request body","Payment token is missing from request body" -"Quote ID provided must be a positive integer","Quote ID provided must be a positive integer" -"Quote ID is missing from request body","Quote ID is missing from request body" -"Card BIN is empty string","Card BIN is empty string" -"Success URL provided is not a string","Success URL provided is not a string" -"Success URL is empty string","Success URL is empty string" -"Failure URL provided is not a string","Failure URL provided is not a string" -"Failure URL is empty string","Failure URL is empty string" -"An error occurred and the order could not be created.","An error occurred and the order could not be created." -"Your order number %1 has been created successfully.","Your order number %1 has been created successfully." -"The transaction could not be processed.","The transaction could not be processed." -"The order could not be processed.","The order could not be processed." -"The request is invalid or there was no quote found.","The request is invalid or there was no quote found." -"Please enter valid card details.","Please enter valid card details." -"The transaction could not be processed or has been cancelled.","The transaction could not be processed or has been cancelled." -"Invalid request. No order found.","Invalid request. No order found." -"Invalid request. No session ID found.","Invalid request. No session ID found." -"Webhook and order successfully processed.","Webhook and order successfully processed." -"The order creation failed. Please check the error logs.","The order creation failed. Please check the error logs." -"The webhook response is invalid.","The webhook response is invalid." -"The webhook payment response is invalid.","The webhook payment response is invalid." -"Unauthorized request. No matching private shared key.","Unauthorized request. No matching private shared key." -Black,Black -White,White -"White with line","White with line" -"Credit cards","Credit cards" -"Debit cards","Debit cards" -Visa,Visa -Mastercard,Mastercard -"American Express","American Express" -None,None -title,title -Test,Test -Production,Production -Standard,Standard -Simple,Simple -JCB,JCB -Discover,Discover -English,English -Spanish,Spanish -German,German -Korean,Korean -French,French -Italian,Italian -Dutch,Dutch -"Cancel the order","Cancel the order" -"Delete the order","Delete the order" -"Do nothing","Do nothing" -Processing,Processing -Pending,Pending -Authorize,Authorize -"Authorize and Capture","Authorize and Capture" -"Single iframe","Single iframe" -"Multiple iframes","Multiple iframes" -Webhook,Webhook -"Cron Job","Cron Job" -"Payment request from %1","Payment request from %1" -"The capture action is not available.","The capture action is not available." -"The capture request could not be processed.","The capture request could not be processed." -"The void action is not available.","The void action is not available." -"The void request could not be processed.","The void request could not be processed." -"The refund action is not available.","The refund action is not available." -"The refund request could not be processed.","The refund request could not be processed." -"The CVV value is required.","The CVV value is required." -"There is no quote available to place an order.","There is no quote available to place an order." -"A payment method ID is required to place an order.","A payment method ID is required to place an order." " for an amount of %1. Action ID: %2. Event ID: %3. Payment ID: %4. Error: %5 %6"," for an amount of %1. Action ID: %2. Event ID: %3. Payment ID: %4. Error: %5 %6" -"The payment was declined, please try again. If the problem persists, try another card or payment method.","The payment was declined, please try again. If the problem persists, try another card or payment method." -"You have reached the limit allowed for this card/account, please try again with another card or payment method.","You have reached the limit allowed for this card/account, please try again with another card or payment method." -"Something went wrong, please try again later","Something went wrong, please try again later" -"It looks like your card is invalid or blocked, please try with another card","It looks like your card is invalid or blocked, please try with another card" -"It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method","It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method" +"3DS authorization code","3DS authorization code" "3DS has expired or authentication failed, please try again","3DS has expired or authentication failed, please try again" -"The transaction could not be processed","The transaction could not be processed" -"Payment capture initiated, awaiting capture confirmation.","Payment capture initiated, awaiting capture confirmation." "3DS payment expired.","3DS payment expired." -"This card is already saved.","This card is already saved." -ending,ending -expires,expires -"Missing action ID for webhook with payment ID %","Missing action ID for webhook with payment ID %" -"The payment request was successfully processed.","The payment request was successfully processed." -"The transaction could not be processed. Please check the payment details.","The transaction could not be processed. Please check the payment details." -"Please provide the required card information for the MOTO payment.","Please provide the required card information for the MOTO payment." -"Missing required card information for the MOTO payment.","Missing required card information for the MOTO payment." -CVV,CVV -"Get your credentials here.","Get your credentials here." -"Add a card","Add a card" -"Save the card","Save the card" -"Card Number","Card Number" -"Expiration Date","Expiration Date" -Type,Type -Actions,Actions -Delete,Delete -"The card ending with %1 will be deleted.","The card ending with %1 will be deleted." -"Delete a card","Delete a card" -Name,Name -"Cadastro de Pessoas Físicas or Cadastro Nacional da Pessoa Jurídica","Cadastro de Pessoas Físicas or Cadastro Nacional da Pessoa Jurídica" -"Birth date (YYYY-MM-DD)","Birth date (YYYY-MM-DD)" -BIC,BIC -Description,Description -"Could not load the Klarna script.","Could not load the Klarna script." -"Account IBAN","Account IBAN" -Continue,Continue -"SEPA Direct Debit Mandate for single payment","SEPA Direct Debit Mandate for single payment" -Creditor,Creditor -"Creditor ID","Creditor ID" -Debitor,Debitor -"By accepting this mandate form, you authorise (A) b4payment GmbH to send instructions to your bank to debit your account (B) your bank to debit your account in accordance with the instructions from b4payment GmbH.","By accepting this mandate form, you authorise (A) b4payment GmbH to send instructions to your bank to debit your account (B) your bank to debit your account in accordance with the instructions from b4payment GmbH." -"As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited.","As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited." -"I accept the mandate for a single payment","I accept the mandate for a single payment" -"Your rights regarding the above mandate are explained in a statement that you can obtain from your bank.","Your rights regarding the above mandate are explained in a statement that you can obtain from your bank." -"Place Order","Place Order" -"Card number","Card number" -"Save this card for later use.","Save this card for later use." -"Set Webhooks","Set Webhooks" -"Attention, webhook not properly configured!","Attention, webhook not properly configured!" -"Your webhook is all set!","Your webhook is all set!" -"Error! Could not set webhooks. Please check your secret key.","Error! Could not set webhooks. Please check your secret key." -"Attention, secret key incorrect!","Attention, secret key incorrect!" -"Use Risk Rules For MOTO","Use Risk Rules For MOTO" -"3DS authorization code","3DS authorization code" -"Payment Method refunded","Payment Method refunded" -"Mismatched Address (fraud check)","Mismatched Address (fraud check)" -"Alternative payment method","Alternative payment method" -"Transaction Id","Transaction Id" -"Card Country","Card Country" -"Card Bank","Card Bank" -"Card expiry year","Card expiry year" -"Card expiry month","Card expiry month" -"Card 4 last numbers","Card 4 last numbers" -"Card type","Card type" -"Payment Additional Information","Payment Additional Information" "5 Digit Postal Match","5 Digit Postal Match" +"A payment method ID is required to place an order.","A payment method ID is required to place an order." "AVS Not Available","AVS Not Available" +"Account IBAN","Account IBAN" +"Add a card","Add a card" +"Alternative payment method","Alternative payment method" +"American Express","American Express" +"An error occurred and the order could not be created.","An error occurred and the order could not be created." +"As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited.","As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited." "Attempt at processing performed. Not authenticated or verified, but a proof of attempted authentication/verification is provided.","Attempt at processing performed. Not authenticated or verified, but a proof of attempted authentication/verification is provided." +"Attention, secret key incorrect!","Attention, secret key incorrect!" +"Attention, webhook not properly configured!","Attention, webhook not properly configured!" "Authentication or account verification could not be performed. This is due to a technical problem, or another problem as indicated in ARes or RReq.","Authentication or account verification could not be performed. This is due to a technical problem, or another problem as indicated in ARes or RReq." "Authentication or account verification rejected. Issuer is rejecting and requests that authorization not be attempted.","Authentication or account verification rejected. Issuer is rejecting and requests that authorization not be attempted." "Authentication verification successful.","Authentication verification successful." +"Authorize and Capture","Authorize and Capture" "Authorizing entity has not attempted card verification or could not verify the CVD due to a security device error","Authorizing entity has not attempted card verification or could not verify the CVD due to a security device error" +"Birth date (YYYY-MM-DD)","Birth date (YYYY-MM-DD)" +"By accepting this mandate form, you authorise (A) b4payment GmbH to send instructions to your bank to debit your account (B) your bank to debit your account in accordance with the instructions from b4payment GmbH.","By accepting this mandate form, you authorise (A) b4payment GmbH to send instructions to your bank to debit your account (B) your bank to debit your account in accordance with the instructions from b4payment GmbH." +"Cadastro de Pessoas Físicas or Cadastro Nacional da Pessoa Jurídica","Cadastro de Pessoas Físicas or Cadastro Nacional da Pessoa Jurídica" +"Cancel the order","Cancel the order" +"Card 4 last numbers","Card 4 last numbers" +"Card BIN is empty string","Card BIN is empty string" +"Card Bank","Card Bank" +"Card Country","Card Country" +"Card Number","Card Number" +"Card expiry month","Card expiry month" +"Card expiry year","Card expiry year" +"Card number","Card number" +"Card type","Card type" "Card verification not performed, CVD was not on the card. Not all cards have a CVD value encoded","Card verification not performed, CVD was not on the card. Not all cards have a CVD value encoded" "Card verification performed, and CVD was invalid","Card verification performed, and CVD was invalid" "Card verification performed, and CVD was valid","Card verification performed, and CVD was valid" @@ -170,19 +44,141 @@ Debitor,Debitor "Cardholder Name, Street and Postal/ZIP Match","Cardholder Name, Street and Postal/ZIP Match" "Challenge required. Additional authentication is required using the CReq or CRes.","Challenge required. Additional authentication is required using the CReq or CRes." "Challenge required. Decoupled authentication confirmed.","Challenge required. Decoupled authentication confirmed." +"Could not load the Klarna script.","Could not load the Klarna script." +"Credit cards","Credit cards" +"Creditor ID","Creditor ID" +"Cron Job","Cron Job" +"Debit cards","Debit cards" +"Delete a card","Delete a card" +"Delete the order","Delete the order" +"Do nothing","Do nothing" +"Error! Could not set webhooks. Please check your secret key.","Error! Could not set webhooks. Please check your secret key." +"Expiration Date","Expiration Date" +"Failure URL is empty string","Failure URL is empty string" +"Failure URL provided is not a string","Failure URL provided is not a string" +"Get your credentials here.","Get your credentials here." +"I accept the mandate for a single payment","I accept the mandate for a single payment" "Informational only. 3DS requestor challenge preference acknowledged.","Informational only. 3DS requestor challenge preference acknowledged." +"Invalid request. No order found.","Invalid request. No order found." +"Invalid request. No session ID found.","Invalid request. No session ID found." +"It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method","It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method" +"It looks like your card is invalid or blocked, please try with another card","It looks like your card is invalid or blocked, please try with another card" +"Learn More","Learn More" "Match Not Capable","Match Not Capable" +"Mismatched Address (fraud check)","Mismatched Address (fraud check)" +"Missing action ID for webhook with payment ID %","Missing action ID for webhook with payment ID %" +"Missing required card information for the MOTO payment.","Missing required card information for the MOTO payment." +"Multiple iframes","Multiple iframes" "No Address Match","No Address Match" "No CVV2 information is available",,"No CVV2 information is available" +"No quote found with the provided ID","No quote found with the provided ID" +"No quote was found with the provided ID.","No quote was found with the provided ID." "Not Verified or Not Supported","Not Verified or Not Supported" "Not authenticated or account not verified. This means the transaction was denied.","Not authenticated or account not verified. This means the transaction was denied." "Not supported","Not supported" +"Payment Additional Information","Payment Additional Information" +"Payment Method refunded","Payment Method refunded" +"Payment capture initiated, awaiting capture confirmation.","Payment capture initiated, awaiting capture confirmation." +"Payment request from %1","Payment request from %1" +"Payment token is missing from request body","Payment token is missing from request body" +"Payment token provided is empty string","Payment token provided is empty string" +"Payment token provided is not a string","Payment token provided is not a string" +"Place Order","Place Order" +"Please enter valid card details.","Please enter valid card details." +"Please keep your website safe! Your checkout plugin (v' . . ') is not the latest version (v' . . '). Update now to get the latest features and security updates. See https://github.com/checkout/checkout-magento2-plugin for detailed instructions.","Please keep your website safe! Your checkout plugin (v' . . ') is not the latest version (v' . . '). Update now to get the latest features and security updates. See https://github.com/checkout/checkout-magento2-plugin for detailed instructions." +"Please provide the required card information for the MOTO payment.","Please provide the required card information for the MOTO payment." +"Quote ID is missing from request body","Quote ID is missing from request body" +"Quote ID provided must be a positive integer","Quote ID provided must be a positive integer" +"SEPA Direct Debit Mandate for single payment","SEPA Direct Debit Mandate for single payment" +"Save the card","Save the card" +"Save this card for later use.","Save this card for later use." +"Set Webhooks","Set Webhooks" +"Single iframe","Single iframe" +"Something went wrong with paypal method. Please choose another method.","Something went wrong with paypal method. Please choose another method." +"Something went wrong, please try again later","Something went wrong, please try again later" "Street Match Postal Not Verified","Street Match Postal Not Verified" "Street Match","Street Match" "Street Not Verified Postal Match","Street Not Verified Postal Match" "Street and 5 Digit Postal Match","Street and 5 Digit Postal Match" "Street and Postal Match","Street and Postal Match" "Street and Postal Not Verified","Street and Postal Not Verified" +"Success URL is empty string","Success URL is empty string" +"Success URL provided is not a string","Success URL provided is not a string" +"The CVV value is required.","The CVV value is required." +"The capture action is not available.","The capture action is not available." +"The capture request could not be processed.","The capture request could not be processed." +"The card could not be saved.","The card could not be saved." +"The card ending with %1 will be deleted.","The card ending with %1 will be deleted." "The issuer has not certified or has not provided the encryption keys to the interchange","The issuer has not certified or has not provided the encryption keys to the interchange" +"The order could not be created.","The order could not be created." +"The order could not be processed.","The order could not be processed." +"The order creation failed. Please check the error logs.","The order creation failed. Please check the error logs." +"The payment card has been stored successfully.","The payment card has been stored successfully." +"The payment request was declined by the gateway.","The payment request was declined by the gateway." +"The payment request was successfully processed.","The payment request was successfully processed." +"The payment token is missing or invalid.","The payment token is missing or invalid." +"The payment was declined, please try again. If the problem persists, try another card or payment method.","The payment was declined, please try again. If the problem persists, try another card or payment method." +"The public key is invalid.","The public key is invalid." +"The quote ID is missing or invalid.","The quote ID is missing or invalid." +"The refund action is not available.","The refund action is not available." +"The refund request could not be processed.","The refund request could not be processed." +"The request is invalid or there was no quote found.","The request is invalid or there was no quote found." +"The request is invalid.","The request is invalid." +"The transaction could not be processed or has been cancelled.","The transaction could not be processed or has been cancelled." +"The transaction could not be processed","The transaction could not be processed" +"The transaction could not be processed. Please check the payment details.","The transaction could not be processed. Please check the payment details." +"The transaction could not be processed.","The transaction could not be processed." +"The void action is not available.","The void action is not available." +"The void request could not be processed.","The void request could not be processed." +"The webhook payment response is invalid.","The webhook payment response is invalid." +"The webhook response is invalid.","The webhook response is invalid." +"There is no quote available to place an order.","There is no quote available to place an order." +"This card is already saved.","This card is already saved." +"Transaction Id","Transaction Id" +"Unauthorized request. No matching private shared key.","Unauthorized request. No matching private shared key." +"Use Risk Rules For MOTO","Use Risk Rules For MOTO" +"View Demo","View Demo" +"Webhook and order successfully processed.","Webhook and order successfully processed." +"White with line","White with line" +"You have reached the limit allowed for this card/account, please try again with another card or payment method.","You have reached the limit allowed for this card/account, please try again with another card or payment method." "Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.","Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers." -"Something went wrong with paypal method. Please choose another method.","Something went wrong with paypal method. Please choose another method." +"Your order number %1 has been created successfully.","Your order number %1 has been created successfully." +"Your rights regarding the above mandate are explained in a statement that you can obtain from your bank.","Your rights regarding the above mandate are explained in a statement that you can obtain from your bank." +"Your webhook is all set!","Your webhook is all set!" +Actions,Actions +Authorize,Authorize +BIC,BIC +Black,Black +CVV,CVV +Close,Close +Configure,Configure +Continue,Continue +Creditor,Creditor +Debitor,Debitor +Delete,Delete +Description,Description +Discover,Discover +Dutch,Dutch +English,English +French,French +German,German +Italian,Italian +JCB,JCB +Korean,Korean +Mastercard,Mastercard +Name,Name +None,None +Pending,Pending +Processing,Processing +Production,Production +Simple,Simple +Spanish,Spanish +Standard,Standard +Test,Test +Type,Type +Visa,Visa +Webhook,Webhook +White,White +ending,ending +expires,expires +title,title From 114e6d93b727da10c3dcd8e6a2e7d2f3b57310eb Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Mon, 11 Mar 2024 11:53:16 +0100 Subject: [PATCH 070/147] CHECMAG2003-218: fix bad merge on checkout --- .../method-renderer/checkoutcom_apple_pay.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js index 45db58ac..1c21c044 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js @@ -277,7 +277,19 @@ define( // Start the payment session Utilities.log(paymentRequest); - var session = new ApplePaySession(14, paymentRequest); + var session = ApplePayUtilities.initializeApplePaySession(paymentRequest); + + if (!session) { + Utilities.log('Your browser is not compatible with the Apple Pay version'); + + Utilities.showMessage( + 'error', + __('Your browser is not compatible with the Apple Pay version. Please use the most updated OS system and browsers.'), + METHOD_ID + ); + + return false; + } // Merchant Validation session.onvalidatemerchant = function (event) { From b12d789dfc05273d6eac001334b045782b1c5f6d Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Mon, 11 Mar 2024 15:19:37 +0100 Subject: [PATCH 071/147] CHECMAG2003-206: process review return --- view/frontend/layout/default.xml | 4 ++-- .../templates/cart/minicart-config.phtml | 22 +++++++++++++++---- .../payment/paypal/review/place-order.phtml | 2 +- .../method-renderer/checkoutcom_apple_pay.js | 1 - .../method-renderer/checkoutcom_paypal.js | 7 ++++++ .../checkoutcom_paypal_express.js | 5 +++-- 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/view/frontend/layout/default.xml b/view/frontend/layout/default.xml index 5131eaf0..23743293 100644 --- a/view/frontend/layout/default.xml +++ b/view/frontend/layout/default.xml @@ -40,9 +40,9 @@ - + - + diff --git a/view/frontend/templates/cart/minicart-config.phtml b/view/frontend/templates/cart/minicart-config.phtml index 20d44f73..2f88adfa 100644 --- a/view/frontend/templates/cart/minicart-config.phtml +++ b/view/frontend/templates/cart/minicart-config.phtml @@ -1,16 +1,29 @@ - * @copyright 2004-present Agence Dn'D - * @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) - * @link https://www.dnd.fr/ + * Checkout.com + * Authorized and regulated as an electronic money institution + * by the UK Financial Conduct Authority (FCA) under number 900816. + * + * PHP version 7 + * + * @category Magento2 + * @package Checkout.com + * @author Platforms Development Team + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ */ + use CheckoutCom\Magento2\Block\Cart\CheckoutConfig; use Magento\Framework\View\Helper\SecureHtmlRenderer; +/** TODO: set this variable to true if paypal express or apple pay is enable on minicart */ +$expressMethodEnabled = true; + /** @var CheckoutConfig $block */ /** @var SecureHtmlRenderer $secureRenderer */ +if ($expressMethodEnabled): ?> getProductCount() > 0 ? $block->getSerializedCheckoutConfig() : $block->getSerializedCheckoutComConfig(); $scriptString = << + +
From 678f3d17ce240ab392c45cb66c28d18703f239bf Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Thu, 23 May 2024 08:44:33 +0200 Subject: [PATCH 106/147] CHECMAG2003-233: set current user email before placing order --- .../js/view/payment/method-renderer/checkoutcom_apple_pay.js | 2 ++ .../js/view/payment/method-renderer/checkoutcom_card_payment.js | 2 ++ .../js/view/payment/method-renderer/checkoutcom_google_pay.js | 2 ++ .../web/js/view/payment/method-renderer/checkoutcom_vault.js | 2 ++ 4 files changed, 8 insertions(+) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js index 1c21c044..89699286 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js @@ -232,6 +232,8 @@ define( let self = this; if (Utilities.methodIsSelected(METHOD_ID)) { + Utilities.setEmail(); + // Validate T&C submission if (!AdditionalValidators.validate()) { return; diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index 9071f472..06cf5bd0 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -315,6 +315,8 @@ define( placeOrder: function () { if (Utilities.methodIsSelected(METHOD_ID)) { + Utilities.setEmail(); + // Validate the order placement if (AdditionalValidators.validate() && Frames.isCardValid()) { // Start the loader diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js index d8f7861c..ebd7860e 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js @@ -95,6 +95,8 @@ define( $(self.button_target).click( function(evt) { if (Utilities.methodIsSelected(METHOD_ID)) { + Utilities.setEmail(); + // Validate T&C submission if (!AdditionalValidators.validate()) { return; diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js index 54311ef5..350c360a 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js @@ -251,6 +251,8 @@ define( */ placeOrder: function () { if (Utilities.methodIsSelected(METHOD_ID)) { + Utilities.setEmail(); + if (AdditionalValidators.validate()) { // Prepare the payload var payload = { From 1983e7d796c9802faa08b20e54839293dca3e119 Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Thu, 23 May 2024 14:51:41 +0200 Subject: [PATCH 107/147] CHECMAG2003-233: use step navigator on payemnt step in order to know if customer return to shipping step --- .../method-renderer/checkoutcom_apm.js | 1 + .../method-renderer/checkoutcom_apple_pay.js | 1 + .../checkoutcom_card_payment.js | 1 + .../method-renderer/checkoutcom_google_pay.js | 1 + .../method-renderer/checkoutcom_paypal.js | 2 + .../method-renderer/checkoutcom_vault.js | 1 + .../frontend/web/js/view/payment/utilities.js | 37 ++++++++++++++++++- 7 files changed, 43 insertions(+), 1 deletion(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apm.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apm.js index 460008a1..c050e6bf 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apm.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apm.js @@ -45,6 +45,7 @@ define( initialize: function () { this._super(); Utilities.loadCss('apm', 'apm'); + Utilities.initSubscribers(this); }, /** diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js index 89699286..24b45e11 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js @@ -55,6 +55,7 @@ define( initialize: function () { this._super(); Utilities.setEmail(); + Utilities.initSubscribers(this); Utilities.loadCss('apple-pay', 'apple-pay'); this.launchApplePay(); diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index 06cf5bd0..9ffbacd3 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -60,6 +60,7 @@ define( this._super(); Utilities.loadCss(this.getFormLayout(), 'frames'); Utilities.setEmail(); + Utilities.initSubscribers(this); return this; }, diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js index ebd7860e..48b86add 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js @@ -46,6 +46,7 @@ define( initialize: function() { this._super(); Utilities.setEmail(); + Utilities.initSubscribers(this); Utilities.loadCss('google-pay', 'google-pay'); return this; diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js index ddbaa608..45508495 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js @@ -64,6 +64,8 @@ define([ }).catch((error) => { Utilities.log(error); }); + + Utilities.initSubscribers(this); }, /** diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js index 350c360a..a70b46bd 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js @@ -44,6 +44,7 @@ define( initialize: function () { this._super(); Utilities.setEmail(); + Utilities.initSubscribers(this); Utilities.loadCss('vault', 'vault'); return this; diff --git a/view/frontend/web/js/view/payment/utilities.js b/view/frontend/web/js/view/payment/utilities.js index a03d453f..6a0ea1b3 100755 --- a/view/frontend/web/js/view/payment/utilities.js +++ b/view/frontend/web/js/view/payment/utilities.js @@ -24,15 +24,19 @@ define( 'Magento_Checkout/js/model/full-screen-loader', 'Magento_Customer/js/model/customer', 'mage/translate', + 'Magento_Checkout/js/model/step-navigator', + 'Magento_Checkout/js/action/set-payment-information', 'mage/cookies' ], - function ($, Config, Quote, CheckoutData, Url, RedirectOnSuccessAction, FullScreenLoader, Customer, __) { + function ($, Config, Quote, CheckoutData, Url, RedirectOnSuccessAction, FullScreenLoader, Customer, __, StepNavigator, setPaymentInformationAction) { 'use strict'; const KEY_CONFIG = 'checkoutcom_configuration'; const KEY_DATA = 'checkoutcom_data'; + const PAYMENT_STEP_CODE = 'payment'; return { + /** * Gets a field value. * @@ -446,6 +450,37 @@ define( */ cleanCustomerShippingAddress: function() { CheckoutData.setNewCustomerShippingAddress(null); + }, + + /** + * Workaround to refresh payment method information when guest customer + * go back to shipping step & change his email address + * + * @param {UiClass} Component + * @public + */ + initSubscribers: function (Component) { + const code = Component.getCode(); + + StepNavigator.steps.subscribe((steps) => { + if (this.getCurrentCheckoutStep(steps) === PAYMENT_STEP_CODE && + this.methodIsSelected(code)) { + setPaymentInformationAction(Component.messageContainer, { + method: code + }); + } + }); + }, + + /** + * Return current checkout step code + * + * @param {Array} steps + * @return string + * @public + */ + getCurrentCheckoutStep: function (steps) { + return steps[StepNavigator.getActiveItemIndex()]['code']; } }; } From 0520cf3bd214f7059a65d0f0d72a7daee7e2448e Mon Sep 17 00:00:00 2001 From: Antoine FONTAINE Date: Mon, 27 May 2024 11:13:42 +0200 Subject: [PATCH 108/147] CHECMAG2003-233: create checkout utilities file in order use checkout data only in checkout page and not in minicart --- .../web/js/model/checkout-utilities.js | 59 +++++++++++++++++++ .../method-renderer/checkoutcom_apm.js | 5 +- .../method-renderer/checkoutcom_apple_pay.js | 4 +- .../checkoutcom_card_payment.js | 5 +- .../method-renderer/checkoutcom_google_pay.js | 5 +- .../method-renderer/checkoutcom_paypal.js | 5 +- .../method-renderer/checkoutcom_vault.js | 9 ++- .../frontend/web/js/view/payment/utilities.js | 38 +----------- 8 files changed, 80 insertions(+), 50 deletions(-) create mode 100644 view/frontend/web/js/model/checkout-utilities.js diff --git a/view/frontend/web/js/model/checkout-utilities.js b/view/frontend/web/js/model/checkout-utilities.js new file mode 100644 index 00000000..e929b396 --- /dev/null +++ b/view/frontend/web/js/model/checkout-utilities.js @@ -0,0 +1,59 @@ +/** + * Checkout.com + * Authorized and regulated as an electronic money institution + * by the UK Financial Conduct Authority (FCA) under number 900816. + * + * PHP version 7 + * + * @category Magento2 + * @package Checkout.com + * @author Platforms Development Team + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +define([ + 'jquery', + 'CheckoutCom_Magento2/js/view/payment/utilities', + 'Magento_Checkout/js/model/step-navigator', + 'Magento_Checkout/js/action/set-payment-information' +], function ($, Utilities, StepNavigator, setPaymentInformationAction) { + 'use strict'; + + const PAYMENT_STEP_CODE = 'payment'; + + return { + + /** + * Workaround to refresh payment method information when guest customer + * go back to shipping step & change his email address + * + * @param {UiClass} Component + * @public + */ + initSubscribers: function (Component) { + const code = Component.getCode(); + + StepNavigator.steps.subscribe((steps) => { + if (this.getCurrentCheckoutStep(steps) === PAYMENT_STEP_CODE && + Utilities.methodIsSelected(code)) { + setPaymentInformationAction(Component.messageContainer, { + method: code + }); + } + }); + }, + + /** + * Return current checkout step code + * + * @param {Array} steps + * @return string + * @public + */ + getCurrentCheckoutStep: function (steps) { + return steps[StepNavigator.getActiveItemIndex()]['code']; + } + }; +}); diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apm.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apm.js index c050e6bf..5ff0a041 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apm.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apm.js @@ -18,13 +18,14 @@ define( 'jquery', 'Magento_Checkout/js/view/payment/default', 'CheckoutCom_Magento2/js/view/payment/utilities', + 'CheckoutCom_Magento2/js/model/checkout-utilities', 'Magento_Checkout/js/model/full-screen-loader', 'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Checkout/js/model/quote', 'mage/translate', 'jquery/ui' ], - function ($, Component, Utilities, FullScreenLoader, AdditionalValidators, Quote, __) { + function ($, Component, Utilities, CheckoutUtilities, FullScreenLoader, AdditionalValidators, Quote, __) { 'use strict'; window.checkoutConfig.reloadOnBillingAddress = true; @@ -45,7 +46,7 @@ define( initialize: function () { this._super(); Utilities.loadCss('apm', 'apm'); - Utilities.initSubscribers(this); + CheckoutUtilities.initSubscribers(this); }, /** diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js index 24b45e11..08f7b431 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_apple_pay.js @@ -19,6 +19,7 @@ define( 'ko', 'Magento_Checkout/js/view/payment/default', 'CheckoutCom_Magento2/js/view/payment/utilities', + 'CheckoutCom_Magento2/js/model/checkout-utilities', "CheckoutCom_Magento2/js/view/payment/applepay-utilities", 'Magento_Checkout/js/model/full-screen-loader', 'Magento_Checkout/js/model/payment/additional-validators', @@ -30,6 +31,7 @@ define( ko, Component, Utilities, + CheckoutUtilities, ApplePayUtilities, FullScreenLoader, AdditionalValidators, @@ -55,7 +57,7 @@ define( initialize: function () { this._super(); Utilities.setEmail(); - Utilities.initSubscribers(this); + CheckoutUtilities.initSubscribers(this); Utilities.loadCss('apple-pay', 'apple-pay'); this.launchApplePay(); diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index 9ffbacd3..0cc2f866 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -19,6 +19,7 @@ define( 'ko', 'Magento_Checkout/js/view/payment/default', 'CheckoutCom_Magento2/js/view/payment/utilities', + 'CheckoutCom_Magento2/js/model/checkout-utilities', 'CheckoutCom_Magento2/js/frames/multi', 'CheckoutCom_Magento2/js/frames/single', 'Magento_Checkout/js/model/payment/additional-validators', @@ -27,7 +28,7 @@ define( 'Magento_Checkout/js/model/full-screen-loader', 'framesjs' ], - function ($, ko, Component, Utilities, FramesMulti, FramesSingle, AdditionalValidators, Customer, Quote, FullScreenLoader) { + function ($, ko, Component, Utilities, CheckoutUtilities, FramesMulti, FramesSingle, AdditionalValidators, Customer, Quote, FullScreenLoader) { 'use strict'; window.checkoutConfig.reloadOnBillingAddress = true; const METHOD_ID = 'checkoutcom_card_payment'; @@ -60,7 +61,7 @@ define( this._super(); Utilities.loadCss(this.getFormLayout(), 'frames'); Utilities.setEmail(); - Utilities.initSubscribers(this); + CheckoutUtilities.initSubscribers(this); return this; }, diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js index 48b86add..2669d1af 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_google_pay.js @@ -18,6 +18,7 @@ define( 'jquery', 'Magento_Checkout/js/view/payment/default', 'CheckoutCom_Magento2/js/view/payment/utilities', + 'CheckoutCom_Magento2/js/model/checkout-utilities', 'Magento_Checkout/js/model/full-screen-loader', 'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Checkout/js/action/redirect-on-success', @@ -25,7 +26,7 @@ define( 'googlepayjs', ], function( - $, Component, Utilities, FullScreenLoader, AdditionalValidators, + $, Component, Utilities, ChekcoutUtilities, FullScreenLoader, AdditionalValidators, RedirectOnSuccessAction, __) { 'use strict'; window.checkoutConfig.reloadOnBillingAddress = true; @@ -46,7 +47,7 @@ define( initialize: function() { this._super(); Utilities.setEmail(); - Utilities.initSubscribers(this); + ChekcoutUtilities.initSubscribers(this); Utilities.loadCss('google-pay', 'google-pay'); return this; diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js index 45508495..d5b64e46 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_paypal.js @@ -18,13 +18,14 @@ define([ 'knockout', 'Magento_Checkout/js/view/payment/default', 'CheckoutCom_Magento2/js/view/payment/utilities', + 'CheckoutCom_Magento2/js/model/checkout-utilities', 'CheckoutCom_Magento2/js/view/payment/paypal-utilities', 'Magento_Checkout/js/model/full-screen-loader', 'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Checkout/js/model/quote', 'mage/translate', 'mage/url', -], function ($, ko, Component, Utilities, PaypalUtilities, FullScreenLoader, AdditionalValidators, Quote, __, Url) { +], function ($, ko, Component, Utilities, CheckoutUtilities, PaypalUtilities, FullScreenLoader, AdditionalValidators, Quote, __, Url) { 'use strict'; window.checkoutConfig.reloadOnBillingAddress = true; @@ -65,7 +66,7 @@ define([ Utilities.log(error); }); - Utilities.initSubscribers(this); + CheckoutUtilities.initSubscribers(this); }, /** diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js index a70b46bd..2385c70a 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_vault.js @@ -13,16 +13,15 @@ * @link https://docs.checkout.com/ */ -define( - [ +define([ 'jquery', 'Magento_Checkout/js/view/payment/default', 'CheckoutCom_Magento2/js/view/payment/utilities', + 'CheckoutCom_Magento2/js/model/checkout-utilities', 'Magento_Checkout/js/model/payment/additional-validators', 'Magento_Checkout/js/model/full-screen-loader', 'mage/translate' - ], - function ($, Component, Utilities, AdditionalValidators, FullScreenLoader, __) { + ], function ($, Component, Utilities, CheckoutUtilities, AdditionalValidators, FullScreenLoader, __) { 'use strict'; window.checkoutConfig.reloadOnBillingAddress = true; const METHOD_ID = 'checkoutcom_vault'; @@ -44,7 +43,7 @@ define( initialize: function () { this._super(); Utilities.setEmail(); - Utilities.initSubscribers(this); + CheckoutUtilities.initSubscribers(this); Utilities.loadCss('vault', 'vault'); return this; diff --git a/view/frontend/web/js/view/payment/utilities.js b/view/frontend/web/js/view/payment/utilities.js index 6a0ea1b3..5ffcfe19 100755 --- a/view/frontend/web/js/view/payment/utilities.js +++ b/view/frontend/web/js/view/payment/utilities.js @@ -24,16 +24,13 @@ define( 'Magento_Checkout/js/model/full-screen-loader', 'Magento_Customer/js/model/customer', 'mage/translate', - 'Magento_Checkout/js/model/step-navigator', - 'Magento_Checkout/js/action/set-payment-information', 'mage/cookies' ], - function ($, Config, Quote, CheckoutData, Url, RedirectOnSuccessAction, FullScreenLoader, Customer, __, StepNavigator, setPaymentInformationAction) { + function ($, Config, Quote, CheckoutData, Url, RedirectOnSuccessAction, FullScreenLoader, Customer, __) { 'use strict'; const KEY_CONFIG = 'checkoutcom_configuration'; const KEY_DATA = 'checkoutcom_data'; - const PAYMENT_STEP_CODE = 'payment'; return { @@ -402,7 +399,7 @@ define( methodIsSelected: function (idSelector) { var id = idSelector.replace('#', ''); var selected = CheckoutData.getSelectedPaymentMethod(); - return id == selected || selected == null; + return id === selected; }, /** @@ -451,37 +448,6 @@ define( cleanCustomerShippingAddress: function() { CheckoutData.setNewCustomerShippingAddress(null); }, - - /** - * Workaround to refresh payment method information when guest customer - * go back to shipping step & change his email address - * - * @param {UiClass} Component - * @public - */ - initSubscribers: function (Component) { - const code = Component.getCode(); - - StepNavigator.steps.subscribe((steps) => { - if (this.getCurrentCheckoutStep(steps) === PAYMENT_STEP_CODE && - this.methodIsSelected(code)) { - setPaymentInformationAction(Component.messageContainer, { - method: code - }); - } - }); - }, - - /** - * Return current checkout step code - * - * @param {Array} steps - * @return string - * @public - */ - getCurrentCheckoutStep: function (steps) { - return steps[StepNavigator.getActiveItemIndex()]['code']; - } }; } ); From 7f2ee0ac47aebbbba0b36fdbecc6fa0c2a8f08ce Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Wed, 5 Jun 2024 10:16:10 +0200 Subject: [PATCH 109/147] Bump composer version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7f30a392..cfe2fd99 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "6.1.1", + "version": "6.2.0", "autoload": { "files": [ "registration.php" From e2cca84457b1d467470c4e8a51aaa21675807533 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Wed, 19 Jun 2024 12:11:01 +0200 Subject: [PATCH 110/147] CHECMAG2003-236 - Introducing Klarna --- Model/Methods/KlarnaMethod.php | 502 ++++++++++++++++++ etc/adminhtml/system.xml | 41 +- etc/config.xml | 18 + view/frontend/layout/checkout_index_index.xml | 9 + .../templates/script/klarna-script.phtml | 18 + 5 files changed, 587 insertions(+), 1 deletion(-) create mode 100755 Model/Methods/KlarnaMethod.php create mode 100644 view/frontend/templates/script/klarna-script.phtml diff --git a/Model/Methods/KlarnaMethod.php b/Model/Methods/KlarnaMethod.php new file mode 100755 index 00000000..9aba8d3e --- /dev/null +++ b/Model/Methods/KlarnaMethod.php @@ -0,0 +1,502 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +declare(strict_types=1); + +namespace CheckoutCom\Magento2\Model\Methods; + +use Checkout\CheckoutApiException; +use Checkout\CheckoutArgumentException; +use Checkout\Payments\BillingDescriptor; +use Checkout\Payments\Previous\PaymentRequest as PreviousPaymentRequest; +use Checkout\Payments\Previous\Source\RequestTokenSource as PreviousRequestTokenSource; +use Checkout\Payments\ProcessingSettings; +use Checkout\Payments\Request\PaymentRequest; +use Checkout\Payments\Request\Source\RequestTokenSource; +use CheckoutCom\Magento2\Gateway\Config\Config; +use CheckoutCom\Magento2\Helper\Logger as LoggerHelper; +use CheckoutCom\Magento2\Helper\Utilities; +use CheckoutCom\Magento2\Model\Service\ApiHandlerService; +use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; +use CheckoutCom\Magento2\Model\Service\QuoteHandlerService; +use Magento\Backend\Model\Auth\Session; +use Magento\Directory\Helper\Data as DirectoryHelper; +use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\Api\ExtensionAttributesFactory; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Data\Collection\AbstractDb; +use Magento\Framework\DataObjectFactory; +use Magento\Framework\Exception\FileSystemException; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Model\Context; +use Magento\Framework\Model\ResourceModel\AbstractResource; +use Magento\Framework\Registry; +use Magento\Framework\Serialize\Serializer\Json; +use Magento\Payment\Helper\Data; +use Magento\Payment\Model\InfoInterface; +use Magento\Payment\Model\Method\Logger; +use Magento\Quote\Api\Data\CartInterface; +use Magento\Store\Model\ScopeInterface; +use Magento\Store\Model\StoreManagerInterface; + +/** + * Class GooglePayMethod + */ +class KlarnaMethod extends AbstractMethod +{ + /** + * CODE constant + * + * @var string CODE + */ + const CODE = 'checkoutcom_klarna'; + /** + * $_code field + * + * @var string $_code + */ + protected $_code = self::CODE; + /** + * $_canAuthorize field + * + * @var bool $_canAuthorize + */ + protected $_canAuthorize = true; + /** + * $_canCapture field + * + * @var bool $_canCapture + */ + protected $_canCapture = true; + /** + * $_canCapturePartial field + * + * @var bool $_canCapturePartial + */ + protected $_canCapturePartial = true; + /** + * $_canVoid field + * + * @var bool $_canVoid + */ + protected $_canVoid = true; + /** + * $_canUseInternal field + * + * @var bool $_canUseInternal + */ + protected $_canUseInternal = false; + /** + * $_canUseCheckout field + * + * @var bool $_canUseCheckout + */ + protected $_canUseCheckout = true; + /** + * $_canRefund field + * + * @var bool $_canRefund + */ + protected $_canRefund = true; + /** + * $_canRefundInvoicePartial field + * + * @var bool $_canRefundInvoicePartial + */ + protected $_canRefundInvoicePartial = true; + /** + * @var Json + */ + private $json; + /** + * $config field + * + * @var Config $config + */ + private $config; + /** + * $apiHandler field + * + * @var ApiHandlerService $apiHandler + */ + private $apiHandler; + /** + * $utilities field + * + * @var Utilities $utilities + */ + private $utilities; + /** + * $quoteHandler field + * + * @var QuoteHandlerService $quoteHandler + */ + private $quoteHandler; + /** + * $ckoLogger field + * + * @var Logger $ckoLogger + */ + private $ckoLogger; + /** + * $storeManager field + * + * @var StoreManagerInterface $storeManager + */ + private $storeManager; + /** + * $backendAuthSession field + * + * @var Session $backendAuthSession + */ + private $backendAuthSession; + + private PaymentContextRequestService $contextService; + + /** + * GooglePayMethod constructor + * + * @param Context $context + * @param Registry $registry + * @param ExtensionAttributesFactory $extensionFactory + * @param AttributeValueFactory $customAttributeFactory + * @param Data $paymentData + * @param ScopeConfigInterface $scopeConfig + * @param Logger $logger + * @param Config $config + * @param ApiHandlerService $apiHandler + * @param Utilities $utilities + * @param StoreManagerInterface $storeManager + * @param QuoteHandlerService $quoteHandler + * @param LoggerHelper $ckoLogger + * @param Session $backendAuthSession + * @param DirectoryHelper $directoryHelper + * @param DataObjectFactory $dataObjectFactory + * @param Json $json + * @param AbstractResource|null $resource + * @param AbstractDb|null $resourceCollection + * @param array $data + */ + public function __construct( + Context $context, + Registry $registry, + ExtensionAttributesFactory $extensionFactory, + AttributeValueFactory $customAttributeFactory, + Data $paymentData, + ScopeConfigInterface $scopeConfig, + Logger $logger, + Config $config, + ApiHandlerService $apiHandler, + Utilities $utilities, + StoreManagerInterface $storeManager, + QuoteHandlerService $quoteHandler, + LoggerHelper $ckoLogger, + Session $backendAuthSession, + DirectoryHelper $directoryHelper, + DataObjectFactory $dataObjectFactory, + Json $json, + PaymentContextRequestService $contextService, + AbstractResource $resource = null, + AbstractDb $resourceCollection = null, + array $data = [] + ) { + parent::__construct( + $config, + $context, + $registry, + $extensionFactory, + $customAttributeFactory, + $paymentData, + $scopeConfig, + $logger, + $directoryHelper, + $dataObjectFactory, + $resource, + $resourceCollection, + $data + ); + + $this->config = $config; + $this->apiHandler = $apiHandler; + $this->utilities = $utilities; + $this->storeManager = $storeManager; + $this->quoteHandler = $quoteHandler; + $this->ckoLogger = $ckoLogger; + $this->backendAuthSession = $backendAuthSession; + $this->json = $json; + $this->contextService = $contextService; + } + + /** + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws FileSystemException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function sendPaymentRequest(array $data, float $amount, string $currency, string $reference = ''): array + { + // Get the store code + $storeCode = $this->storeManager->getStore()->getCode(); + + // Initialize the API handler + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + + // Get the quote + $quote = $this->quoteHandler->getQuote(); + + // Set the payment + if ($this->apiHandler->isPreviousMode()) { + $request = new PreviousPaymentRequest(); + } else { + $request = new PaymentRequest(); + } + + // Set parameters + $request->capture = $this->config->needsAutoCapture(); + $request->amount = $this->utilities->formatDecimals($amount * 100); + $request->payment_context_id = $data['contextPaymentId']; + $request->processing_channel_id = $this->config->getValue('channel_id'); + $request->reference = $reference; + $request->metadata['methodId'] = $this->_code; + $request->description = __('Payment request from %1', $this->config->getStoreName())->render(); + $request->customer = $api->createCustomer($quote); + $request->payment_type = 'Regular'; + $request->shipping = $api->createShippingAddress($quote); + $request->metadata['quoteData'] = $this->json->serialize($this->quoteHandler->getQuoteRequestData($quote)); + $request->metadata = array_merge( + $request->metadata, + $this->apiHandler->getBaseMetadata() + ); + // Billing descriptor + if ($this->config->needsDynamicDescriptor()) { + $billingDescriptor = new BillingDescriptor(); + $billingDescriptor->city = $this->config->getValue('descriptor_city'); + $billingDescriptor->name = $this->config->getValue('descriptor_name', null, null, ScopeInterface::SCOPE_STORE); + $request->billing_descriptor = $billingDescriptor; + } + // Set the token source + if ($this->apiHandler->isPreviousMode()) { + $tokenSource = new PreviousRequestTokenSource(); + } else { + $tokenSource = new RequestTokenSource(); + } + + // Shipping fee + $shipping = $quote->getShippingAddress(); + if ($shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { + $processing = new ProcessingSettings(); + $processing->shipping_amount = $this->utilities->formatDecimals($shipping->getShippingInclTax() * 100); + $request->processing = $processing; + } + + $tokenSource->token = $data['contextPaymentId']; + $tokenSource->billing_address = $api->createBillingAddress($quote); + $request->source = $tokenSource; + $request->currency = $currency; + + $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); + + // Send the charge request + return $api->getCheckoutApi()->getPaymentsClient()->requestPayment($request); + } + + /** + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function capture(InfoInterface $payment, $amount): AbstractMethod + { + if ($this->backendAuthSession->isLoggedIn()) { + // Get the store code + $storeCode = $payment->getOrder()->getStore()->getCode(); + + // Initialize the API handler + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + + // Check the status + if (!$this->canCapture()) { + throw new LocalizedException( + __('The capture action is not available.') + ); + } + + // Process the capture request + $response = $api->captureOrder($payment, (float)$amount); + if (!$api->isValidResponse($response)) { + throw new LocalizedException( + __('The capture request could not be processed.') + ); + } + + // Set the transaction id from response + $payment->setTransactionId($response['action_id']); + } + + return $this; + } + + /** + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws LocalizedException + */ + public function void(InfoInterface $payment): AbstractMethod + { + if ($this->backendAuthSession->isLoggedIn()) { + // Get the store code + $storeCode = $payment->getOrder()->getStore()->getCode(); + + // Initialize the API handler + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + + // Check the status + if (!$this->canVoid()) { + throw new LocalizedException( + __('The void action is not available.') + ); + } + + // Process the void request + $response = $api->voidOrder($payment); + if (!$api->isValidResponse($response)) { + throw new LocalizedException( + __('The void request could not be processed.') + ); + } + + // Set the transaction id from response + $payment->setTransactionId($response['action_id']); + } + + return $this; + } + + /** + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws LocalizedException + */ + public function cancel(InfoInterface $payment): AbstractMethod + { + if ($this->backendAuthSession->isLoggedIn()) { + $order = $payment->getOrder(); + // Get the store code + $storeCode = $order->getStore()->getCode(); + + // Initialize the API handler + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + + // Check the status + if (!$this->canVoid()) { + throw new LocalizedException( + __('The void action is not available.') + ); + } + + // Process the void request + $response = $api->voidOrder($payment); + if (!$api->isValidResponse($response)) { + throw new LocalizedException( + __('The void request could not be processed.') + ); + } + + $comment = __( + 'Canceled order online, the voided amount is %1.', + $order->formatPriceTxt($order->getGrandTotal()) + ); + $payment->setMessage($comment); + // Set the transaction id from response + $payment->setTransactionId($response['action_id']); + } + + return $this; + } + + /** + * @throws CheckoutApiException + * @throws CheckoutArgumentException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function refund(InfoInterface $payment, $amount): AbstractMethod + { + if ($this->backendAuthSession->isLoggedIn()) { + // Get the store code + $storeCode = $payment->getOrder()->getStore()->getCode(); + + // Initialize the API handler + try { + $api = $this->apiHandler->init($storeCode, ScopeInterface::SCOPE_STORE); + } catch (CheckoutArgumentException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + } + + // Check the status + if (!$this->canRefund()) { + throw new LocalizedException( + __('The refund action is not available.') + ); + } + + // Process the refund request + try { + $response = $api->refundOrder($payment, $amount); + } catch (CheckoutApiException $e) { + if (!$this->config->isAbcRefundAfterNasMigrationActive($storeCode)) { + throw new LocalizedException(__($e->getMessage())); + } + $api = $this->apiHandler->initAbcForRefund($storeCode, ScopeInterface::SCOPE_STORE); + $response = $api->refundOrder($payment, $amount); + } + + if (!$api->isValidResponse($response)) { + throw new LocalizedException( + __('The refund request could not be processed.') + ); + } + + // Set the transaction id from response + $payment->setTransactionId($response['action_id']); + } + + return $this; + } + + /** + * Check whether method is available + * + * @param CartInterface|null $quote + * + * @throws LocalizedException + */ + public function isAvailable(CartInterface $quote = null): bool + { + if ($this->isModuleActive() && parent::isAvailable($quote) && null !== $quote) { + return $this->config->getValue('active', $this->_code) && !$this->backendAuthSession->isLoggedIn(); + } + + return false; + } +} diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 3407fd9e..70053822 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -627,7 +627,46 @@ Select the Google Pay supported cards - + + + + + payment/checkoutcom_klarna/title + + + + Magento\Config\Model\Config\Source\Yesno + payment/checkoutcom_klarnal/active + + + + + + + + + payment/checkoutcom_klarnal/merchant_id + Provided by Checkout.com during integration. + + + + payment/checkoutcom_klarnal/merchant_username + Provided by Checkout.com during integration. + + + + payment/checkoutcom_klarnal/merchant_password + Provided by Checkout.com during integration. + + + + validate-number + payment/checkoutcom_klarnal/sort_order + + + NAS + + diff --git a/etc/config.xml b/etc/config.xml index acdb82b5..37d0ab05 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -173,6 +173,24 @@ TEST white + + CheckoutCom\Magento2\Model\Methods\KlarnaMethod + Klarna with Checkout.com + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + CheckoutCom\Magento2\Model\Methods\PaypalMethod Paypal with Checkout.com diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml index fee7da2b..1b5379c8 100755 --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -17,6 +17,12 @@ + + + @@ -54,6 +60,9 @@ true + + true + true diff --git a/view/frontend/templates/script/klarna-script.phtml b/view/frontend/templates/script/klarna-script.phtml new file mode 100644 index 00000000..544d25d3 --- /dev/null +++ b/view/frontend/templates/script/klarna-script.phtml @@ -0,0 +1,18 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +?> + From 06e3532111297de4b90904cb156a38ee714ea8d2 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Wed, 19 Jun 2024 16:07:03 +0200 Subject: [PATCH 111/147] CHECMAG2003-236 - Introducing Klarna --- Controller/Klarna/Context.php | 81 ++++++++++ Controller/Paypal/Context.php | 12 +- .../Service/PaymentContextRequestService.php | 21 ++- etc/adminhtml/system.xml | 10 +- view/frontend/layout/checkout_index_index.xml | 5 +- .../method-renderer/checkoutcom_klarna.js | 151 ++++++++++++++++++ .../template/payment/checkoutcom_klarna.html | 58 +++++++ 7 files changed, 322 insertions(+), 16 deletions(-) create mode 100644 Controller/Klarna/Context.php create mode 100755 view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js create mode 100755 view/frontend/web/template/payment/checkoutcom_klarna.html diff --git a/Controller/Klarna/Context.php b/Controller/Klarna/Context.php new file mode 100644 index 00000000..5654c5d3 --- /dev/null +++ b/Controller/Klarna/Context.php @@ -0,0 +1,81 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +namespace CheckoutCom\Magento2\Controller\Klarna; + +use Checkout\Common\AccountHolder; +use Checkout\Common\Address; +use Checkout\Payments\Request\Source\AbstractRequestSource; +use Checkout\Payments\Request\Source\Contexts\PaymentContextsKlarnaSource; +use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; +use CheckoutCom\Magento2\Model\Service\QuoteHandlerService; +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Controller\Result\Json; +use Magento\Framework\Controller\Result\JsonFactory; + +class Context implements HttpPostActionInterface +{ + protected JsonFactory $resultJsonFactory; + protected PaymentContextRequestService $paymentContextRequestService; + protected RequestInterface $request; + protected QuoteHandlerService $quoteHandlerService; + + public function __construct( + JsonFactory $resultJsonFactory, + PaymentContextRequestService $paymentContextRequestService, + RequestInterface $request, + QuoteHandlerService $quoteHandlerService + ) { + $this->resultJsonFactory = $resultJsonFactory; + $this->paymentContextRequestService = $paymentContextRequestService; + $this->request = $request; + $this->quoteHandlerService = $quoteHandlerService; + } + + /** + * @inheritDoc + */ + public function execute(): Json + { + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'content' => $this->paymentContextRequestService->makePaymentContextRequests( + $this->getKlarnaContextSource(), + (bool)$this->request->getParam('forceAuthorizeMode') + ), + ] + ); + + return $resultJson; + } + + private function getKlarnaContextSource(): AbstractRequestSource + { + $klarnaRequestSource = new PaymentContextsKlarnaSource(); + $accountHolder = new AccountHolder(); + $billingAddress = new Address(); + $billingAddress->country = + $this->quoteHandlerService->getBillingAddress()->getCountry() ?: $this->quoteHandlerService->getQuote()->getShippingAddress()->getCountry(); + $accountHolder->billing_address = $billingAddress; + $klarnaRequestSource->account_holder = $accountHolder; + + return $klarnaRequestSource; + } +} diff --git a/Controller/Paypal/Context.php b/Controller/Paypal/Context.php index 4659c3fb..f610c753 100644 --- a/Controller/Paypal/Context.php +++ b/Controller/Paypal/Context.php @@ -15,8 +15,11 @@ * @license https://opensource.org/licenses/mit-license.html MIT License * @link https://docs.checkout.com/ */ + namespace CheckoutCom\Magento2\Controller\Paypal; +use Checkout\Payments\Request\Source\AbstractRequestSource; +use Checkout\Payments\Request\Source\Contexts\PaymentContextsPayPalSource; use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\RequestInterface; @@ -48,12 +51,17 @@ public function execute(): Json $resultJson->setData( [ 'content' => $this->paymentContextRequestService->makePaymentContextRequests( - 'paypal', + $this->getPaypalContext(), (bool)$this->request->getParam('forceAuthorizeMode') - ) + ), ] ); return $resultJson; } + + private function getPaypalContext(): AbstractRequestSource + { + return new PaymentContextsPayPalSource(); + } } diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index 213a0f16..bc195fbb 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -53,6 +53,7 @@ class PaymentContextRequestService protected AddressInterfaceFactory $addressInterfaceFactory; protected CartRepositoryInterface $cartRepository; protected RegionCollectionFactory $regionCollectionFactory; + protected ShopperHandlerService $shopperHandlerService; public function __construct( StoreManagerInterface $storeManager, @@ -65,7 +66,8 @@ public function __construct( Utilities $utilities, AddressInterfaceFactory $addressInterfaceFactory, RegionCollectionFactory $regionCollectionFactory, - CartRepositoryInterface $cartRepository + CartRepositoryInterface $cartRepository, + ShopperHandlerService $shopperHandlerService ) { $this->storeManager = $storeManager; $this->apiHandlerService = $apiHandler; @@ -77,10 +79,11 @@ public function __construct( $this->addressInterfaceFactory = $addressInterfaceFactory; $this->cartRepository = $cartRepository; $this->regionCollectionFactory = $regionCollectionFactory; + $this->shopperHandlerService = $shopperHandlerService; } public function makePaymentContextRequests( - string $sourceType, + AbstractRequestSource $source, ?bool $forceAuthorize = false, ?string $paymentType = null, ?string $authorizationType = null @@ -90,7 +93,7 @@ public function makePaymentContextRequests( return []; } - $request = $this->getContextRequest($quote, $sourceType, $forceAuthorize, $paymentType, $authorizationType); + $request = $this->getContextRequest($quote, $source, $forceAuthorize, $paymentType, $authorizationType); $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); @@ -174,7 +177,7 @@ public function refreshQuoteWithPaymentContext(array $contextDatas, ?PaymentInte private function getContextRequest( CartInterface $quote, - string $sourceType, + AbstractRequestSource $source, ?bool $forceAuthorize = false, ?string $paymentType = null, ?string $authorizationType = null @@ -200,11 +203,12 @@ private function getContextRequest( if ($shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { $processing = new ProcessingSettings(); $processing->shipping_amount = $this->utilities->formatDecimals($shipping->getShippingInclTax() * 100); + $processing->locale = str_replace('_', '-', $this->shopperHandlerService->getCustomerLocale()); $request->processing = $processing; } - // Source Type - $request->source = new AbstractRequestSource($sourceType); + // Source + $request->source = $source; // Items $request->items = $this->getRequestItems($quote); @@ -222,8 +226,10 @@ public function getRequestItems(CartInterface $quote): array /** @var Quote\Item $item */ foreach ($quote->getAllVisibleItems() as $item) { $discount = $this->utilities->formatDecimals($item->getDiscountAmount()) * 100; + $rowAmount = ($this->utilities->formatDecimals($item->getRowTotalInclTax()) * 100) - + ($this->utilities->formatDecimals($discount)); $unitPrice = ($this->utilities->formatDecimals($item->getRowTotalInclTax() / $item->getQty()) * 100) - - ($this->utilities->formatDecimals($discount / $item->getQty())); + ($this->utilities->formatDecimals($discount / $item->getQty())); // Api does not accept 0 prices if (!$unitPrice) { continue; @@ -235,6 +241,7 @@ public function getRequestItems(CartInterface $quote): array $contextItem->name = $item->getName(); $contextItem->discount_amount = $discount; $contextItem->unit_price = $unitPrice; + $contextItem->total_amount = $rowAmount; $items[] = $contextItem; } diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 70053822..ccb3d93d 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -636,7 +636,7 @@ Magento\Config\Model\Config\Source\Yesno - payment/checkoutcom_klarnal/active + payment/checkoutcom_klarna/active @@ -645,23 +645,23 @@ - payment/checkoutcom_klarnal/merchant_id + payment/checkoutcom_klarna/merchant_id Provided by Checkout.com during integration. - payment/checkoutcom_klarnal/merchant_username + payment/checkoutcom_klarna/merchant_username Provided by Checkout.com during integration. - payment/checkoutcom_klarnal/merchant_password + payment/checkoutcom_klarna/merchant_password Provided by Checkout.com during integration. validate-number - payment/checkoutcom_klarnal/sort_order + payment/checkoutcom_klarna/sort_order NAS diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml index 1b5379c8..2417413a 100755 --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -17,14 +17,15 @@ + + + - - diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js new file mode 100755 index 00000000..3c228dd7 --- /dev/null +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -0,0 +1,151 @@ +/** + * Checkout.com + * Authorized and regulated as an electronic money institution + * by the UK Financial Conduct Authority (FCA) under number 900816. + * + * PHP version 7 + * + * @category Magento2 + * @package Checkout.com + * @author Platforms Development Team + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +define([ + 'jquery', + 'knockout', + 'Magento_Checkout/js/view/payment/default', + 'CheckoutCom_Magento2/js/view/payment/utilities', + 'CheckoutCom_Magento2/js/model/checkout-utilities', + 'Magento_Checkout/js/model/full-screen-loader', + 'Magento_Checkout/js/model/payment/additional-validators', + 'Magento_Checkout/js/model/quote', + 'mage/translate', + 'mage/url', +], function($, ko, Component, Utilities, CheckoutUtilities, FullScreenLoader, + AdditionalValidators, Quote, __, Url) { + 'use strict'; + + window.checkoutConfig.reloadOnBillingAddress = true; + const METHOD_ID = 'checkoutcom_klarna'; + let loadEvents = true; + let loaded = false; + + return Component.extend({ + defaults: { + template: 'CheckoutCom_Magento2/payment/' + METHOD_ID + + '.html', + }, + placeOrderEnable: ko.observable(false), + buttonId: METHOD_ID + '_btn', + chkKlarnaSessionId: null, + chkKlarnaClientToken: null, + chkKlarnaContextId: null, + + /** + * @return {void} + */ + initialize: function() { + this._super(); + CheckoutUtilities.initSubscribers(this); + this.getKlarnaContextDatas(); + }, + + /** + * @return {string} + */ + getCode: function() { + return METHOD_ID; + }, + + /** + * @param {string} field + * @return {string} + */ + getValue: function(field) { + return Utilities.getValue(METHOD_ID, field); + }, + + /** + * @return {void} + */ + checkLastPaymentMethod: function() { + return Utilities.checkLastPaymentMethod(); + }, + + /** + * @return {Promise} + */ + getKlarnaContextDatas: function() { + + + fetch(Url.build('checkout_com/klarna/context'), { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest', + }, + }).then(response => response.json()).then(response => { + this.chkKlarnaClientToken = response.content.partner_metadata.client_token; + this.chkKlarnaSessionId = response.content.partner_metadata.session_id; + this.chkKlarnaContextId = response.content.id; + window.klarnaAsyncCallback = function() { + Klarna.Payments.init({ + client_token: this.chkKlarnaClientToken, + }); + }; + Klarna.Payments.load( + { + container: '#klarna-payments-container', + }, + {}, + function(res) { + alert('lalala2'); + alert(res); + console.log('ICICICICICI'); + console.log(res); + }, + ); + }).catch((response) => { + Utilities.log(response); + Utilities.showMessage('error', + __('Something went wrong with klarna method. Please choose another method.'), + METHOD_ID); + }); + }, + + /** + * @return {void} + */ + placeOrder: function() { + FullScreenLoader.startLoader(); + + if (Utilities.methodIsSelected(METHOD_ID) && + this.chkKlarnaContextId) { + let data = { + methodId: METHOD_ID, + contextPaymentId: this.chkKlarnaContextId, + }; + + // Place the order + if (AdditionalValidators.validate()) { + Utilities.placeOrder( + data, + METHOD_ID, + function() { + Utilities.log(__('Success')); + }, + function() { + Utilities.log(__('Fail')); + }, + ); + Utilities.cleanCustomerShippingAddress(); + } + + FullScreenLoader.stopLoader(); + } + }, + }); +}); diff --git a/view/frontend/web/template/payment/checkoutcom_klarna.html b/view/frontend/web/template/payment/checkoutcom_klarna.html new file mode 100755 index 00000000..5b16566d --- /dev/null +++ b/view/frontend/web/template/payment/checkoutcom_klarna.html @@ -0,0 +1,58 @@ + + +
+
+ + +
+ +
+ + + + + + +
+
+
+ + +
+ + + +
+ + +
+ + + +
+ + +
+ OKOKOKOKO +
+
+ +
+
From fa6c98060bafc8ddbb389fe13ecaf2c527663fb5 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Thu, 20 Jun 2024 15:36:02 +0200 Subject: [PATCH 112/147] CHECMAG2003-236 - Introducing Klarna Process --- Controller/Klarna/Context.php | 5 +- Model/Methods/KlarnaMethod.php | 8 +-- .../Service/PaymentContextRequestService.php | 29 ++++++++--- etc/adminhtml/system.xml | 20 -------- etc/di.xml | 1 + .../method-renderer/checkoutcom_klarna.js | 51 ++++++++++++++----- .../template/payment/checkoutcom_klarna.html | 17 +++++-- 7 files changed, 85 insertions(+), 46 deletions(-) diff --git a/Controller/Klarna/Context.php b/Controller/Klarna/Context.php index 5654c5d3..43aa7ac9 100644 --- a/Controller/Klarna/Context.php +++ b/Controller/Klarna/Context.php @@ -58,7 +58,10 @@ public function execute(): Json [ 'content' => $this->paymentContextRequestService->makePaymentContextRequests( $this->getKlarnaContextSource(), - (bool)$this->request->getParam('forceAuthorizeMode') + (bool)$this->request->getParam('forceAuthorizeMode'), + null, + null, + true ), ] ); diff --git a/Model/Methods/KlarnaMethod.php b/Model/Methods/KlarnaMethod.php index 9aba8d3e..7d65eb01 100755 --- a/Model/Methods/KlarnaMethod.php +++ b/Model/Methods/KlarnaMethod.php @@ -298,16 +298,16 @@ public function sendPaymentRequest(array $data, float $amount, string $currency, } // Shipping fee - $shipping = $quote->getShippingAddress(); + /*$shipping = $quote->getShippingAddress(); if ($shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { $processing = new ProcessingSettings(); $processing->shipping_amount = $this->utilities->formatDecimals($shipping->getShippingInclTax() * 100); $request->processing = $processing; - } + }*/ - $tokenSource->token = $data['contextPaymentId']; + /*$tokenSource->token = $data['contextPaymentId']; $tokenSource->billing_address = $api->createBillingAddress($quote); - $request->source = $tokenSource; + $request->source = $tokenSource;*/ $request->currency = $currency; $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index bc195fbb..c80bc9be 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -86,14 +86,15 @@ public function makePaymentContextRequests( AbstractRequestSource $source, ?bool $forceAuthorize = false, ?string $paymentType = null, - ?string $authorizationType = null + ?string $authorizationType = null, + ?bool $setShippingFeesAsItem = false ): array { $quote = $this->getQuote(); if (!$quote->getId() || ($quote->getId() && !$quote->getItemsQty())) { return []; } - $request = $this->getContextRequest($quote, $source, $forceAuthorize, $paymentType, $authorizationType); + $request = $this->getContextRequest($quote, $source, $forceAuthorize, $paymentType, $authorizationType, setShippingFeesAsItem); $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); @@ -180,7 +181,8 @@ private function getContextRequest( AbstractRequestSource $source, ?bool $forceAuthorize = false, ?string $paymentType = null, - ?string $authorizationType = null + ?string $authorizationType = null, + ?bool $setShippingFeesAsItem = false ): PaymentContextsRequest { // Set Default values if (!$paymentType) { @@ -202,7 +204,9 @@ private function getContextRequest( $shipping = $quote->getShippingAddress(); if ($shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { $processing = new ProcessingSettings(); - $processing->shipping_amount = $this->utilities->formatDecimals($shipping->getShippingInclTax() * 100); + if (!$setShippingFeesAsItem) { + $processing->shipping_amount = $this->utilities->formatDecimals($shipping->getShippingInclTax() * 100); + } $processing->locale = str_replace('_', '-', $this->shopperHandlerService->getCustomerLocale()); $request->processing = $processing; } @@ -211,7 +215,7 @@ private function getContextRequest( $request->source = $source; // Items - $request->items = $this->getRequestItems($quote); + $request->items = $this->getRequestItems($quote, $setShippingFeesAsItem); // Urls $request->success_url = $this->urlBuilder->getUrl('checkout/onepage/success'); @@ -220,7 +224,7 @@ private function getContextRequest( return $request; } - public function getRequestItems(CartInterface $quote): array + public function getRequestItems(CartInterface $quote, ?bool $setShippingFeesAsItem = false): array { $items = []; /** @var Quote\Item $item */ @@ -246,6 +250,19 @@ public function getRequestItems(CartInterface $quote): array $items[] = $contextItem; } + // Shipping fee + $shipping = $quote->getShippingAddress(); + + if ($setShippingFeesAsItem && $shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { + $product = new PaymentContextsItems(); + $product->name = $shipping->getShippingDescription(); + $product->quantity = 1; + $product->unit_price = $shipping->getShippingInclTax() * 100; + $product->total_amount = $shipping->getShippingInclTax() * 100; + + $items[] = $product; + } + return $items; } diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index ccb3d93d..9c2bb46e 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -637,26 +637,6 @@ Magento\Config\Model\Config\Source\Yesno payment/checkoutcom_klarna/active - - - - - -
- - - payment/checkoutcom_klarna/merchant_id - Provided by Checkout.com during integration. - - - - payment/checkoutcom_klarna/merchant_username - Provided by Checkout.com during integration. - - - - payment/checkoutcom_klarna/merchant_password - Provided by Checkout.com during integration. diff --git a/etc/di.xml b/etc/di.xml index ffc6eb2c..7dce885f 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -42,6 +42,7 @@ CheckoutCom\Magento2\Model\Methods\ApplePayMethod CheckoutCom\Magento2\Model\Methods\GooglePayMethod CheckoutCom\Magento2\Model\Methods\PaypalMethod + CheckoutCom\Magento2\Model\Methods\KlarnaMethod CheckoutCom\Magento2\Model\Methods\VaultMethod diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index 3c228dd7..2614e4a8 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -50,7 +50,6 @@ define([ initialize: function() { this._super(); CheckoutUtilities.initSubscribers(this); - this.getKlarnaContextDatas(); }, /** @@ -79,8 +78,7 @@ define([ * @return {Promise} */ getKlarnaContextDatas: function() { - - + let self = this; fetch(Url.build('checkout_com/klarna/context'), { method: 'POST', headers: { @@ -88,27 +86,34 @@ define([ 'X-Requested-With': 'XMLHttpRequest', }, }).then(response => response.json()).then(response => { + // Store given token this.chkKlarnaClientToken = response.content.partner_metadata.client_token; this.chkKlarnaSessionId = response.content.partner_metadata.session_id; this.chkKlarnaContextId = response.content.id; - window.klarnaAsyncCallback = function() { - Klarna.Payments.init({ - client_token: this.chkKlarnaClientToken, - }); - }; + + // Init klarna api + Klarna.Payments.init({ + client_token: this.chkKlarnaClientToken, + }); + + // Load the klarna methods Klarna.Payments.load( { container: '#klarna-payments-container', }, {}, function(res) { - alert('lalala2'); - alert(res); - console.log('ICICICICICI'); - console.log(res); + if (res.show_form === true) { + self.placeOrderEnable(true); + } else { + Utilities.showMessage('error', + __('Something went wrong with klarna method. Please choose another method.'), + METHOD_ID); + } }, ); }).catch((response) => { + // Here we know that klarna is disallowed for this context Utilities.log(response); Utilities.showMessage('error', __('Something went wrong with klarna method. Please choose another method.'), @@ -116,6 +121,28 @@ define([ }); }, + authorizePayment: function() { + let self = this; + + let billingDatas = window.checkoutConfig.billingAddressFromData; + + // Open the klarna popin with customer datas + Klarna.Payments.authorize( + {}, + {}, + function(res) { + console.log('Authorize outcome:', res); + if (res.approved === true) { + self.placeOrder(); + } else { + Utilities.showMessage('error', + __('Your payment has failed. Please try again.'), + METHOD_ID); + } + }, + ); + }, + /** * @return {void} */ diff --git a/view/frontend/web/template/payment/checkoutcom_klarna.html b/view/frontend/web/template/payment/checkoutcom_klarna.html index 5b16566d..65025506 100755 --- a/view/frontend/web/template/payment/checkoutcom_klarna.html +++ b/view/frontend/web/template/payment/checkoutcom_klarna.html @@ -23,7 +23,7 @@
-
+
@@ -50,9 +50,20 @@
- OKOKOKOKO +
+ +
-
+ +
From dd94c1a4aa74647dd10aa995d0e0f22f8895ceb8 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Mon, 24 Jun 2024 11:34:46 +0200 Subject: [PATCH 113/147] CHECMAG2003-236 - Finalize Klarna process --- Controller/Klarna/Context.php | 14 +-- Controller/Klarna/GetCustomerDatas.php | 67 ++++++++++ Controller/Paypal/Context.php | 11 +- .../Service/PaymentContextRequestService.php | 118 +++++++++++++----- .../method-renderer/checkoutcom_klarna.js | 57 ++++++--- .../template/payment/checkoutcom_klarna.html | 9 +- 6 files changed, 214 insertions(+), 62 deletions(-) create mode 100644 Controller/Klarna/GetCustomerDatas.php diff --git a/Controller/Klarna/Context.php b/Controller/Klarna/Context.php index 43aa7ac9..45f2da2e 100644 --- a/Controller/Klarna/Context.php +++ b/Controller/Klarna/Context.php @@ -56,13 +56,13 @@ public function execute(): Json $resultJson = $this->resultJsonFactory->create(); $resultJson->setData( [ - 'content' => $this->paymentContextRequestService->makePaymentContextRequests( - $this->getKlarnaContextSource(), - (bool)$this->request->getParam('forceAuthorizeMode'), - null, - null, - true - ), + 'content' => $this->paymentContextRequestService + ->setShippingFeesAsItem(true) + ->collectDiscountAmountOnItemUnitPrice(false) + ->setForceAuthorizeMode((bool)$this->request->getParam('forceAuthorizeMode')) + ->makePaymentContextRequests( + $this->getKlarnaContextSource() + ), ] ); diff --git a/Controller/Klarna/GetCustomerDatas.php b/Controller/Klarna/GetCustomerDatas.php new file mode 100644 index 00000000..53beda39 --- /dev/null +++ b/Controller/Klarna/GetCustomerDatas.php @@ -0,0 +1,67 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +namespace CheckoutCom\Magento2\Controller\Klarna; + +use CheckoutCom\Magento2\Model\Service\QuoteHandlerService; +use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Controller\Result\Json; +use Magento\Framework\Controller\Result\JsonFactory; + +class GetCustomerDatas implements HttpPostActionInterface +{ + protected JsonFactory $resultJsonFactory; + protected RequestInterface $request; + protected QuoteHandlerService $quoteHandlerService; + + public function __construct( + JsonFactory $resultJsonFactory, + RequestInterface $request, + QuoteHandlerService $quoteHandlerService + ) { + $this->resultJsonFactory = $resultJsonFactory; + $this->request = $request; + $this->quoteHandlerService = $quoteHandlerService; + } + + /** + * @inheritDoc + */ + public function execute(): Json + { + // Get the request data + $quoteId = $this->request->getParam('quote_id'); + $storeId = $this->request->getParam('store_id'); + + // Try to load a quote + $quote = $this->quoteHandlerService->getQuote([ + 'entity_id' => $quoteId, + 'store_id' => $storeId, + ]); + + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'billing' => $this->quoteHandlerService->getBillingAddress()->toArray(), + ] + ); + + return $resultJson; + } +} diff --git a/Controller/Paypal/Context.php b/Controller/Paypal/Context.php index f610c753..3016431e 100644 --- a/Controller/Paypal/Context.php +++ b/Controller/Paypal/Context.php @@ -50,10 +50,13 @@ public function execute(): Json $resultJson = $this->resultJsonFactory->create(); $resultJson->setData( [ - 'content' => $this->paymentContextRequestService->makePaymentContextRequests( - $this->getPaypalContext(), - (bool)$this->request->getParam('forceAuthorizeMode') - ), + 'content' => $this->paymentContextRequestService + ->setShippingFeesAsItem(false) + ->collectDiscountAmountOnItemUnitPrice(true) + ->setForceAuthorizeMode((bool)$this->request->getParam('forceAuthorizeMode')) + ->makePaymentContextRequests( + $this->getPaypalContext() + ), ] ); diff --git a/Model/Service/PaymentContextRequestService.php b/Model/Service/PaymentContextRequestService.php index c80bc9be..1b1665a1 100644 --- a/Model/Service/PaymentContextRequestService.php +++ b/Model/Service/PaymentContextRequestService.php @@ -54,6 +54,30 @@ class PaymentContextRequestService protected CartRepositoryInterface $cartRepository; protected RegionCollectionFactory $regionCollectionFactory; protected ShopperHandlerService $shopperHandlerService; + /** + * Should we set the shipping fils as an item line (if no it's used on "processing" request part) + */ + protected bool $setShippingFeesAsItem = false; + /** + * Should we substract the dicount amount from the unit price of each item ? + */ + protected bool $collectDiscountAmountOnItemUnitPrice = true; + /** + * Should we force authorise mode instead of capture for this context + */ + protected bool $forceAuthorize = false; + /** + * The payment type for this context (default Regular) + * + * @see PaymentType + */ + protected ?string $paymentType = null; + /** + * The Authorize type type for this context (Default Final) + * + * @see AuthorizationType + */ + protected ?string $authorizeType = null; public function __construct( StoreManagerInterface $storeManager, @@ -83,18 +107,14 @@ public function __construct( } public function makePaymentContextRequests( - AbstractRequestSource $source, - ?bool $forceAuthorize = false, - ?string $paymentType = null, - ?string $authorizationType = null, - ?bool $setShippingFeesAsItem = false + AbstractRequestSource $source ): array { $quote = $this->getQuote(); if (!$quote->getId() || ($quote->getId() && !$quote->getItemsQty())) { return []; } - $request = $this->getContextRequest($quote, $source, $forceAuthorize, $paymentType, $authorizationType, setShippingFeesAsItem); + $request = $this->getContextRequest($quote, $source); $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); @@ -178,44 +198,35 @@ public function refreshQuoteWithPaymentContext(array $contextDatas, ?PaymentInte private function getContextRequest( CartInterface $quote, - AbstractRequestSource $source, - ?bool $forceAuthorize = false, - ?string $paymentType = null, - ?string $authorizationType = null, - ?bool $setShippingFeesAsItem = false + AbstractRequestSource $source ): PaymentContextsRequest { - // Set Default values - if (!$paymentType) { - $paymentType = PaymentType::$regular; - } - if (!$authorizationType) { - $authorizationType = AuthorizationType::$final; - } - $capture = $forceAuthorize ? false : $this->checkoutConfigProvider->needsAutoCapture(); + $capture = $this->forceAuthorize ? false : $this->checkoutConfigProvider->needsAutoCapture(); // Global informations $request = new PaymentContextsRequest(); $request->amount = $this->utilities->formatDecimals($quote->getGrandTotal() * 100); - $request->payment_type = $paymentType; + $request->payment_type = $this->getPaymentType(); $request->currency = $quote->getCurrency()->getQuoteCurrencyCode(); $request->capture = $capture; $request->processing_channel_id = $this->checkoutConfigProvider->getValue('channel_id'); + $request->authorizationType = $this->getAuthorizeType(); + + $processing = new ProcessingSettings(); + $processing->locale = str_replace('_', '-', $this->shopperHandlerService->getCustomerLocale()); $shipping = $quote->getShippingAddress(); if ($shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { - $processing = new ProcessingSettings(); - if (!$setShippingFeesAsItem) { + if (!$this->setShippingFeesAsItem) { $processing->shipping_amount = $this->utilities->formatDecimals($shipping->getShippingInclTax() * 100); } - $processing->locale = str_replace('_', '-', $this->shopperHandlerService->getCustomerLocale()); - $request->processing = $processing; } + $request->processing = $processing; // Source $request->source = $source; // Items - $request->items = $this->getRequestItems($quote, $setShippingFeesAsItem); + $request->items = $this->getRequestItems($quote); // Urls $request->success_url = $this->urlBuilder->getUrl('checkout/onepage/success'); @@ -224,16 +235,19 @@ private function getContextRequest( return $request; } - public function getRequestItems(CartInterface $quote, ?bool $setShippingFeesAsItem = false): array + public function getRequestItems(CartInterface $quote): array { $items = []; /** @var Quote\Item $item */ foreach ($quote->getAllVisibleItems() as $item) { - $discount = $this->utilities->formatDecimals($item->getDiscountAmount()) * 100; + $discount = $discountOnUnitPrice = $this->utilities->formatDecimals($item->getDiscountAmount()) * 100; + if (!$this->collectDiscountAmountOnItemUnitPrice) { + $discountOnUnitPrice = 0; + } $rowAmount = ($this->utilities->formatDecimals($item->getRowTotalInclTax()) * 100) - ($this->utilities->formatDecimals($discount)); $unitPrice = ($this->utilities->formatDecimals($item->getRowTotalInclTax() / $item->getQty()) * 100) - - ($this->utilities->formatDecimals($discount / $item->getQty())); + ($this->utilities->formatDecimals($discountOnUnitPrice / $item->getQty())); // Api does not accept 0 prices if (!$unitPrice) { continue; @@ -253,7 +267,7 @@ public function getRequestItems(CartInterface $quote, ?bool $setShippingFeesAsIt // Shipping fee $shipping = $quote->getShippingAddress(); - if ($setShippingFeesAsItem && $shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { + if ($this->setShippingFeesAsItem && $shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { $product = new PaymentContextsItems(); $product->name = $shipping->getShippingDescription(); $product->quantity = 1; @@ -270,4 +284,50 @@ private function getQuote(): CartInterface { return $this->checkoutSession->getQuote(); } + + public function setShippingFeesAsItem(bool $value): self + { + $this->setShippingFeesAsItem = $value; + + return $this; + } + + public function setForceAuthorizeMode(bool $value): self + { + $this->forceAuthorize = $value; + + return $this; + } + + public function collectDiscountAmountOnItemUnitPrice(bool $value): self + { + $this->collectDiscountAmountOnItemUnitPrice = $value; + + return $this; + } + + public function setPaymentType(string $paymentType): self + { + $this->paymentType = $paymentType; + + return $this; + } + + private function getPaymentType(): string + { + if (!$this->paymentType) { + return PaymentType::$regular; + } + + return $this->paymentType; + } + + private function getAuthorizeType(): string + { + if (!$this->authorizeType) { + return AuthorizationType::$final; + } + + return $this->authorizeType; + } } diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index 2614e4a8..60a24a7f 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -40,7 +40,6 @@ define([ }, placeOrderEnable: ko.observable(false), buttonId: METHOD_ID + '_btn', - chkKlarnaSessionId: null, chkKlarnaClientToken: null, chkKlarnaContextId: null, @@ -50,6 +49,7 @@ define([ initialize: function() { this._super(); CheckoutUtilities.initSubscribers(this); + this.getKlarnaContextDatas(); }, /** @@ -88,7 +88,6 @@ define([ }).then(response => response.json()).then(response => { // Store given token this.chkKlarnaClientToken = response.content.partner_metadata.client_token; - this.chkKlarnaSessionId = response.content.partner_metadata.session_id; this.chkKlarnaContextId = response.content.id; // Init klarna api @@ -126,21 +125,47 @@ define([ let billingDatas = window.checkoutConfig.billingAddressFromData; - // Open the klarna popin with customer datas - Klarna.Payments.authorize( - {}, - {}, - function(res) { - console.log('Authorize outcome:', res); - if (res.approved === true) { - self.placeOrder(); - } else { - Utilities.showMessage('error', - __('Your payment has failed. Please try again.'), - METHOD_ID); - } + + + $.ajax({ + type: 'POST', + url: Url.build('checkout_com/klarna/getCustomerDatas'), + data: { + quote_id: window.checkoutConfig.quoteItemData[0].quote_id, + form_key: window.checkoutConfig.formKey, + store_id: window.checkoutConfig.quoteData.store_id, }, - ); + success: function(data) { + Klarna.Payments.authorize( + {}, + { + billing_address: { + given_name: data.billing.firstname, + family_name: data.billing.lastname, + email: data.billing.email || Utilities.getEmail(), + //title: data.billing.email, + street_address: data.billing.street, + //street_address2: data.billing.email, + postal_code: data.billing.postcode, + city: data.billing.city, + region: data.billing.region, + phone: data.billing.phone, + country: data.billing.country_id.toLowerCase() + }, + }, + function(res) { + if (res.approved === true) { + self.placeOrder(); + } else { + Utilities.showMessage('error', + __('Your payment has failed. Please try again.'), + METHOD_ID); + } + }, + ); + }, + error: self.placeOrderEnable(false), + }); }, /** diff --git a/view/frontend/web/template/payment/checkoutcom_klarna.html b/view/frontend/web/template/payment/checkoutcom_klarna.html index 65025506..8cb52f59 100755 --- a/view/frontend/web/template/payment/checkoutcom_klarna.html +++ b/view/frontend/web/template/payment/checkoutcom_klarna.html @@ -14,7 +14,7 @@ -->
+ data-bind="visible: placeOrderEnable,css: {'_active': (getCode() == isChecked())}, attr: {'id': getCode() + '_container'}">
@@ -23,7 +23,7 @@
-
+
@@ -48,7 +48,6 @@
-
- - -
+
From fcbccb0b4efc30b383ea061c099dda8d6edc7e4e Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Mon, 24 Jun 2024 11:44:03 +0200 Subject: [PATCH 114/147] CHECMAG2003-236 - Code cleanup --- Model/Methods/KlarnaMethod.php | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Model/Methods/KlarnaMethod.php b/Model/Methods/KlarnaMethod.php index 7d65eb01..d226a41c 100755 --- a/Model/Methods/KlarnaMethod.php +++ b/Model/Methods/KlarnaMethod.php @@ -24,7 +24,6 @@ use Checkout\Payments\BillingDescriptor; use Checkout\Payments\Previous\PaymentRequest as PreviousPaymentRequest; use Checkout\Payments\Previous\Source\RequestTokenSource as PreviousRequestTokenSource; -use Checkout\Payments\ProcessingSettings; use Checkout\Payments\Request\PaymentRequest; use Checkout\Payments\Request\Source\RequestTokenSource; use CheckoutCom\Magento2\Gateway\Config\Config; @@ -296,18 +295,7 @@ public function sendPaymentRequest(array $data, float $amount, string $currency, } else { $tokenSource = new RequestTokenSource(); } - - // Shipping fee - /*$shipping = $quote->getShippingAddress(); - if ($shipping->getShippingDescription() && $shipping->getShippingInclTax() > 0) { - $processing = new ProcessingSettings(); - $processing->shipping_amount = $this->utilities->formatDecimals($shipping->getShippingInclTax() * 100); - $request->processing = $processing; - }*/ - - /*$tokenSource->token = $data['contextPaymentId']; - $tokenSource->billing_address = $api->createBillingAddress($quote); - $request->source = $tokenSource;*/ + $request->currency = $currency; $this->ckoLogger->additional($this->utilities->objectToArray($request), 'payment'); From f388dd9c870e0a88441b25e1fbb44654c154c1d2 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Mon, 24 Jun 2024 13:05:08 +0200 Subject: [PATCH 115/147] CHECMAG2003-236 - Code cleanup --- Model/Methods/KlarnaMethod.php | 5 +++-- Model/Methods/PaypalMethod.php | 5 ++--- .../payment/method-renderer/checkoutcom_klarna.js | 13 ++++++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Model/Methods/KlarnaMethod.php b/Model/Methods/KlarnaMethod.php index d226a41c..97cf40f6 100755 --- a/Model/Methods/KlarnaMethod.php +++ b/Model/Methods/KlarnaMethod.php @@ -22,6 +22,7 @@ use Checkout\CheckoutApiException; use Checkout\CheckoutArgumentException; use Checkout\Payments\BillingDescriptor; +use Checkout\Payments\PaymentType; use Checkout\Payments\Previous\PaymentRequest as PreviousPaymentRequest; use Checkout\Payments\Previous\Source\RequestTokenSource as PreviousRequestTokenSource; use Checkout\Payments\Request\PaymentRequest; @@ -272,11 +273,11 @@ public function sendPaymentRequest(array $data, float $amount, string $currency, $request->payment_context_id = $data['contextPaymentId']; $request->processing_channel_id = $this->config->getValue('channel_id'); $request->reference = $reference; - $request->metadata['methodId'] = $this->_code; $request->description = __('Payment request from %1', $this->config->getStoreName())->render(); $request->customer = $api->createCustomer($quote); - $request->payment_type = 'Regular'; + $request->payment_type = PaymentType::$regular; $request->shipping = $api->createShippingAddress($quote); + $request->metadata['methodId'] = $this->_code; $request->metadata['quoteData'] = $this->json->serialize($this->quoteHandler->getQuoteRequestData($quote)); $request->metadata = array_merge( $request->metadata, diff --git a/Model/Methods/PaypalMethod.php b/Model/Methods/PaypalMethod.php index d7723edf..46dcbc0d 100755 --- a/Model/Methods/PaypalMethod.php +++ b/Model/Methods/PaypalMethod.php @@ -22,11 +22,10 @@ use Checkout\CheckoutApiException; use Checkout\CheckoutArgumentException; use Checkout\Payments\BillingDescriptor; +use Checkout\Payments\PaymentType; use Checkout\Payments\Previous\PaymentRequest as PreviousPaymentRequest; -use Checkout\Payments\Previous\Source\RequestTokenSource as PreviousRequestTokenSource; use Checkout\Payments\ProcessingSettings; use Checkout\Payments\Request\PaymentRequest; -use Checkout\Payments\Request\Source\RequestTokenSource; use CheckoutCom\Magento2\Gateway\Config\Config; use CheckoutCom\Magento2\Helper\Logger as LoggerHelper; use CheckoutCom\Magento2\Helper\Utilities; @@ -276,7 +275,7 @@ public function sendPaymentRequest(array $data, float $amount, string $currency, $request->metadata['methodId'] = $this->_code; $request->description = __('Payment request from %1', $this->config->getStoreName())->render(); $request->customer = $api->createCustomer($quote); - $request->payment_type = 'Regular'; + $request->payment_type = PaymentType::$regular; $request->shipping = $api->createShippingAddress($quote); $request->metadata['quoteData'] = $this->json->serialize($this->quoteHandler->getQuoteRequestData($quote)); $request->metadata = array_merge( diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index 60a24a7f..59610b42 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -95,7 +95,7 @@ define([ client_token: this.chkKlarnaClientToken, }); - // Load the klarna methods + // Load the klarna, check if context (res_form) allow purchase Klarna.Payments.load( { container: '#klarna-payments-container', @@ -103,6 +103,7 @@ define([ {}, function(res) { if (res.show_form === true) { + // Display method self.placeOrderEnable(true); } else { Utilities.showMessage('error', @@ -120,13 +121,13 @@ define([ }); }, + /** + * Display the Klarna popin + */ authorizePayment: function() { let self = this; - let billingDatas = window.checkoutConfig.billingAddressFromData; - - - + // Retrieve current quote datas in order to give billing informations to Klarna $.ajax({ type: 'POST', url: Url.build('checkout_com/klarna/getCustomerDatas'), @@ -136,6 +137,8 @@ define([ store_id: window.checkoutConfig.quoteData.store_id, }, success: function(data) { + + // Launch klarna popin with retrieved customer datas Klarna.Payments.authorize( {}, { From 55e8fbf55dd67a63ddb29fc4f439f52814796b04 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Mon, 24 Jun 2024 14:11:36 +0200 Subject: [PATCH 116/147] CHECMAG2003-236 - Code cleanup --- .../method-renderer/checkoutcom_klarna.js | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index 59610b42..86b2a0d6 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -142,18 +142,17 @@ define([ Klarna.Payments.authorize( {}, { - billing_address: { - given_name: data.billing.firstname, - family_name: data.billing.lastname, - email: data.billing.email || Utilities.getEmail(), - //title: data.billing.email, + billing_address: { + given_name: data.billing.firstname, + family_name: data.billing.lastname, + email: data.billing.email || + Utilities.getEmail(), street_address: data.billing.street, - //street_address2: data.billing.email, - postal_code: data.billing.postcode, - city: data.billing.city, - region: data.billing.region, - phone: data.billing.phone, - country: data.billing.country_id.toLowerCase() + postal_code: data.billing.postcode, + city: data.billing.city, + region: data.billing.region, + phone: data.billing.phone, + country: data.billing.country_id.toLowerCase(), }, }, function(res) { From b012ca6a463e044c48f17d10bf3ac260ccb01c88 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Wed, 26 Jun 2024 09:08:41 +0200 Subject: [PATCH 117/147] CHECMAG2003-236 - Code cleanup --- .../web/js/view/payment/method-renderer/checkoutcom_klarna.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index 86b2a0d6..a07589a1 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -145,8 +145,7 @@ define([ billing_address: { given_name: data.billing.firstname, family_name: data.billing.lastname, - email: data.billing.email || - Utilities.getEmail(), + email: data.billing.email || Utilities.getEmail(), street_address: data.billing.street, postal_code: data.billing.postcode, city: data.billing.city, From 0c83428af5d674c9da4bf8d31af02b98ed1ea671 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Wed, 26 Jun 2024 10:45:43 +0200 Subject: [PATCH 118/147] CHECMAG2003-238 - Remove Giropay from APM --- Model/Files/Mada/apm_list.csv | 3 +-- Model/Methods/AlternativePaymentMethod.php | 24 ---------------------- README.md | 2 +- etc/apm.xml | 6 ------ view/frontend/web/css/apm/apm.css | 4 ---- view/frontend/web/css/apm/apm.min.css | 2 +- 6 files changed, 3 insertions(+), 38 deletions(-) diff --git a/Model/Files/Mada/apm_list.csv b/Model/Files/Mada/apm_list.csv index 5f9d6e68..d95e296a 100644 --- a/Model/Files/Mada/apm_list.csv +++ b/Model/Files/Mada/apm_list.csv @@ -1,10 +1,9 @@ Id,Title alipay,Alipay boleto,Boleto -giropay,Giropay ideal,Ideal poli,Poli sepa,Sepa sofort,Sofort klarna,Klarna -eps,EPS \ No newline at end of file +eps,EPS diff --git a/Model/Methods/AlternativePaymentMethod.php b/Model/Methods/AlternativePaymentMethod.php index 231fd6b6..d53d71bd 100755 --- a/Model/Methods/AlternativePaymentMethod.php +++ b/Model/Methods/AlternativePaymentMethod.php @@ -27,8 +27,6 @@ use Checkout\Payments\Previous\Source\Apm\RequestBoletoSource; use Checkout\Payments\Previous\Source\Apm\RequestEpsSource as PreviousRequestEpsSource; use Checkout\Payments\Previous\Source\Apm\RequestFawrySource as PreviousRequestFawrySource; -use Checkout\Payments\Previous\Source\Apm\RequestGiropaySource as PreviousRequestGiropaySource; -use Checkout\Payments\Request\Source\Apm\RequestGiropaySource; use Checkout\Payments\Previous\Source\Apm\RequestIdealSource as PreviousRequestIdealSource; use Checkout\Payments\Previous\Source\Apm\RequestKlarnaSource; use Checkout\Payments\Previous\Source\Apm\RequestKnetSource; @@ -678,28 +676,6 @@ public function boleto(array $data): RequestBoletoSource return $boletoSource; } - /** - * Create source - * - * @param array $data - * - * @return RequestGiropaySource|PreviousRequestGiropaySource - * @throws NoSuchEntityException - */ - public function giropay(array $data) - { - if ($this->apiHandler->isPreviousMode()) { - $source = new PreviousRequestGiropaySource(); - $source->purpose = null; - $source->bic = $this->getValue('bic', $data); - $source->info_fields = null; - } else { - $source = new RequestGiropaySource(); - } - - return $source; - } - /** * @param array $data * diff --git a/README.md b/README.md index 51f946b8..cd90e9df 100755 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The Frames.js payment form is cross-browser and cross-device compatible, and can * Alternative Payments
Users can place orders with the following alternative and local payment options used around the world: -Alipay, Bancontact, Boleto, EPS, Fawry, Giropay, Ideal, Klarna, KNet, Poli, Sepa, Sofort. +Alipay, Bancontact, Boleto, EPS, Fawry, Ideal, Klarna, KNet, Poli, Sepa, Sofort. * Apple Pay Payments
Users can place orders with an Apple Pay wallet. diff --git a/etc/apm.xml b/etc/apm.xml index 9e235be0..a40be41d 100755 --- a/etc/apm.xml +++ b/etc/apm.xml @@ -26,12 +26,6 @@ BRL,USD BR - - giropay - Giropay - EUR - DE - ideal iDEAL diff --git a/view/frontend/web/css/apm/apm.css b/view/frontend/web/css/apm/apm.css index 39c94aac..728bb3c8 100644 --- a/view/frontend/web/css/apm/apm.css +++ b/view/frontend/web/css/apm/apm.css @@ -153,10 +153,6 @@ div.cko-alternative-form { background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU1XzNfIiBjbGFzcz0ic3QxNSIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTUuNCwxMS44QzE1LjQsMTEuOCwxNS40LDExLjgsMTUuNCwxMS44Yy0wLjEtMC4xLTAuMS0wLjEtMC4yLTAuMmMtMC40LTAuOC0wLjgtMS42LTEuMi0yLjNjLTAuMy0wLjYtMC43LTEuMy0xLTEuOWMwLTAuMS0wLjEtMC4xLTAuMi0wLjFjLTAuNCwwLTAuOSwwLTEuMywwYy0wLjIsMC0wLjIsMC4xLTAuMiwwLjJjMCwyLjEsMCw0LjIsMCw2LjJjMCwwLjEsMC4xLDAuMiwwLjIsMC4yYzAuMywwLDAuNSwwLDAuOCwwYzAuMiwwLDAuMiwwLDAuMi0wLjJjMC0xLjQsMC0yLjgsMC00LjJjMC0wLjEsMC0wLjEsMC0wLjJjMCwwLjEsMC4xLDAuMSwwLjEsMC4yYzAuMywwLjYsMC42LDEuMSwwLjksMS43YzAuNSwwLjksMSwxLjgsMS40LDIuN2MwLDAuMSwwLjEsMC4xLDAuMiwwLjFjMC40LDAsMC45LDAsMS4zLDBjMC4xLDAsMC4yLDAsMC4yLTAuMmMwLTIuMSwwLTQuMiwwLTYuM2MwLTAuMiwwLTAuMi0wLjItMC4yYy0wLjIsMC0wLjUsMC0wLjcsMGMtMC4yLDAtMC4yLDAtMC4yLDAuMmMwLDEuNCwwLDIuOCwwLDQuMUMxNS40LDExLjYsMTUuNCwxMS43LDE1LjQsMTEuOHogTTE5LDguM0MxOSw4LjMsMTksOC4zLDE5LDguM2MwLjksMCwxLjYsMCwyLjQsMGMwLjEsMCwwLjIsMCwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4yLDAtMC4yLTAuMi0wLjJjLTEuMiwwLTIuNSwwLTMuNywwYy0wLjIsMC0wLjIsMC4xLTAuMiwwLjJjMCwwLjMsMCwwLjUsMCwwLjhjMCwxLjgsMCwzLjYsMCw1LjRjMCwwLjIsMCwwLjIsMC4yLDAuMmMxLjMsMCwyLjcsMCw0LDBjMC4xLDAsMC4yLTAuMSwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4yLDAtMC4yLTAuMi0wLjJjLTAuOCwwLTEuNiwwLTIuNCwwYy0wLjEsMC0wLjEsMC0wLjIsMGMwLTAuNiwwLTEuMSwwLTEuN2MwLjEsMCwwLjEsMCwwLjIsMGMwLjYsMCwxLjEsMCwxLjcsMGMwLjEsMCwwLjIsMCwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4yLDAtMC4yLTAuMi0wLjJjLTAuNiwwLTEuMiwwLTEuNywwYy0wLjEsMC0wLjEsMC0wLjIsMEMxOSw5LjIsMTksOC44LDE5LDguM3ogTTcuNSw3Yy0wLjMsMC0wLjUsMC0wLjgsMC4xQzUuOSw3LjMsNS4zLDcuNyw0LjgsOC4zQzQuMSw5LjEsMy45LDEwLDQsMTFjMC4xLDAuOSwwLjYsMS43LDEuMywyLjJjMC44LDAuNiwxLjgsMC45LDIuOCwwLjdjMC43LTAuMSwxLjMtMC41LDEuOC0wLjljMC4zLTAuMywwLjMtMC43LDAtMC45Yy0wLjMtMC4zLTAuNy0wLjMtMC45LDBjLTAuNSwwLjUtMS4xLDAuNy0xLjgsMC42Yy0wLjQtMC4xLTAuOC0wLjItMS4yLTAuNWMtMC41LTAuNS0wLjgtMS4xLTAuNy0xLjhDNS40LDkuOCw1LjYsOS40LDUuOSw5QzYuNCw4LjUsNyw4LjMsNy43LDguNEM4LjIsOC40LDguNiw4LjYsOSw5YzAuMiwwLjIsMC43LDAuMywxLDBjMC4yLTAuMiwwLjItMC43LDAtMC45QzkuOCw4LDkuOCw3LjksOS43LDcuOUM5LjEsNy4zLDguMyw3LjEsNy41LDd6IE0yOS42LDEzLjljMC4zLDAsMC43LTAuMSwxLTAuMWMwLjYtMC4xLDEtMC40LDEuMy0xYzAuMi0wLjMsMC4yLTAuNywwLjItMWMwLTAuNS0wLjItMC45LTAuNi0xLjJjLTAuNC0wLjMtMC44LTAuNi0xLjItMC44Yy0wLjItMC4yLTAuNS0wLjMtMC43LTAuNWMtMC4zLTAuMi0wLjItMC42LDAuMS0wLjhjMC4zLTAuMiwwLjctMC4yLDEuMS0wLjFjMC40LDAuMSwwLjcsMC4yLDEsMC40YzAuMiwwLjEsMC4yLDAsMC4yLTAuMmMwLTAuMywwLTAuNiwwLTAuOGMwLTAuMi0wLjEtMC4yLTAuMi0wLjNjLTAuNC0wLjEtMC43LTAuMi0xLjEtMC4yYy0wLjYsMC0xLjIsMC0xLjcsMC4yYy0wLjQsMC4yLTAuNywwLjQtMC45LDAuOGMtMC4yLDAuMy0wLjIsMC42LTAuMiwxYzAsMC42LDAuMywxLjEsMC44LDEuNWMwLjUsMC40LDEsMC43LDEuNSwxYzAuMiwwLjEsMC4zLDAuMywwLjMsMC42YzAsMC4zLTAuMiwwLjUtMC41LDAuNmMtMC41LDAuMS0xLDAuMS0xLjQtMC4xYy0wLjMtMC4xLTAuNS0wLjItMC43LTAuM2MtMC4yLTAuMS0wLjMsMC0wLjMsMC4xYzAsMC4yLDAsMC41LDAsMC43YzAsMC4xLDAuMSwwLjIsMC4yLDAuM2MwLjEsMC4xLDAuMiwwLjEsMC4zLDAuMUMyOC42LDEzLjgsMjkuMSwxMy45LDI5LjYsMTMuOXogTTI0LDguM2MwLDAuMSwwLDAuMSwwLDAuMmMwLDEuNywwLDMuNCwwLDVjMCwwLjIsMCwwLjIsMC4yLDAuMmMwLjQsMCwwLjgsMCwxLjIsMGMwLjIsMCwwLjIsMCwwLjItMC4yYzAtMS43LDAtMy40LDAtNWMwLTAuMSwwLTAuMSwwLTAuMmMwLjEsMCwwLjEsMCwwLjIsMGMwLjUsMCwxLjEsMCwxLjYsMGMwLjIsMCwwLjIsMCwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4xLTAuMS0wLjItMC4yLTAuMmMwLDAtMC4xLDAtMC4xLDBjLTEuNiwwLTMuMywwLTQuOSwwYzAsMC0wLjEsMC0wLjEsMGMtMC4xLDAtMC4yLDAuMS0wLjIsMC4yYzAsMC4zLDAsMC41LDAsMC44YzAsMC4xLDAuMSwwLjIsMC4yLDAuMmMwLjUsMCwxLjEsMCwxLjYsMEMyMy45LDguMywyNCw4LjMsMjQsOC4zeiBNOCwxMS4yYzAuNiwwLDEuMSwwLDEuNywwYzAuMywwLDAuNC0wLjEsMC42LTAuM2MwLjItMC41LTAuMS0xLTAuNi0xYy0xLjEsMC0yLjIsMC0zLjMsMGMtMC40LDAtMC43LDAuMi0wLjcsMC42YzAsMC41LDAuMywwLjcsMC42LDAuN0M2LjgsMTEuMiw3LjQsMTEuMiw4LDExLjJ6Ii8+PC9zdmc+); } -.bg-giropay { - background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfNF8iIGNsYXNzPSJzdDIwIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnPjxwYXRoIGlkPSJfOTIxODYxODRfMV8iIGNsYXNzPSJzdDAiIGQ9Ik0zLjgsNi44djguNWMwLDAuOCwwLjcsMS41LDEuNSwxLjVoMTMuOVY1LjJINS4zQzQuNSw1LjIsMy44LDUuOSwzLjgsNi44TDMuOCw2Ljh6IE0yMi44LDExYzAsMC41LTAuMywwLjktMC43LDAuOWMtMC40LDAtMC43LTAuNC0wLjctMC45YzAtMC41LDAuMy0wLjksMC43LTAuOUMyMi42LDEwLjEsMjIuOCwxMC41LDIyLjgsMTF6IE0yMC4yLDE0LjFoMS4ydi0xLjhoMGMwLjIsMC40LDAuNywwLjYsMS4xLDAuNmMxLDAsMS42LTAuOCwxLjYtMS44YzAtMC44LTAuNS0xLjctMS41LTEuN2MtMC41LDAtMSwwLjItMS4zLDAuN2gwVjkuM2gtMS4xVjE0LjF6IE0yNS43LDExLjZjMC0wLjMsMC4zLTAuNCwwLjctMC40YzAuMiwwLDAuMywwLDAuNSwwYzAsMC40LTAuMywwLjgtMC43LDAuOEMyNS45LDEyLDI1LjcsMTEuOSwyNS43LDExLjZ6IE0yOCwxMi43QzI4LDEyLjQsMjgsMTIuMiwyOCwxMS45di0xLjNjMC0xLTAuNy0xLjQtMS42LTEuNGMtMC41LDAtMC45LDAuMS0xLjQsMC4ybDAsMC44YzAuMy0wLjIsMC43LTAuMywxLjEtMC4zYzAuNCwwLDAuOCwwLjEsMC44LDAuNmMtMC4xLDAtMC40LDAtMC41LDBjLTAuNiwwLTEuOCwwLjEtMS44LDEuMmMwLDAuNywwLjYsMS4xLDEuMywxLjFjMC41LDAsMC44LTAuMiwxLjEtMC42aDBjMCwwLjIsMCwwLjQsMCwwLjVMMjgsMTIuN0wyOCwxMi43eiBNMjguNSwxNC4xYzAuMiwwLjEsMC41LDAuMSwwLjcsMC4xYzEuMSwwLDEuMy0wLjgsMS43LTEuN2wxLjItMy4ySDMxbC0wLjcsMi4yaDBsLTAuNy0yLjJoLTEuM2wxLjQsMy41Yy0wLjEsMC4zLTAuMywwLjUtMC42LDAuNWMtMC4yLDAtMC4zLDAtMC41LTAuMUwyOC41LDE0LjF6Ii8+PHBhdGggaWQ9Il80NzMwMzAzMl8xXyIgY2xhc3M9InN0MzMiIGQ9Ik02LjcsMTFjMC0wLjUsMC4yLTAuOCwwLjctMC44YzAuNSwwLDAuNywwLjQsMC43LDAuOGMwLDAuNS0wLjMsMC45LTAuNywwLjlDNywxMS44LDYuNywxMS41LDYuNywxMXogTTkuMiw5LjNIOC4ydjAuNmgwQzcuOSw5LjUsNy41LDkuMiw3LDkuMkM1LjksOS4yLDUuNSwxMCw1LjUsMTFjMCwxLDAuNiwxLjcsMS41LDEuN2MwLjUsMCwwLjktMC4yLDEuMS0wLjZoMHYwLjJjMCwwLjctMC40LDEtMSwxYy0wLjUsMC0wLjgtMC4xLTEuMS0wLjNsLTAuMSwwLjljMC4zLDAuMSwwLjcsMC4yLDEuMywwLjJjMS40LDAsMi0wLjUsMi0xLjhWOS4zTDkuMiw5LjN6IE0xMS4yLDcuOUgxMHYwLjloMS4yTDExLjIsNy45TDExLjIsNy45eiBNMTAsMTIuN2gxLjJWOS4zSDEwVjEyLjdMMTAsMTIuN3ogTTE0LjUsOS4zYy0wLjEsMC0wLjMsMC0wLjQsMGMtMC41LDAtMC44LDAuMy0xLDAuN2gwVjkuM0gxMnYzLjRoMS4ydi0xLjRjMC0wLjcsMC4zLTEuMSwwLjktMS4xYzAuMSwwLDAuMywwLDAuNCwwTDE0LjUsOS4zeiBNMTYuNSwxMS45Yy0wLjUsMC0wLjgtMC40LTAuOC0xYzAtMC41LDAuMi0xLDAuOC0xYzAuNSwwLDAuOCwwLjQsMC44LDFDMTcuMywxMS41LDE3LDExLjksMTYuNSwxMS45eiBNMTYuNSwxMi44YzEuMSwwLDItMC43LDItMS44YzAtMS4xLTAuOS0xLjgtMi0xLjhjLTEuMSwwLTIsMC43LTIsMS44QzE0LjUsMTIuMSwxNS40LDEyLjgsMTYuNSwxMi44eiIvPjwvZz48L3N2Zz4=); -} - .bg-gpay { background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfN18iIGNsYXNzPSJzdDIzIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnIGlkPSJHUGF5LUxpZ2h0LXRoZW1lZC1idXR0b25zIj48ZyBpZD0iR1BBWS0tLVNWR3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xODUuMDAwMDAwLCAtNDAwLjAwMDAwMCkiPjxnIGlkPSJHUGF5LUJyYW5kLU1hcmsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE4NS4wMDAwMDAsIDQwMC4wMDAwMDApIj48ZyBpZD0iR1BheSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4yNjE0NzQsIDAuMjYxNDc0KSI+PGcgaWQ9IlBheSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTcuNjE1MDY5LCAwLjgyNTcwNikiPjxwYXRoIGlkPSJGaWxsLTEiIGNsYXNzPSJzdDAiIGQ9Ik0tMC42LDcuM3YyLjZIMWMwLjQsMCwwLjctMC4xLDAuOS0wLjRjMC4zLTAuMywwLjQtMC42LDAuNC0wLjljMC0wLjMtMC4xLTAuNi0wLjQtMC45QzEuNyw3LjQsMS40LDcuMywxLDcuM0wtMC42LDcuM0wtMC42LDcuM3ogTS0wLjYsMTAuOHYzaC0xVjYuNEgxYzAuNiwwLDEuMiwwLjIsMS42LDAuNmMwLjUsMC40LDAuNywxLDAuNywxLjZjMCwwLjYtMC4yLDEuMi0wLjcsMS42Yy0wLjQsMC40LTEsMC42LTEuNiwwLjZMLTAuNiwxMC44TC0wLjYsMTAuOHoiLz48cGF0aCBpZD0iRmlsbC0zIiBjbGFzcz0ic3QwIiBkPSJNNC4zLDEyLjNjMCwwLjIsMC4xLDAuNSwwLjMsMC42YzAuMiwwLjIsMC41LDAuMiwwLjcsMC4yYzAuNCwwLDAuOC0wLjEsMS4xLTAuNGMwLjMtMC4zLDAuNS0wLjYsMC41LTEuMWMtMC4zLTAuMi0wLjctMC40LTEuMi0wLjRjLTAuNCwwLTAuNywwLjEtMSwwLjNDNC40LDExLjcsNC4zLDEyLDQuMywxMi4zIE01LjUsOC41YzAuNywwLDEuMywwLjIsMS43LDAuNmMwLjQsMC40LDAuNiwwLjksMC42LDEuNnYzLjFINi45di0wLjdoMEM2LjUsMTMuNyw2LDE0LDUuMywxNGMtMC42LDAtMS0wLjItMS40LTAuNWMtMC40LTAuMy0wLjYtMC43LTAuNi0xLjJjMC0wLjUsMC4yLTAuOSwwLjYtMS4zYzAuNC0wLjMsMC45LTAuNSwxLjYtMC41YzAuNiwwLDEsMC4xLDEuNCwwLjN2LTAuMmMwLTAuMy0wLjEtMC42LTAuNC0wLjhDNi4zLDkuNSw2LDkuNCw1LjYsOS40Yy0wLjUsMC0xLDAuMi0xLjMsMC43TDMuNSw5LjVDMy45LDguOSw0LjYsOC41LDUuNSw4LjUiLz48ZyBpZD0iR3JvdXAtNyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTUuMDg0OTIzLCAzLjc1OTQ0NykiPjxwb2x5Z29uIGlkPSJGaWxsLTUiIGNsYXNzPSJzdDAiIHBvaW50cz0iLTIsNSAtNS4yLDEyLjMgLTYuMiwxMi4zIC01LDkuNyAtNy4xLDUgLTYuMSw1IC00LjUsOC42IC00LjUsOC42IC0zLDUgIi8+PC9nPjwvZz48ZyBpZD0iRyI+PHBhdGggaWQ9IkZpbGwtOCIgY2xhc3M9InN0MCIgZD0iTTEzLjIsMTFjMC0wLjMsMC0wLjYtMC4xLTAuOWgtNHYxLjZoMi4zYy0wLjEsMC41LTAuNCwxLTAuOSwxLjN2MS4xaDEuNEMxMi43LDEzLjQsMTMuMiwxMi4zLDEzLjIsMTEiLz48cGF0aCBpZD0iRmlsbC0xMCIgY2xhc3M9InN0MCIgZD0iTTkuMSwxNS4yYzEuMiwwLDIuMS0wLjQsMi44LTFMMTAuNSwxM2MtMC40LDAuMy0wLjksMC40LTEuNSwwLjRjLTEuMSwwLTIuMS0wLjgtMi40LTEuOEg1LjJ2MS4xQzUuOSwxNC4yLDcuNCwxNS4yLDkuMSwxNS4yIi8+PHBhdGggaWQ9IkZpbGwtMTIiIGNsYXNzPSJzdDAiIGQ9Ik02LjYsMTEuN2MtMC4xLTAuMy0wLjEtMC41LTAuMS0wLjhjMC0wLjMsMC0wLjYsMC4xLTAuOFY5SDUuMmMtMC4zLDAuNi0wLjUsMS4yLTAuNSwxLjljMCwwLjcsMC4yLDEuMywwLjUsMS45TDYuNiwxMS43eiIvPjxwYXRoIGlkPSJGaWxsLTE0IiBjbGFzcz0ic3QwIiBkPSJNOS4xLDguM2MwLjYsMCwxLjIsMC4yLDEuNiwwLjZ2MGwxLjItMS4yQzExLjIsNywxMC4yLDYuNiw5LjEsNi42Yy0xLjcsMC0zLjEsMS0zLjgsMi40bDEuNCwxLjFDNyw5LDcuOSw4LjMsOS4xLDguMyIvPjwvZz48L2c+PC9nPjwvZz48L2c+PC9zdmc+); } diff --git a/view/frontend/web/css/apm/apm.min.css b/view/frontend/web/css/apm/apm.min.css index 6d6feff2..1b3c3a57 100644 --- a/view/frontend/web/css/apm/apm.min.css +++ b/view/frontend/web/css/apm/apm.min.css @@ -13,4 +13,4 @@ * @link https://docs.checkout.com/ */ -.alternative-selector input{margin:0;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.alternative-selector input:active+label div.alternative-icon{opacity:.9}.alternative-selector input:checked+label div.alternative-icon{-webkit-filter:none;-moz-filter:none;filter:none}.alternative-selector label:hover *{-webkit-filter:brightness(1.2) grayscale(.5) opacity(.9);-moz-filter:brightness(1.2) grayscale(.5) opacity(.9);filter:brightness(1.2) grayscale(.5) opacity(.9)}.alternative-icon{display:inline-block;width:4em;height:3em;-webkit-transition:all .1s ease-in;-moz-transition:all .1s ease-in;transition:all .1s ease-in;-webkit-filter:brightness(1) grayscale(.8) opacity(.7);-moz-filter:brightness(1) grayscale(.8) opacity(.7);filter:brightness(1) grayscale(.8) opacity(.7)}.alternative-selector h2{display:inline-block;margin:0 0 0 10px;vertical-align:middle}div.alternative-selector label{cursor:pointer}div.alternative-selector>div{margin-bottom:10px}div.alternative-selector>div:last-child{margin-bottom:0}div.cko-alternative-form{padding-left:2em}#apm-container{margin-bottom:20px}#apm-container div[data-role=collapsible]{border-bottom:1px solid #ccc;cursor:pointer;padding:15px}#apm-container div[aria-selected=true],#apm-container div[data-role=collapsible]:focus,#apm-container div[data-role=collapsible]:hover{background-color:#f1f1f1}#apm-container div.cko-apm:last-child{border-bottom:none!important}#apm-container div[data-role=trigger]{cursor:pointer}#apm-container div[data-role=content]{padding:1rem 2rem}.cko-apm.paypal{display:block!important}.bg-apm{background-repeat:no-repeat;background-position:center center;background-size:contain;vertical-align:middle;display:inline-block;width:45px;height:30px;margin-right:10px}.bg-alipay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfM18iIGNsYXNzPSJzdDE3IiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGNsYXNzPSJzdDE4IiBkPSJNMjAuMiwxMi40YzAuNy0xLjMsMS4zLTIuNiwxLjctNGgtNFY3LjFoNVY2LjJoLTVWNGgtMi4zdjIuMmgtNXYwLjhoNXYxLjRoLTQuMnYwLjdoOC4xYy0wLjMsMC45LTAuNywxLjgtMS4yLDIuN2MtMS45LTAuNi0zLjgtMS01LjgtMS4xYy0zLjksMC00LjcsMS45LTQuNSwzLjZjMC4xLDEuNCwxLjIsMy40LDQuNCwzLjRjMi43LTAuMSw1LjItMS40LDYuOC0zLjZjMi44LDEuMiw1LjcsMi44LDcuOCwzLjl2LTMuM0MyNC44LDE0LDIyLjUsMTMuMiwyMC4yLDEyLjR6IE0xMiwxNi41Yy0yLjcsMC0zLjEtMS41LTMuMi0yLjRjMC0wLjgsMC41LTIuMiwzLjYtMi4yYzEuNywwLjIsMy40LDAuNyw1LDEuNEMxNi4yLDE0LjgsMTQuMywxNi41LDEyLDE2LjVMMTIsMTYuNXoiLz48L3N2Zz4=)}.bg-amex{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU1XzJfIiBjbGFzcz0ic3QyIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMywxMmgyLjd2MC42aC0xLjl2MC42aDEuOHYwLjZoLTEuOHYwLjZoMS45VjE1SDIzVjEyeiBNMzAuOSwxMy4yYzEsMCwxLjEsMC41LDEuMSwxYzAsMC41LTAuNSwwLjktMSwwLjljMCwwLDAsMCwwLDBoLTEuN3YtMC42aDEuM2MwLjIsMCwwLjYsMCwwLjYtMC4zYzAtMC4xLTAuMS0wLjItMC4zLTAuMmMtMC4xLDAtMC41LDAtMC42LDBjLTAuOSwwLTEuMS0wLjQtMS4xLTAuOWMwLTAuNSwwLjQtMC45LDAuOS0wLjljMCwwLDAuMSwwLDAuMSwwaDEuN3YwLjZoLTEuM2MtMC4zLDAtMC42LDAtMC42LDAuM2MwLDAuMiwwLjIsMC4yLDAuMywwLjJDMzAuNCwxMy4xLDMwLjgsMTMuMiwzMC45LDEzLjJMMzAuOSwxMy4yeiBNMjcuOCwxMy4yYzEsMCwxLjEsMC41LDEuMSwxYzAsMC41LTAuNSwwLjktMSwwLjljMCwwLDAsMCwwLDBoLTEuN3YtMC42aDEuM2MwLjIsMCwwLjYsMCwwLjYtMC4zYzAtMC4xLTAuMS0wLjItMC4zLTAuMmMtMC4xLDAtMC41LDAtMC42LDBjLTAuOSwwLTEuMS0wLjQtMS4xLTAuOWMwLTAuNSwwLjQtMC45LDAuOS0wLjljMCwwLDAuMSwwLDAuMSwwaDEuN3YwLjZoLTEuM2MtMC4zLDAtMC42LDAtMC42LDAuM2MwLDAuMiwwLjIsMC4yLDAuMywwLjJDMjcuMywxMy4xLDI3LjcsMTMuMiwyNy44LDEzLjJMMjcuOCwxMy4yeiBNMTgsMTJoLTIuOWwtMC45LDAuOUwxMy4zLDEySDEwdjNoMy4xbDEtMWwxLDFoMS42di0xaDEuMWMwLjUsMC4xLDEuMS0wLjIsMS4yLTAuN2MwLTAuMSwwLTAuMiwwLTAuM2MwLTAuNS0wLjQtMC45LTAuOC0wLjlDMTguMSwxMiwxOC4xLDEyLDE4LDEyeiBNMTIuOCwxNC40aC0xLjl2LTAuNmgxLjh2LTAuNmgtMS44di0wLjZoMmwwLjgsMC44TDEyLjgsMTQuNHogTTE1LjksMTQuN2wtMS4yLTEuMmwxLjItMS4yVjE0Ljd6IE0xNy44LDEzLjRoLTF2LTAuN2gxYzAuMiwwLDAuNCwwLjEsMC40LDAuM2MwLDAuMi0wLjEsMC40LTAuMywwLjRDMTcuOSwxMy40LDE3LjgsMTMuNCwxNy44LDEzLjRMMTcuOCwxMy40eiBNMjIsMTMuNmMwLjQtMC4xLDAuNi0wLjUsMC42LTAuOGMwLTAuNS0wLjQtMC44LTAuOS0wLjhjMCwwLTAuMSwwLTAuMSwwaC0yLjF2M2gwLjh2LTEuMWgxLjFjMC4yLDAsMC40LDAuMiwwLjQsMC41YzAsMCwwLDAsMCwwbDAsMC41aDAuOGwwLTAuNmMwLjEtMC4zLTAuMS0wLjYtMC40LTAuN0MyMi4xLDEzLjYsMjIuMSwxMy42LDIyLDEzLjZMMjIsMTMuNnogTTIxLjMsMTMuM2gtMXYtMC43aDFjMC4yLDAsMC40LDAuMSwwLjQsMC4zYzAsMCwwLDAsMCwwQzIxLjgsMTMuMiwyMS42LDEzLjMsMjEuMywxMy4zTDIxLjMsMTMuM3ogTTIwLjksMTFWOGgtMC44djNIMjAuOXogTTEzLjMsOEgxNnYwLjZoLTEuOXYwLjZIMTZ2MC42aC0xLjh2MC42SDE2VjExaC0yLjdWOHogTTE5LjEsOS42YzAuNC0wLjEsMC42LTAuNSwwLjYtMC44YzAtMC41LTAuNC0wLjgtMC45LTAuOGMwLDAtMC4xLDAtMC4xLDBoLTIuMnYzaDAuOFY5LjloMS4xYzAuMiwwLDAuNCwwLjIsMC40LDAuNWMwLDAsMCwwLDAsMGwwLDAuNmgwLjhsMC0wLjZjMC4xLTAuMy0wLjEtMC42LTAuNC0wLjdDMTkuMiw5LjYsMTkuMSw5LjYsMTkuMSw5LjZMMTkuMSw5LjZ6IE0xOC40LDkuM2gtMVY4LjZoMWMwLjIsMCwwLjQsMC4xLDAuNSwwLjNjMCwwLDAsMCwwLDBDMTguOCw5LjIsMTguNyw5LjMsMTguNCw5LjNMMTguNCw5LjN6IE0xMS40LDhsLTEsMmwtMS0ySDh2Mi45TDYuNiw4SDUuNUw0LDExaDAuOWwwLjMtMC43aDEuN0w3LjIsMTFoMS43VjguOEwxMCwxMWgwLjhsMS4xLTIuMlYxMWgwLjhWOEgxMS40TDExLjQsOHogTTUuNSw5LjdsMC41LTFsMC41LDFINS41TDUuNSw5Ljd6IE0yOS41LDh2Mi4xTDI4LjEsOGgtMS4ydjIuOEwyNS41LDhoLTEuMWwtMS4xLDIuM2MwLDAtMC41LDAtMC41LDBjLTAuMywwLTAuNi0wLjQtMC41LTAuN2MwLDAsMCwwLDAsMFY5LjRjMC0wLjcsMC40LTAuOCwxLTAuOGgwLjVWOGgtMS4xYy0wLjgsMC4xLTEuNCwwLjktMS4yLDEuOGMwLjEsMC43LDAuNiwxLjIsMS4zLDEuMmgxLjFsMC4zLTAuN2gxLjdsMC4zLDAuN2gxLjZWOC44bDEuNSwyLjJoMS4xVjhIMjkuNUwyOS41LDh6IE0yNC40LDkuN2wwLjUtMWwwLjUsMUgyNC40TDI0LjQsOS43eiIvPjwvc3ZnPg==)}.bg-applepay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5XzFfIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGlkPSJBcHBsZV8xXyIgY2xhc3M9InN0MCIgZD0iTTExLjcsMTFjMCwwLjgsMC41LDEuNiwxLjMsMS45Yy0wLjIsMC41LTAuNCwwLjktMC43LDEuM2MtMC4zLDAuNi0wLjgsMS0xLjUsMS4xYy0wLjcsMC0wLjktMC40LTEuNi0wLjRzLTEsMC40LTEuNiwwLjRjLTAuNy0wLjEtMS4yLTAuNi0xLjUtMS4yQzUuMiwxMyw0LjUsMTAuOSw1LjQsOS41YzAuNC0wLjcsMS4yLTEuMiwyLTEuMkM4LDguNCw4LjUsOC41LDkuMSw4LjdjMC42LTAuMiwxLjItMC40LDEuOS0wLjRjMC43LDAsMS40LDAuNCwxLjgsMC45QzEyLjEsOS42LDExLjcsMTAuMiwxMS43LDExIE0xMC40LDcuNUMxMC44LDcuMSwxMSw2LjUsMTAuOSw2Yy0wLjYsMC0xLjEsMC4zLTEuNCwwLjdDOS4xLDcuMSw4LjksNy42LDksOC4yQzkuNSw4LjIsMTAuMSw3LjksMTAuNCw3LjUiLz48cGF0aCBpZD0iUGF5XzFfIiBjbGFzcz0ic3QwIiBkPSJNMTUuNCw2LjhjMC4zLDAsMC42LTAuMSwwLjgtMC4xYzAuMywwLDAuNy0wLjEsMSwwYzAuNSwwLDAuOSwwLjEsMS40LDAuMmMwLjMsMC4xLDAuNywwLjMsMC45LDAuNWMwLjIsMC4yLDAuNCwwLjQsMC41LDAuN2MwLjEsMC4zLDAuMiwwLjYsMC4yLDFjMCwwLjQtMC4xLDAuOC0wLjIsMS4xYy0wLjIsMC4zLTAuNCwwLjYtMC43LDAuOGMtMC4zLDAuMi0wLjYsMC40LTEsMC41Yy0wLjQsMC4xLTAuOCwwLjItMS4zLDAuMmMtMC4zLDAtMC43LDAtMS0wLjF2My42aC0wLjZWNi44TDE1LjQsNi44TDE1LjQsNi44eiBNMTYsMTEuMWMwLjIsMCwwLjMsMC4xLDAuNSwwLjFjMC4yLDAsMC40LDAsMC42LDBjMC43LDAsMS4zLTAuMSwxLjgtMC41YzAuNC0wLjQsMC43LTEsMC42LTEuNmMwLTAuMy0wLjEtMC42LTAuMi0wLjljLTAuMS0wLjItMC4zLTAuNC0wLjUtMC42Yy0wLjItMC4yLTAuNS0wLjMtMC43LTAuNGMtMC4zLTAuMS0wLjYtMC4xLTEtMC4xYy0wLjIsMC0wLjUsMC0wLjcsMGMtMC4yLDAtMC40LDAtMC41LDAuMUwxNiwxMS4xTDE2LDExLjFMMTYsMTEuMXogTTI1LjEsMTMuOGMwLDAuMiwwLDAuNSwwLDAuN2MwLDAuMiwwLDAuNSwwLjEsMC43aC0wLjZsLTAuMS0wLjloMGMtMC4xLDAuMS0wLjIsMC4yLTAuMywwLjRjLTAuMSwwLjEtMC4zLDAuMi0wLjQsMC4zYy0wLjIsMC4xLTAuNCwwLjItMC42LDAuMmMtMC4yLDAuMS0wLjQsMC4xLTAuNywwLjFjLTAuMywwLTAuNSwwLTAuOC0wLjFjLTAuMi0wLjEtMC40LTAuMi0wLjYtMC40Yy0wLjEtMC4yLTAuMy0wLjMtMC4zLTAuNWMtMC4xLTAuMi0wLjEtMC40LTAuMS0wLjZjMC0wLjcsMC4zLTEuMywwLjktMS43YzAuOS0wLjQsMS45LTAuNiwyLjgtMC42di0wLjJjMC0wLjIsMC0wLjQsMC0wLjVjMC0wLjItMC4xLTAuNC0wLjItMC42QzI0LjEsMTAsMjQsOS44LDIzLjgsOS43Yy0wLjMtMC4xLTAuNi0wLjItMC45LTAuMmMtMC4zLDAtMC41LDAtMC44LDAuMWMtMC4zLDAuMS0wLjUsMC4yLTAuNywwLjNsLTAuMi0wLjRjMC4zLTAuMiwwLjYtMC4zLDAuOS0wLjRDMjIuMyw5LjEsMjIuNyw5LDIzLDljMC40LDAsMC43LDAuMSwxLjEsMC4yYzAuMywwLjEsMC41LDAuMywwLjYsMC42YzAuMiwwLjIsMC4zLDAuNSwwLjMsMC44YzAuMSwwLjMsMC4xLDAuNiwwLjEsMC44TDI1LjEsMTMuOEwyNS4xLDEzLjhMMjUuMSwxMy44eiBNMjQuNSwxMmMtMC4zLDAtMC43LDAtMSwwYy0wLjMsMC0wLjcsMC4xLTEsMC4yYy0wLjMsMC4xLTAuNiwwLjMtMC44LDAuNWMtMC4yLDAuMi0wLjMsMC42LTAuMywwLjljMCwwLjQsMC4xLDAuNywwLjQsMC45YzAuMiwwLjIsMC41LDAuMywwLjksMC4zYzAuMiwwLDAuNSwwLDAuNy0wLjFjMC4yLTAuMSwwLjQtMC4yLDAuNS0wLjNjMC4xLTAuMSwwLjMtMC4yLDAuNC0wLjRjMC4xLTAuMSwwLjItMC4zLDAuMi0wLjRjMC0wLjEsMC4xLTAuMiwwLjEtMC40TDI0LjUsMTJMMjQuNSwxMkwyNC41LDEyeiBNMjYuMyw5LjJsMS42LDMuOWMwLjEsMC4yLDAuMiwwLjQsMC4yLDAuN3MwLjEsMC40LDAuMiwwLjZoMGMwLjEtMC4yLDAuMS0wLjQsMC4yLTAuNnMwLjItMC41LDAuMy0wLjdsMS41LTMuOUgzMWwtMS44LDQuNGMtMC4yLDAuNC0wLjMsMC45LTAuNSwxLjNjLTAuMSwwLjQtMC4zLDAuNy0wLjUsMWMtMC4xLDAuMy0wLjMsMC42LTAuNSwwLjhjLTAuMiwwLjItMC40LDAuNC0wLjYsMC42Yy0wLjIsMC4yLTAuNCwwLjMtMC43LDAuNUMyNi4yLDE3LjksMjYuMSwxOCwyNiwxOGwtMC4yLTAuNWMwLjItMC4xLDAuNC0wLjIsMC41LTAuM2MwLjItMC4xLDAuNC0wLjMsMC42LTAuNGMwLjItMC4yLDAuNC0wLjQsMC41LTAuNmMwLjItMC4zLDAuNC0wLjYsMC41LTAuOWMwLTAuMSwwLjEtMC4yLDAuMS0wLjNjMC0wLjEsMC0wLjItMC4xLTAuM2wtMi4zLTUuNkwyNi4zLDkuMkwyNi4zLDkuMnoiLz48L3N2Zz4=)}.bg-astro{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHlfMl8yXyIgY2xhc3M9InN0MjciIGQ9Ik0zLDBoMzBjMS43LDAsMywxLjMsMywzdjE2YzAsMS43LTEuMywzLTMsM0gzYy0xLjcsMC0zLTEuMy0zLTNWM0MwLDEuMywxLjMsMCwzLDB6Ii8+PGc+PHBhdGggY2xhc3M9InN0MCIgZD0iTTUuOSwxNC44YzAuMS0wLjIsMC4yLTAuNCwwLjItMC43QzYuOCwxMiw3LjYsOS44LDguMyw3LjZjMC4xLTAuMiwwLjItMC40LDAuMi0wLjdjMC0wLjEsMC0wLjEsMC4xLTAuMWMwLjQsMCwwLjcsMCwxLjEsMGMwLjEsMCwwLjEsMCwwLjEsMC4xYzAuNCwxLjMsMC45LDIuNiwxLjMsMy45YzAuNCwxLjMsMC45LDIuNiwxLjMsMy45YzAsMCwwLDAuMSwwLDAuMWMtMC40LDAtMC43LDAtMSwwYzAsMC0wLjEsMC0wLjEtMC4xYy0wLjItMC41LTAuMy0xLTAuNS0xLjVjLTAuMS0wLjMtMC4yLTAuNi0wLjMtMC45YzAtMC4xLDAtMC4xLTAuMS0wLjFjLTAuOSwwLTEuOCwwLTIuNywwYy0wLjEsMC0wLjEsMC0wLjEsMC4xQzcuNSwxMy4yLDcuMiwxNCw3LDE0LjhjMCwwLjEtMC4xLDAuMS0wLjEsMC4xQzYuNSwxNC45LDYuMiwxNC45LDUuOSwxNC44QzUuOSwxNC44LDUuOSwxNC44LDUuOSwxNC44eiBNOS4yLDcuOEM4LjksOS4xLDguNCwxMC4zLDgsMTEuNWMwLjgsMCwxLjYsMCwyLjQsMEMxMCwxMC4zLDkuNSw5LjEsOS4yLDcuOHoiLz48cGF0aCBkPSJNMTcuMyw1YzAuMSwwLDAuMywwLDAuNCwwLjFjMC43LDAuMSwxLjMsMC4zLDEuOSwwLjZjMS4xLDAuNSwyLjEsMS4yLDIuOSwyYzAsMCwwLDAsMC4xLDAuMWMtMC4xLDAtMC4yLDAtMC4zLDBjLTAuOC0wLjYtMS42LTEuMS0yLjYtMS41Yy0wLjctMC4zLTEuNS0wLjUtMi4yLTAuNWMtMS4yLTAuMS0yLjIsMC4yLTMuMywwLjhjLTAuNiwwLjQtMS4yLDAuOC0xLjcsMS4zQzEyLjUsOCwxMi4zLDgsMTIsOGMtMC40LDAtMC45LDAtMS4zLDBjMCwwLTAuMSwwLTAuMSwwYzAsMCwwLjEtMC4xLDAuMS0wLjFjMS4zLTEuNCwyLjgtMi4zLDQuNi0yLjdjMC40LTAuMSwwLjktMC4yLDEuNC0wLjJjMCwwLDAuMSwwLDAuMSwwQzE2LjksNSwxNy4xLDUsMTcuMyw1eiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yNS41LDEyYzAtMC43LDAuMi0xLjQsMC42LTJjMC41LTAuNiwxLjEtMC45LDEuOC0xYzAuNi0wLjEsMS4xLDAsMS42LDAuMmMwLjcsMC4zLDEuMSwwLjgsMS4zLDEuNWMwLjMsMC45LDAuMywxLjktMC4xLDIuN2MtMC40LDAuOS0xLjEsMS4zLTIsMS41Yy0wLjYsMC4xLTEuMiwwLTEuOC0wLjNjLTAuNy0wLjQtMS4xLTEtMS4zLTEuOEMyNS42LDEyLjYsMjUuNiwxMi4zLDI1LjUsMTJ6IE0zMC4xLDEyYzAtMC4yLTAuMS0wLjUtMC4xLTAuN2MtMC4xLTAuNC0wLjMtMC44LTAuNy0xLjFjLTAuNy0wLjYtMS44LTAuNC0yLjMsMC40Yy0wLjMsMC41LTAuNCwxLTAuNCwxLjVjMCwwLjUsMC4xLDEsMC40LDEuNGMwLjYsMSwxLjksMSwyLjYsMEMzMCwxMywzMC4xLDEyLjUsMzAuMSwxMnoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTYuNSwxMC4xQzE2LjMsMTAsMTYsOS45LDE1LjgsOS44Yy0wLjMtMC4xLTAuNi0wLjEtMC45LDBjLTAuMywwLjEtMC41LDAuMy0wLjUsMC42YzAsMC4zLDAuMSwwLjYsMC4zLDAuN2MwLjMsMC4yLDAuNSwwLjMsMC44LDAuNGMwLjMsMC4xLDAuNywwLjMsMSwwLjZjMC40LDAuMywwLjUsMC44LDAuNSwxLjNjLTAuMSwwLjgtMC42LDEuMy0xLjQsMS41Yy0wLjgsMC4yLTEuNSwwLjEtMi4yLTAuMmMtMC4xLDAtMC4xLTAuMS0wLjItMC4xYzAuMS0wLjMsMC4yLTAuNSwwLjItMC44YzAsMCwwLjEsMCwwLjEsMC4xYzAuNSwwLjIsMC45LDAuNCwxLjQsMC4zYzAuMywwLDAuNS0wLjEsMC43LTAuM2MwLjMtMC4zLDAuMy0wLjksMC0xLjJjLTAuMi0wLjItMC40LTAuMy0wLjctMC40Yy0wLjMtMC4xLTAuNy0wLjMtMS0wLjVjLTAuMy0wLjItMC41LTAuNS0wLjYtMC45Yy0wLjEtMC42LDAuMS0xLjMsMC43LTEuN0MxNC41LDkuMSwxNC45LDksMTUuMyw5YzAuNCwwLDAuOSwwLjEsMS4zLDAuM2MwLjEsMC4xLDAuMSwwLjEsMC4xLDAuMkMxNi42LDkuNywxNi42LDkuOSwxNi41LDEwLjF6Ii8+PHBhdGggY2xhc3M9InN0MCIgZD0iTTIxLDkuMWMwLDAuMywwLDAuNSwwLDAuOGMtMC41LDAtMSwwLTEuNSwwYzAsMCwwLDAsMCwwLjFjMCwxLjEsMCwyLjEsMCwzLjJjMCwwLjIsMCwwLjQsMC4xLDAuNWMwLjEsMC4zLDAuMywwLjQsMC42LDAuNGMwLjIsMCwwLjQsMCwwLjcsMGMwLDAuMiwwLDAuNCwwLDAuNWMwLDAuMiwwLDAuMi0wLjIsMC4zYy0wLjQsMC4xLTAuNywwLjEtMS4xLDBjLTAuNi0wLjEtMS0wLjUtMS4xLTEuMWMwLTAuMi0wLjEtMC41LTAuMS0wLjdjMC0xLDAtMi4xLDAtMy4xYzAsMCwwLTAuMSwwLTAuMWMtMC4zLDAtMC42LDAtMC45LDBjMC0wLjMsMC0wLjUsMC0wLjhjMC4zLDAsMC42LDAsMC45LDBjMC0wLjEsMC0wLjIsMC0wLjNjMC0wLjIsMC0wLjUsMC0wLjdjMCwwLDAtMC4xLDAtMC4xYzAuMy0wLjEsMC42LTAuMiwxLTAuM2MwLDAuNSwwLDAuOSwwLDEuNEMyMCw5LjEsMjAuNSw5LjEsMjEsOS4xeiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMi4yLDkuMWMwLjMsMCwwLjYsMCwwLjksMGMwLDAuNCwwLDAuOCwwLDEuMWMwLDAsMCwwLDAsMGMwLDAsMC0wLjEsMC0wLjFjMC4yLTAuNiwwLjYtMSwxLjItMS4xYzAuMiwwLDAuMywwLDAuNSwwQzI1LDksMjUsOSwyNSw5LjFjMCwwLjMsMCwwLjYsMCwwLjljMCwwLDAsMCwwLDBjLTAuMiwwLTAuNCwwLTAuNywwYy0wLjUsMC4xLTAuOCwwLjUtMSwwLjljLTAuMSwwLjMtMC4xLDAuNi0wLjEsMC45YzAsMSwwLDEuOSwwLDIuOWMwLDAsMCwwLjEsMCwwLjFjLTAuMywwLTAuNywwLTEuMSwwQzIyLjIsMTIuOSwyMi4yLDExLDIyLjIsOS4xeiIvPjwvZz48L3N2Zz4=)}.bg-boleto{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfMl8iIGQ9Ik0zLDBoMzBjMS43LDAsMywxLjMsMywzdjE2YzAsMS43LTEuMywzLTMsM0gzYy0xLjcsMC0zLTEuMy0zLTNWM0MwLDEuMywxLjMsMCwzLDB6Ii8+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzYxXzFfIiBjbGFzcz0ic3QwIiBkPSJNMTQsMTZWNmg0YzAuNywwLDEuMywwLjEsMS45LDAuM2MwLjUsMC4yLDAuOSwwLjUsMS4xLDAuOWMwLjMsMC40LDAuNCwwLjgsMC40LDEuM2MwLDAuNC0wLjEsMC44LTAuNCwxLjJjLTAuMywwLjQtMC43LDAuNy0xLjEsMC45YzAuNiwwLjEsMS4xLDAuNSwxLjUsMC45YzAuMywwLjQsMC41LDEsMC41LDEuNWMwLDAuNS0wLjEsMC45LTAuMywxLjNjLTAuMiwwLjQtMC40LDAuNy0wLjgsMC45Yy0wLjQsMC4yLTAuNywwLjQtMS4yLDAuNUMxOS4yLDE2LDE4LjYsMTYsMTgsMTZMMTQsMTZMMTQsMTZ6IE0xNS40LDEwLjJoMi4zYzAuNCwwLDAuOSwwLDEuMy0wLjFjMC4zLTAuMSwwLjYtMC4zLDAuOC0wLjVDMjAsOS4zLDIwLjEsOSwyMC4xLDguN2MwLTAuMy0wLjEtMC42LTAuMy0wLjljLTAuMi0wLjMtMC40LTAuNC0wLjctMC41Yy0wLjUtMC4xLTEuMS0wLjItMS42LTAuMWgtMi4xTDE1LjQsMTAuMkwxNS40LDEwLjJMMTUuNCwxMC4yeiBNMTUuNCwxNC44SDE4YzAuMywwLDAuNiwwLDEsMGMwLjMsMCwwLjYtMC4xLDAuOC0wLjNjMC4yLTAuMSwwLjQtMC4zLDAuNS0wLjZjMC4xLTAuMywwLjItMC41LDAuMi0wLjhjMC0wLjctMC41LTEuNC0xLjEtMS42Yy0wLjUtMC4xLTEtMC4yLTEuNS0wLjJoLTIuNFYxNC44TDE1LjQsMTQuOEwxNS40LDE0Ljh6Ii8+PC9zdmc+)}.bg-diners{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU0XzFfIiBjbGFzcz0ic3QxMiIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTkuMSwxOGgtMi40Yy0zLjctMC4xLTYuNy0zLjItNi42LTYuOUM5LjgsNy40LDEyLjYsNC4yLDE2LjMsNGgyLjdjMy44LDAsNi45LDMuMiw2LjksN2MwLDAsMCwwLDAsMHYwLjFDMjUuOSwxNC45LDIyLjksMTcuOSwxOS4xLDE4eiBNMTYuOCw1LjJjLTMuMi0wLjEtNS44LDIuNC01LjksNS42Yy0wLjEsMy4yLDIuNCw1LjgsNS42LDUuOWMzLjIsMC4xLDUuOC0yLjQsNS45LTUuNmMwLTAuMSwwLTAuMSwwLTAuMkMyMi41LDcuOSwxOS45LDUuMywxNi44LDUuMkwxNi44LDUuMnogTTE3LjcsMTQuOVY3LjJjMi4xLDAuNiwzLjQsMi43LDIuOCw0LjhDMjAuMiwxMy40LDE5LjEsMTQuNSwxNy43LDE0LjlMMTcuNywxNC45eiBNMTUuOSwxNC45Yy0yLjEtMC42LTMuMy0yLjgtMi44LTQuOWMwLjMtMS40LDEuNC0yLjUsMi44LTIuOVYxNC45eiIvPjwvc3ZnPg==)}.bg-discover{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2XzFfIiBjbGFzcz0ic3QxMSIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjkuOSwxMS4zaC0wLjNWOS45aDAuM2MwLjQtMC4xLDAuNywwLjIsMC44LDAuNWMwLDAuMSwwLDAuMSwwLDAuMmMwLDAuNC0wLjMsMC43LTAuNiwwLjhDMzAsMTEuMywyOS45LDExLjMsMjkuOSwxMS4zTDI5LjksMTEuM3ogTTMxLjYsMTAuNWMwLTAuNy0wLjUtMS40LTEuMy0xLjRjLTAuMSwwLTAuMiwwLTAuMywwaC0xLjN2NC44aDAuOVYxMmgwLjFsMS4yLDEuOUgzMmwtMS40LTJDMzEuMiwxMS44LDMxLjcsMTEuMiwzMS42LDEwLjVMMzEuNiwxMC41TDMxLjYsMTAuNXogTTI1LjcsMTMuOWgyLjV2LTAuOGgtMS42di0xLjNoMS41VjExaC0xLjVWOS45aDEuNlY5LjFoLTIuNUwyNS43LDEzLjlMMjUuNywxMy45TDI1LjcsMTMuOXogTTIzLjEsMTIuM2wtMS4yLTMuMkgyMWwxLjksNC45aDAuNWwxLjktNC45aC0wLjlMMjMuMSwxMi4zTDIzLjEsMTIuM3ogTTEyLjcsMTEuNWMwLDEuMywxLDIuNCwyLjMsMi41YzAuNCwwLDAuOC0wLjEsMS4xLTAuM3YtMS4xYy0wLjIsMC4zLTAuNiwwLjUtMSwwLjVjLTAuOCwwLTEuNS0wLjYtMS41LTEuNWMwLDAsMCwwLDAsMHYtMC4xYzAtMC45LDAuNi0xLjYsMS40LTEuN2MwLjQsMCwwLjgsMC4yLDEuMSwwLjVWOS40Yy0wLjMtMC4yLTAuNy0wLjMtMS4xLTAuM2MtMS4zLTAuMS0yLjMsMC45LTIuNCwyLjJDMTIuNywxMS40LDEyLjcsMTEuNCwxMi43LDExLjVMMTIuNywxMS41TDEyLjcsMTEuNXogTTExLjEsMTAuOWMtMC41LTAuMi0wLjctMC4zLTAuNy0wLjZjMC0wLjMsMC4zLTAuNiwwLjYtMC41YzAsMCwwLDAsMCwwYzAuMywwLDAuNSwwLjIsMC43LDAuNGwwLjUtMC42QzExLjgsOS4yLDExLjQsOSwxMC45LDljLTAuNywwLTEuNCwwLjUtMS40LDEuM3YwLjFjMCwwLjYsMC40LDEuMiwxLjEsMS4zYzAuMiwwLjEsMC40LDAuMiwwLjYsMC4zYzAuMiwwLjEsMC4zLDAuMywwLjMsMC41YzAsMC40LTAuMywwLjctMC42LDAuN2gtMC4xYy0wLjQsMC0wLjgtMC4zLTAuOS0wLjZMOS4zLDEzYzAuMywwLjYsMC45LDAuOSwxLjUsMC45YzAuOCwwLDEuNS0wLjYsMS41LTEuNGMwLDAsMCwwLDAsMHYtMC4yQzEyLjQsMTEuNywxMi4xLDExLjQsMTEuMSwxMC45TDExLjEsMTAuOUwxMS4xLDEwLjl6IE04LjEsMTMuOWgwLjlWOS4xSDguMVYxMy45TDguMSwxMy45eiBNNi4zLDEyLjdDNiwxMyw1LjYsMTMuMSw1LjEsMTMuMUg0LjlWOS45aDAuM2MwLjQsMCwwLjksMC4xLDEuMiwwLjRjMC4zLDAuMywwLjUsMC43LDAuNSwxLjJDNi44LDExLjksNi42LDEyLjQsNi4zLDEyLjdMNi4zLDEyLjd6IE01LjMsOS4xSDR2NC44aDEuM2MwLjYsMCwxLjItMC4yLDEuNi0wLjVjMC41LTAuNSwwLjgtMS4xLDAuOC0xLjhjMC4xLTEuMy0wLjktMi4zLTIuMi0yLjRINS4zTDUuMyw5LjF6IE0xOC43LDljLTEuMywwLTIuNCwxLjEtMi40LDIuNWMwLDAsMCwwLDAsMGMwLDEuMywxLDIuNCwyLjQsMi41YzEuMywwLDIuNC0xLjEsMi40LTIuNGMwLDAsMCwwLDAsMEMyMS4yLDEwLjIsMjAuMSw5LjEsMTguNyw5TDE4LjcsOUwxOC43LDl6Ii8+PC9zdmc+)}.bg-enets{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU1XzNfIiBjbGFzcz0ic3QxNSIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTUuNCwxMS44QzE1LjQsMTEuOCwxNS40LDExLjgsMTUuNCwxMS44Yy0wLjEtMC4xLTAuMS0wLjEtMC4yLTAuMmMtMC40LTAuOC0wLjgtMS42LTEuMi0yLjNjLTAuMy0wLjYtMC43LTEuMy0xLTEuOWMwLTAuMS0wLjEtMC4xLTAuMi0wLjFjLTAuNCwwLTAuOSwwLTEuMywwYy0wLjIsMC0wLjIsMC4xLTAuMiwwLjJjMCwyLjEsMCw0LjIsMCw2LjJjMCwwLjEsMC4xLDAuMiwwLjIsMC4yYzAuMywwLDAuNSwwLDAuOCwwYzAuMiwwLDAuMiwwLDAuMi0wLjJjMC0xLjQsMC0yLjgsMC00LjJjMC0wLjEsMC0wLjEsMC0wLjJjMCwwLjEsMC4xLDAuMSwwLjEsMC4yYzAuMywwLjYsMC42LDEuMSwwLjksMS43YzAuNSwwLjksMSwxLjgsMS40LDIuN2MwLDAuMSwwLjEsMC4xLDAuMiwwLjFjMC40LDAsMC45LDAsMS4zLDBjMC4xLDAsMC4yLDAsMC4yLTAuMmMwLTIuMSwwLTQuMiwwLTYuM2MwLTAuMiwwLTAuMi0wLjItMC4yYy0wLjIsMC0wLjUsMC0wLjcsMGMtMC4yLDAtMC4yLDAtMC4yLDAuMmMwLDEuNCwwLDIuOCwwLDQuMUMxNS40LDExLjYsMTUuNCwxMS43LDE1LjQsMTEuOHogTTE5LDguM0MxOSw4LjMsMTksOC4zLDE5LDguM2MwLjksMCwxLjYsMCwyLjQsMGMwLjEsMCwwLjIsMCwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4yLDAtMC4yLTAuMi0wLjJjLTEuMiwwLTIuNSwwLTMuNywwYy0wLjIsMC0wLjIsMC4xLTAuMiwwLjJjMCwwLjMsMCwwLjUsMCwwLjhjMCwxLjgsMCwzLjYsMCw1LjRjMCwwLjIsMCwwLjIsMC4yLDAuMmMxLjMsMCwyLjcsMCw0LDBjMC4xLDAsMC4yLTAuMSwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4yLDAtMC4yLTAuMi0wLjJjLTAuOCwwLTEuNiwwLTIuNCwwYy0wLjEsMC0wLjEsMC0wLjIsMGMwLTAuNiwwLTEuMSwwLTEuN2MwLjEsMCwwLjEsMCwwLjIsMGMwLjYsMCwxLjEsMCwxLjcsMGMwLjEsMCwwLjIsMCwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4yLDAtMC4yLTAuMi0wLjJjLTAuNiwwLTEuMiwwLTEuNywwYy0wLjEsMC0wLjEsMC0wLjIsMEMxOSw5LjIsMTksOC44LDE5LDguM3ogTTcuNSw3Yy0wLjMsMC0wLjUsMC0wLjgsMC4xQzUuOSw3LjMsNS4zLDcuNyw0LjgsOC4zQzQuMSw5LjEsMy45LDEwLDQsMTFjMC4xLDAuOSwwLjYsMS43LDEuMywyLjJjMC44LDAuNiwxLjgsMC45LDIuOCwwLjdjMC43LTAuMSwxLjMtMC41LDEuOC0wLjljMC4zLTAuMywwLjMtMC43LDAtMC45Yy0wLjMtMC4zLTAuNy0wLjMtMC45LDBjLTAuNSwwLjUtMS4xLDAuNy0xLjgsMC42Yy0wLjQtMC4xLTAuOC0wLjItMS4yLTAuNWMtMC41LTAuNS0wLjgtMS4xLTAuNy0xLjhDNS40LDkuOCw1LjYsOS40LDUuOSw5QzYuNCw4LjUsNyw4LjMsNy43LDguNEM4LjIsOC40LDguNiw4LjYsOSw5YzAuMiwwLjIsMC43LDAuMywxLDBjMC4yLTAuMiwwLjItMC43LDAtMC45QzkuOCw4LDkuOCw3LjksOS43LDcuOUM5LjEsNy4zLDguMyw3LjEsNy41LDd6IE0yOS42LDEzLjljMC4zLDAsMC43LTAuMSwxLTAuMWMwLjYtMC4xLDEtMC40LDEuMy0xYzAuMi0wLjMsMC4yLTAuNywwLjItMWMwLTAuNS0wLjItMC45LTAuNi0xLjJjLTAuNC0wLjMtMC44LTAuNi0xLjItMC44Yy0wLjItMC4yLTAuNS0wLjMtMC43LTAuNWMtMC4zLTAuMi0wLjItMC42LDAuMS0wLjhjMC4zLTAuMiwwLjctMC4yLDEuMS0wLjFjMC40LDAuMSwwLjcsMC4yLDEsMC40YzAuMiwwLjEsMC4yLDAsMC4yLTAuMmMwLTAuMywwLTAuNiwwLTAuOGMwLTAuMi0wLjEtMC4yLTAuMi0wLjNjLTAuNC0wLjEtMC43LTAuMi0xLjEtMC4yYy0wLjYsMC0xLjIsMC0xLjcsMC4yYy0wLjQsMC4yLTAuNywwLjQtMC45LDAuOGMtMC4yLDAuMy0wLjIsMC42LTAuMiwxYzAsMC42LDAuMywxLjEsMC44LDEuNWMwLjUsMC40LDEsMC43LDEuNSwxYzAuMiwwLjEsMC4zLDAuMywwLjMsMC42YzAsMC4zLTAuMiwwLjUtMC41LDAuNmMtMC41LDAuMS0xLDAuMS0xLjQtMC4xYy0wLjMtMC4xLTAuNS0wLjItMC43LTAuM2MtMC4yLTAuMS0wLjMsMC0wLjMsMC4xYzAsMC4yLDAsMC41LDAsMC43YzAsMC4xLDAuMSwwLjIsMC4yLDAuM2MwLjEsMC4xLDAuMiwwLjEsMC4zLDAuMUMyOC42LDEzLjgsMjkuMSwxMy45LDI5LjYsMTMuOXogTTI0LDguM2MwLDAuMSwwLDAuMSwwLDAuMmMwLDEuNywwLDMuNCwwLDVjMCwwLjIsMCwwLjIsMC4yLDAuMmMwLjQsMCwwLjgsMCwxLjIsMGMwLjIsMCwwLjIsMCwwLjItMC4yYzAtMS43LDAtMy40LDAtNWMwLTAuMSwwLTAuMSwwLTAuMmMwLjEsMCwwLjEsMCwwLjIsMGMwLjUsMCwxLjEsMCwxLjYsMGMwLjIsMCwwLjIsMCwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4xLTAuMS0wLjItMC4yLTAuMmMwLDAtMC4xLDAtMC4xLDBjLTEuNiwwLTMuMywwLTQuOSwwYzAsMC0wLjEsMC0wLjEsMGMtMC4xLDAtMC4yLDAuMS0wLjIsMC4yYzAsMC4zLDAsMC41LDAsMC44YzAsMC4xLDAuMSwwLjIsMC4yLDAuMmMwLjUsMCwxLjEsMCwxLjYsMEMyMy45LDguMywyNCw4LjMsMjQsOC4zeiBNOCwxMS4yYzAuNiwwLDEuMSwwLDEuNywwYzAuMywwLDAuNC0wLjEsMC42LTAuM2MwLjItMC41LTAuMS0xLTAuNi0xYy0xLjEsMC0yLjIsMC0zLjMsMGMtMC40LDAtMC43LDAuMi0wLjcsMC42YzAsMC41LDAuMywwLjcsMC42LDAuN0M2LjgsMTEuMiw3LjQsMTEuMiw4LDExLjJ6Ii8+PC9zdmc+)}.bg-giropay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfNF8iIGNsYXNzPSJzdDIwIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnPjxwYXRoIGlkPSJfOTIxODYxODRfMV8iIGNsYXNzPSJzdDAiIGQ9Ik0zLjgsNi44djguNWMwLDAuOCwwLjcsMS41LDEuNSwxLjVoMTMuOVY1LjJINS4zQzQuNSw1LjIsMy44LDUuOSwzLjgsNi44TDMuOCw2Ljh6IE0yMi44LDExYzAsMC41LTAuMywwLjktMC43LDAuOWMtMC40LDAtMC43LTAuNC0wLjctMC45YzAtMC41LDAuMy0wLjksMC43LTAuOUMyMi42LDEwLjEsMjIuOCwxMC41LDIyLjgsMTF6IE0yMC4yLDE0LjFoMS4ydi0xLjhoMGMwLjIsMC40LDAuNywwLjYsMS4xLDAuNmMxLDAsMS42LTAuOCwxLjYtMS44YzAtMC44LTAuNS0xLjctMS41LTEuN2MtMC41LDAtMSwwLjItMS4zLDAuN2gwVjkuM2gtMS4xVjE0LjF6IE0yNS43LDExLjZjMC0wLjMsMC4zLTAuNCwwLjctMC40YzAuMiwwLDAuMywwLDAuNSwwYzAsMC40LTAuMywwLjgtMC43LDAuOEMyNS45LDEyLDI1LjcsMTEuOSwyNS43LDExLjZ6IE0yOCwxMi43QzI4LDEyLjQsMjgsMTIuMiwyOCwxMS45di0xLjNjMC0xLTAuNy0xLjQtMS42LTEuNGMtMC41LDAtMC45LDAuMS0xLjQsMC4ybDAsMC44YzAuMy0wLjIsMC43LTAuMywxLjEtMC4zYzAuNCwwLDAuOCwwLjEsMC44LDAuNmMtMC4xLDAtMC40LDAtMC41LDBjLTAuNiwwLTEuOCwwLjEtMS44LDEuMmMwLDAuNywwLjYsMS4xLDEuMywxLjFjMC41LDAsMC44LTAuMiwxLjEtMC42aDBjMCwwLjIsMCwwLjQsMCwwLjVMMjgsMTIuN0wyOCwxMi43eiBNMjguNSwxNC4xYzAuMiwwLjEsMC41LDAuMSwwLjcsMC4xYzEuMSwwLDEuMy0wLjgsMS43LTEuN2wxLjItMy4ySDMxbC0wLjcsMi4yaDBsLTAuNy0yLjJoLTEuM2wxLjQsMy41Yy0wLjEsMC4zLTAuMywwLjUtMC42LDAuNWMtMC4yLDAtMC4zLDAtMC41LTAuMUwyOC41LDE0LjF6Ii8+PHBhdGggaWQ9Il80NzMwMzAzMl8xXyIgY2xhc3M9InN0MzMiIGQ9Ik02LjcsMTFjMC0wLjUsMC4yLTAuOCwwLjctMC44YzAuNSwwLDAuNywwLjQsMC43LDAuOGMwLDAuNS0wLjMsMC45LTAuNywwLjlDNywxMS44LDYuNywxMS41LDYuNywxMXogTTkuMiw5LjNIOC4ydjAuNmgwQzcuOSw5LjUsNy41LDkuMiw3LDkuMkM1LjksOS4yLDUuNSwxMCw1LjUsMTFjMCwxLDAuNiwxLjcsMS41LDEuN2MwLjUsMCwwLjktMC4yLDEuMS0wLjZoMHYwLjJjMCwwLjctMC40LDEtMSwxYy0wLjUsMC0wLjgtMC4xLTEuMS0wLjNsLTAuMSwwLjljMC4zLDAuMSwwLjcsMC4yLDEuMywwLjJjMS40LDAsMi0wLjUsMi0xLjhWOS4zTDkuMiw5LjN6IE0xMS4yLDcuOUgxMHYwLjloMS4yTDExLjIsNy45TDExLjIsNy45eiBNMTAsMTIuN2gxLjJWOS4zSDEwVjEyLjdMMTAsMTIuN3ogTTE0LjUsOS4zYy0wLjEsMC0wLjMsMC0wLjQsMGMtMC41LDAtMC44LDAuMy0xLDAuN2gwVjkuM0gxMnYzLjRoMS4ydi0xLjRjMC0wLjcsMC4zLTEuMSwwLjktMS4xYzAuMSwwLDAuMywwLDAuNCwwTDE0LjUsOS4zeiBNMTYuNSwxMS45Yy0wLjUsMC0wLjgtMC40LTAuOC0xYzAtMC41LDAuMi0xLDAuOC0xYzAuNSwwLDAuOCwwLjQsMC44LDFDMTcuMywxMS41LDE3LDExLjksMTYuNSwxMS45eiBNMTYuNSwxMi44YzEuMSwwLDItMC43LDItMS44YzAtMS4xLTAuOS0xLjgtMi0xLjhjLTEuMSwwLTIsMC43LTIsMS44QzE0LjUsMTIuMSwxNS40LDEyLjgsMTYuNSwxMi44eiIvPjwvZz48L3N2Zz4=)}.bg-gpay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfN18iIGNsYXNzPSJzdDIzIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnIGlkPSJHUGF5LUxpZ2h0LXRoZW1lZC1idXR0b25zIj48ZyBpZD0iR1BBWS0tLVNWR3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xODUuMDAwMDAwLCAtNDAwLjAwMDAwMCkiPjxnIGlkPSJHUGF5LUJyYW5kLU1hcmsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE4NS4wMDAwMDAsIDQwMC4wMDAwMDApIj48ZyBpZD0iR1BheSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4yNjE0NzQsIDAuMjYxNDc0KSI+PGcgaWQ9IlBheSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTcuNjE1MDY5LCAwLjgyNTcwNikiPjxwYXRoIGlkPSJGaWxsLTEiIGNsYXNzPSJzdDAiIGQ9Ik0tMC42LDcuM3YyLjZIMWMwLjQsMCwwLjctMC4xLDAuOS0wLjRjMC4zLTAuMywwLjQtMC42LDAuNC0wLjljMC0wLjMtMC4xLTAuNi0wLjQtMC45QzEuNyw3LjQsMS40LDcuMywxLDcuM0wtMC42LDcuM0wtMC42LDcuM3ogTS0wLjYsMTAuOHYzaC0xVjYuNEgxYzAuNiwwLDEuMiwwLjIsMS42LDAuNmMwLjUsMC40LDAuNywxLDAuNywxLjZjMCwwLjYtMC4yLDEuMi0wLjcsMS42Yy0wLjQsMC40LTEsMC42LTEuNiwwLjZMLTAuNiwxMC44TC0wLjYsMTAuOHoiLz48cGF0aCBpZD0iRmlsbC0zIiBjbGFzcz0ic3QwIiBkPSJNNC4zLDEyLjNjMCwwLjIsMC4xLDAuNSwwLjMsMC42YzAuMiwwLjIsMC41LDAuMiwwLjcsMC4yYzAuNCwwLDAuOC0wLjEsMS4xLTAuNGMwLjMtMC4zLDAuNS0wLjYsMC41LTEuMWMtMC4zLTAuMi0wLjctMC40LTEuMi0wLjRjLTAuNCwwLTAuNywwLjEtMSwwLjNDNC40LDExLjcsNC4zLDEyLDQuMywxMi4zIE01LjUsOC41YzAuNywwLDEuMywwLjIsMS43LDAuNmMwLjQsMC40LDAuNiwwLjksMC42LDEuNnYzLjFINi45di0wLjdoMEM2LjUsMTMuNyw2LDE0LDUuMywxNGMtMC42LDAtMS0wLjItMS40LTAuNWMtMC40LTAuMy0wLjYtMC43LTAuNi0xLjJjMC0wLjUsMC4yLTAuOSwwLjYtMS4zYzAuNC0wLjMsMC45LTAuNSwxLjYtMC41YzAuNiwwLDEsMC4xLDEuNCwwLjN2LTAuMmMwLTAuMy0wLjEtMC42LTAuNC0wLjhDNi4zLDkuNSw2LDkuNCw1LjYsOS40Yy0wLjUsMC0xLDAuMi0xLjMsMC43TDMuNSw5LjVDMy45LDguOSw0LjYsOC41LDUuNSw4LjUiLz48ZyBpZD0iR3JvdXAtNyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTUuMDg0OTIzLCAzLjc1OTQ0NykiPjxwb2x5Z29uIGlkPSJGaWxsLTUiIGNsYXNzPSJzdDAiIHBvaW50cz0iLTIsNSAtNS4yLDEyLjMgLTYuMiwxMi4zIC01LDkuNyAtNy4xLDUgLTYuMSw1IC00LjUsOC42IC00LjUsOC42IC0zLDUgIi8+PC9nPjwvZz48ZyBpZD0iRyI+PHBhdGggaWQ9IkZpbGwtOCIgY2xhc3M9InN0MCIgZD0iTTEzLjIsMTFjMC0wLjMsMC0wLjYtMC4xLTAuOWgtNHYxLjZoMi4zYy0wLjEsMC41LTAuNCwxLTAuOSwxLjN2MS4xaDEuNEMxMi43LDEzLjQsMTMuMiwxMi4zLDEzLjIsMTEiLz48cGF0aCBpZD0iRmlsbC0xMCIgY2xhc3M9InN0MCIgZD0iTTkuMSwxNS4yYzEuMiwwLDIuMS0wLjQsMi44LTFMMTAuNSwxM2MtMC40LDAuMy0wLjksMC40LTEuNSwwLjRjLTEuMSwwLTIuMS0wLjgtMi40LTEuOEg1LjJ2MS4xQzUuOSwxNC4yLDcuNCwxNS4yLDkuMSwxNS4yIi8+PHBhdGggaWQ9IkZpbGwtMTIiIGNsYXNzPSJzdDAiIGQ9Ik02LjYsMTEuN2MtMC4xLTAuMy0wLjEtMC41LTAuMS0wLjhjMC0wLjMsMC0wLjYsMC4xLTAuOFY5SDUuMmMtMC4zLDAuNi0wLjUsMS4yLTAuNSwxLjljMCwwLjcsMC4yLDEuMywwLjUsMS45TDYuNiwxMS43eiIvPjxwYXRoIGlkPSJGaWxsLTE0IiBjbGFzcz0ic3QwIiBkPSJNOS4xLDguM2MwLjYsMCwxLjIsMC4yLDEuNiwwLjZ2MGwxLjItMS4yQzExLjIsNywxMC4yLDYuNiw5LjEsNi42Yy0xLjcsMC0zLjEsMS0zLjgsMi40bDEuNCwxLjFDNyw5LDcuOSw4LjMsOS4xLDguMyIvPjwvZz48L2c+PC9nPjwvZz48L2c+PC9zdmc+)}.bg-ideal{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHlfMl8xXyIgY2xhc3M9InN0MTkiIGQ9Ik0zLDBoMzBjMS43LDAsMywxLjMsMywzdjE2YzAsMS43LTEuMywzLTMsM0gzYy0xLjcsMC0zLTEuMy0zLTNWM0MwLDEuMywxLjMsMCwzLDB6Ii8+PGc+PHJlY3QgeD0iMTEuNCIgeT0iMTEuOSIgY2xhc3M9InN0MCIgd2lkdGg9IjIuNyIgaGVpZ2h0PSI0LjUiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTQuMyw5LjdjMCwwLjktMC43LDEuNS0xLjUsMS41Yy0wLjksMC0xLjUtMC43LTEuNS0xLjVjMC0wLjksMC43LTEuNSwxLjUtMS41QzEzLjYsOC4xLDE0LjMsOC44LDE0LjMsOS43eiIvPjxnPjxnPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xOS4zLDMuNkg5LjV2MTQuOWg5Ljh2MGMyLjEsMCwzLjgtMC42LDUtMS42YzEuNS0xLjIsMi4yLTMuMiwyLjItNS44YzAtMS4zLTAuMi0yLjQtMC42LTMuNGMtMC40LTAuOS0wLjktMS43LTEuNi0yLjNDMjMuMSw0LjIsMjEuMywzLjYsMTkuMywzLjZDMTkuMywzLjYsMTkuMywzLjYsMTkuMywzLjZ6IE0xOS4xLDQuNmMxLjksMCwzLjUsMC41LDQuNiwxLjVjMS4yLDEuMSwxLjksMi44LDEuOSw1YzAsNC4zLTIuMSw2LjQtNi40LDYuNGMtMC4zLDAtNy44LDAtOC42LDBjMC0wLjksMC0xMiwwLTEyLjlDMTEuMyw0LjYsMTguOCw0LjYsMTkuMSw0LjZ6Ii8+PC9nPjwvZz48Zz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTYsMTAuNmMwLjEsMCwwLjEsMCwwLjItMC4xYzAsMCwwLjEtMC4xLDAuMS0wLjJjMC0wLjEsMC0wLjMsMC0wLjVjMC0wLjIsMC0wLjMsMC0wLjRjMC0wLjEtMC4xLTAuMi0wLjEtMC4yYy0wLjEtMC4xLTAuMS0wLjEtMC4yLTAuMWMwLDAtMC4yLDAtMC40LDBjMCwwLTAuMSwwLTAuMiwwdjEuNmMwLjEsMCwwLjMsMCwwLjMsMEMxNS44LDEwLjYsMTUuOSwxMC42LDE2LDEwLjZ6Ii8+PHBhdGggY2xhc3M9InN0MCIgZD0iTTIwLjgsMTBjMC4xLDAsMC40LDAsMC41LDBjMC0wLjEtMC4yLTAuNS0wLjMtMC43QzIxLDkuNSwyMC45LDkuOSwyMC44LDEweiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMi43LDExLjJWOC41aDAuN2MwLDAsMCwyLDAsMi4xYzAuMSwwLDEsMCwxLjIsMGMtMC4zLTMuOC0zLjItNC44LTYtNC44aC0zLjN2Mi43aDAuNGMwLjIsMCwwLjQsMCwwLjUsMC4xYzAuMiwwLDAuMywwLjEsMC40LDAuM2MwLjEsMC4xLDAuMiwwLjMsMC4zLDAuNEMxNyw5LjQsMTcsOS42LDE3LDkuOGMwLDAuMiwwLDAuNC0wLjEsMC42Yy0wLjEsMC4yLTAuMiwwLjQtMC4zLDAuNWMtMC4xLDAuMS0wLjIsMC4yLTAuNCwwLjJjLTAuMSwwLTAuMywwLjEtMC41LDAuMWgtMC40djUuM2gzLjNjMi45LDAsNS45LTAuOSw2LTUuM0gyMi43eiBNMTkuNSwxMS4yaC0yLjFWOC41aDIuMVY5YzAsMC0xLjMsMC0xLjQsMGMwLDAuMSwwLDAuMywwLDAuNGMwLjEsMCwxLjMsMCwxLjMsMFYxMGMwLDAtMS4yLDAtMS4zLDBjMCwwLjEsMCwwLjUsMCwwLjZjMC4xLDAsMS40LDAsMS40LDBWMTEuMnogTTIxLjgsMTEuMmMwLDAtMC4yLTAuNS0wLjItMC42Yy0wLjEsMC0wLjgsMC0wLjksMGMwLDAuMS0wLjIsMC42LTAuMiwwLjZoLTAuN2wxLjEtMi43aDAuN2wxLjEsMi43SDIxLjh6Ii8+PC9nPjwvZz48L3N2Zz4=)}.bg-jcb{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU3XzJfIiBjbGFzcz0ic3QxMyIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48Zz48ZyBpZD0iZzYzMjciPjxwYXRoIGlkPSJwYXRoNjMzOCIgY2xhc3M9InN0MCIgZD0iTTIyLjcsMTIuNWgxLjNjMCwwLDAuMSwwLDAuMiwwYzAuMy0wLjEsMC41LTAuMywwLjUtMC42YzAtMC4zLTAuMi0wLjUtMC41LTAuNmMwLDAtMC4xLDAtMC4yLDBoLTEuM1YxMi41TDIyLjcsMTIuNXoiLz48cGF0aCBpZD0icGF0aDYzNDkiIGNsYXNzPSJzdDAiIGQ9Ik0yMy45LDRjLTEuMywwLTIuMywxLTIuMywyLjN2Mi40aDMuM2MwLjEsMCwwLjIsMCwwLjIsMGMwLjcsMCwxLjMsMC40LDEuMywxLjFjMCwwLjUtMC40LDEtMS4xLDEuMXYwYzAuOCwwLjEsMS4zLDAuNSwxLjMsMS4xYzAsMC43LTAuNiwxLjItMS41LDEuMmgtMy42VjE4SDI1YzEuMywwLDIuMy0xLDIuMy0yLjNWNEwyMy45LDRMMjMuOSw0eiIvPjxwYXRoIGlkPSJwYXRoNjM2MCIgY2xhc3M9InN0MCIgZD0iTTI0LjUsMTBjMC0wLjMtMC4yLTAuNS0wLjUtMC42YzAsMC0wLjEsMC0wLjEsMGgtMS4ydjEuMWgxLjJjMCwwLDAuMSwwLDAuMSwwQzI0LjMsMTAuNSwyNC41LDEwLjMsMjQuNSwxMHoiLz48L2c+PHBhdGggaWQ9InBhdGg2MzcxIiBjbGFzcz0ic3QwIiBkPSJNMTEsNEM5LjcsNCw4LjcsNSw4LjcsNi4zdjUuOGMwLjcsMC4zLDEuMywwLjUsMiwwLjVjMC44LDAsMS4yLTAuNSwxLjItMS4yVjguN2gydjIuN2MwLDEuMS0wLjcsMS45LTIuOSwxLjljLTEuMywwLTIuNC0wLjMtMi40LTAuM1YxOGgzLjRjMS4zLDAsMi4zLTEsMi4zLTIuM1Y0QzE0LjQsNCwxMSw0LDExLDR6Ii8+PHBhdGggaWQ9InBhdGg2Mzg0IiBjbGFzcz0ic3QwIiBkPSJNMTcuNSw0Yy0xLjMsMC0yLjMsMS0yLjMsMi4zdjMuMWMwLjYtMC41LDEuNi0wLjgsMy4zLTAuN2MwLjksMCwxLjgsMC4zLDEuOCwwLjN2MWMtMC41LTAuMi0xLTAuNS0xLjgtMC41Yy0xLjMtMC4xLTIsMC41LTIsMS42YzAsMS4xLDAuOCwxLjcsMiwxLjZjMC43LTAuMSwxLjMtMC4zLDEuOC0wLjV2MWMwLDAtMC45LDAuMi0xLjgsMC4zYy0xLjcsMC4xLTIuNy0wLjItMy4zLTAuN1YxOGgzLjRjMS4zLDAsMi4zLTEsMi4zLTIuM1Y0QzIwLjksNCwxNy41LDQsMTcuNSw0eiIvPjwvZz48L3N2Zz4=)}.bg-maestro{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzUzXzNfIiBjbGFzcz0ic3Q0IiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxjaXJjbGUgY2xhc3M9InN0OCIgY3g9IjE0IiBjeT0iMTEiIHI9IjYiLz48Y2lyY2xlIGlkPSJFbGxpcHNlXzhfY29weV8zXyIgY2xhc3M9InN0OSIgY3g9IjIyIiBjeT0iMTEiIHI9IjYiLz48cGF0aCBpZD0iUm91bmRlZF9SZWN0YW5nbGVfMjVfM18iIGNsYXNzPSJzdDEwIiBkPSJNMTgsNmMtMi44LDEuNS0zLjgsNC45LTIuMyw3LjZjMC40LDAuOCwxLDEuNCwxLjcsMS45YzAuMiwwLjIsMC41LDAuMywwLjcsMC40bDAuMSwwYzIuNy0xLjQsMy43LTQuOSwyLjMtNy42QzE5LjgsNy40LDE5LDYuNSwxOCw2Ii8+PC9zdmc+)}.bg-mastercard{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzUzXzRfIiBjbGFzcz0ic3QzIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxjaXJjbGUgY2xhc3M9InN0NSIgY3g9IjE0IiBjeT0iMTEiIHI9IjYiLz48Y2lyY2xlIGlkPSJFbGxpcHNlXzhfY29weV80XyIgY2xhc3M9InN0NiIgY3g9IjIyIiBjeT0iMTEiIHI9IjYiLz48cGF0aCBpZD0iUm91bmRlZF9SZWN0YW5nbGVfMjVfNF8iIGNsYXNzPSJzdDciIGQ9Ik0xOCw2TDE4LDZjLTIuOCwxLjUtMy44LDQuOS0yLjMsNy42YzAuNCwwLjgsMSwxLjQsMS43LDEuOWMwLjIsMC4yLDAuNSwwLjMsMC43LDAuNGwwLjEsMGMyLjctMS40LDMuNy00LjksMi4zLTcuNkMxOS44LDcuNCwxOSw2LjUsMTgsNiIvPjwvc3ZnPg==)}.bg-mol{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfMTJfIiBjbGFzcz0ic3QyNiIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjYuOSwxMy4xYy0wLjUsMC0wLjYtMC4xLTAuNi0wLjZjMC0xLjEsMC0yLjIsMC0zLjNjMC0xLjItMC4yLTEuNC0xLjQtMS40Yy0yLDAtNC4xLDAtNi4xLDBjLTEuMSwwLTIuNSwxLjQtMi41LDIuNWMwLDEuMiwwLDIuNCwwLDMuNmMtMC4yLDAtMC4xLTAuMy0wLjMtMC4zYy0xLTAuMS0wLjgtMC45LTAuOC0xLjVjMC0xLjMsMC0yLjUtMC45LTMuNkMxNCw4LDEzLjcsNy44LDEzLjIsNy44Yy0yLjEsMC00LjIsMC02LjMsMEM2LDcuOCw1LjcsOC4xLDUuNyw5YzAsMS42LDAsMy4yLDAsNC44YzAsMC43LDAuMywxLjEsMC45LDEuMWMwLjYsMCwwLjktMC40LDAuOS0xLjFjMC0xLDAtMiwwLTNjMC0xLjIsMC0xLjIsMS4yLTEuMmMwLjYsMCwwLjcsMC4yLDAuNywwLjdjMCwxLjEsMCwyLjIsMCwzLjNjMCwwLjgsMC4zLDEuMywxLDEuM2MwLjYsMCwwLjktMC40LDAuOS0xLjJjMC0xLjIsMC0yLjMsMC0zLjVjMC0wLjQsMC4xLTAuNiwwLjYtMC42YzAuOSwwLDEuNCwwLjUsMS40LDEuNGMwLDAuOSwwLDEuOCwwLDIuN2MwLDAuOCwwLjMsMS4xLDEuMSwxLjFjMi4yLDAsNC40LDAsNi42LDBjMC4zLDAsMC41LDAsMC43LTAuMmMwLjUtMC42LDEuMS0xLjEsMS41LTEuOGMwLjEtMS4xLDAtMi4yLDAtMy4zYzAtMC4xLTAuMi0wLjQsMC4yLTAuNWMwLjgsMC4xLDAuOSwwLjYsMC45LDEuM2MtMC4xLDEuMSwwLDIuMywwLDMuNGMwLDAuOCwwLjMsMSwxLjEsMWMwLjksMCwxLjktMC4xLDIuOCwwYzEuNSwwLjIsMi4xLTAuOSwzLTEuOUMyOS43LDEzLjEsMjguMywxMywyNi45LDEzLjF6IE0yMS41LDEyYzAsMC45LTAuNywxLjQtMS44LDEuNGMtMS41LDAtMS41LDAtMS41LTEuNWMwLDAsMC0wLjEsMC0wLjFjMC0wLjQsMC0wLjgsMC0xLjJjMC0wLjgsMC43LTEuMywxLjctMS4zYzEuNiwwLDEuNiwwLDEuNiwxLjZDMjEuNSwxMS4zLDIxLjUsMTEuNywyMS41LDEyeiIvPjwvc3ZnPg==)}.bg-paypal{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU4XzFfIiBjbGFzcz0ic3QxMyIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjMsOS45YzAsMC4zLDAsMC41LTAuMSwwLjhjLTAuMiwxLjgtMS45LDMuMi0zLjcsM2gtMC4zYy0wLjIsMC0wLjQsMC4yLTAuNSwwLjRMMTgsMTYuNmMwLDAuMi0wLjIsMC40LTAuNSwwLjRoLTEuNGMtMC4yLDAtMC4zLTAuMS0wLjMtMC4zYzAsMCwwLDAsMCwwbDAuNy00LjRsMCwwaDEuMWMyLjMsMC4yLDQuNC0xLjUsNC43LTMuOEMyMi44LDguOCwyMyw5LjMsMjMsOS45eiBNMTUuOSwxMmMwLTAuMywwLjItMC42LDAuNi0wLjZjMCwwLDAuMSwwLDAuMSwwaDEuMWMyLjMsMCwzLjYtMSw0LTMuMmMwLjQtMi4xLTEuMS0zLjItMy0zLjJIMTVjLTAuMywwLTAuNSwwLjItMC41LDAuNWMtMS4yLDcuNC0xLjUsOS4zLTEuNSw5LjljMCwwLjIsMC4xLDAuMywwLjMsMC4zYzAsMCwwLDAsMCwwaDJMMTUuOSwxMnoiLz48L3N2Zz4=)}.bg-poli{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfOV8iIGNsYXNzPSJzdDMxIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnIGlkPSJwb2xpXzFfIj48cGF0aCBpZD0icG9saS1sb2dvXzFfIiBjbGFzcz0ic3QwIiBkPSJNMTguNSwxNC44YzAuMy0wLjEsMC43LTAuNCwxLTAuNmMwLjgtMC43LDEuNy0yLDEuNi0zLjVDMjEsOSwyMC4xLDcuOSwxOSw3LjNjMC4zLDAuMSwwLjYsMC4zLDAuOSwwLjVjMC43LDAuNiwxLjMsMS41LDEuMywyLjhjMCwxLjctMC45LDIuOS0xLjgsMy43YzAuMy0wLjEsMC41LTAuNCwwLjctMC43YzAuNi0wLjcsMS4yLTEuOCwxLjItMy4xYzAtMS44LTEtMi45LTIuMi0zLjZjMC40LDAuMSwwLjgsMC40LDEsMC42YzAuNywwLjYsMS40LDEuNywxLjMsMy4xYy0wLjEsMS40LTAuNywyLjUtMS42LDMuNGMtMC45LDAuOC0yLDEuNC0zLjQsMS41Yy0wLjEsMC0wLjMsMC0wLjUsMGMtMi4xLTAuMi0zLjYtMS41LTMuOC0zLjZjMC0wLjIsMC0wLjQsMC0wLjZjMC4xLTEuMywwLjctMi4zLDEuNS0zLjFjMC44LTAuOSwxLjktMS41LDMuNC0xLjZDMTcsNi42LDE3LDYuNCwxNyw2LjNjMC41LDAuNSwxLjEsMS4xLDEuNywxLjdjLTAuNywwLjQtMS41LDAuOC0yLjIsMS4yYzAtMC4xLDAtMC4zLDAuMS0wLjRjLTEuMiwwLjItMi4zLDEuMS0yLjUsMi40Yy0wLjMsMS41LDAuOCwyLjcsMi4yLDIuN2MxLjUsMCwyLjgtMS4xLDMtMi41YzAuMi0xLjEtMC4zLTEuOC0wLjktMi4zYzAuNiwwLjQsMS4yLDEsMS4xLDJjLTAuMSwxLjYtMS42LDIuOS0zLjEsMi45Yy0wLjgsMC0xLjYtMC40LTIuMS0xYzAuNSwwLjcsMS40LDEuMSwyLjQsMWMwLjgtMC4xLDEuNC0wLjQsMS45LTAuOWMwLjUtMC41LDAuOS0xLjEsMS0xLjhjMC0wLjMsMC0wLjYsMC0wLjhjLTAuMS0wLjgtMC42LTEuMi0xLjEtMS43YzAuNiwwLjUsMS4zLDEuMiwxLjMsMi4zYy0wLjEsMS42LTEuNiwzLTMuMiwzLjFjLTEuMSwwLjEtMS43LTAuMy0yLjMtMC44YzAuNSwwLjcsMS41LDEsMi42LDAuOGMxLjUtMC4yLDIuOC0xLjUsMy0zYzAuMS0xLjQtMC42LTItMS4yLTIuN2MwLjcsMC41LDEuMywxLjEsMS40LDIuMmMwLDEtMC40LDEuOS0xLDIuNWMtMSwxLTIuOCwxLjYtNC4zLDAuN2MxLjIsMC45LDMuMiwwLjQsNC4yLTAuNWMwLjctMC43LDEuMy0xLjYsMS4yLTIuOWMtMC4xLTEuMS0wLjctMS42LTEuNC0yLjJjMC43LDAuNCwxLjQsMS4xLDEuNSwyLjFjMC4xLDEuNC0wLjUsMi40LTEuMywzLjFjLTAuOSwwLjgtMi4yLDEuMy0zLjcsMC45YzIuNCwwLjgsNC43LTEuMSw1LTMuMWMwLjItMS41LTAuNS0yLjQtMS4zLTNjLTAuMS0wLjEtMC4xLTAuMS0wLjItMC4yYzEsMC41LDEuOSwxLjcsMS42LDMuNGMtMC40LDItMi40LDMuNi00LjksMy4yYzAuNCwwLjEsMC44LDAuMSwxLjIsMC4xYzEuMi0wLjEsMi4yLTAuNiwyLjgtMS4zYzAuNy0wLjgsMS4yLTEuNywxLjEtMy4xYy0wLjEtMS4yLTAuOC0xLjgtMS42LTIuNWMwLjQsMC4xLDAuNywwLjQsMC45LDAuN2MwLjQsMC41LDAuOCwxLjEsMC44LDEuOWMwLjEsMS40LTAuNiwyLjUtMS4zLDMuMmMtMC44LDAuOC0xLjgsMS4zLTMuMSwxLjNjMi4xLDAuMSwzLjQtMS4yLDQuMS0yLjZjMC40LTAuOCwwLjUtMiwwLjItMi44Yy0wLjMtMC44LTAuOS0xLjQtMS42LTEuOGMxLjEsMC42LDIuMSwxLjcsMS45LDMuNWMtMC4xLDAuNy0wLjMsMS4yLTAuNiwxLjdjLTAuNiwxLTEuNiwxLjgtMi44LDIuMmMwLjgtMC4yLDEuNi0wLjcsMi4yLTEuM2MwLjctMC44LDEuMy0xLjgsMS4yLTMuMmMwLTEuNS0xLTIuNC0xLjktM2MwLDAsMCwwLDAsMGMxLDAuNSwxLjgsMS40LDIsMi44QzIxLjIsMTIuNCwxOS44LDE0LDE4LjUsMTQuOCIvPjxwYXRoIGlkPSJwb2xpLXR4dF8xXyIgY2xhc3M9InN0MzQiIGQ9Ik04LDExLjRjMCwwLDAsMCwwLjEsMGMwLjcsMCwwLjktMC4yLDEtMC4zYzAuMi0wLjIsMC4yLTAuNywwLjItMS4xYzAtMC40LDAtMC43LTAuMy0xQzguOSw4LjgsOC40LDguNyw4LDguN2wwLDAuMUw4LDExLjRMOCwxMS40eiBNNS42LDE1LjRWNy4yaDIuMWMwLjgsMCwxLjUsMCwxLjksMC4xYzAuNCwwLjEsMC45LDAuMiwxLjEsMC40YzAuMywwLjIsMC42LDAuNSwwLjgsMC45YzAuMiwwLjQsMC4zLDAuOSwwLjMsMS41YzAsMC45LTAuMiwxLjctMC43LDIuMWMtMC41LDAuNS0xLjYsMC43LTIuNSwwLjdIOHYyLjVINS42eiBNMjcuNCwxNS4zSDIyVjcuMmgyLjZ2NS43aDIuN1YxNS4zeiBNMzAuNCwxNS40aC0yLjVWMTBoMi41VjE1LjR6IE0zMC40LDkuNGgtMi42VjcuMmgyLjZWOS40eiIvPjwvZz48L3N2Zz4=)}.bg-qiwi{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfMTFfIiBjbGFzcz0ic3QyOCIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTAuOSwxNC44YzAuMSwwLjMsMC4yLDAuNSwwLjQsMC43YzAuMiwwLjIsMC40LDAuNCwwLjYsMC41YzAuMiwwLjEsMC41LDAuMywwLjcsMC4zYzAuMSwwLjEsMC4zLDAuMSwwLjQsMC4xYzAuMSwwLDAuMiwwLjEsMC4zLDAuM2MwLDAuMi0wLjEsMC4zLTAuMywwLjNjLTAuMiwwLTAuMy0wLjEtMC41LTAuMWMtMC45LTAuMS0xLjctMC42LTIuNC0xLjJjLTAuMS0wLjEtMC4yLTAuMi0wLjMtMC40UzkuNiwxNSw5LjUsMTQuOWMtMC42LTAuMS0xLjItMC40LTEuNi0wLjhjLTAuNC0wLjUtMC43LTEuMS0wLjgtMS43QzYuOSwxMS43LDcsMTEsNy4yLDEwLjJDNy40LDksOC42LDgsOS45LDhjMC40LDAsMC44LDAuMSwxLjEsMC4yYzAuMywwLjEsMC43LDAuMywwLjksMC42YzAsMCwwLDAsMCwwQzEyLDguOSwxMi4yLDksMTIuMiw5LjFjMCwwLDAsMC4xLDAsMC4xYzAsMCwwLjEsMC4xLDAuMSwwLjFzMCwwLDAsMC4xczAsMC4xLDAuMSwwLjFjMCwwLDAsMCwwLDBjMCwwLjEsMC4xLDAuMiwwLjEsMC4zczAuMSwwLjIsMC4xLDAuM2MwLjEsMC4zLDAuMiwwLjYsMC4yLDAuOWMwLjEsMC44LTAuMSwxLjctMC40LDIuNGMtMC4yLDAuMy0wLjQsMC42LTAuNywwLjhDMTEuNSwxNC41LDExLjIsMTQuNywxMC45LDE0Ljh6IE05LjcsOC44QzkuNiw4LjksOS40LDguOSw5LjIsOUM5LjEsOS4xLDksOS4yLDguOSw5LjNDOC44LDkuNCw4LjcsOS41LDguNiw5LjdjLTAuMSwwLjMtMC4yLDAuNS0wLjIsMC44Yy0wLjEsMC4zLTAuMSwwLjYtMC4xLDFjMCwwLjcsMC4xLDEuNSwwLjUsMi4xQzksMTMuOCw5LjIsMTQsOS41LDE0LjFjMC4yLDAsMC4zLDAuMSwwLjUsMC4xYzAuMSwwLDAuMiwwLDAuMy0wLjFjMC4xLDAsMC4yLDAsMC4zLTAuMWMwLjEtMC4xLDAuMS0wLjEsMC4yLTAuMmMwLjEtMC4xLDAuMi0wLjIsMC4zLTAuM2MwLTAuMSwwLjEtMC4yLDAuMS0wLjJjMC40LTEsMC41LTIuMSwwLjItMy4yYy0wLjEtMC4zLTAuMi0wLjYtMC40LTAuOGMtMC4yLTAuMi0wLjQtMC4zLTAuNi0wLjVDMTAuMiw4LjgsMTAsOC44LDkuNyw4LjhDOS44LDguOCw5LjgsOC44LDkuNyw4LjhMOS43LDguOEw5LjcsOC44eiBNMTQuNyw4LjJjMC40LDAsMC44LDAsMS4xLDBjMC4xLDAuMSwwLjEsMC4zLDAsMC40YzAsMS43LDAsMy42LDAsNS40YzAsMC4xLDAsMC4zLDAsMC40YzAsMC4xLDAsMC4yLDAsMC40Yy0wLjIsMC0wLjQsMC0wLjYsMGMtMC4yLDAtMC40LDAtMC42LDBDMTQuNiwxMi42LDE0LjYsMTAuNCwxNC43LDguMkMxNC42LDguMiwxNC43LDguMiwxNC43LDguMkwxNC43LDguMnogTTE3LjUsOC4yaDEuMWMwLjEsMC4yLDAuMSwwLjQsMC4yLDAuNWMwLjMsMS4zLDAuNywyLjYsMSwzLjljMC4xLDAsMC0wLjEsMC4xLTAuMXMwLTAuMSwwLTAuMWMwLTAuMSwwLjEtMC4yLDAuMS0wLjNjMC4xLTAuMiwwLjEtMC40LDAuMi0wLjVjMC4xLTAuNCwwLjItMC43LDAuMy0xLjFzMC4yLTAuNywwLjMtMS4xYzAuMi0wLjMsMC4yLTAuOCwwLjQtMS4xaDAuNWMwLjIsMC4zLDAuMiwwLjgsMC40LDEuMWMwLjEsMC40LDAuMiwwLjcsMC4zLDEuMWMwLjIsMC43LDAuNSwxLjUsMC43LDIuMmMwLjEtMC4yLDAuMS0wLjQsMC4yLTAuNWMwLTAuMiwwLjEtMC40LDAuMS0wLjVjMC4yLTAuOCwwLjQtMS41LDAuNi0yLjJjMC4xLTAuNCwwLjItMC43LDAuMy0xLjFjMC4zLDAsMC42LDAsMSwwYzAsMC4zLTAuMSwwLjYtMC4yLDAuOGMwLDAuMy0wLjIsMC41LTAuMiwwLjhjLTAuMiwwLjUtMC4zLDEuMS0wLjUsMS42Yy0wLjEsMC42LTAuMywxLjEtMC40LDEuN2MtMC4xLDAuMy0wLjIsMC42LTAuMiwwLjhjLTAuMSwwLjMtMC4xLDAuNS0wLjMsMC44aC0wLjdjLTAuMi0wLjMtMC4yLTAuNy0wLjQtMWMtMC4zLTEtMC43LTIuMS0xLTMuMWMtMC4xLDAuMi0wLjEsMC4zLTAuMiwwLjVjMCwwLjItMC4xLDAuNC0wLjIsMC41Yy0wLjEsMC40LTAuMiwwLjctMC4zLDFjLTAuMSwwLjMtMC4yLDAuNy0wLjMsMWMtMC4xLDAuMy0wLjIsMC43LTAuNCwxYy0wLjIsMC0wLjQsMC0wLjcsMEMxOS4xLDE0LjUsMTksMTQuMywxOSwxNGMtMC4xLTAuMy0wLjEtMC42LTAuMi0wLjhjLTAuMS0wLjYtMC4zLTEuMS0wLjQtMS43Yy0wLjItMC41LTAuMy0xLjEtMC41LTEuNmMtMC4xLTAuMy0wLjItMC41LTAuMi0wLjhDMTcuNSw4LjgsMTcuNCw4LjUsMTcuNSw4LjJDMTcuNSw4LjIsMTcuNSw4LjIsMTcuNSw4LjJMMTcuNSw4LjJ6IE0yNi44LDguMmMwLjQsMCwwLjgsMCwxLjEsMEMyOCw4LjUsMjgsOC43LDI4LDl2NWMwLDAuMywwLDAuNSwwLDAuOGMtMC4zLDAtMC42LDAtMC45LDBjLTAuMSwwLTAuMiwwLTAuMywwYy0wLjEtMC4zLTAuMS0wLjUsMC0wLjhWOUMyNi42LDguNywyNi43LDguNSwyNi44LDguMkMyNi43LDguMiwyNi44LDguMiwyNi44LDguMnoiLz48L3N2Zz4=)}.bg-safetypay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfMTBfIiBjbGFzcz0ic3QyOSIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTgsNGwtNyw3bDcsN2w3LTdMMTgsNHogTTE2LjYsMTUuM2wtMi4xLTIuMWwyLjEtMi4xbC0yLjEtMi4xbDIuMS0yLjFMMTguOCw5bDIuMSwyLjFMMTYuNiwxNS4zeiBNMjIuOSwxMS44bC0zLjUsMy41bC0wLjgtMC44bDMuNS0zLjVsLTMuNS0zLjVsMC44LTAuOGw0LjMsNC4zTDIyLjksMTEuOEwyMi45LDExLjhMMjIuOSwxMS44eiIvPjwvc3ZnPg==)}.bg-sepa{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHlfMl8zXyIgY2xhc3M9InN0MjUiIGQ9Ik0zLDBoMzBjMS43LDAsMywxLjMsMywzdjE2YzAsMS43LTEuMywzLTMsM0gzYy0xLjcsMC0zLTEuMy0zLTNWM0MwLDEuMywxLjMsMCwzLDB6Ii8+PGc+PHBhdGggY2xhc3M9InN0MCIgZD0iTTExLjIsOS44SDkuNWMwLTAuMiwwLTAuNC0wLjEtMC42QzkuMyw5LjEsOSw5LDguNiw5QzguMyw5LDgsOSw3LjcsOS4xQzcuNSw5LjMsNy40LDkuNSw3LjUsOS43YzAsMC4yLDAsMC40LDAuMiwwLjVjMC4xLDAuMSwwLjIsMC4xLDAuNCwwLjFsMC4zLDBjMC43LDAsMS4yLDAuMSwxLjQsMC4xYzAuNSwwLDAuOSwwLjIsMS4zLDAuNWMwLjIsMC4yLDAuMywwLjUsMC40LDAuOGMwLDAuMiwwLDAuNCwwLDAuNmMwLDAuNCwwLDAuOC0wLjIsMS4yYy0wLjIsMC41LTAuNiwwLjgtMS4zLDAuOWMtMC40LDAuMS0wLjgsMC4xLTEuMywwLjFjLTAuNywwLTEuMywwLTItMC4yYy0wLjQtMC4xLTAuOC0wLjQtMC45LTAuOGMtMC4xLTAuNC0wLjEtMC44LTAuMS0xLjJoMS43YzAsMC4xLDAsMC4xLDAsMC4xYzAsMC4yLDAuMSwwLjQsMC4yLDAuNkM3LjgsMTMsNy45LDEzLDgsMTNoMC42YzAuMiwwLDAuNCwwLDAuNi0wLjFjMC4xLDAsMC4zLTAuMiwwLjMtMC4zYzAtMC4xLDAtMC4yLDAtMC4zYzAtMC4yLTAuMS0wLjUtMC4zLTAuNWMtMC40LTAuMS0wLjctMC4xLTEuMS0wLjFjLTAuNSwwLTAuOS0wLjEtMS4xLTAuMWMtMC40LDAtMC44LTAuMy0xLjEtMC42Yy0wLjItMC40LTAuMy0wLjgtMC4yLTEuMmMwLTAuMywwLTAuNywwLjEtMWMwLjEtMC4yLDAuMi0wLjQsMC40LTAuNkM2LjYsNy45LDcsNy43LDcuMyw3LjdjMC40LDAsMC44LDAsMS4yLDBjMC41LDAsMSwwLDEuNSwwLjFjMC43LDAuMiwxLjEsMC43LDEuMSwxLjdDMTEuMiw5LjUsMTEuMiw5LjYsMTEuMiw5Ljh6IE0xOC42LDE0LjRWNy42aDMuNGMwLjQsMCwwLjcsMCwxLjEsMC4xYzAuNSwwLjEsMC45LDAuNSwxLjEsMS4xYzAuMSwwLjQsMC4yLDAuOCwwLjEsMS4zYzAsMC41LDAsMS0wLjIsMS41Yy0wLjIsMC42LTAuNywxLTEuMywxYy0wLjEsMC0wLjQsMC0xLDBsLTAuMywwaC0xLjF2MS43SDE4LjZ6IE0yMC40LDExLjFoMS4xYzAuMiwwLDAuNCwwLDAuNy0wLjFjMC4xLTAuMSwwLjItMC4yLDAuMi0wLjRjMC0wLjIsMC0wLjQsMC0wLjVjMC0wLjIsMC0wLjQtMC4xLTAuNmMtMC4xLTAuMi0wLjMtMC4zLTAuNS0wLjRjLTAuMSwwLTAuMiwwLTAuNCwwaC0xLjFMMjAuNCwxMS4xTDIwLjQsMTEuMXogTTI4LjEsMTMuMmgtMi40bC0wLjMsMS4yaC0xLjlsMi02LjdoMi43bDIsNi43aC0xLjhMMjguMSwxMy4yeiBNMjcuOCwxMS45TDI2LjksOWwtMC44LDIuOUgyNy44eiIvPjxwYXRoIGNsYXNzPSJzdDM2IiBkPSJNMTQsOS44aDMuN2wwLDBsLTAuNCwxbDAsMGgtMy42bDAsMGMwLDAuMSwwLDAuMiwwLDAuMmMwLDAuMSwwLDAuMiwwLDAuNGwwLDBIMTdsMCwwbC0wLjUsMWwwLDBIMTRsMCwwYzAuNywxLjEsMi4yLDEuNCwzLjMsMC43YzAuMi0wLjEsMC40LTAuMywwLjUtMC40bC0wLjEsMHYxLjJsMCwwYy0xLjYsMS0zLjcsMC42LTQuNy0wLjljLTAuMS0wLjItMC4yLTAuMy0wLjMtMC41bDAsMGgtMS4ybDAsMGwwLjQtMWwwLDBoMC41bDAsMGMwLTAuMSwwLTAuMiwwLTAuM2MwLTAuMSwwLTAuMiwwLTAuM2wwLDBoLTFsMCwwbDAuNS0xbDAsMGgwLjhsMCwwYzAuMi0wLjYsMC43LTEuMSwxLjItMS41YzEuMy0wLjksMy4xLTAuNyw0LjIsMC4zbDAsMGwtMC40LDAuOGwwLDBjLTAuOC0xLTIuNC0xLjItMy40LTAuNEMxNC4zLDkuMywxNC4xLDkuNSwxNCw5LjhMMTQsOS44TDE0LDkuOEwxNCw5Ljh6Ii8+PC9nPjwvc3ZnPg==)}.bg-sofort{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHlfMV8iIGNsYXNzPSJzdDMwIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMC43LDVjLTEuMS0wLjEtMi4yLDAuMS0zLjMsMC41Yy0xLjMsMC43LTIuMiwxLjktMi42LDMuNGMtMC4xLDAuMy0wLjIsMC43LTAuMiwxLjFjMCwwLjMsMCwwLjYsMC4yLDAuOGMwLjIsMC4zLDAuNCwwLjYsMC43LDAuOGMwLjMsMC4yLDAuNywwLjQsMS4xLDAuNWwwLjUsMC4xYzAuMywwLjEsMC42LDAuMiwwLjcsMC4yYzAuMSwwLDAuMiwwLjEsMC4zLDAuMWMwLjEsMC4xLDAuMiwwLjEsMC4zLDAuM2MwLDAuMSwwLjEsMC4yLDAuMSwwLjJjMCwwLjEsMCwwLjItMC4xLDAuM2MtMC4xLDAuMi0wLjMsMC40LTAuNSwwLjVjLTAuNCwwLjEtMC44LDAuMi0xLjMsMC4xSDkuMkw4LDE3aDhjMS4yLDAsMi40LTAuMSwzLjUtMC41YzEuNi0wLjYsMi44LTIsMy4xLTMuN2MwLjItMC43LDAuMS0xLjQtMC4yLTJjLTAuNC0wLjYtMS4xLTEtMS44LTEuMWwtMC40LTAuMWwtMC42LTAuMmMtMC4yLDAtMC40LTAuMi0wLjUtMC4zQzE5LDguOSwxOC45LDguNywxOSw4LjVjMC4xLTAuMiwwLjItMC40LDAuNC0wLjVjMC4zLTAuMSwwLjUtMC4yLDAuOC0wLjJoNC43YzAsMCwwLjEtMC4xLDAuMS0wLjFjMC44LTEuMSwxLjgtMiwzLTIuN0gyMC43TDIwLjcsNXoiLz48L3N2Zz4=)}.bg-tenpay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfOF8iIGNsYXNzPSJzdDMyIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGlkPSJUZW5wYXktMl8xXyIgY2xhc3M9InN0MCIgZD0iTTcuNCwxMy42aDFWOS45aDEuNFY5SDZ2MC45aDEuNFYxMy42eiBNMTAuNiwxMi42YzAuMSwwLjIsMC4yLDAuNCwwLjQsMC42YzAuMiwwLjIsMC40LDAuMywwLjYsMC40YzAuMiwwLjEsMC41LDAuMSwwLjgsMC4xYzAuMiwwLDAuNSwwLDAuNy0wLjFjMC4yLTAuMSwwLjUtMC4yLDAuNy0wLjNsLTAuMy0wLjZjLTAuMSwwLjEtMC4zLDAuMS0wLjQsMC4yYy0wLjEsMC0wLjMsMC4xLTAuNSwwLjFjLTAuMiwwLTAuNS0wLjEtMC43LTAuMmMtMC4yLTAuMS0wLjMtMC4zLTAuNC0wLjZoMi40YzAtMC4xLDAtMC4xLDAtMC4yYzAtMC4xLDAtMC4yLDAtMC4zYzAtMC4yLDAtMC41LTAuMS0wLjdjLTAuMS0wLjItMC4yLTAuNC0wLjMtMC41Yy0wLjEtMC4yLTAuMy0wLjMtMC41LTAuNGMtMC41LTAuMi0wLjktMC4yLTEuNCwwYy0wLjIsMC4xLTAuNCwwLjItMC42LDAuNGMtMC4yLDAuMi0wLjMsMC40LTAuNCwwLjZjLTAuMSwwLjItMC4yLDAuNS0wLjIsMC44QzEwLjQsMTIuMSwxMC41LDEyLjQsMTAuNiwxMi42TDEwLjYsMTIuNnogTTExLjUsMTEuNWMwLTAuMiwwLjEtMC40LDAuMy0wLjVjMC4xLTAuMSwwLjMtMC4yLDAuNS0wLjJjMC4yLDAsMC40LDAuMSwwLjUsMC4yYzAuMSwwLjEsMC4yLDAuMywwLjIsMC41TDExLjUsMTEuNUwxMS41LDExLjV6IE0xNC44LDEzLjZoMXYtMi4zYzAuMS0wLjEsMC4yLTAuMiwwLjMtMC4zYzAuMS0wLjEsMC4yLTAuMSwwLjQtMC4xYzAuMiwwLDAuMywwLDAuNCwwLjJjMC4xLDAuMiwwLjEsMC4zLDAuMSwwLjV2Mmgxdi0yLjJjMC0wLjQtMC4xLTAuNy0wLjMtMUMxNy43LDEwLjEsMTcuMywxMCwxNywxMGMtMC4yLDAtMC41LDAuMS0wLjcsMC4yYy0wLjIsMC4xLTAuNCwwLjItMC41LDAuNGgwbC0wLjEtMC41aC0wLjlMMTQuOCwxMy42TDE0LjgsMTMuNnogTTIwLjEsMTMuM2MwLjIsMC4yLDAuNSwwLjQsMC45LDAuNGMwLjIsMCwwLjQsMCwwLjYtMC4xYzAuMi0wLjEsMC40LTAuMiwwLjUtMC40YzAuMS0wLjIsMC4zLTAuNCwwLjMtMC42YzAuMS0wLjMsMC4xLTAuNSwwLjEtMC44YzAtMC4yLDAtMC41LTAuMS0wLjdjLTAuMS0wLjItMC4yLTAuNC0wLjMtMC42Yy0wLjEtMC4yLTAuMy0wLjMtMC40LTAuNGMtMC4yLTAuMS0wLjQtMC4xLTAuNi0wLjFjLTAuMiwwLTAuNCwwLTAuNiwwLjFjLTAuMiwwLjEtMC4zLDAuMi0wLjUsMC4zaDBsLTAuMS0wLjRoLTAuOXY0LjhoMXYtMUwyMC4xLDEzLjN6IE0yMC4xLDExLjJjMC4yLTAuMiwwLjQtMC4zLDAuNy0wLjNjMC40LDAsMC42LDAuMywwLjYsMC45YzAsMC4zLDAsMC42LTAuMiwwLjhjLTAuMSwwLjItMC4zLDAuMi0wLjUsMC4yYy0wLjIsMC0wLjQtMC4xLTAuNi0wLjJMMjAuMSwxMS4yTDIwLjEsMTEuMnogTTIzLjMsMTMuMWMwLjEsMC4xLDAuMSwwLjIsMC4yLDAuM2MwLjEsMC4xLDAuMiwwLjIsMC40LDAuMmMwLjIsMC4xLDAuMywwLjEsMC41LDAuMWMwLjIsMCwwLjUsMCwwLjctMC4xYzAuMi0wLjEsMC40LTAuMiwwLjYtMC4zaDBsMC4xLDAuNGgwLjl2LTJjMC0wLjQtMC4xLTAuOS0wLjQtMS4yQzI1LjksMTAuMSwyNS41LDEwLDI1LDEwYy0wLjMsMC0wLjYsMC0wLjksMC4xYy0wLjMsMC4xLTAuNSwwLjItMC44LDAuM2wwLjQsMC43YzAuMi0wLjEsMC40LTAuMiwwLjYtMC4yYzAuMi0wLjEsMC4zLTAuMSwwLjUtMC4xYzAuMiwwLDAuNCwwLDAuNSwwLjFjMC4xLDAuMSwwLjIsMC4yLDAuMiwwLjRjLTAuNCwwLTAuNywwLjEtMS4xLDAuMWMtMC4zLDAtMC41LDAuMS0wLjcsMC4zYy0wLjIsMC4xLTAuMywwLjItMC40LDAuNGMtMC4xLDAuMi0wLjEsMC4zLTAuMSwwLjVDMjMuMywxMi44LDIzLjMsMTIuOSwyMy4zLDEzLjFMMjMuMywxMy4xeiBNMjQuMywxMi40YzAuMS0wLjEsMC4xLTAuMSwwLjItMC4yYzAuMS0wLjEsMC4zLTAuMSwwLjQtMC4xYzAuMiwwLDAuNC0wLjEsMC42LTAuMXYwLjZjLTAuMSwwLjEtMC4zLDAuMi0wLjQsMC4yYy0wLjEsMC4xLTAuMywwLjEtMC40LDAuMWMtMC4xLDAtMC4yLDAtMC40LTAuMWMtMC4xLTAuMS0wLjEtMC4xLTAuMS0wLjNDMjQuMywxMi41LDI0LjMsMTIuNCwyNC4zLDEyLjRMMjQuMywxMi40eiBNMjcuNywxNC4xbC0wLjIsMC44YzAuMSwwLDAuMiwwLDAuMiwwLjFjMC4xLDAsMC4yLDAsMC4zLDBjMC4yLDAsMC40LDAsMC42LTAuMWMwLjItMC4xLDAuMy0wLjEsMC40LTAuM2MwLjEtMC4xLDAuMy0wLjMsMC4zLTAuNGMwLjEtMC4yLDAuMi0wLjQsMC4zLTAuNmwxLjQtMy42aC0xbC0wLjUsMS41Yy0wLjEsMC4yLTAuMSwwLjQtMC4yLDAuNWMtMC4xLDAuMi0wLjEsMC40LTAuMiwwLjVoMGMtMC4xLTAuMi0wLjEtMC40LTAuMi0wLjVDMjksMTIsMjksMTEuOCwyOC45LDExLjZsLTAuNi0xLjVoLTFsMS41LDMuNGwtMC4xLDAuMmMtMC4xLDAuMS0wLjEsMC4yLTAuMywwLjNjLTAuMSwwLjEtMC4zLDAuMS0wLjUsMC4xQzI3LjksMTQuMiwyNy44LDE0LjIsMjcuNywxNC4xTDI3LjcsMTQuMUwyNy43LDE0LjF6Ii8+PC9zdmc+)}.bg-trustpay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfNV8iIGNsYXNzPSJzdDIxIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnIGlkPSJ0cnVzdHBheSI+PHBhdGggaWQ9IlhNTElEXzY4NV8iIGQ9Ik0yMC44LDEzLjRjLTAuNCwwLTAuNywwLTEuMSwwYzAuNC0xLjgsMC43LTMuNiwxLjEtNS40YzAuOSwwLDEuOCwwLDIuNywwYzAuMiwwLDAuNCwwLjEsMC42LDAuMWMwLjMsMC4xLDAuNiwwLjQsMC42LDAuN2MwLjEsMC43LTAuMSwxLjMtMC41LDEuOWMtMC40LDAuNS0wLjksMC42LTEuNCwwLjZjLTAuNCwwLTAuOSwwLTEuMywwYy0wLjEsMC0wLjIsMC0wLjIsMC4xQzIxLjEsMTIuMiwyMC45LDEyLjgsMjAuOCwxMy40eiBNMjEuNCwxMC41YzAuNCwwLDAuNywwLDEuMSwwYzAuNiwwLDAuOC0wLjIsMS0wLjhjMC0wLjEsMC0wLjEsMC0wLjJjMC0wLjItMC4xLTAuNC0wLjMtMC40Yy0wLjUtMC4xLTEtMC4xLTEuNS0wLjFDMjEuNiw5LjUsMjEuNSwxMCwyMS40LDEwLjV6IE0yNy40LDEzLjRjLTAuMywwLTAuNiwwLTEsMGMwLTAuMSwwLTAuMSwwLTAuMmMtMC4yLDAuMS0wLjUsMC4yLTAuNywwLjJjLTAuMywwLTAuNywwLjEtMSwwYy0wLjUtMC4xLTAuNy0wLjUtMC42LTEuMWMwLjEtMC43LDAuNy0xLjIsMS40LTEuM2MwLjQtMC4xLDAuOC0wLjEsMS4yLTAuMmMwLjEsMCwwLjIsMCwwLjItMC4yYzAtMC4xLDAtMC4xLDAtMC4yYzAtMC4yLDAtMC40LTAuMy0wLjRjLTAuMiwwLTAuMywwLTAuNSwwYy0wLjMsMC0wLjUsMC4xLTAuNiwwLjRjLTAuMywwLTAuNiwwLTEsMGMwLTAuNCwwLjQtMC45LDAuOC0xLjFjMC41LTAuMiwxLTAuMiwxLjQtMC4yYzAuMiwwLDAuNCwwLjEsMC42LDAuMWMwLjQsMC4xLDAuNSwwLjQsMC41LDAuOUMyNy44LDExLjQsMjcuNiwxMi4zLDI3LjQsMTMuNEMyNy40LDEzLjMsMjcuNCwxMy40LDI3LjQsMTMuNHogTTI2LjcsMTEuNmMtMC40LDAuMS0wLjgsMC4xLTEuMSwwLjJjLTAuMywwLjEtMC41LDAuMy0wLjUsMC42YzAsMC4xLDAsMC4yLDAuMiwwLjNjMC40LDAuMiwxLDAsMS4yLTAuNEMyNi42LDEyLDI2LjcsMTEuOCwyNi43LDExLjZ6IE0zMCwxMi4zYzAuMy0wLjUsMC41LTEsMC44LTEuNmMwLjItMC40LDAuNC0wLjgsMC42LTEuMWMwLTAuMSwwLjEtMC4xLDAuMi0wLjFjMC4zLDAsMC42LDAsMSwwYy0wLjEsMC4yLTAuMiwwLjQtMC4zLDAuNmMtMC43LDEuMy0xLjUsMi42LTIuMiwzLjljMCwwLDAsMCwwLDAuMUMyOS40LDE0LjksMjksMTUsMjgsMTVjMCwwLDAsMC0wLjEsMGMwLjEtMC4zLDAuMS0wLjUsMC4yLTAuOGMwLjEsMCwwLjMsMCwwLjQsMGMwLjMsMCwwLjYtMC4zLDAuNy0wLjZjMCwwLDAtMC4xLDAtMC4xYy0wLjMtMS4xLTAuNS0yLjMtMC42LTMuNGMwLTAuMiwwLTAuNCwwLTAuNmMwLjQsMCwwLjgsMCwxLjEsMEMyOS43LDEwLjQsMjkuOCwxMS4zLDMwLDEyLjNDMjkuOSwxMi4zLDMwLDEyLjMsMzAsMTIuM3oiLz48cGF0aCBpZD0iWE1MSURfNjc4XyIgY2xhc3M9InN0MCIgZD0iTTE3LDEwLjZjLTAuMywwLTAuNywwLTEsMGMwLTAuMSwwLTAuMSwwLTAuMWMwLTAuMi0wLjEtMC4zLTAuMi0wLjNjLTAuMiwwLTAuNSwwLTAuNywwYy0wLjEsMC0wLjIsMC0wLjIsMC4xYy0wLjEsMC4xLTAuMSwwLjItMC4xLDAuM2MwLDAuMSwwLjEsMC4yLDAuMiwwLjJjMC40LDAuMSwwLjcsMC4yLDEuMSwwLjNjMC4xLDAsMC4yLDAuMSwwLjMsMC4xYzAuNSwwLjIsMC43LDAuNiwwLjUsMS4yYy0wLjIsMC42LTAuNywwLjktMS4zLDFjLTAuNSwwLjEtMSwwLjEtMS41LTAuMWMtMC41LTAuMS0wLjgtMC41LTAuOC0xLjFjMC0wLjEsMC0wLjIsMC4yLTAuMmMwLjMsMCwwLjUsMCwwLjgsMGMwLjEsMCwwLjEsMCwwLjEsMC4xYzAsMC4zLDAuMSwwLjQsMC40LDAuNGMwLjIsMCwwLjQsMCwwLjcsMGMwLjEsMCwwLjIsMCwwLjItMC4xYzAuMi0wLjEsMC4yLTAuMiwwLjItMC40YzAtMC4yLTAuMS0wLjItMC4zLTAuM2MtMC40LTAuMS0wLjctMC4yLTEuMS0wLjNjLTAuMSwwLTAuMi0wLjEtMC4zLTAuMWMtMC40LTAuMi0wLjUtMC40LTAuNS0wLjhjMC4xLTAuOSwwLjYtMS4zLDEuNC0xLjRjMC40LDAsMC44LDAsMS4xLDBjMC4yLDAsMC40LDAuMSwwLjUsMC4yQzE3LDkuNywxNy4xLDEwLjIsMTcsMTAuNnogTTEzLjEsOS40Yy0wLjEsMC40LTAuMSwwLjgtMC4yLDEuMWMtMC4yLDAuOS0wLjQsMS44LTAuNSwyLjdjMCwwLjEtMC4xLDAuMS0wLjEsMC4xYy0wLjMsMC0wLjYsMC0wLjksMGMwLTAuMSwwLTAuMiwwLTAuM2MtMC4yLDAuMS0wLjQsMC4yLTAuNiwwLjNjLTAuNCwwLjEtMC45LDAuMS0xLjMsMEM5LjEsMTMuMyw5LDEzLjEsOSwxMi44YzAtMC40LDAuMS0wLjgsMC4xLTEuMmMwLjEtMC42LDAuMy0xLjMsMC40LTEuOWMwLTAuMSwwLjEtMC4yLDAuMi0wLjJjMC4zLDAsMC42LDAsMC45LDBjLTAuMSwwLjMtMC4xLDAuNi0wLjIsMC45Yy0wLjEsMC42LTAuMiwxLjEtMC4zLDEuN2MtMC4xLDAuNCwwLjEsMC42LDAuNSwwLjZjMC43LDAsMC45LTAuMywxLTAuOGMwLjEtMC43LDAuMy0xLjUsMC40LTIuMmMwLTAuMSwwLjEtMC4yLDAuMi0wLjJDMTIuNSw5LjUsMTIuOCw5LjQsMTMuMSw5LjR6IE0xMS40LDEzLjFMMTEuNCwxMy4xTDExLjQsMTMuMUwxMS40LDEzLjF6IE00LjYsMTMuNGMtMC40LDAtMC43LDAtMS4xLDBDMy44LDExLjksNCwxMC40LDQuMyw5QzMuOCw5LDMuMyw5LDIuNyw5YzAuMS0wLjMsMC4xLTAuNiwwLjItMC45QzIuOSw4LjEsMyw4LDMsOGMwLjQsMCwwLjgsMCwxLjIsMGMwLjUsMCwwLjksMCwxLjQsMGMwLjUsMCwxLDAsMS41LDBjMCwwLDAuMSwwLDAuMSwwQzcuMiw4LjMsNy4yLDguNiw3LjEsOC45QzcuMSw4LjksNyw5LDYuOSw5QzYuNSw5LDYuMSw5LDUuNiw5QzUuNSw5LDUuNSw5LDUuNCw5LjFDNS4yLDEwLjUsNC45LDExLjksNC42LDEzLjRDNC42LDEzLjMsNC42LDEzLjQsNC42LDEzLjR6IE0xOS4zLDguNWMtMC4xLDAuMy0wLjEsMC42LTAuMiwxYzAuMiwwLDAuNCwwLDAuNywwYy0wLjEsMC4zLTAuMSwwLjYtMC4yLDAuOWMtMC4yLDAtMC40LDAtMC43LDBjLTAuMSwwLjUtMC4yLDAuOS0wLjMsMS4zYzAsMC4yLTAuMSwwLjQtMC4xLDAuNmMtMC4xLDAuMywwLDAuNCwwLjMsMC40YzAuMSwwLDAuMiwwLDAuMywwYzAsMC4zLTAuMSwwLjUtMC4xLDAuN2MwLDAtMC4xLDAuMS0wLjEsMC4xYy0wLjMsMC0wLjcsMC0xLDBjLTAuMywwLTAuNS0wLjItMC40LTAuNmMwLjEtMC41LDAuMi0xLDAuMy0xLjVjMC4xLTAuNCwwLjEtMC43LDAuMi0xLjFjLTAuMiwwLTAuMywwLTAuNSwwYzAuMS0wLjMsMC4xLTAuNSwwLjItMC44YzAsMCwwLjEtMC4xLDAuMS0wLjFjMC40LDAsMC40LDAsMC41LTAuNGMwLTAuMSwwLTAuMSwwLTAuMmMwLjEtMC40LDAuMS0wLjQsMC41LTAuNEMxOC45LDguNSwxOS4xLDguNSwxOS4zLDguNXogTTcuNyw5LjRjMCwwLjEsMCwwLjMtMC4xLDAuNEM4LDkuNCw4LjUsOS4zLDksOS40QzksOS43LDguOSwxMCw4LjksMTAuNGMtMC4yLDAtMC40LDAtMC42LDBjLTAuNCwwLjEtMC42LDAuMy0wLjcsMC43Yy0wLjEsMC41LTAuMiwwLjktMC40LDEuNGMtMC4xLDAuMy0wLjEsMC41LTAuMiwwLjhjMCwwLTAuMSwwLjEtMC4xLDAuMWMtMC4zLDAtMC42LDAtMSwwYzAuMS0wLjUsMC4yLTEsMC4zLTEuNWMwLjItMC44LDAuMy0xLjUsMC41LTIuM2MwLTAuMSwwLjEtMC4yLDAuMi0wLjJDNy4yLDkuNSw3LjUsOS40LDcuNyw5LjR6Ii8+PC9nPjwvc3ZnPg==)}.bg-unionpay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzUyXzNfIiBjbGFzcz0ic3QxNCIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48Zz48Zz48cGF0aCBjbGFzcz0ic3QxNiIgZD0iTTI0LjksMTZoLTAuM2wxLTMuNkgyNmwwLjEtMC40djAuNGMwLDAuMiwwLjIsMC41LDAuNywwLjRoMC42bDAuMi0wLjdoLTAuMmMtMC4xLDAtMC4yLDAtMC4yLTAuMXYtMC40aC0xLjFsMCwwYy0wLjMsMC0xLjQsMC0xLjYsMC4xQzI0LjMsMTEuOSwyNCwxMiwyNCwxMmwwLjEtMC40aC0xbC0wLjIsMC43bC0xLDMuNmgtMC4ybC0wLjIsMC43aDJsLTAuMSwwLjJoMWwwLjEtMC4yaDAuM0wyNC45LDE2eiBNMjMuNywxNmgtMC44bDAuMi0wLjhoMC44TDIzLjcsMTZ6IE0yNC4xLDE0LjVjMCwwLTAuMiwwLTAuNCwwLjFjLTAuMiwwLjEtMC41LDAuMi0wLjUsMC4ybDAuMy0wLjloMC44TDI0LjEsMTQuNXogTTI0LjEsMTMuMmMtMC4yLDAuMS0wLjUsMC4yLTAuNSwwLjJsMC4zLTAuOWgwLjhsLTAuMiwwLjdDMjQuNSwxMy4xLDI0LjMsMTMuMSwyNC4xLDEzLjJ6IE0yNS42LDEzLjhoMS4ybC0wLjIsMC42aC0xLjJMMjUuMiwxNWgxbC0wLjgsMS4xYy0wLjEsMC4xLTAuMSwwLjEtMC4yLDAuMWMtMC4xLDAtMC4xLDAuMS0wLjIsMC4xaC0wLjNMMjQuNiwxN2gwLjhjMC40LDAsMC42LTAuMiwwLjgtMC40bDAuNS0wLjhsMC4xLDAuOGMwLDAuMSwwLjEsMC4yLDAuMiwwLjNjMC4xLDAsMC4yLDAuMSwwLjMsMC4xczAuMiwwLDAuMywwaDAuNGwwLjItMC44SDI4Yy0wLjEsMC0wLjIsMC0wLjItMC4xczAtMC4xLDAtMC4ybC0wLjEtMC44aC0wLjVsMC4yLTAuM2gxLjJsMC4yLTAuNmgtMS4xbDAuMi0wLjZoMS4xbDAuMi0wLjdoLTMuMkwyNS42LDEzLjh6IE0xNS44LDE2LjJsMC4zLTAuOWgxLjFsMC4yLTAuN2gtMS4xbDAuMi0wLjZoMS4xbDAuMi0wLjdIMTVMMTQuOCwxNGgwLjZsLTAuMiwwLjZoLTAuNmwtMC4yLDAuN0gxNWwtMC4zLDEuMmMtMC4xLDAuMiwwLDAuMiwwLjEsMC4zYzAuMSwwLjEsMC4xLDAuMSwwLjIsMC4yYzAuMSwwLDAuMiwwLjEsMC4zLDAuMWgxLjNsMC4yLTAuOGwtMC42LDAuMUMxNi4xLDE2LjMsMTUuOCwxNi4zLDE1LjgsMTYuMnogTTE1LjksMTEuN2wtMC4zLDAuNWMtMC4xLDAuMS0wLjEsMC4yLTAuMiwwLjJjLTAuMSwwLTAuMSwwLTAuMiwwaC0wLjFsLTAuMiwwLjdoMC41YzAuMiwwLDAuNC0wLjEsMC41LTAuMWMwLjEtMC4xLDAuMSwwLDAuMi0wLjFsMC4yLTAuMmgxLjVsMC4yLTAuN2gtMS4xbDAuMi0wLjRIMTUuOXogTTE4LjIsMTYuMmMwLDAsMC0wLjEsMC0wLjJsMC40LTEuNGgxLjVjMC4yLDAsMC40LDAsMC41LDBjMC4xLDAsMC4yLTAuMSwwLjMtMC4xYzAuMS0wLjEsMC4yLTAuMiwwLjMtMC4yYzAuMS0wLjEsMC4yLTAuMywwLjMtMC42bDAuNS0xLjhoLTEuNmMwLDAtMC41LDAuMS0wLjcsMC4ycy0wLjUsMC4zLTAuNSwwLjNsMC4xLTAuNWgtMWwtMS4zLDQuNkMxNywxNi41LDE3LDE2LjYsMTcsMTYuN3MwLjEsMC4yLDAuMiwwLjJjMC4xLDAuMSwwLjIsMC4xLDAuMywwLjFjMC4xLDAsMC4zLDAsMC41LDBoMC43bDAuMi0wLjhsLTAuNiwwQzE4LjMsMTYuMiwxOC4yLDE2LjIsMTguMiwxNi4yeiBNMTkuMiwxMi41aDEuNmwtMC4xLDAuNGMwLDAtMC44LDAtMC45LDBDMTkuMywxMywxOSwxMy4yLDE5LDEzLjJMMTkuMiwxMi41eiBNMTguOSwxMy41aDEuNmwtMC4xLDAuM2MwLDAtMC4xLDAtMC4yLDBoLTEuM0wxOC45LDEzLjV6IE0yMC40LDE0LjljMCwwLjEsMCwwLjEtMC4xLDAuMWMwLDAtMC4xLDAtMC4yLDBIMjB2LTAuNGgtMC45bDAsMS45YzAsMC4xLDAsMC4yLDAuMSwwLjNjMC4xLDAuMSwwLjQsMC4xLDAuOCwwLjFoMC42bDAuMi0wLjdsLTAuNSwwaC0wLjJjMCwwLTAuMSwwLTAuMS0wLjFjMCwwLTAuMSwwLTAuMS0wLjF2LTAuNWwwLjUsMGMwLjMsMCwwLjQtMC4xLDAuNS0wLjJzMC4xLTAuMiwwLjItMC4zbDAuMS0wLjRoLTAuN0wyMC40LDE0Ljl6IE05LjIsNS4xYy0wLjksMC0xLjEsMC0xLjIsMGMwLDAuMi0wLjYsMy0wLjYsM0M3LjMsOC42LDcuMiw5LDYuOSw5LjNDNi43LDkuNCw2LjUsOS41LDYuMiw5LjVjLTAuNCwwLTAuNi0wLjItMC42LTAuNlY4LjhMNS43LDhjMCwwLDAuNi0yLjYsMC43LTIuOWMwLDAsMCwwLDAsMEM1LjIsNSw1LDUsNSw1YzAsMCwwLDAuMiwwLDAuMkw0LjMsOC4xTDQuMiw4LjNMNC4xLDkuMWMwLDAuMiwwLjEsMC40LDAuMSwwLjZjMC4zLDAuNSwxLjEsMC42LDEuNiwwLjZjMC42LDAsMS4yLTAuMSwxLjYtMC40YzAuNy0wLjQsMC44LTEsMS0xLjZsMC4xLTAuM0M4LjUsOC4xLDkuMSw1LjQsOS4yLDUuMUM5LjIsNS4xLDkuMiw1LjEsOS4yLDUuMXogTTExLjQsNy4yYy0wLjIsMC0wLjQsMC0wLjcsMC4yYy0wLjEsMC4xLTAuMiwwLjEtMC4zLDAuMmwwLjEtMC4zbC0wLjEtMC4xQzkuOSw3LjMsOS44LDcuNCw5LjMsNy40bC0wLjEsMEM5LjIsNy45LDkuMiw4LjMsOC45LDkuM0M4LjksOS42LDguOCwxMCw4LjcsMTAuM2wwLDAuMWMwLjUsMCwwLjcsMCwxLjEsMGwwLTAuMWMwLjEtMC4zLDAuMS0wLjQsMC4yLTFjMC4xLTAuMywwLjItMC45LDAuMi0xLjFjMC4xLTAuMSwwLjItMC4xLDAuMy0wLjFjMC4yLDAsMC4yLDAuMiwwLjIsMC4zYzAsMC4yLTAuMSwwLjYtMC4yLDFsLTAuMSwwLjNjLTAuMSwwLjItMC4xLDAuNC0wLjEsMC42bDAsMGMwLjUsMCwwLjYsMCwxLjEsMGwwLjEtMC4xYzAuMS0wLjUsMC4xLTAuNiwwLjItMS4zbDAuMS0wLjNjMC4xLTAuNiwwLjItMC45LDAuMS0xLjJDMTEuOSw3LjMsMTEuNyw3LjIsMTEuNCw3LjJ6IE0xMy45LDcuOUMxMy42LDcuOSwxMy40LDgsMTMuMiw4Yy0wLjIsMC0wLjMsMC4xLTAuNiwwLjFsMCwwbDAsMGMwLDAuMi0wLjEsMC40LTAuMSwwLjZjMCwwLjItMC4xLDAuNS0wLjIsMC44Yy0wLjEsMC4zLTAuMSwwLjMtMC4xLDAuNGMwLDAuMS0wLjEsMC4yLTAuMSwwLjRsMCwwdjBjMC4yLDAsMC40LDAsMC42LDBzMC4zLDAsMC42LDBsMCwwbDAsMGMwLTAuMiwwLjEtMC4zLDAuMS0wLjRjMC0wLjEsMC4xLTAuMywwLjItMC43YzAuMS0wLjIsMC4xLTAuNCwwLjEtMC42QzEzLjcsOC4zLDEzLjgsOC4xLDEzLjksNy45TDEzLjksNy45TDEzLjksNy45eiBNMTUuMywxMC41YzAuNSwwLDEtMC4xLDEuNC0wLjZjMC4zLTAuMywwLjQtMC44LDAuNS0xYzAuMi0wLjcsMC0xLTAuMS0xLjJjLTAuMi0wLjMtMC42LTAuNC0xLTAuNGMtMC4yLDAtMC44LDAtMS4zLDAuNWMtMC4zLDAuMy0wLjUsMC44LTAuNiwxLjJjLTAuMSwwLjQtMC4yLDEuMiwwLjUsMS40QzE0LjgsMTAuNCwxNS4xLDEwLjUsMTUuMywxMC41eiBNMTUuMyw4LjlDMTUuNCw4LjQsMTUuNSw4LDE1LjksOGMwLjMsMCwwLjMsMC4zLDAuMiwwLjhjMCwwLjEtMC4xLDAuNS0wLjIsMC43Yy0wLjEsMC4xLTAuMiwwLjItMC4zLDAuMmMwLDAtMC4yLDAtMC4yLTAuM0MxNS4yLDkuMywxNS4yLDkuMSwxNS4zLDguOXogTTI0LjksOC45Yy0wLjEsMC40LTAuMiwxLjIsMC41LDEuNGMwLjIsMC4xLDAuNCwwLjEsMC42LDAuMWMwLjIsMCwwLjQtMC4xLDAuNi0wLjNjMCwwLjEsMCwwLjEtMC4xLDAuMmwwLDBjMC41LDAsMC42LDAsMS4yLDBsMC4xLDBjMC4xLTAuNSwwLjEtMC45LDAuMy0xLjhjMC4xLTAuNCwwLjItMC44LDAuMy0xLjNsMC0wLjFjLTAuNSwwLjEtMC43LDAuMS0xLjIsMC4ybDAsMGMwLDAuMSwwLDAuMSwwLDAuMWMtMC4xLTAuMS0wLjItMC4yLTAuNC0wLjNjLTAuMi0wLjEtMC44LDAtMS4yLDAuNUMyNS4yLDguMSwyNSw4LjUsMjQuOSw4Ljl6IE0yNiw5QzI2LjIsOC40LDI2LjMsOCwyNi42LDhjMC4yLDAsMC4zLDAuMiwwLjMsMC42YzAsMC4xLDAsMC4yLTAuMSwwLjNjMCwwLjItMC4xLDAuMy0wLjEsMC41YzAsMC4xLTAuMSwwLjItMC4xLDAuM2MtMC4xLDAuMS0wLjMsMC4yLTAuNCwwLjJjMCwwLTAuMiwwLTAuMi0wLjNDMjYsOS4zLDI2LDkuMSwyNiw5eiBNMTguNCwxMC40TDE4LjQsMTAuNGMwLjEtMC4zLDAuMS0wLjQsMC4yLTFjMC4xLTAuMywwLjItMC45LDAuMi0xLjFjMC4xLTAuMSwwLjItMC4xLDAuMy0wLjFjMC4yLDAsMC4yLDAuMiwwLjIsMC4zYzAsMC4yLTAuMSwwLjYtMC4yLDFsLTAuMSwwLjNjLTAuMSwwLjItMC4xLDAuNC0wLjEsMC42bDAsMGMwLjUsMCwwLjYsMCwxLjEsMGwwLjEtMC4xYzAuMS0wLjUsMC4xLTAuNiwwLjItMS4zbDAuMS0wLjNjMC4xLTAuNiwwLjItMC45LDAuMS0xLjJjLTAuMS0wLjMtMC40LTAuMy0wLjYtMC4zYy0wLjIsMC0wLjQsMC0wLjcsMC4yYy0wLjEsMC4xLTAuMiwwLjEtMC4zLDAuMmwwLjEtMC4zTDE5LDcuMmMtMC41LDAuMS0wLjcsMC4xLTEuMiwwLjJsMCwwYy0wLjEsMC41LTAuMSwwLjktMC4zLDEuOGMtMC4xLDAuMy0wLjIsMC43LTAuMiwxLjFsMCwwLjFDMTcuOCwxMC40LDE4LDEwLjQsMTguNCwxMC40eiBNMjIuMSwxMC40YzAtMC4yLDAuMi0xLjEsMC4yLTEuMXMwLjItMC43LDAuMi0wLjdjMCwwLDAuMS0wLjEsMC4xLTAuMWgwLjFjMC43LDAsMS41LDAsMi4xLTAuNWMwLjQtMC4zLDAuNy0wLjgsMC44LTEuNGMwLTAuMSwwLjEtMC4zLDAuMS0wLjVjMC0wLjItMC4xLTAuNC0wLjItMC42Yy0wLjMtMC41LTAuOS0wLjUtMS43LTAuNWgtMC4zYy0wLjksMC0xLjMsMC0xLjQsMGMwLDAuMSwwLDAuMiwwLDAuMmwtMC4zLDEuNmMwLDAtMC44LDMuNC0wLjgsMy41QzIxLjYsMTAuNCwyMS45LDEwLjQsMjIuMSwxMC40eiBNMjIuNyw3LjZMMjMuMSw2VjUuOVY1LjlsMC4xLDBjMCwwLDAuNywwLjEsMC44LDAuMWMwLjMsMC4xLDAuNCwwLjQsMC4zLDAuOGMtMC4xLDAuMy0wLjMsMC42LTAuNiwwLjhjLTAuMiwwLjEtMC41LDAuMS0wLjgsMC4xaC0wLjJMMjIuNyw3LjZ6IE0zMS45LDcuM0wzMS45LDcuM2MtMC42LDAuMS0wLjcsMC4xLTEuMiwwLjFsMCwwdjBsMCwwYy0wLjQsMC45LTAuMywwLjctMC42LDEuNGMwLDAsMC0wLjEsMC0wLjFMMzAsNy4zbC0wLjEtMC4xYy0wLjYsMC4xLTAuNiwwLjEtMS4xLDAuMmwwLDBjMCwwLDAsMCwwLDAuMWwwLDBjMC4xLDAuMywwLjEsMC4zLDAuMSwwLjhjMCwwLjMsMC4xLDAuNSwwLjEsMC44YzAuMSwwLjQsMC4xLDAuNiwwLjEsMS4zYy0wLjMsMC42LTAuNCwwLjgtMC44LDEuM2wwLDBsLTAuMiwwLjRjMCwwLjEtMC4xLDAuMS0wLjEsMC4xYzAsMC0wLjEsMC0wLjIsMGgtMC4xbC0wLjIsMC43aDAuN2MwLjQsMCwwLjYtMC4yLDAuOC0wLjRsMC40LTAuOGwwLDBsMC4xLTAuMUMyOS44LDExLjEsMzEuOSw3LjMsMzEuOSw3LjN6IE0xMy45LDdjLTAuMi0wLjItMC43LTAuMS0xLDAuMWMtMC4zLDAuMi0wLjMsMC41LTAuMSwwLjZjMC4yLDAuMSwwLjcsMC4xLDAuOS0wLjFDMTQuMSw3LjUsMTQuMSw3LjIsMTMuOSw3eiIvPjwvZz48L2c+PC9zdmc+)}.bg-visa{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzUyXzJfIiBjbGFzcz0ic3QxIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwxNUg4LjlMNy40LDguN0M3LjMsOC41LDcuMSw4LjIsNi45LDguMUM2LjMsNy44LDUuNyw3LjUsNSw3LjRWNy4yaDMuM2MwLjQsMCwwLjgsMC4zLDAuOSwwLjhsMC44LDQuNWwyLjEtNS4zaDJMMTEsMTV6IE0xNS4zLDE1aC0ybDEuNi03LjhoMkwxNS4zLDE1eiBNMTkuNCw5LjNjMC4xLTAuNCwwLjQtMC43LDAuOC0wLjdjMC43LTAuMSwxLjMsMC4xLDEuOSwwLjRsMC4zLTEuN0MyMS45LDcuMSwyMS4zLDcsMjAuNyw3Yy0xLjksMC0zLjMsMS4xLTMuMywyLjZjMC4xLDEsMC44LDEuOCwxLjcsMi4xYzAuOCwwLjQsMSwwLjYsMSwxYy0wLjEsMC41LTAuNiwwLjktMS4xLDAuOGMwLDAsMCwwLDAsMGMtMC43LDAtMS40LTAuMi0yLTAuNWwtMC4zLDEuN2MwLjcsMC4zLDEuNCwwLjQsMi4xLDAuNGMyLjEsMC4xLDMuNS0xLDMuNS0yLjZDMjIuMSwxMC4zLDE5LjQsMTAuMiwxOS40LDkuM0wxOS40LDkuM0wxOS40LDkuM3ogTTI5LDE1bC0xLjYtNy44aC0xLjdjLTAuNCwwLTAuNywwLjItMC44LDAuNkwyMi4xLDE1aDJsMC40LTEuMUgyN2wwLjIsMS4xTDI5LDE1TDI5LDE1eiBNMjYuMSw5LjNsMC42LDIuOUgyNUwyNi4xLDkuM3oiLz48L3N2Zz4=)}.bg-webmoney{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHkiIGNsYXNzPSJzdDIyIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGlkPSJDb21iaW5lZC1TaGFwZSIgY2xhc3M9InN0MCIgZD0iTTE4LDQuM2MxLjEsMCwyLjEsMC4yLDMsMC43YzAuMSwwLjEsMC4zLDAuMSwwLjQsMC4ybC0wLjYsMC42bC0wLjktMWwtMS42LDEuNGwtMS0xbC0zLDIuNmwxLjksMi4xbC0wLjcsMC42bDEuOSwyLjFsLTAuNywwLjZsMi43LDIuOWwxLjYtMS40bDEuNCwxLjVjLTAuMywwLjItMC42LDAuNC0wLjksMC42Yy0xLDAuNi0yLjEsMC45LTMuNCwwLjljLTMuOCwwLTYuOC0zLTYuOC02LjdDMTEuMSw3LjMsMTQuMiw0LjMsMTgsNC4zeiBNMTYuNywxMC42bDEuNi0xLjRsMS41LDEuNmwtMS42LDEuNEwxNi43LDEwLjZMMTYuNywxMC42eiBNMTcuOSwxMy40bDEuNi0xLjVsMS41LDEuNkwxOS4zLDE1TDE3LjksMTMuNEwxNy45LDEzLjR6IE0xNS42LDcuOGwxLjYtMS40TDE4LjYsOEwxNyw5LjRMMTUuNiw3Ljh6IE0xOC41LDcuMUwxOS44LDZsMS4xLDEuMmwtMS4yLDEuMUwxOC41LDcuMXogTTIwLjcsMTJsMS4yLTEuMWwxLjEsMS4ybC0xLjIsMS4xTDIwLjcsMTJ6IE0yMS44LDE0LjVsMS4yLTEuMWwxLjEsMS4ybC0xLjIsMS4xTDIxLjgsMTQuNUwyMS44LDE0LjV6IE0yMi4zLDguOWwwLjgtMC43TDIzLjgsOUwyMyw5LjdMMjIuMyw4Ljl6IE0yMS4yLDYuNUwyMiw1LjhsMC43LDAuOEwyMiw3LjNMMjEuMiw2LjV6IE0yMy4zLDExLjNsMC44LTAuN2wwLjcsMC44TDI0LDEyLjFMMjMuMywxMS4zTDIzLjMsMTEuM3ogTTE5LjcsOS41bDEuMi0xLjFMMjIsOS42bC0xLjIsMS4xTDE5LjcsOS41eiIvPjwvc3ZnPg==)}.bg-yandex{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfNl8iIGNsYXNzPSJzdDI0IiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnPjxwYXRoIGlkPSJzdmdfMyIgY2xhc3M9InN0MCIgZD0iTTEwLjMsNi40YzAuMSwwLDAuMywwLDAuNCwwYzAuMiwwLDAuNCwwLDAuNSwwYzAsMC4xLDAsMC4xLDAsMC4yYy0wLjcsMS45LTEuNCwzLjgtMi4xLDUuN2MwLDAuMSwwLDAuMSwwLDAuMmMwLDEsMCwxLjksMCwyLjljLTAuMSwwLTAuMiwwLTAuMiwwYy0wLjIsMC0wLjQsMC0wLjYsMGMwLTEsMC0yLjEsMC0zLjFDNy42LDEwLjgsNyw5LjIsNi40LDcuNmMwLTAuMS0wLjEtMC4zLTAuMS0wLjRjMC4yLDAsMC41LDAsMC43LDBjMC4xLDAsMC4yLDAsMC4yLDAuMWMwLjMsMSwwLjcsMiwxLDNjMC4xLDAuNCwwLjMsMC44LDAuNCwxLjJjMC4xLTAuNSwwLjMtMS4xLDAuNS0xLjZDOS41LDguNyw5LjksNy41LDEwLjMsNi40eiIvPjxwYXRoIGlkPSJYTUxJRF8xMzYwXyIgY2xhc3M9InN0MzUiIGQ9Ik0xNy43LDExYzAsMS41LDAsMywwLDQuNWMwLDAtMC4xLDAtMC4xLDAuMWMtMC4zLDAtMC41LDAtMC44LDBjMC0xLjUsMC0yLjksMC00LjRjLTAuMS0wLjItMC4yLTAuNC0wLjQtMC40Yy0wLjMtMC4xLTAuNywwLTEsMC4yYzAsMS40LDAsMi44LDAsNC4yYzAsMC4yLDAsMC4zLDAsMC41Yy0wLjMsMC0wLjUsMC0wLjgsMGMwLDAtMC4xLDAtMC4xLTAuMWMwLTEuOCwwLTMuNiwwLTUuNGMwLjEsMCwwLjEsMCwwLjIsMGMwLjIsMCwwLjUsMCwwLjcsMGMwLDAuMSwwLDAuMiwwLDAuM2MwLjEtMC4xLDAuMi0wLjEsMC4zLTAuMmMwLDAsMC4xLDAsMC4xLDBsMCwwYzAuNC0wLjIsMC45LTAuMiwxLjMtMC4xQzE3LjUsMTAuMSwxNy44LDEwLjYsMTcuNywxMXogTTEzLjYsMTUuNGMwLDAuMS0wLjEsMC4xLTAuMSwwLjFjLTAuMSwwLTAuMywwLTAuNCwwYzAtMC4xLTAuMS0wLjEtMC4xLTAuMmMwLTAuMS0wLjEtMC4yLTAuMS0wLjJjLTAuMiwwLjMtMC41LDAuNS0wLjksMC41Yy0wLjMsMC4xLTAuNy0wLjEtMC45LTAuM2MtMC4yLTAuMi0wLjQtMC41LTAuNS0wLjdjMC0wLjEsMC0wLjEtMC4xLTAuMmMwLDAsMC0wLjEsMC0wLjFjMC0wLjEsMC0wLjEsMC0wLjJjMC0wLjIsMC0wLjUsMC0wLjdjMC0wLjIsMC4xLTAuNCwwLjEtMC41YzAuMS0wLjMsMC4zLTAuNiwwLjYtMC44YzAuNC0wLjQsMS4xLTAuMywxLjYtMC4xYzAtMC4zLDAtMC41LDAtMC41YzAtMC4xLDAtMC4zLTAuMS0wLjRjMCwwLDAtMC4xLDAtMC4xYy0wLjEtMC4yLTAuMi0wLjQtMC4zLTAuNGMtMC4yLTAuMS0wLjQsMC0wLjYsMGMwLDAtMC4xLDAtMC4xLDBjMCwwLTAuMSwwLTAuMSwwLjFjLTAuMSwwLjEtMC4zLDAuMi0wLjQsMC4xYzAtMC4xLTAuMS0wLjItMC4xLTAuMmMtMC4xLTAuMS0wLjItMC4zLTAuMi0wLjRjMCwwLDAuMSwwLDAuMS0wLjFjMC4yLTAuMSwwLjMtMC4xLDAuNS0wLjJsMCwwdjBjMC4yLTAuMSwwLjUtMC4xLDAuOC0wLjFjMC4xLDAsMC4zLDAsMC40LDAuMWMwLjMsMC4xLDAuNSwwLjMsMC43LDAuNWMwLDAsMCwwLjEsMC4xLDAuMWMwLDAuMSwwLjEsMC4xLDAuMSwwLjJjMCwwLDAsMC4xLDAsMC4xYzAsMCwwLDAuMSwwLDAuMWMwLDAuMSwwLDAuMSwwLDAuMmMwLDAuMiwwLDAuNCwwLjEsMC41QzEzLjYsMTIuOSwxMy42LDE0LjIsMTMuNiwxNS40eiBNMTIuNywxMi43Yy0wLjEtMC4xLTAuNy0wLjQtMS0wLjFjLTAuNCwwLjQtMC40LDEtMC40LDEuM2MwLDAuMiwwLjIsMSwwLjcsMWMwLjUsMCwwLjctMC4zLDAuNy0wLjNDMTIuNywxNC41LDEyLjcsMTMuNSwxMi43LDEyLjd6IE0xMi43LDEyLjdDMTIuNywxMi43LDEyLjcsMTIuNywxMi43LDEyLjdDMTIuNywxMi43LDEyLjcsMTIuNywxMi43LDEyLjd6IE0yNiwxMS42QzI2LDEyLDI2LDEyLjUsMjYsMTIuOWMtMC4yLDAtMS44LDAtMi4zLTAuMWMwLDAuMiwwLDAuNCwwLDAuN2MwLDAuMSwwLDAuMSwwLDAuMmMwLDAsMCwwLjEsMCwwLjFjMCwwLDAsMC4xLDAsMC4xYzAsMC4xLDAuMSwwLjIsMC4xLDAuMmMwLjEsMC4zLDAuNCwwLjUsMC43LDAuNmMwLjQsMC4xLDAuOCwwLDEuMi0wLjFjMCwwLDAsMC4xLDAsMC4xYzAsMC4xLDAsMC4xLDAsMC4yYzAsMC4xLDAsMC4xLDAuMSwwLjJjMCwwLDAsMC4xLDAsMC4xYy0wLjMsMC4yLTAuNywwLjMtMSwwLjNjLTAuNCwwLjEtMC44LDAtMS4xLTAuM2MtMC4zLTAuMi0wLjQtMC40LTAuNi0wLjdjMCwwLDAtMC4xLDAtMC4xYzAtMC4xLTAuMS0wLjEtMC4xLTAuMmMwLTAuMSwwLTAuMS0wLjEtMC4yYzAsMCwwLTAuMSwwLTAuMWMtMC4xLTAuMy0wLjEtMC42LTAuMS0wLjljMC0wLjMsMC0wLjYsMC0xYzAtMC4yLDAuMS0wLjQsMC4xLTAuNmMwLTAuMSwwLTAuMiwwLjEtMC4zYzAsMCwwLTAuMSwwLTAuMWMwLDAsMC0wLjEsMC0wLjFjMC0wLjEsMC0wLjEsMC4xLTAuMmMwLTAuMSwwLjEtMC4xLDAuMS0wLjJjMC4xLTAuMiwwLjMtMC41LDAuNS0wLjZsMCwwYzAuNC0wLjMsMC45LTAuMywxLjMtMC4xYzAuMiwwLjEsMC4zLDAuMiwwLjQsMC40YzAuMSwwLjEsMC4yLDAuMywwLjIsMC41YzAsMC4xLDAuMSwwLjIsMC4xLDAuNGMwLDAuMSwwLDAuMSwwLDAuMkMyNS45LDExLjQsMjUuOSwxMS41LDI2LDExLjZ6IE0yNC41LDEwLjVjLTAuNS0wLjEtMC43LDAuOC0wLjcsMS44YzAuMy0wLjEsMS4yLTAuMSwxLjMtMC4xQzI1LjEsMTAuNiwyNC42LDEwLjUsMjQuNSwxMC41eiBNMjkuNSwxNC44YzAtMC4xLTAuMS0wLjItMC4xLTAuM2MtMC4xLTAuMy0wLjMtMC42LTAuNC0xYzAtMC4xLTAuMS0wLjItMC4xLTAuM2MtMC4xLTAuMi0wLjEtMC4zLTAuMi0wLjVjMC0wLjEtMC4xLTAuMS0wLjEtMC4yYzAuMS0wLjEsMC4xLTAuMywwLjItMC40YzAuMS0wLjEsMC4xLTAuMiwwLjItMC40YzAuMS0wLjEsMC4xLTAuMiwwLjItMC40YzAuMS0wLjEsMC4xLTAuMywwLjItMC40YzAuMS0wLjEsMC4xLTAuMiwwLjEtMC4zYzAuMS0wLjEsMC4xLTAuMiwwLjItMC40YzAtMC4xLDAuMS0wLjIsMC4xLTAuNGMwLDAsMCwwLDAsMGMtMC4yLDAtMC40LDAtMC43LDBjLTAuMSwwLTAuMSwwLjEtMC4yLDAuMmMwLDAsMCwwLjEtMC4xLDAuMWMwLDAuMSwwLDAuMS0wLjEsMC4yYzAsMCwwLDAuMS0wLjEsMC4xYzAsMC4xLDAsMC4xLTAuMSwwLjJjMCwwLDAsMC4xLTAuMSwwLjFjLTAuMSwwLjItMC4xLDAuMy0wLjIsMC41YzAsMCwwLDAuMSwwLDAuMWMwLDAsMCwwLjEtMC4xLDAuMWMwLDAuMS0wLjEsMC4yLTAuMSwwLjNjLTAuMS0wLjEtMC4xLTAuMi0wLjEtMC40YzAsMCwwLTAuMS0wLjEtMC4xYzAtMC4xLDAtMC4xLTAuMS0wLjJjMCwwLDAtMC4xLTAuMS0wLjFjMC0wLjEtMC4xLTAuMi0wLjEtMC4zYzAtMC4xLTAuMS0wLjItMC4xLTAuM2MwLDAsMC0wLjEtMC4xLTAuMWMwLTAuMS0wLjEtMC4yLTAuMS0wLjNjLTAuMS0wLjEtMC4zLDAtMC41LDBjLTAuMSwwLTAuMywwLTAuNCwwLjFsMCwwYzAuMSwwLjEsMC4xLDAuMiwwLjEsMC4zYzAsMC4xLDAuMSwwLjIsMC4xLDAuM2MwLDAuMSwwLjEsMC4yLDAuMSwwLjNjMC4xLDAuMSwwLjEsMC4zLDAuMiwwLjRjMCwwLjEsMC4xLDAuMiwwLjEsMC4zYzAuMSwwLjMsMC4yLDAuNSwwLjQsMC44YzAuMSwwLjEsMCwwLjIsMCwwLjNjMCwwLjEtMC4xLDAuMS0wLjEsMC4yYzAsMC4xLTAuMSwwLjItMC4xLDAuM2MwLDAuMS0wLjEsMC4yLTAuMSwwLjNjMCwwLjEtMC4xLDAuMi0wLjEsMC4yYzAsMC4xLTAuMSwwLjEtMC4xLDAuMmMwLDAuMS0wLjEsMC4yLTAuMSwwLjNjMCwwLjEtMC4xLDAuMi0wLjEsMC4zYzAsMC4xLTAuMSwwLjItMC4xLDAuMmMwLDAuMS0wLjEsMC4yLTAuMSwwLjNjMCwwLjEtMC4xLDAuMi0wLjEsMC4zYzAsMC4xLDAsMC4xLTAuMSwwLjJjMCwwLDAuMSwwLDAuMSwwLjFjMC4yLDAsMC41LDAsMC43LDBjMC0wLjEsMC4xLTAuMiwwLjEtMC4zYzAtMC4xLDAtMC4xLDAuMS0wLjJjMCwwLDAtMC4xLDAuMS0wLjFjMCwwLDAtMC4xLDAtMC4xYzAtMC4xLDAtMC4xLDAuMS0wLjJjMCwwLDAtMC4xLDAuMS0wLjFjMCwwLDAtMC4xLDAtMC4xYzAuMS0wLjMsMC4yLTAuNSwwLjMtMC44YzAtMC4xLDAtMC4xLDAuMS0wLjJjMCwwLDAsMCwwLjEsMGMwLDAuMSwwLjEsMC4zLDAuMSwwLjRjMCwwLDAsMC4xLDAuMSwwLjFjMCwwLDAsMC4xLDAsMC4xYzAsMC4xLDAsMC4xLDAuMSwwLjJjMCwwLDAsMC4xLDAuMSwwLjFjMCwwLjEsMCwwLjEsMC4xLDAuMmMwLDAuMSwwLjEsMC4yLDAuMSwwLjNjMCwwLjEsMC4xLDAuMiwwLjEsMC4zYzAsMC4xLDAsMC4xLDAuMSwwLjJjMCwwLDAsMC4xLDAsMC4xYzAsMCwwLjEsMC4xLDAuMiwwLjFjMC4yLDAsMC40LDAsMC43LDBjMCwwLDAtMC4xLDAuMS0wLjFjLTAuMS0wLjEtMC4xLTAuMy0wLjItMC40QzI5LjUsMTQuOSwyOS41LDE0LjksMjkuNSwxNC44eiBNMjIsNy4zYzAsMi43LDAsNS40LDAsOC4xYzAsMC0wLjEsMC0wLjEsMC4xYy0wLjIsMC0wLjMsMC0wLjUsMGMtMC4xLTAuMS0wLjEtMC4yLTAuMi0wLjNjLTAuMywwLjMtMC43LDAuNS0xLjIsMC40Yy0wLjMsMC0wLjctMC4yLTAuOS0wLjVjLTAuMS0wLjEtMC4yLTAuMy0wLjMtMC41YzAtMC4xLTAuMS0wLjItMC4xLTAuMmMwLDAsMC0wLjEsMC0wLjFjMCwwLDAtMC4xLDAtMC4xYzAsMCwwLTAuMSwwLTAuMWMwLTAuMSwwLTAuMSwwLTAuMmMtMC4xLTAuNC0wLjEtMC44LTAuMS0xLjNjMC0wLjMsMC0wLjYsMC4xLTAuOWMwLTAuMSwwLTAuMSwwLTAuMmMwLDAsMC0wLjEsMC0wLjFjMCwwLDAtMC4xLDAtMC4xYzAtMC4xLDAtMC4xLDAuMS0wLjJjMC0wLjEsMC4xLTAuMiwwLjEtMC4zYzAtMC4xLDAuMS0wLjEsMC4xLTAuMmMwLjEtMC4zLDAuNC0wLjQsMC42LTAuNmMwLjQtMC4yLDAuOS0wLjIsMS40LDBjMC0wLjksMC0xLjgsMC0yLjhDMjEuNCw3LjIsMjEuNyw3LjIsMjIsNy4zQzIyLDcuMiwyMiw3LjIsMjIsNy4zeiBNMjEuMSwxNC43YzAtMC4yLDAtMi43LDAtNGMwLDAsMCwwLDAsMGMtMC4yLTAuMS0wLjUtMC4zLTAuOS0wLjJjLTEsMC4zLTEuMiw0LjEsMC4xLDQuM0MyMC40LDE0LjksMjAuOCwxNC45LDIxLjEsMTQuN3ogTTIxLjIsNy4yTDIxLjIsNy4yQzIxLjIsNy4yLDIxLjIsNy4yLDIxLjIsNy4yTDIxLjIsNy4yeiIvPjwvZz48L3N2Zz4=)}.bg-klarna{background-image:url(data:image/svg+xml;base64,PHN2ZyBpZD0nS2xhcm5hJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSczNicgaGVpZ2h0PScyMic+PHN0eWxlPi5zdDF7ZmlsbDojZmZmfTwvc3R5bGU+PHBhdGggaWQ9J1JvdW5kZWRfUmVjdGFuZ2xlXzUyXzZfJyBkPSdNMyAwaDMwYzEuNyAwIDMgMS4zIDMgM3YxNmMwIDEuNy0xLjMgMy0zIDNIM2MtMS43IDAtMy0xLjMtMy0zVjNjMC0xLjcgMS4zLTMgMy0zeicgZmlsbD0nI2ViNmY5MycvPjxnIHRyYW5zZm9ybT0ndHJhbnNsYXRlKDIwIDQ0KSc+PHBhdGggaWQ9J1NoYXBlXzFfJyBjbGFzcz0nc3QxJyBkPSdNLTEwLjEtMzYuMWgtMS40YzAgMS4xLS41IDIuMi0xLjQgMi44bC0uNS40IDIuMSAyLjloMS43bC0xLjktMi42Yy45LTEgMS40LTIuMiAxLjQtMy41eicvPjxwYXRoIGlkPSdSZWN0YW5nbGUtcGF0aF8xXycgY2xhc3M9J3N0MScgZD0nTS0xNS0zNi4xaDEuNHY2LjFILTE1eicvPjxwYXRoIGNsYXNzPSdzdDEnIGQ9J00tOS4yLTM2LjFoMS4zdjYuMWgtMS4zek0zLjgtMzQuNGMtLjUgMC0xIC4yLTEuMy42di0uNUgxLjN2NC4yaDEuM3YtMi4yYzAtLjYuNC0xIDEtMXMuOS4zLjkuOXYyLjJoMS4zdi0yLjdjLS4yLS44LS45LTEuNS0yLTEuNXpNLTMuOC0zNC4ydi4zYy0uNC0uMi0uOC0uNC0xLjMtLjQtMS4yIDAtMi4yIDEtMi4yIDIuMiAwIDEuMiAxIDIuMiAyLjIgMi4yLjUgMCAuOS0uMSAxLjMtLjR2LjNoMS4zdi00LjJoLTEuM3pNLTUtMzEuMWMtLjYgMC0xLjEtLjUtMS4xLTEuMSAwLS42LjUtMS4xIDEuMS0xLjFzMS4xLjUgMS4xIDEuMWMuMS43LS40IDEuMS0xLjEgMS4xek0tLjYtMzMuN3YtLjVoLTEuM3Y0LjJoMS4zdi0yYzAtLjcuNy0xIDEuMi0xdi0xLjJjLS40IDAtLjkuMi0xLjIuNXpNOS42LTM0LjJ2LjNjLS40LS4yLS44LS40LTEuMy0uNC0xLjIgMC0yLjIgMS0yLjIgMi4yIDAgMS4yIDEgMi4yIDIuMiAyLjIuNSAwIC45LS4xIDEuMy0uNHYuM2gxLjN2LTQuMkg5LjZ6bS0xLjIgMy4xYy0uNiAwLTEuMS0uNS0xLjEtMS4xIDAtLjYuNS0xLjEgMS4xLTEuMS42IDAgMS4xLjUgMS4xIDEuMS4xLjctLjQgMS4xLTEuMSAxLjF6TTEyLjItMzEuNWMtLjQgMC0uOC40LS44LjhzLjQuOC44LjguOC0uNC44LS44YzAtLjUtLjQtLjgtLjgtLjh6Jy8+PC9nPjwvc3ZnPg==)}.bg-eps{background-image:url(data:image/svg+xml;base64,PHN2ZyBpZD0iS2xhcm5hIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDM2IDIyIj4gIDx0aXRsZT5pY29uLWVwczwvdGl0bGU+ICA8cGF0aCBpZD0iUm91bmRlZF9SZWN0YW5nbGVfNTIiIGRhdGEtbmFtZT0iUm91bmRlZCBSZWN0YW5nbGUgNTIiIGQ9Ik0zLDBIMzNhMywzLDAsMCwxLDMsM1YxOWEzLDMsMCwwLDEtMywzSDNhMywzLDAsMCwxLTMtM1YzQTMsMywwLDAsMSwzLDBaIiBmaWxsPSIjZjFmMGYyIi8+ICA8Zz4gICAgPGc+ICAgICAgPHBhdGggZD0iTTI3LjYzLDExLjM3SDI1LjU3YS40OC40OCwwLDAsMSwwLS45NWgzLjMyVjguODRIMjUuNDdhMi4wNSwyLjA1LDAsMCwwLTIsMi4wNWgwYTIuMDUsMi4wNSwwLDAsMCwyLDIuMDZoMi4yMWEuNDcuNDcsMCwxLDEsMCwuOTRIMjNhNCw0LDAsMCwxLTEuNDcsMS42OWg2LjA2YTIuMTEsMi4xMSwwLDAsMCwyLjEtMi4xMWgwQTIuMSwyLjEsMCwwLDAsMjcuNjMsMTEuMzdaIiBmaWxsPSIjNzE3MDZmIi8+ICAgICAgPHBhdGggZD0iTTIyLjY4LDEyLjIxaDBhMy4zNywzLjM3LDAsMCwwLTMuMzctMy4zN2gwYTMuMjksMy4yOSwwLDAsMC0zLjI2LDMuMzd2Ni45NGgxLjU4VjE1LjU4aDEuNjhBMy4zNywzLjM3LDAsMCwwLDIyLjY4LDEyLjIxWm0tMS41OC0uMDVhMS43MiwxLjcyLDAsMCwxLTEuNzMsMS43M0gxNy42M1YxMi4xNmExLjc0LDEuNzQsMCwxLDEsMy40NywwWiIgZmlsbD0iIzcxNzA2ZiIvPiAgICA8L2c+ICAgIDxnPiAgICAgIDxwYXRoIGQ9Ik05LjIyLDUuNzlhMS40NywxLjQ3LDAsMCwxLDIuOTQsMHYuODRoMS4zN1Y1LjY5YTIuODQsMi44NCwwLDAsMC01LjY4LDB2Ljk0SDkuMjJaIiBmaWxsPSIjYzgwMjZlIi8+ICAgICAgPHBhdGggZD0iTTE1LjIxLDEzLjg5VjkuMTNhMS40MywxLjQzLDAsMCwwLTEuNDQtMS40NEg3LjcxQTEuNDQsMS40NCwwLDAsMCw2LjI3LDkuMTN2Ni4wNmExLjQ1LDEuNDUsMCwwLDAsMS40NCwxLjQ0aDYuMDZhMS40NSwxLjQ1LDAsMCwwLDEuMzktMUgxMC42OWEzLjM3LDMuMzcsMCwwLDEtMy4zNy0zLjM3aDBhMy4zNywzLjM3LDAsMCwxLDMuMzctMy4zN2gwYTMuMzcsMy4zNywwLDAsMSwzLjM3LDMuMzdWMTNIOS4yYTEuNzIsMS43MiwwLDAsMCwxLjU0Ljk0aDQuNDdaIiBmaWxsPSIjYzgwMjZlIi8+ICAgICAgPHBhdGggZD0iTTEwLjc0LDEwLjQyYTEuNzMsMS43MywwLDAsMC0xLjU0Ljk1aDMuMDlBMS43NCwxLjc0LDAsMCwwLDEwLjc0LDEwLjQyWiIgZmlsbD0iI2M4MDI2ZSIvPiAgICA8L2c+ICA8L2c+PC9zdmc+)}.bg-bancontact{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNiIgaGVpZ2h0PSIxNiI+ICAgIDxwYXRoIGQ9Ik0yIDBoMjJjMS4xIDAgMiAuOSAyIDJ2MTJjMCAxLjEtLjkgMi0yIDJIMmMtMS4xIDAtMi0uOS0yLTJWMkMwIC45LjkgMCAyIDB6IiBmaWxsPSIjZjBmM2Y1Ij48L3BhdGg+ICAgIDxwYXRoIGQ9Ik0yMS4zIDZoLTYuNmwtMy41IDRINC43bDEuNi0xLjloLTNjLS41IDAtMSAuNS0xIDF2Mi4xYzAgLjYuNCAxIDEgMWgxMS40Yy41IDAgMS4zLS4zIDEuNy0uOEwyMS4zIDZ6IiBmaWxsPSIjMDA0ZTkxIj48L3BhdGg+ICAgIDxwYXRoIGQ9Ik0yMi42IDMuN2MuNSAwIDEgLjUgMSAxdjIuMWMwIC42LS40IDEtMSAxaC0zTDIxLjMgNmgtNi42bC0zLjUgNEg0LjdsNC44LTUuNWMuNC0uNCAxLjEtLjggMS43LS44aDExLjR6IiBmaWxsPSIjZmQwIj48L3BhdGg+PC9zdmc+)}.bg-knet{background-image:url(data:image/svg+xml;base64,PHN2ZyBpZD0nS2xhcm5hLXNtYWxsJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScyNicgaGVpZ2h0PScxNic+ICAgIDxzdHlsZT4uc3Qye2ZpbGw6I2ZmZn08L3N0eWxlPiAgICA8cGF0aCBkPSdNMiAwaDIyYzEuMSAwIDIgLjkgMiAydjEyYzAgMS4xLS45IDItMiAySDJjLTEuMSAwLTItLjktMi0yVjJDMCAuOS45IDAgMiAweicgZmlsbD0nIzAwNzhkYycvPiAgICA8cGF0aCBmaWxsPScjZmZlMTAwJyBkPSdNMjEuNiA3LjRsLTMuOS0yLjkgMy44LTIuM2gtNy42bC0zLjIgMi4xVjIuMkg1LjZ2NS4yaDUuMVY0LjhsMy4yIDIuNnonLz4gICAgPHBhdGggY2xhc3M9J3N0MicgZD0nTTYuMyAxMi44djEuNWgtLjR2LTEuNGMwLS41LS4yLS43LS43LS43LS4yIDAtLjMuMS0uNS4yLS4xLjEtLjIuMy0uMi41djEuNEg0di0yLjRoLjR2LjRjLjEtLjEuMi0uMi40LS4zLjEtLjEuMy0uMS41LS4xLjYtLjEgMSAuMiAxIC45ek0xMy43IDEyLjJjLjIuMi4zLjYuMyAxaC0yLjFjMCAuMy4xLjUuMi42LjEuMS4zLjIuNi4yLjIgMCAuNC0uMS41LS4xLjEtLjEuMi0uMi4zLS40aC41Yy0uMS4yLS4yLjQtLjQuNi0uMi4yLS41LjMtLjkuM3MtLjctLjEtLjktLjMtLjQtLjUtLjQtLjkuMS0uNi4zLS45Yy4yLS4yLjUtLjQuOS0uNC42LS4xLjkgMCAxLjEuM3ptLTEuNS4xYy0uMS4xLS4yLjMtLjMuNmgxLjdjLS4xLS41LS4zLS44LS44LS44LS4zIDAtLjUuMS0uNi4yek0yMC45IDExLjloLjV2LjNoLS41djEuNWMwIC4xIDAgLjIuMS4yIDAgMCAuMS4xLjIuMWguM3YuM2gtLjRjLS4yIDAtLjQtLjEtLjUtLjItLjEtLjEtLjEtLjItLjEtLjR2LTEuNWgtLjN2LS4zaC4zdi0uNmwuNC0uMnYuOHpNMCA5LjRoMjZ2LjRIMHonLz48L3N2Zz4=)}.bg-fawry{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSczNicgaGVpZ2h0PScyMic+ICAgIDxzdHlsZT4uc3Qye2ZpbGw6IzAxNmQ5Yn08L3N0eWxlPiAgICA8cGF0aCBpZD0nUm91bmRlZF9SZWN0YW5nbGVfNTJfNl8nIGQ9J00zIDBoMzBjMS43IDAgMyAxLjMgMyAzdjE2YzAgMS43LTEuMyAzLTMgM0gzYy0xLjcgMC0zLTEuMy0zLTNWM2MwLTEuNyAxLjMtMyAzLTN6JyBmaWxsPScjZmVkMzAxJy8+ICAgIDxnIGlkPSd5eEFZeXkudGlmJz48cGF0aCBkPSdNMy4xIDEzLjRjLS41LS44LS44LTEuNy0uNy0yLjYuMS0xLjYuOS0yLjkgMi40LTMuNy44LS40IDEuNi0uNiAyLjQtLjUuOCAwIDEuNS4yIDIuMS43IDAgLjIuMS40IDAgLjUgMCAuNS0uMi45LS41IDEuMy0uMS4zLS4zLjUtLjUuOC0uMS4xLS4xLjIgMCAuM2guMmMuMyAwIC41IDAgLjgtLjEuMSAwIC4xIDAgLjEuMSAwIC4yIDAgLjMtLjEuNSAwIC4xIDAgLjIuMS4ycy4yIDAgLjItLjFjLjUtLjcuOS0xLjMgMS0yLjEuMy40LjQuOS41IDEuNC4zIDEuNS0uMSAyLjktMS4yIDQtLjguOC0xLjcgMS4yLTIuOCAxLjMtMSAuMS0xLjktLjEtMi44LS43LjQgMCAuNy0uMSAxLS4zLjgtLjMgMS40LS44IDIuMS0xLjMuMyAwIC40LS4xLjUtLjEuMSAwIC4yLjIuMy4zLjEuMS4xLjIuMy4xLjIgMCAuMS0uMi4xLS4zbC4zLTIuMWMwLS4yIDAtLjMtLjMtLjMtLjUgMC0xLjEuMS0xLjYuMS0uMiAwLS40IDAtLjYuMS0uMSAwLS4yIDAtLjIuMS0uMS4xIDAgLjIuMS4zbC4zLjNjLjEuMS4xLjEgMCAuMi0uNi41LTEuMi45LTEuOSAxLjItLjMuMi0uNy4zLTEgLjRoLS42eicgZmlsbD0nI2ZkZmRmZCcvPiAgICAgICAgPHBhdGggY2xhc3M9J3N0MicgZD0nTTIyLjYgMTAuN2MtLjIuNi0uNCAxLjItLjYgMS45LS4xLjMtLjIuNC0uNS40aC0uNGMtLjMgMC0uNC0uMS0uNS0uNC0uMy0uOS0uNi0xLjctLjktMi42LS4xLS4yLS4xLS4zLS4yLS41di0uMmMwLS4xIDAtLjIuMS0uMmguOGMuMiAwIC4zLjIuNC40LjEuNS4zIDEgLjQgMS40IDAgLjEgMCAuMi4xLjMuMi0uNi4zLTEuMS41LTEuNy4yLS4yLjItLjMuNi0uM2guNWMuMyAwIC40LjEuNS4zLjEuNS4zIDEgLjQgMS40IDAgLjEgMCAuMi4xLjMuMS0uNS4zLS45LjQtMS40IDAtLjEuMS0uMy4xLS40LjEtLjIuMi0uMy40LS4zaC43Yy4xIDAgLjIuMS4yLjJ2LjJjLS4zIDEtLjcgMi0xIDMtLjEuMy0uMi40LS41LjRoLS40Yy0uMyAwLS40LS4xLS41LS40LS4zLS41LS41LTEuMS0uNy0xLjggMCAuMSAwIDAgMCAwek0zLjEgMTMuNGguNmMuNC0uMS43LS4yIDEtLjQuNy0uMyAxLjMtLjggMS44LTEuMi4xLS4xLjEtLjEgMC0uMmwtLjMtLjNjLS4xLS4xLS4yLS4xLS4xLS4zIDAtLjEuMi0uMS4yLS4xLjIgMCAuNCAwIC42LS4xLjUgMCAxLjEtLjEgMS42LS4xLjIgMCAuMy4xLjMuM2wtLjMgMi4xYzAgLjEgMCAuMy0uMS4zcy0uMi0uMS0uMy0uMWMwLS4xLS4xLS4zLS4yLS4zcy0uMi4yLS4zLjNjLS42LjUtMS4zIDEtMi4xIDEuMy0uMy4xLS43LjItMSAuMy0uNi0uNS0xLS45LTEuNC0xLjV6TTI5LjkgOS4yaC4zYy4yIDAgLjMuMS4zLjMuMS4zLjIuNy4zIDEgLjEuMy4yLjUuMy44LjEuMi4xLjMuMy41bC4xLjFjLjIuMS4yLjEuMi0uMS4yLS43LjQtMS40LjYtMi4yLjEtLjMuMS0uMy40LS4zaC41Yy4yIDAgLjMuMS4yLjMtLjIuNy0uNCAxLjQtLjYgMi0uMS41LS4zLjktLjQgMS40LS4xLjMtLjIuNS0uNC44LS4yLjQtLjYuNS0xIC42aC0uOGMtLjEgMC0uMiAwLS4yLS4xLS4yLS4xLS4yLS42IDAtLjdIMzAuNmMuMy4xLjUtLjEuNi0uMyAwIDAgLjEtLjEuMS0uMi4xLS4yLjEtLjItLjEtLjItLjQtLjEtLjgtLjMtMS0uNi0uMi0uNC0uNC0uNy0uNS0xLjEtLjEtLjUtLjMtLjktLjQtMS40di0uMmMwLS4xLjEtLjIuMi0uMi4xLS4yLjMtLjIuNC0uMnpNMTIuNCAxMS4xVjkuNmMwLS4yIDAtLjUuMS0uNy4yLS41LjUtLjggMS4xLS45LjUtLjEgMS0uMSAxLjYgMCAuNCAwIC40LjEuNC41di4yYzAgLjEtLjEuMi0uMi4yaC0xLjFjLS40LjEtLjUuMi0uNS42LS4xLjQtLjEuNC4zLjRoLjhjLjIgMCAuMy4xLjMuM3YuMmMwIC4yLS4xLjMtLjMuM2gtMWMtLjEgMC0uMiAwLS4yLjJ2MS45YzAgLjMgMCAuMy0uMy4zaC0uNmMtLjMgMC0uMy0uMS0uMy0uMy0uMS0uNi0uMS0xLjItLjEtMS43ek0yNi4xIDExLjFWOS41YzAtLjMgMC0uMy4zLS4zaC42Yy4yIDAgLjMgMCAuMy4zIDAgLjEgMCAuMS4xLjEuNC0uMy44LS40IDEuMy0uNC4zLS4xLjMgMCAuMy4ydi40YzAgLjItLjEuMi0uMy4yaC0uNmMtLjQgMC0uNi4yLS44LjUtLjEuMSAwIC4xIDAgLjJ2Mi4xYzAgLjEtLjEuMS0uMi4xaC0uN2MtLjIgMC0uMy0uMS0uMy0uM3YtMS41ek0xMC43IDguOGMtLjEuOC0uNSAxLjUtMSAyLjEgMCAuMS0uMS4xLS4yLjFzLS4xLS4yLS4xLS4yYzAtLjIgMC0uMy4xLS41IDAtLjEgMC0uMS0uMS0uMS0uMyAwLS41IDAtLjguMWgtLjJjLS4xLS4xLS4xLS4yIDAtLjMuMi0uMi40LS41LjUtLjguMi0uNC40LS44LjUtMS4zdi0uNWMuNS4yIDEgLjcgMS4zIDEuNHpNMTguMiA5LjJjLS42LS4yLTEuMi0uMS0xLjkgMC0uMSAwLS4zLjEtLjQuMi0uMi4yLS4zLjQtLjMuNiAwIC4yLjEuMy4yLjNoLjRjLjIgMCAuNC0uMS41LS4yLjItLjEuMy0uMS41LS4yaC40Yy4zIDAgLjUuMi41LjYgMCAuMSAwIC4xLS4xLjFoLS45Yy0uMyAwLS42IDAtLjguMS0uMy4xLS42LjItLjguNS0uNC42LS4xIDEuMy41IDEuNi43LjMgMS4zLjMgMiAwbC4xLS4xaC4xYy4xLjIuMS4yLjMuMmguNWMuMyAwIC4zIDAgLjMtLjN2LTEtMWMwLS43LS4zLTEuMi0xLjEtMS40em0tLjQgMi45Yy0uMi4xLS40LjEtLjYuMWgtLjNjLS4yLS4xLS4zLS4yLS4zLS40cy4yLS4zLjQtLjRoMWMuMSAwIC4xIDAgLjEuMSAwIC41LjEuNC0uMy42eicvPiAgICA8L2c+PC9zdmc+)} +.alternative-selector input{margin:0;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.alternative-selector input:active+label div.alternative-icon{opacity:.9}.alternative-selector input:checked+label div.alternative-icon{-webkit-filter:none;-moz-filter:none;filter:none}.alternative-selector label:hover *{-webkit-filter:brightness(1.2) grayscale(.5) opacity(.9);-moz-filter:brightness(1.2) grayscale(.5) opacity(.9);filter:brightness(1.2) grayscale(.5) opacity(.9)}.alternative-icon{display:inline-block;width:4em;height:3em;-webkit-transition:all .1s ease-in;-moz-transition:all .1s ease-in;transition:all .1s ease-in;-webkit-filter:brightness(1) grayscale(.8) opacity(.7);-moz-filter:brightness(1) grayscale(.8) opacity(.7);filter:brightness(1) grayscale(.8) opacity(.7)}.alternative-selector h2{display:inline-block;margin:0 0 0 10px;vertical-align:middle}div.alternative-selector label{cursor:pointer}div.alternative-selector>div{margin-bottom:10px}div.alternative-selector>div:last-child{margin-bottom:0}div.cko-alternative-form{padding-left:2em}#apm-container{margin-bottom:20px}#apm-container div[data-role=collapsible]{border-bottom:1px solid #ccc;cursor:pointer;padding:15px}#apm-container div[aria-selected=true],#apm-container div[data-role=collapsible]:focus,#apm-container div[data-role=collapsible]:hover{background-color:#f1f1f1}#apm-container div.cko-apm:last-child{border-bottom:none!important}#apm-container div[data-role=trigger]{cursor:pointer}#apm-container div[data-role=content]{padding:1rem 2rem}.cko-apm.paypal{display:block!important}.bg-apm{background-repeat:no-repeat;background-position:center center;background-size:contain;vertical-align:middle;display:inline-block;width:45px;height:30px;margin-right:10px}.bg-alipay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfM18iIGNsYXNzPSJzdDE3IiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGNsYXNzPSJzdDE4IiBkPSJNMjAuMiwxMi40YzAuNy0xLjMsMS4zLTIuNiwxLjctNGgtNFY3LjFoNVY2LjJoLTVWNGgtMi4zdjIuMmgtNXYwLjhoNXYxLjRoLTQuMnYwLjdoOC4xYy0wLjMsMC45LTAuNywxLjgtMS4yLDIuN2MtMS45LTAuNi0zLjgtMS01LjgtMS4xYy0zLjksMC00LjcsMS45LTQuNSwzLjZjMC4xLDEuNCwxLjIsMy40LDQuNCwzLjRjMi43LTAuMSw1LjItMS40LDYuOC0zLjZjMi44LDEuMiw1LjcsMi44LDcuOCwzLjl2LTMuM0MyNC44LDE0LDIyLjUsMTMuMiwyMC4yLDEyLjR6IE0xMiwxNi41Yy0yLjcsMC0zLjEtMS41LTMuMi0yLjRjMC0wLjgsMC41LTIuMiwzLjYtMi4yYzEuNywwLjIsMy40LDAuNyw1LDEuNEMxNi4yLDE0LjgsMTQuMywxNi41LDEyLDE2LjVMMTIsMTYuNXoiLz48L3N2Zz4=)}.bg-amex{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU1XzJfIiBjbGFzcz0ic3QyIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMywxMmgyLjd2MC42aC0xLjl2MC42aDEuOHYwLjZoLTEuOHYwLjZoMS45VjE1SDIzVjEyeiBNMzAuOSwxMy4yYzEsMCwxLjEsMC41LDEuMSwxYzAsMC41LTAuNSwwLjktMSwwLjljMCwwLDAsMCwwLDBoLTEuN3YtMC42aDEuM2MwLjIsMCwwLjYsMCwwLjYtMC4zYzAtMC4xLTAuMS0wLjItMC4zLTAuMmMtMC4xLDAtMC41LDAtMC42LDBjLTAuOSwwLTEuMS0wLjQtMS4xLTAuOWMwLTAuNSwwLjQtMC45LDAuOS0wLjljMCwwLDAuMSwwLDAuMSwwaDEuN3YwLjZoLTEuM2MtMC4zLDAtMC42LDAtMC42LDAuM2MwLDAuMiwwLjIsMC4yLDAuMywwLjJDMzAuNCwxMy4xLDMwLjgsMTMuMiwzMC45LDEzLjJMMzAuOSwxMy4yeiBNMjcuOCwxMy4yYzEsMCwxLjEsMC41LDEuMSwxYzAsMC41LTAuNSwwLjktMSwwLjljMCwwLDAsMCwwLDBoLTEuN3YtMC42aDEuM2MwLjIsMCwwLjYsMCwwLjYtMC4zYzAtMC4xLTAuMS0wLjItMC4zLTAuMmMtMC4xLDAtMC41LDAtMC42LDBjLTAuOSwwLTEuMS0wLjQtMS4xLTAuOWMwLTAuNSwwLjQtMC45LDAuOS0wLjljMCwwLDAuMSwwLDAuMSwwaDEuN3YwLjZoLTEuM2MtMC4zLDAtMC42LDAtMC42LDAuM2MwLDAuMiwwLjIsMC4yLDAuMywwLjJDMjcuMywxMy4xLDI3LjcsMTMuMiwyNy44LDEzLjJMMjcuOCwxMy4yeiBNMTgsMTJoLTIuOWwtMC45LDAuOUwxMy4zLDEySDEwdjNoMy4xbDEtMWwxLDFoMS42di0xaDEuMWMwLjUsMC4xLDEuMS0wLjIsMS4yLTAuN2MwLTAuMSwwLTAuMiwwLTAuM2MwLTAuNS0wLjQtMC45LTAuOC0wLjlDMTguMSwxMiwxOC4xLDEyLDE4LDEyeiBNMTIuOCwxNC40aC0xLjl2LTAuNmgxLjh2LTAuNmgtMS44di0wLjZoMmwwLjgsMC44TDEyLjgsMTQuNHogTTE1LjksMTQuN2wtMS4yLTEuMmwxLjItMS4yVjE0Ljd6IE0xNy44LDEzLjRoLTF2LTAuN2gxYzAuMiwwLDAuNCwwLjEsMC40LDAuM2MwLDAuMi0wLjEsMC40LTAuMywwLjRDMTcuOSwxMy40LDE3LjgsMTMuNCwxNy44LDEzLjRMMTcuOCwxMy40eiBNMjIsMTMuNmMwLjQtMC4xLDAuNi0wLjUsMC42LTAuOGMwLTAuNS0wLjQtMC44LTAuOS0wLjhjMCwwLTAuMSwwLTAuMSwwaC0yLjF2M2gwLjh2LTEuMWgxLjFjMC4yLDAsMC40LDAuMiwwLjQsMC41YzAsMCwwLDAsMCwwbDAsMC41aDAuOGwwLTAuNmMwLjEtMC4zLTAuMS0wLjYtMC40LTAuN0MyMi4xLDEzLjYsMjIuMSwxMy42LDIyLDEzLjZMMjIsMTMuNnogTTIxLjMsMTMuM2gtMXYtMC43aDFjMC4yLDAsMC40LDAuMSwwLjQsMC4zYzAsMCwwLDAsMCwwQzIxLjgsMTMuMiwyMS42LDEzLjMsMjEuMywxMy4zTDIxLjMsMTMuM3ogTTIwLjksMTFWOGgtMC44djNIMjAuOXogTTEzLjMsOEgxNnYwLjZoLTEuOXYwLjZIMTZ2MC42aC0xLjh2MC42SDE2VjExaC0yLjdWOHogTTE5LjEsOS42YzAuNC0wLjEsMC42LTAuNSwwLjYtMC44YzAtMC41LTAuNC0wLjgtMC45LTAuOGMwLDAtMC4xLDAtMC4xLDBoLTIuMnYzaDAuOFY5LjloMS4xYzAuMiwwLDAuNCwwLjIsMC40LDAuNWMwLDAsMCwwLDAsMGwwLDAuNmgwLjhsMC0wLjZjMC4xLTAuMy0wLjEtMC42LTAuNC0wLjdDMTkuMiw5LjYsMTkuMSw5LjYsMTkuMSw5LjZMMTkuMSw5LjZ6IE0xOC40LDkuM2gtMVY4LjZoMWMwLjIsMCwwLjQsMC4xLDAuNSwwLjNjMCwwLDAsMCwwLDBDMTguOCw5LjIsMTguNyw5LjMsMTguNCw5LjNMMTguNCw5LjN6IE0xMS40LDhsLTEsMmwtMS0ySDh2Mi45TDYuNiw4SDUuNUw0LDExaDAuOWwwLjMtMC43aDEuN0w3LjIsMTFoMS43VjguOEwxMCwxMWgwLjhsMS4xLTIuMlYxMWgwLjhWOEgxMS40TDExLjQsOHogTTUuNSw5LjdsMC41LTFsMC41LDFINS41TDUuNSw5Ljd6IE0yOS41LDh2Mi4xTDI4LjEsOGgtMS4ydjIuOEwyNS41LDhoLTEuMWwtMS4xLDIuM2MwLDAtMC41LDAtMC41LDBjLTAuMywwLTAuNi0wLjQtMC41LTAuN2MwLDAsMCwwLDAsMFY5LjRjMC0wLjcsMC40LTAuOCwxLTAuOGgwLjVWOGgtMS4xYy0wLjgsMC4xLTEuNCwwLjktMS4yLDEuOGMwLjEsMC43LDAuNiwxLjIsMS4zLDEuMmgxLjFsMC4zLTAuN2gxLjdsMC4zLDAuN2gxLjZWOC44bDEuNSwyLjJoMS4xVjhIMjkuNUwyOS41LDh6IE0yNC40LDkuN2wwLjUtMWwwLjUsMUgyNC40TDI0LjQsOS43eiIvPjwvc3ZnPg==)}.bg-applepay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5XzFfIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGlkPSJBcHBsZV8xXyIgY2xhc3M9InN0MCIgZD0iTTExLjcsMTFjMCwwLjgsMC41LDEuNiwxLjMsMS45Yy0wLjIsMC41LTAuNCwwLjktMC43LDEuM2MtMC4zLDAuNi0wLjgsMS0xLjUsMS4xYy0wLjcsMC0wLjktMC40LTEuNi0wLjRzLTEsMC40LTEuNiwwLjRjLTAuNy0wLjEtMS4yLTAuNi0xLjUtMS4yQzUuMiwxMyw0LjUsMTAuOSw1LjQsOS41YzAuNC0wLjcsMS4yLTEuMiwyLTEuMkM4LDguNCw4LjUsOC41LDkuMSw4LjdjMC42LTAuMiwxLjItMC40LDEuOS0wLjRjMC43LDAsMS40LDAuNCwxLjgsMC45QzEyLjEsOS42LDExLjcsMTAuMiwxMS43LDExIE0xMC40LDcuNUMxMC44LDcuMSwxMSw2LjUsMTAuOSw2Yy0wLjYsMC0xLjEsMC4zLTEuNCwwLjdDOS4xLDcuMSw4LjksNy42LDksOC4yQzkuNSw4LjIsMTAuMSw3LjksMTAuNCw3LjUiLz48cGF0aCBpZD0iUGF5XzFfIiBjbGFzcz0ic3QwIiBkPSJNMTUuNCw2LjhjMC4zLDAsMC42LTAuMSwwLjgtMC4xYzAuMywwLDAuNy0wLjEsMSwwYzAuNSwwLDAuOSwwLjEsMS40LDAuMmMwLjMsMC4xLDAuNywwLjMsMC45LDAuNWMwLjIsMC4yLDAuNCwwLjQsMC41LDAuN2MwLjEsMC4zLDAuMiwwLjYsMC4yLDFjMCwwLjQtMC4xLDAuOC0wLjIsMS4xYy0wLjIsMC4zLTAuNCwwLjYtMC43LDAuOGMtMC4zLDAuMi0wLjYsMC40LTEsMC41Yy0wLjQsMC4xLTAuOCwwLjItMS4zLDAuMmMtMC4zLDAtMC43LDAtMS0wLjF2My42aC0wLjZWNi44TDE1LjQsNi44TDE1LjQsNi44eiBNMTYsMTEuMWMwLjIsMCwwLjMsMC4xLDAuNSwwLjFjMC4yLDAsMC40LDAsMC42LDBjMC43LDAsMS4zLTAuMSwxLjgtMC41YzAuNC0wLjQsMC43LTEsMC42LTEuNmMwLTAuMy0wLjEtMC42LTAuMi0wLjljLTAuMS0wLjItMC4zLTAuNC0wLjUtMC42Yy0wLjItMC4yLTAuNS0wLjMtMC43LTAuNGMtMC4zLTAuMS0wLjYtMC4xLTEtMC4xYy0wLjIsMC0wLjUsMC0wLjcsMGMtMC4yLDAtMC40LDAtMC41LDAuMUwxNiwxMS4xTDE2LDExLjFMMTYsMTEuMXogTTI1LjEsMTMuOGMwLDAuMiwwLDAuNSwwLDAuN2MwLDAuMiwwLDAuNSwwLjEsMC43aC0wLjZsLTAuMS0wLjloMGMtMC4xLDAuMS0wLjIsMC4yLTAuMywwLjRjLTAuMSwwLjEtMC4zLDAuMi0wLjQsMC4zYy0wLjIsMC4xLTAuNCwwLjItMC42LDAuMmMtMC4yLDAuMS0wLjQsMC4xLTAuNywwLjFjLTAuMywwLTAuNSwwLTAuOC0wLjFjLTAuMi0wLjEtMC40LTAuMi0wLjYtMC40Yy0wLjEtMC4yLTAuMy0wLjMtMC4zLTAuNWMtMC4xLTAuMi0wLjEtMC40LTAuMS0wLjZjMC0wLjcsMC4zLTEuMywwLjktMS43YzAuOS0wLjQsMS45LTAuNiwyLjgtMC42di0wLjJjMC0wLjIsMC0wLjQsMC0wLjVjMC0wLjItMC4xLTAuNC0wLjItMC42QzI0LjEsMTAsMjQsOS44LDIzLjgsOS43Yy0wLjMtMC4xLTAuNi0wLjItMC45LTAuMmMtMC4zLDAtMC41LDAtMC44LDAuMWMtMC4zLDAuMS0wLjUsMC4yLTAuNywwLjNsLTAuMi0wLjRjMC4zLTAuMiwwLjYtMC4zLDAuOS0wLjRDMjIuMyw5LjEsMjIuNyw5LDIzLDljMC40LDAsMC43LDAuMSwxLjEsMC4yYzAuMywwLjEsMC41LDAuMywwLjYsMC42YzAuMiwwLjIsMC4zLDAuNSwwLjMsMC44YzAuMSwwLjMsMC4xLDAuNiwwLjEsMC44TDI1LjEsMTMuOEwyNS4xLDEzLjhMMjUuMSwxMy44eiBNMjQuNSwxMmMtMC4zLDAtMC43LDAtMSwwYy0wLjMsMC0wLjcsMC4xLTEsMC4yYy0wLjMsMC4xLTAuNiwwLjMtMC44LDAuNWMtMC4yLDAuMi0wLjMsMC42LTAuMywwLjljMCwwLjQsMC4xLDAuNywwLjQsMC45YzAuMiwwLjIsMC41LDAuMywwLjksMC4zYzAuMiwwLDAuNSwwLDAuNy0wLjFjMC4yLTAuMSwwLjQtMC4yLDAuNS0wLjNjMC4xLTAuMSwwLjMtMC4yLDAuNC0wLjRjMC4xLTAuMSwwLjItMC4zLDAuMi0wLjRjMC0wLjEsMC4xLTAuMiwwLjEtMC40TDI0LjUsMTJMMjQuNSwxMkwyNC41LDEyeiBNMjYuMyw5LjJsMS42LDMuOWMwLjEsMC4yLDAuMiwwLjQsMC4yLDAuN3MwLjEsMC40LDAuMiwwLjZoMGMwLjEtMC4yLDAuMS0wLjQsMC4yLTAuNnMwLjItMC41LDAuMy0wLjdsMS41LTMuOUgzMWwtMS44LDQuNGMtMC4yLDAuNC0wLjMsMC45LTAuNSwxLjNjLTAuMSwwLjQtMC4zLDAuNy0wLjUsMWMtMC4xLDAuMy0wLjMsMC42LTAuNSwwLjhjLTAuMiwwLjItMC40LDAuNC0wLjYsMC42Yy0wLjIsMC4yLTAuNCwwLjMtMC43LDAuNUMyNi4yLDE3LjksMjYuMSwxOCwyNiwxOGwtMC4yLTAuNWMwLjItMC4xLDAuNC0wLjIsMC41LTAuM2MwLjItMC4xLDAuNC0wLjMsMC42LTAuNGMwLjItMC4yLDAuNC0wLjQsMC41LTAuNmMwLjItMC4zLDAuNC0wLjYsMC41LTAuOWMwLTAuMSwwLjEtMC4yLDAuMS0wLjNjMC0wLjEsMC0wLjItMC4xLTAuM2wtMi4zLTUuNkwyNi4zLDkuMkwyNi4zLDkuMnoiLz48L3N2Zz4=)}.bg-astro{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHlfMl8yXyIgY2xhc3M9InN0MjciIGQ9Ik0zLDBoMzBjMS43LDAsMywxLjMsMywzdjE2YzAsMS43LTEuMywzLTMsM0gzYy0xLjcsMC0zLTEuMy0zLTNWM0MwLDEuMywxLjMsMCwzLDB6Ii8+PGc+PHBhdGggY2xhc3M9InN0MCIgZD0iTTUuOSwxNC44YzAuMS0wLjIsMC4yLTAuNCwwLjItMC43QzYuOCwxMiw3LjYsOS44LDguMyw3LjZjMC4xLTAuMiwwLjItMC40LDAuMi0wLjdjMC0wLjEsMC0wLjEsMC4xLTAuMWMwLjQsMCwwLjcsMCwxLjEsMGMwLjEsMCwwLjEsMCwwLjEsMC4xYzAuNCwxLjMsMC45LDIuNiwxLjMsMy45YzAuNCwxLjMsMC45LDIuNiwxLjMsMy45YzAsMCwwLDAuMSwwLDAuMWMtMC40LDAtMC43LDAtMSwwYzAsMC0wLjEsMC0wLjEtMC4xYy0wLjItMC41LTAuMy0xLTAuNS0xLjVjLTAuMS0wLjMtMC4yLTAuNi0wLjMtMC45YzAtMC4xLDAtMC4xLTAuMS0wLjFjLTAuOSwwLTEuOCwwLTIuNywwYy0wLjEsMC0wLjEsMC0wLjEsMC4xQzcuNSwxMy4yLDcuMiwxNCw3LDE0LjhjMCwwLjEtMC4xLDAuMS0wLjEsMC4xQzYuNSwxNC45LDYuMiwxNC45LDUuOSwxNC44QzUuOSwxNC44LDUuOSwxNC44LDUuOSwxNC44eiBNOS4yLDcuOEM4LjksOS4xLDguNCwxMC4zLDgsMTEuNWMwLjgsMCwxLjYsMCwyLjQsMEMxMCwxMC4zLDkuNSw5LjEsOS4yLDcuOHoiLz48cGF0aCBkPSJNMTcuMyw1YzAuMSwwLDAuMywwLDAuNCwwLjFjMC43LDAuMSwxLjMsMC4zLDEuOSwwLjZjMS4xLDAuNSwyLjEsMS4yLDIuOSwyYzAsMCwwLDAsMC4xLDAuMWMtMC4xLDAtMC4yLDAtMC4zLDBjLTAuOC0wLjYtMS42LTEuMS0yLjYtMS41Yy0wLjctMC4zLTEuNS0wLjUtMi4yLTAuNWMtMS4yLTAuMS0yLjIsMC4yLTMuMywwLjhjLTAuNiwwLjQtMS4yLDAuOC0xLjcsMS4zQzEyLjUsOCwxMi4zLDgsMTIsOGMtMC40LDAtMC45LDAtMS4zLDBjMCwwLTAuMSwwLTAuMSwwYzAsMCwwLjEtMC4xLDAuMS0wLjFjMS4zLTEuNCwyLjgtMi4zLDQuNi0yLjdjMC40LTAuMSwwLjktMC4yLDEuNC0wLjJjMCwwLDAuMSwwLDAuMSwwQzE2LjksNSwxNy4xLDUsMTcuMyw1eiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yNS41LDEyYzAtMC43LDAuMi0xLjQsMC42LTJjMC41LTAuNiwxLjEtMC45LDEuOC0xYzAuNi0wLjEsMS4xLDAsMS42LDAuMmMwLjcsMC4zLDEuMSwwLjgsMS4zLDEuNWMwLjMsMC45LDAuMywxLjktMC4xLDIuN2MtMC40LDAuOS0xLjEsMS4zLTIsMS41Yy0wLjYsMC4xLTEuMiwwLTEuOC0wLjNjLTAuNy0wLjQtMS4xLTEtMS4zLTEuOEMyNS42LDEyLjYsMjUuNiwxMi4zLDI1LjUsMTJ6IE0zMC4xLDEyYzAtMC4yLTAuMS0wLjUtMC4xLTAuN2MtMC4xLTAuNC0wLjMtMC44LTAuNy0xLjFjLTAuNy0wLjYtMS44LTAuNC0yLjMsMC40Yy0wLjMsMC41LTAuNCwxLTAuNCwxLjVjMCwwLjUsMC4xLDEsMC40LDEuNGMwLjYsMSwxLjksMSwyLjYsMEMzMCwxMywzMC4xLDEyLjUsMzAuMSwxMnoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTYuNSwxMC4xQzE2LjMsMTAsMTYsOS45LDE1LjgsOS44Yy0wLjMtMC4xLTAuNi0wLjEtMC45LDBjLTAuMywwLjEtMC41LDAuMy0wLjUsMC42YzAsMC4zLDAuMSwwLjYsMC4zLDAuN2MwLjMsMC4yLDAuNSwwLjMsMC44LDAuNGMwLjMsMC4xLDAuNywwLjMsMSwwLjZjMC40LDAuMywwLjUsMC44LDAuNSwxLjNjLTAuMSwwLjgtMC42LDEuMy0xLjQsMS41Yy0wLjgsMC4yLTEuNSwwLjEtMi4yLTAuMmMtMC4xLDAtMC4xLTAuMS0wLjItMC4xYzAuMS0wLjMsMC4yLTAuNSwwLjItMC44YzAsMCwwLjEsMCwwLjEsMC4xYzAuNSwwLjIsMC45LDAuNCwxLjQsMC4zYzAuMywwLDAuNS0wLjEsMC43LTAuM2MwLjMtMC4zLDAuMy0wLjksMC0xLjJjLTAuMi0wLjItMC40LTAuMy0wLjctMC40Yy0wLjMtMC4xLTAuNy0wLjMtMS0wLjVjLTAuMy0wLjItMC41LTAuNS0wLjYtMC45Yy0wLjEtMC42LDAuMS0xLjMsMC43LTEuN0MxNC41LDkuMSwxNC45LDksMTUuMyw5YzAuNCwwLDAuOSwwLjEsMS4zLDAuM2MwLjEsMC4xLDAuMSwwLjEsMC4xLDAuMkMxNi42LDkuNywxNi42LDkuOSwxNi41LDEwLjF6Ii8+PHBhdGggY2xhc3M9InN0MCIgZD0iTTIxLDkuMWMwLDAuMywwLDAuNSwwLDAuOGMtMC41LDAtMSwwLTEuNSwwYzAsMCwwLDAsMCwwLjFjMCwxLjEsMCwyLjEsMCwzLjJjMCwwLjIsMCwwLjQsMC4xLDAuNWMwLjEsMC4zLDAuMywwLjQsMC42LDAuNGMwLjIsMCwwLjQsMCwwLjcsMGMwLDAuMiwwLDAuNCwwLDAuNWMwLDAuMiwwLDAuMi0wLjIsMC4zYy0wLjQsMC4xLTAuNywwLjEtMS4xLDBjLTAuNi0wLjEtMS0wLjUtMS4xLTEuMWMwLTAuMi0wLjEtMC41LTAuMS0wLjdjMC0xLDAtMi4xLDAtMy4xYzAsMCwwLTAuMSwwLTAuMWMtMC4zLDAtMC42LDAtMC45LDBjMC0wLjMsMC0wLjUsMC0wLjhjMC4zLDAsMC42LDAsMC45LDBjMC0wLjEsMC0wLjIsMC0wLjNjMC0wLjIsMC0wLjUsMC0wLjdjMCwwLDAtMC4xLDAtMC4xYzAuMy0wLjEsMC42LTAuMiwxLTAuM2MwLDAuNSwwLDAuOSwwLDEuNEMyMCw5LjEsMjAuNSw5LjEsMjEsOS4xeiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMi4yLDkuMWMwLjMsMCwwLjYsMCwwLjksMGMwLDAuNCwwLDAuOCwwLDEuMWMwLDAsMCwwLDAsMGMwLDAsMC0wLjEsMC0wLjFjMC4yLTAuNiwwLjYtMSwxLjItMS4xYzAuMiwwLDAuMywwLDAuNSwwQzI1LDksMjUsOSwyNSw5LjFjMCwwLjMsMCwwLjYsMCwwLjljMCwwLDAsMCwwLDBjLTAuMiwwLTAuNCwwLTAuNywwYy0wLjUsMC4xLTAuOCwwLjUtMSwwLjljLTAuMSwwLjMtMC4xLDAuNi0wLjEsMC45YzAsMSwwLDEuOSwwLDIuOWMwLDAsMCwwLjEsMCwwLjFjLTAuMywwLTAuNywwLTEuMSwwQzIyLjIsMTIuOSwyMi4yLDExLDIyLjIsOS4xeiIvPjwvZz48L3N2Zz4=)}.bg-boleto{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfMl8iIGQ9Ik0zLDBoMzBjMS43LDAsMywxLjMsMywzdjE2YzAsMS43LTEuMywzLTMsM0gzYy0xLjcsMC0zLTEuMy0zLTNWM0MwLDEuMywxLjMsMCwzLDB6Ii8+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzYxXzFfIiBjbGFzcz0ic3QwIiBkPSJNMTQsMTZWNmg0YzAuNywwLDEuMywwLjEsMS45LDAuM2MwLjUsMC4yLDAuOSwwLjUsMS4xLDAuOWMwLjMsMC40LDAuNCwwLjgsMC40LDEuM2MwLDAuNC0wLjEsMC44LTAuNCwxLjJjLTAuMywwLjQtMC43LDAuNy0xLjEsMC45YzAuNiwwLjEsMS4xLDAuNSwxLjUsMC45YzAuMywwLjQsMC41LDEsMC41LDEuNWMwLDAuNS0wLjEsMC45LTAuMywxLjNjLTAuMiwwLjQtMC40LDAuNy0wLjgsMC45Yy0wLjQsMC4yLTAuNywwLjQtMS4yLDAuNUMxOS4yLDE2LDE4LjYsMTYsMTgsMTZMMTQsMTZMMTQsMTZ6IE0xNS40LDEwLjJoMi4zYzAuNCwwLDAuOSwwLDEuMy0wLjFjMC4zLTAuMSwwLjYtMC4zLDAuOC0wLjVDMjAsOS4zLDIwLjEsOSwyMC4xLDguN2MwLTAuMy0wLjEtMC42LTAuMy0wLjljLTAuMi0wLjMtMC40LTAuNC0wLjctMC41Yy0wLjUtMC4xLTEuMS0wLjItMS42LTAuMWgtMi4xTDE1LjQsMTAuMkwxNS40LDEwLjJMMTUuNCwxMC4yeiBNMTUuNCwxNC44SDE4YzAuMywwLDAuNiwwLDEsMGMwLjMsMCwwLjYtMC4xLDAuOC0wLjNjMC4yLTAuMSwwLjQtMC4zLDAuNS0wLjZjMC4xLTAuMywwLjItMC41LDAuMi0wLjhjMC0wLjctMC41LTEuNC0xLjEtMS42Yy0wLjUtMC4xLTEtMC4yLTEuNS0wLjJoLTIuNFYxNC44TDE1LjQsMTQuOEwxNS40LDE0Ljh6Ii8+PC9zdmc+)}.bg-diners{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU0XzFfIiBjbGFzcz0ic3QxMiIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTkuMSwxOGgtMi40Yy0zLjctMC4xLTYuNy0zLjItNi42LTYuOUM5LjgsNy40LDEyLjYsNC4yLDE2LjMsNGgyLjdjMy44LDAsNi45LDMuMiw2LjksN2MwLDAsMCwwLDAsMHYwLjFDMjUuOSwxNC45LDIyLjksMTcuOSwxOS4xLDE4eiBNMTYuOCw1LjJjLTMuMi0wLjEtNS44LDIuNC01LjksNS42Yy0wLjEsMy4yLDIuNCw1LjgsNS42LDUuOWMzLjIsMC4xLDUuOC0yLjQsNS45LTUuNmMwLTAuMSwwLTAuMSwwLTAuMkMyMi41LDcuOSwxOS45LDUuMywxNi44LDUuMkwxNi44LDUuMnogTTE3LjcsMTQuOVY3LjJjMi4xLDAuNiwzLjQsMi43LDIuOCw0LjhDMjAuMiwxMy40LDE5LjEsMTQuNSwxNy43LDE0LjlMMTcuNywxNC45eiBNMTUuOSwxNC45Yy0yLjEtMC42LTMuMy0yLjgtMi44LTQuOWMwLjMtMS40LDEuNC0yLjUsMi44LTIuOVYxNC45eiIvPjwvc3ZnPg==)}.bg-discover{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2XzFfIiBjbGFzcz0ic3QxMSIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjkuOSwxMS4zaC0wLjNWOS45aDAuM2MwLjQtMC4xLDAuNywwLjIsMC44LDAuNWMwLDAuMSwwLDAuMSwwLDAuMmMwLDAuNC0wLjMsMC43LTAuNiwwLjhDMzAsMTEuMywyOS45LDExLjMsMjkuOSwxMS4zTDI5LjksMTEuM3ogTTMxLjYsMTAuNWMwLTAuNy0wLjUtMS40LTEuMy0xLjRjLTAuMSwwLTAuMiwwLTAuMywwaC0xLjN2NC44aDAuOVYxMmgwLjFsMS4yLDEuOUgzMmwtMS40LTJDMzEuMiwxMS44LDMxLjcsMTEuMiwzMS42LDEwLjVMMzEuNiwxMC41TDMxLjYsMTAuNXogTTI1LjcsMTMuOWgyLjV2LTAuOGgtMS42di0xLjNoMS41VjExaC0xLjVWOS45aDEuNlY5LjFoLTIuNUwyNS43LDEzLjlMMjUuNywxMy45TDI1LjcsMTMuOXogTTIzLjEsMTIuM2wtMS4yLTMuMkgyMWwxLjksNC45aDAuNWwxLjktNC45aC0wLjlMMjMuMSwxMi4zTDIzLjEsMTIuM3ogTTEyLjcsMTEuNWMwLDEuMywxLDIuNCwyLjMsMi41YzAuNCwwLDAuOC0wLjEsMS4xLTAuM3YtMS4xYy0wLjIsMC4zLTAuNiwwLjUtMSwwLjVjLTAuOCwwLTEuNS0wLjYtMS41LTEuNWMwLDAsMCwwLDAsMHYtMC4xYzAtMC45LDAuNi0xLjYsMS40LTEuN2MwLjQsMCwwLjgsMC4yLDEuMSwwLjVWOS40Yy0wLjMtMC4yLTAuNy0wLjMtMS4xLTAuM2MtMS4zLTAuMS0yLjMsMC45LTIuNCwyLjJDMTIuNywxMS40LDEyLjcsMTEuNCwxMi43LDExLjVMMTIuNywxMS41TDEyLjcsMTEuNXogTTExLjEsMTAuOWMtMC41LTAuMi0wLjctMC4zLTAuNy0wLjZjMC0wLjMsMC4zLTAuNiwwLjYtMC41YzAsMCwwLDAsMCwwYzAuMywwLDAuNSwwLjIsMC43LDAuNGwwLjUtMC42QzExLjgsOS4yLDExLjQsOSwxMC45LDljLTAuNywwLTEuNCwwLjUtMS40LDEuM3YwLjFjMCwwLjYsMC40LDEuMiwxLjEsMS4zYzAuMiwwLjEsMC40LDAuMiwwLjYsMC4zYzAuMiwwLjEsMC4zLDAuMywwLjMsMC41YzAsMC40LTAuMywwLjctMC42LDAuN2gtMC4xYy0wLjQsMC0wLjgtMC4zLTAuOS0wLjZMOS4zLDEzYzAuMywwLjYsMC45LDAuOSwxLjUsMC45YzAuOCwwLDEuNS0wLjYsMS41LTEuNGMwLDAsMCwwLDAsMHYtMC4yQzEyLjQsMTEuNywxMi4xLDExLjQsMTEuMSwxMC45TDExLjEsMTAuOUwxMS4xLDEwLjl6IE04LjEsMTMuOWgwLjlWOS4xSDguMVYxMy45TDguMSwxMy45eiBNNi4zLDEyLjdDNiwxMyw1LjYsMTMuMSw1LjEsMTMuMUg0LjlWOS45aDAuM2MwLjQsMCwwLjksMC4xLDEuMiwwLjRjMC4zLDAuMywwLjUsMC43LDAuNSwxLjJDNi44LDExLjksNi42LDEyLjQsNi4zLDEyLjdMNi4zLDEyLjd6IE01LjMsOS4xSDR2NC44aDEuM2MwLjYsMCwxLjItMC4yLDEuNi0wLjVjMC41LTAuNSwwLjgtMS4xLDAuOC0xLjhjMC4xLTEuMy0wLjktMi4zLTIuMi0yLjRINS4zTDUuMyw5LjF6IE0xOC43LDljLTEuMywwLTIuNCwxLjEtMi40LDIuNWMwLDAsMCwwLDAsMGMwLDEuMywxLDIuNCwyLjQsMi41YzEuMywwLDIuNC0xLjEsMi40LTIuNGMwLDAsMCwwLDAsMEMyMS4yLDEwLjIsMjAuMSw5LjEsMTguNyw5TDE4LjcsOUwxOC43LDl6Ii8+PC9zdmc+)}.bg-enets{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU1XzNfIiBjbGFzcz0ic3QxNSIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTUuNCwxMS44QzE1LjQsMTEuOCwxNS40LDExLjgsMTUuNCwxMS44Yy0wLjEtMC4xLTAuMS0wLjEtMC4yLTAuMmMtMC40LTAuOC0wLjgtMS42LTEuMi0yLjNjLTAuMy0wLjYtMC43LTEuMy0xLTEuOWMwLTAuMS0wLjEtMC4xLTAuMi0wLjFjLTAuNCwwLTAuOSwwLTEuMywwYy0wLjIsMC0wLjIsMC4xLTAuMiwwLjJjMCwyLjEsMCw0LjIsMCw2LjJjMCwwLjEsMC4xLDAuMiwwLjIsMC4yYzAuMywwLDAuNSwwLDAuOCwwYzAuMiwwLDAuMiwwLDAuMi0wLjJjMC0xLjQsMC0yLjgsMC00LjJjMC0wLjEsMC0wLjEsMC0wLjJjMCwwLjEsMC4xLDAuMSwwLjEsMC4yYzAuMywwLjYsMC42LDEuMSwwLjksMS43YzAuNSwwLjksMSwxLjgsMS40LDIuN2MwLDAuMSwwLjEsMC4xLDAuMiwwLjFjMC40LDAsMC45LDAsMS4zLDBjMC4xLDAsMC4yLDAsMC4yLTAuMmMwLTIuMSwwLTQuMiwwLTYuM2MwLTAuMiwwLTAuMi0wLjItMC4yYy0wLjIsMC0wLjUsMC0wLjcsMGMtMC4yLDAtMC4yLDAtMC4yLDAuMmMwLDEuNCwwLDIuOCwwLDQuMUMxNS40LDExLjYsMTUuNCwxMS43LDE1LjQsMTEuOHogTTE5LDguM0MxOSw4LjMsMTksOC4zLDE5LDguM2MwLjksMCwxLjYsMCwyLjQsMGMwLjEsMCwwLjIsMCwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4yLDAtMC4yLTAuMi0wLjJjLTEuMiwwLTIuNSwwLTMuNywwYy0wLjIsMC0wLjIsMC4xLTAuMiwwLjJjMCwwLjMsMCwwLjUsMCwwLjhjMCwxLjgsMCwzLjYsMCw1LjRjMCwwLjIsMCwwLjIsMC4yLDAuMmMxLjMsMCwyLjcsMCw0LDBjMC4xLDAsMC4yLTAuMSwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4yLDAtMC4yLTAuMi0wLjJjLTAuOCwwLTEuNiwwLTIuNCwwYy0wLjEsMC0wLjEsMC0wLjIsMGMwLTAuNiwwLTEuMSwwLTEuN2MwLjEsMCwwLjEsMCwwLjIsMGMwLjYsMCwxLjEsMCwxLjcsMGMwLjEsMCwwLjIsMCwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4yLDAtMC4yLTAuMi0wLjJjLTAuNiwwLTEuMiwwLTEuNywwYy0wLjEsMC0wLjEsMC0wLjIsMEMxOSw5LjIsMTksOC44LDE5LDguM3ogTTcuNSw3Yy0wLjMsMC0wLjUsMC0wLjgsMC4xQzUuOSw3LjMsNS4zLDcuNyw0LjgsOC4zQzQuMSw5LjEsMy45LDEwLDQsMTFjMC4xLDAuOSwwLjYsMS43LDEuMywyLjJjMC44LDAuNiwxLjgsMC45LDIuOCwwLjdjMC43LTAuMSwxLjMtMC41LDEuOC0wLjljMC4zLTAuMywwLjMtMC43LDAtMC45Yy0wLjMtMC4zLTAuNy0wLjMtMC45LDBjLTAuNSwwLjUtMS4xLDAuNy0xLjgsMC42Yy0wLjQtMC4xLTAuOC0wLjItMS4yLTAuNWMtMC41LTAuNS0wLjgtMS4xLTAuNy0xLjhDNS40LDkuOCw1LjYsOS40LDUuOSw5QzYuNCw4LjUsNyw4LjMsNy43LDguNEM4LjIsOC40LDguNiw4LjYsOSw5YzAuMiwwLjIsMC43LDAuMywxLDBjMC4yLTAuMiwwLjItMC43LDAtMC45QzkuOCw4LDkuOCw3LjksOS43LDcuOUM5LjEsNy4zLDguMyw3LjEsNy41LDd6IE0yOS42LDEzLjljMC4zLDAsMC43LTAuMSwxLTAuMWMwLjYtMC4xLDEtMC40LDEuMy0xYzAuMi0wLjMsMC4yLTAuNywwLjItMWMwLTAuNS0wLjItMC45LTAuNi0xLjJjLTAuNC0wLjMtMC44LTAuNi0xLjItMC44Yy0wLjItMC4yLTAuNS0wLjMtMC43LTAuNWMtMC4zLTAuMi0wLjItMC42LDAuMS0wLjhjMC4zLTAuMiwwLjctMC4yLDEuMS0wLjFjMC40LDAuMSwwLjcsMC4yLDEsMC40YzAuMiwwLjEsMC4yLDAsMC4yLTAuMmMwLTAuMywwLTAuNiwwLTAuOGMwLTAuMi0wLjEtMC4yLTAuMi0wLjNjLTAuNC0wLjEtMC43LTAuMi0xLjEtMC4yYy0wLjYsMC0xLjIsMC0xLjcsMC4yYy0wLjQsMC4yLTAuNywwLjQtMC45LDAuOGMtMC4yLDAuMy0wLjIsMC42LTAuMiwxYzAsMC42LDAuMywxLjEsMC44LDEuNWMwLjUsMC40LDEsMC43LDEuNSwxYzAuMiwwLjEsMC4zLDAuMywwLjMsMC42YzAsMC4zLTAuMiwwLjUtMC41LDAuNmMtMC41LDAuMS0xLDAuMS0xLjQtMC4xYy0wLjMtMC4xLTAuNS0wLjItMC43LTAuM2MtMC4yLTAuMS0wLjMsMC0wLjMsMC4xYzAsMC4yLDAsMC41LDAsMC43YzAsMC4xLDAuMSwwLjIsMC4yLDAuM2MwLjEsMC4xLDAuMiwwLjEsMC4zLDAuMUMyOC42LDEzLjgsMjkuMSwxMy45LDI5LjYsMTMuOXogTTI0LDguM2MwLDAuMSwwLDAuMSwwLDAuMmMwLDEuNywwLDMuNCwwLDVjMCwwLjIsMCwwLjIsMC4yLDAuMmMwLjQsMCwwLjgsMCwxLjIsMGMwLjIsMCwwLjIsMCwwLjItMC4yYzAtMS43LDAtMy40LDAtNWMwLTAuMSwwLTAuMSwwLTAuMmMwLjEsMCwwLjEsMCwwLjIsMGMwLjUsMCwxLjEsMCwxLjYsMGMwLjIsMCwwLjIsMCwwLjItMC4yYzAtMC4zLDAtMC41LDAtMC44YzAtMC4xLTAuMS0wLjItMC4yLTAuMmMwLDAtMC4xLDAtMC4xLDBjLTEuNiwwLTMuMywwLTQuOSwwYzAsMC0wLjEsMC0wLjEsMGMtMC4xLDAtMC4yLDAuMS0wLjIsMC4yYzAsMC4zLDAsMC41LDAsMC44YzAsMC4xLDAuMSwwLjIsMC4yLDAuMmMwLjUsMCwxLjEsMCwxLjYsMEMyMy45LDguMywyNCw4LjMsMjQsOC4zeiBNOCwxMS4yYzAuNiwwLDEuMSwwLDEuNywwYzAuMywwLDAuNC0wLjEsMC42LTAuM2MwLjItMC41LTAuMS0xLTAuNi0xYy0xLjEsMC0yLjIsMC0zLjMsMGMtMC40LDAtMC43LDAuMi0wLjcsMC42YzAsMC41LDAuMywwLjcsMC42LDAuN0M2LjgsMTEuMiw3LjQsMTEuMiw4LDExLjJ6Ii8+PC9zdmc+)}.bg-gpay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfN18iIGNsYXNzPSJzdDIzIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnIGlkPSJHUGF5LUxpZ2h0LXRoZW1lZC1idXR0b25zIj48ZyBpZD0iR1BBWS0tLVNWR3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xODUuMDAwMDAwLCAtNDAwLjAwMDAwMCkiPjxnIGlkPSJHUGF5LUJyYW5kLU1hcmsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE4NS4wMDAwMDAsIDQwMC4wMDAwMDApIj48ZyBpZD0iR1BheSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4yNjE0NzQsIDAuMjYxNDc0KSI+PGcgaWQ9IlBheSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTcuNjE1MDY5LCAwLjgyNTcwNikiPjxwYXRoIGlkPSJGaWxsLTEiIGNsYXNzPSJzdDAiIGQ9Ik0tMC42LDcuM3YyLjZIMWMwLjQsMCwwLjctMC4xLDAuOS0wLjRjMC4zLTAuMywwLjQtMC42LDAuNC0wLjljMC0wLjMtMC4xLTAuNi0wLjQtMC45QzEuNyw3LjQsMS40LDcuMywxLDcuM0wtMC42LDcuM0wtMC42LDcuM3ogTS0wLjYsMTAuOHYzaC0xVjYuNEgxYzAuNiwwLDEuMiwwLjIsMS42LDAuNmMwLjUsMC40LDAuNywxLDAuNywxLjZjMCwwLjYtMC4yLDEuMi0wLjcsMS42Yy0wLjQsMC40LTEsMC42LTEuNiwwLjZMLTAuNiwxMC44TC0wLjYsMTAuOHoiLz48cGF0aCBpZD0iRmlsbC0zIiBjbGFzcz0ic3QwIiBkPSJNNC4zLDEyLjNjMCwwLjIsMC4xLDAuNSwwLjMsMC42YzAuMiwwLjIsMC41LDAuMiwwLjcsMC4yYzAuNCwwLDAuOC0wLjEsMS4xLTAuNGMwLjMtMC4zLDAuNS0wLjYsMC41LTEuMWMtMC4zLTAuMi0wLjctMC40LTEuMi0wLjRjLTAuNCwwLTAuNywwLjEtMSwwLjNDNC40LDExLjcsNC4zLDEyLDQuMywxMi4zIE01LjUsOC41YzAuNywwLDEuMywwLjIsMS43LDAuNmMwLjQsMC40LDAuNiwwLjksMC42LDEuNnYzLjFINi45di0wLjdoMEM2LjUsMTMuNyw2LDE0LDUuMywxNGMtMC42LDAtMS0wLjItMS40LTAuNWMtMC40LTAuMy0wLjYtMC43LTAuNi0xLjJjMC0wLjUsMC4yLTAuOSwwLjYtMS4zYzAuNC0wLjMsMC45LTAuNSwxLjYtMC41YzAuNiwwLDEsMC4xLDEuNCwwLjN2LTAuMmMwLTAuMy0wLjEtMC42LTAuNC0wLjhDNi4zLDkuNSw2LDkuNCw1LjYsOS40Yy0wLjUsMC0xLDAuMi0xLjMsMC43TDMuNSw5LjVDMy45LDguOSw0LjYsOC41LDUuNSw4LjUiLz48ZyBpZD0iR3JvdXAtNyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTUuMDg0OTIzLCAzLjc1OTQ0NykiPjxwb2x5Z29uIGlkPSJGaWxsLTUiIGNsYXNzPSJzdDAiIHBvaW50cz0iLTIsNSAtNS4yLDEyLjMgLTYuMiwxMi4zIC01LDkuNyAtNy4xLDUgLTYuMSw1IC00LjUsOC42IC00LjUsOC42IC0zLDUgIi8+PC9nPjwvZz48ZyBpZD0iRyI+PHBhdGggaWQ9IkZpbGwtOCIgY2xhc3M9InN0MCIgZD0iTTEzLjIsMTFjMC0wLjMsMC0wLjYtMC4xLTAuOWgtNHYxLjZoMi4zYy0wLjEsMC41LTAuNCwxLTAuOSwxLjN2MS4xaDEuNEMxMi43LDEzLjQsMTMuMiwxMi4zLDEzLjIsMTEiLz48cGF0aCBpZD0iRmlsbC0xMCIgY2xhc3M9InN0MCIgZD0iTTkuMSwxNS4yYzEuMiwwLDIuMS0wLjQsMi44LTFMMTAuNSwxM2MtMC40LDAuMy0wLjksMC40LTEuNSwwLjRjLTEuMSwwLTIuMS0wLjgtMi40LTEuOEg1LjJ2MS4xQzUuOSwxNC4yLDcuNCwxNS4yLDkuMSwxNS4yIi8+PHBhdGggaWQ9IkZpbGwtMTIiIGNsYXNzPSJzdDAiIGQ9Ik02LjYsMTEuN2MtMC4xLTAuMy0wLjEtMC41LTAuMS0wLjhjMC0wLjMsMC0wLjYsMC4xLTAuOFY5SDUuMmMtMC4zLDAuNi0wLjUsMS4yLTAuNSwxLjljMCwwLjcsMC4yLDEuMywwLjUsMS45TDYuNiwxMS43eiIvPjxwYXRoIGlkPSJGaWxsLTE0IiBjbGFzcz0ic3QwIiBkPSJNOS4xLDguM2MwLjYsMCwxLjIsMC4yLDEuNiwwLjZ2MGwxLjItMS4yQzExLjIsNywxMC4yLDYuNiw5LjEsNi42Yy0xLjcsMC0zLjEsMS0zLjgsMi40bDEuNCwxLjFDNyw5LDcuOSw4LjMsOS4xLDguMyIvPjwvZz48L2c+PC9nPjwvZz48L2c+PC9zdmc+)}.bg-ideal{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHlfMl8xXyIgY2xhc3M9InN0MTkiIGQ9Ik0zLDBoMzBjMS43LDAsMywxLjMsMywzdjE2YzAsMS43LTEuMywzLTMsM0gzYy0xLjcsMC0zLTEuMy0zLTNWM0MwLDEuMywxLjMsMCwzLDB6Ii8+PGc+PHJlY3QgeD0iMTEuNCIgeT0iMTEuOSIgY2xhc3M9InN0MCIgd2lkdGg9IjIuNyIgaGVpZ2h0PSI0LjUiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTQuMyw5LjdjMCwwLjktMC43LDEuNS0xLjUsMS41Yy0wLjksMC0xLjUtMC43LTEuNS0xLjVjMC0wLjksMC43LTEuNSwxLjUtMS41QzEzLjYsOC4xLDE0LjMsOC44LDE0LjMsOS43eiIvPjxnPjxnPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xOS4zLDMuNkg5LjV2MTQuOWg5Ljh2MGMyLjEsMCwzLjgtMC42LDUtMS42YzEuNS0xLjIsMi4yLTMuMiwyLjItNS44YzAtMS4zLTAuMi0yLjQtMC42LTMuNGMtMC40LTAuOS0wLjktMS43LTEuNi0yLjNDMjMuMSw0LjIsMjEuMywzLjYsMTkuMywzLjZDMTkuMywzLjYsMTkuMywzLjYsMTkuMywzLjZ6IE0xOS4xLDQuNmMxLjksMCwzLjUsMC41LDQuNiwxLjVjMS4yLDEuMSwxLjksMi44LDEuOSw1YzAsNC4zLTIuMSw2LjQtNi40LDYuNGMtMC4zLDAtNy44LDAtOC42LDBjMC0wLjksMC0xMiwwLTEyLjlDMTEuMyw0LjYsMTguOCw0LjYsMTkuMSw0LjZ6Ii8+PC9nPjwvZz48Zz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTYsMTAuNmMwLjEsMCwwLjEsMCwwLjItMC4xYzAsMCwwLjEtMC4xLDAuMS0wLjJjMC0wLjEsMC0wLjMsMC0wLjVjMC0wLjIsMC0wLjMsMC0wLjRjMC0wLjEtMC4xLTAuMi0wLjEtMC4yYy0wLjEtMC4xLTAuMS0wLjEtMC4yLTAuMWMwLDAtMC4yLDAtMC40LDBjMCwwLTAuMSwwLTAuMiwwdjEuNmMwLjEsMCwwLjMsMCwwLjMsMEMxNS44LDEwLjYsMTUuOSwxMC42LDE2LDEwLjZ6Ii8+PHBhdGggY2xhc3M9InN0MCIgZD0iTTIwLjgsMTBjMC4xLDAsMC40LDAsMC41LDBjMC0wLjEtMC4yLTAuNS0wLjMtMC43QzIxLDkuNSwyMC45LDkuOSwyMC44LDEweiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMi43LDExLjJWOC41aDAuN2MwLDAsMCwyLDAsMi4xYzAuMSwwLDEsMCwxLjIsMGMtMC4zLTMuOC0zLjItNC44LTYtNC44aC0zLjN2Mi43aDAuNGMwLjIsMCwwLjQsMCwwLjUsMC4xYzAuMiwwLDAuMywwLjEsMC40LDAuM2MwLjEsMC4xLDAuMiwwLjMsMC4zLDAuNEMxNyw5LjQsMTcsOS42LDE3LDkuOGMwLDAuMiwwLDAuNC0wLjEsMC42Yy0wLjEsMC4yLTAuMiwwLjQtMC4zLDAuNWMtMC4xLDAuMS0wLjIsMC4yLTAuNCwwLjJjLTAuMSwwLTAuMywwLjEtMC41LDAuMWgtMC40djUuM2gzLjNjMi45LDAsNS45LTAuOSw2LTUuM0gyMi43eiBNMTkuNSwxMS4yaC0yLjFWOC41aDIuMVY5YzAsMC0xLjMsMC0xLjQsMGMwLDAuMSwwLDAuMywwLDAuNGMwLjEsMCwxLjMsMCwxLjMsMFYxMGMwLDAtMS4yLDAtMS4zLDBjMCwwLjEsMCwwLjUsMCwwLjZjMC4xLDAsMS40LDAsMS40LDBWMTEuMnogTTIxLjgsMTEuMmMwLDAtMC4yLTAuNS0wLjItMC42Yy0wLjEsMC0wLjgsMC0wLjksMGMwLDAuMS0wLjIsMC42LTAuMiwwLjZoLTAuN2wxLjEtMi43aDAuN2wxLjEsMi43SDIxLjh6Ii8+PC9nPjwvZz48L3N2Zz4=)}.bg-jcb{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU3XzJfIiBjbGFzcz0ic3QxMyIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48Zz48ZyBpZD0iZzYzMjciPjxwYXRoIGlkPSJwYXRoNjMzOCIgY2xhc3M9InN0MCIgZD0iTTIyLjcsMTIuNWgxLjNjMCwwLDAuMSwwLDAuMiwwYzAuMy0wLjEsMC41LTAuMywwLjUtMC42YzAtMC4zLTAuMi0wLjUtMC41LTAuNmMwLDAtMC4xLDAtMC4yLDBoLTEuM1YxMi41TDIyLjcsMTIuNXoiLz48cGF0aCBpZD0icGF0aDYzNDkiIGNsYXNzPSJzdDAiIGQ9Ik0yMy45LDRjLTEuMywwLTIuMywxLTIuMywyLjN2Mi40aDMuM2MwLjEsMCwwLjIsMCwwLjIsMGMwLjcsMCwxLjMsMC40LDEuMywxLjFjMCwwLjUtMC40LDEtMS4xLDEuMXYwYzAuOCwwLjEsMS4zLDAuNSwxLjMsMS4xYzAsMC43LTAuNiwxLjItMS41LDEuMmgtMy42VjE4SDI1YzEuMywwLDIuMy0xLDIuMy0yLjNWNEwyMy45LDRMMjMuOSw0eiIvPjxwYXRoIGlkPSJwYXRoNjM2MCIgY2xhc3M9InN0MCIgZD0iTTI0LjUsMTBjMC0wLjMtMC4yLTAuNS0wLjUtMC42YzAsMC0wLjEsMC0wLjEsMGgtMS4ydjEuMWgxLjJjMCwwLDAuMSwwLDAuMSwwQzI0LjMsMTAuNSwyNC41LDEwLjMsMjQuNSwxMHoiLz48L2c+PHBhdGggaWQ9InBhdGg2MzcxIiBjbGFzcz0ic3QwIiBkPSJNMTEsNEM5LjcsNCw4LjcsNSw4LjcsNi4zdjUuOGMwLjcsMC4zLDEuMywwLjUsMiwwLjVjMC44LDAsMS4yLTAuNSwxLjItMS4yVjguN2gydjIuN2MwLDEuMS0wLjcsMS45LTIuOSwxLjljLTEuMywwLTIuNC0wLjMtMi40LTAuM1YxOGgzLjRjMS4zLDAsMi4zLTEsMi4zLTIuM1Y0QzE0LjQsNCwxMSw0LDExLDR6Ii8+PHBhdGggaWQ9InBhdGg2Mzg0IiBjbGFzcz0ic3QwIiBkPSJNMTcuNSw0Yy0xLjMsMC0yLjMsMS0yLjMsMi4zdjMuMWMwLjYtMC41LDEuNi0wLjgsMy4zLTAuN2MwLjksMCwxLjgsMC4zLDEuOCwwLjN2MWMtMC41LTAuMi0xLTAuNS0xLjgtMC41Yy0xLjMtMC4xLTIsMC41LTIsMS42YzAsMS4xLDAuOCwxLjcsMiwxLjZjMC43LTAuMSwxLjMtMC4zLDEuOC0wLjV2MWMwLDAtMC45LDAuMi0xLjgsMC4zYy0xLjcsMC4xLTIuNy0wLjItMy4zLTAuN1YxOGgzLjRjMS4zLDAsMi4zLTEsMi4zLTIuM1Y0QzIwLjksNCwxNy41LDQsMTcuNSw0eiIvPjwvZz48L3N2Zz4=)}.bg-maestro{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzUzXzNfIiBjbGFzcz0ic3Q0IiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxjaXJjbGUgY2xhc3M9InN0OCIgY3g9IjE0IiBjeT0iMTEiIHI9IjYiLz48Y2lyY2xlIGlkPSJFbGxpcHNlXzhfY29weV8zXyIgY2xhc3M9InN0OSIgY3g9IjIyIiBjeT0iMTEiIHI9IjYiLz48cGF0aCBpZD0iUm91bmRlZF9SZWN0YW5nbGVfMjVfM18iIGNsYXNzPSJzdDEwIiBkPSJNMTgsNmMtMi44LDEuNS0zLjgsNC45LTIuMyw3LjZjMC40LDAuOCwxLDEuNCwxLjcsMS45YzAuMiwwLjIsMC41LDAuMywwLjcsMC40bDAuMSwwYzIuNy0xLjQsMy43LTQuOSwyLjMtNy42QzE5LjgsNy40LDE5LDYuNSwxOCw2Ii8+PC9zdmc+)}.bg-mastercard{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzUzXzRfIiBjbGFzcz0ic3QzIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxjaXJjbGUgY2xhc3M9InN0NSIgY3g9IjE0IiBjeT0iMTEiIHI9IjYiLz48Y2lyY2xlIGlkPSJFbGxpcHNlXzhfY29weV80XyIgY2xhc3M9InN0NiIgY3g9IjIyIiBjeT0iMTEiIHI9IjYiLz48cGF0aCBpZD0iUm91bmRlZF9SZWN0YW5nbGVfMjVfNF8iIGNsYXNzPSJzdDciIGQ9Ik0xOCw2TDE4LDZjLTIuOCwxLjUtMy44LDQuOS0yLjMsNy42YzAuNCwwLjgsMSwxLjQsMS43LDEuOWMwLjIsMC4yLDAuNSwwLjMsMC43LDAuNGwwLjEsMGMyLjctMS40LDMuNy00LjksMi4zLTcuNkMxOS44LDcuNCwxOSw2LjUsMTgsNiIvPjwvc3ZnPg==)}.bg-mol{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfMTJfIiBjbGFzcz0ic3QyNiIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjYuOSwxMy4xYy0wLjUsMC0wLjYtMC4xLTAuNi0wLjZjMC0xLjEsMC0yLjIsMC0zLjNjMC0xLjItMC4yLTEuNC0xLjQtMS40Yy0yLDAtNC4xLDAtNi4xLDBjLTEuMSwwLTIuNSwxLjQtMi41LDIuNWMwLDEuMiwwLDIuNCwwLDMuNmMtMC4yLDAtMC4xLTAuMy0wLjMtMC4zYy0xLTAuMS0wLjgtMC45LTAuOC0xLjVjMC0xLjMsMC0yLjUtMC45LTMuNkMxNCw4LDEzLjcsNy44LDEzLjIsNy44Yy0yLjEsMC00LjIsMC02LjMsMEM2LDcuOCw1LjcsOC4xLDUuNyw5YzAsMS42LDAsMy4yLDAsNC44YzAsMC43LDAuMywxLjEsMC45LDEuMWMwLjYsMCwwLjktMC40LDAuOS0xLjFjMC0xLDAtMiwwLTNjMC0xLjIsMC0xLjIsMS4yLTEuMmMwLjYsMCwwLjcsMC4yLDAuNywwLjdjMCwxLjEsMCwyLjIsMCwzLjNjMCwwLjgsMC4zLDEuMywxLDEuM2MwLjYsMCwwLjktMC40LDAuOS0xLjJjMC0xLjIsMC0yLjMsMC0zLjVjMC0wLjQsMC4xLTAuNiwwLjYtMC42YzAuOSwwLDEuNCwwLjUsMS40LDEuNGMwLDAuOSwwLDEuOCwwLDIuN2MwLDAuOCwwLjMsMS4xLDEuMSwxLjFjMi4yLDAsNC40LDAsNi42LDBjMC4zLDAsMC41LDAsMC43LTAuMmMwLjUtMC42LDEuMS0xLjEsMS41LTEuOGMwLjEtMS4xLDAtMi4yLDAtMy4zYzAtMC4xLTAuMi0wLjQsMC4yLTAuNWMwLjgsMC4xLDAuOSwwLjYsMC45LDEuM2MtMC4xLDEuMSwwLDIuMywwLDMuNGMwLDAuOCwwLjMsMSwxLjEsMWMwLjksMCwxLjktMC4xLDIuOCwwYzEuNSwwLjIsMi4xLTAuOSwzLTEuOUMyOS43LDEzLjEsMjguMywxMywyNi45LDEzLjF6IE0yMS41LDEyYzAsMC45LTAuNywxLjQtMS44LDEuNGMtMS41LDAtMS41LDAtMS41LTEuNWMwLDAsMC0wLjEsMC0wLjFjMC0wLjQsMC0wLjgsMC0xLjJjMC0wLjgsMC43LTEuMywxLjctMS4zYzEuNiwwLDEuNiwwLDEuNiwxLjZDMjEuNSwxMS4zLDIxLjUsMTEuNywyMS41LDEyeiIvPjwvc3ZnPg==)}.bg-paypal{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU4XzFfIiBjbGFzcz0ic3QxMyIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjMsOS45YzAsMC4zLDAsMC41LTAuMSwwLjhjLTAuMiwxLjgtMS45LDMuMi0zLjcsM2gtMC4zYy0wLjIsMC0wLjQsMC4yLTAuNSwwLjRMMTgsMTYuNmMwLDAuMi0wLjIsMC40LTAuNSwwLjRoLTEuNGMtMC4yLDAtMC4zLTAuMS0wLjMtMC4zYzAsMCwwLDAsMCwwbDAuNy00LjRsMCwwaDEuMWMyLjMsMC4yLDQuNC0xLjUsNC43LTMuOEMyMi44LDguOCwyMyw5LjMsMjMsOS45eiBNMTUuOSwxMmMwLTAuMywwLjItMC42LDAuNi0wLjZjMCwwLDAuMSwwLDAuMSwwaDEuMWMyLjMsMCwzLjYtMSw0LTMuMmMwLjQtMi4xLTEuMS0zLjItMy0zLjJIMTVjLTAuMywwLTAuNSwwLjItMC41LDAuNWMtMS4yLDcuNC0xLjUsOS4zLTEuNSw5LjljMCwwLjIsMC4xLDAuMywwLjMsMC4zYzAsMCwwLDAsMCwwaDJMMTUuOSwxMnoiLz48L3N2Zz4=)}.bg-poli{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfOV8iIGNsYXNzPSJzdDMxIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnIGlkPSJwb2xpXzFfIj48cGF0aCBpZD0icG9saS1sb2dvXzFfIiBjbGFzcz0ic3QwIiBkPSJNMTguNSwxNC44YzAuMy0wLjEsMC43LTAuNCwxLTAuNmMwLjgtMC43LDEuNy0yLDEuNi0zLjVDMjEsOSwyMC4xLDcuOSwxOSw3LjNjMC4zLDAuMSwwLjYsMC4zLDAuOSwwLjVjMC43LDAuNiwxLjMsMS41LDEuMywyLjhjMCwxLjctMC45LDIuOS0xLjgsMy43YzAuMy0wLjEsMC41LTAuNCwwLjctMC43YzAuNi0wLjcsMS4yLTEuOCwxLjItMy4xYzAtMS44LTEtMi45LTIuMi0zLjZjMC40LDAuMSwwLjgsMC40LDEsMC42YzAuNywwLjYsMS40LDEuNywxLjMsMy4xYy0wLjEsMS40LTAuNywyLjUtMS42LDMuNGMtMC45LDAuOC0yLDEuNC0zLjQsMS41Yy0wLjEsMC0wLjMsMC0wLjUsMGMtMi4xLTAuMi0zLjYtMS41LTMuOC0zLjZjMC0wLjIsMC0wLjQsMC0wLjZjMC4xLTEuMywwLjctMi4zLDEuNS0zLjFjMC44LTAuOSwxLjktMS41LDMuNC0xLjZDMTcsNi42LDE3LDYuNCwxNyw2LjNjMC41LDAuNSwxLjEsMS4xLDEuNywxLjdjLTAuNywwLjQtMS41LDAuOC0yLjIsMS4yYzAtMC4xLDAtMC4zLDAuMS0wLjRjLTEuMiwwLjItMi4zLDEuMS0yLjUsMi40Yy0wLjMsMS41LDAuOCwyLjcsMi4yLDIuN2MxLjUsMCwyLjgtMS4xLDMtMi41YzAuMi0xLjEtMC4zLTEuOC0wLjktMi4zYzAuNiwwLjQsMS4yLDEsMS4xLDJjLTAuMSwxLjYtMS42LDIuOS0zLjEsMi45Yy0wLjgsMC0xLjYtMC40LTIuMS0xYzAuNSwwLjcsMS40LDEuMSwyLjQsMWMwLjgtMC4xLDEuNC0wLjQsMS45LTAuOWMwLjUtMC41LDAuOS0xLjEsMS0xLjhjMC0wLjMsMC0wLjYsMC0wLjhjLTAuMS0wLjgtMC42LTEuMi0xLjEtMS43YzAuNiwwLjUsMS4zLDEuMiwxLjMsMi4zYy0wLjEsMS42LTEuNiwzLTMuMiwzLjFjLTEuMSwwLjEtMS43LTAuMy0yLjMtMC44YzAuNSwwLjcsMS41LDEsMi42LDAuOGMxLjUtMC4yLDIuOC0xLjUsMy0zYzAuMS0xLjQtMC42LTItMS4yLTIuN2MwLjcsMC41LDEuMywxLjEsMS40LDIuMmMwLDEtMC40LDEuOS0xLDIuNWMtMSwxLTIuOCwxLjYtNC4zLDAuN2MxLjIsMC45LDMuMiwwLjQsNC4yLTAuNWMwLjctMC43LDEuMy0xLjYsMS4yLTIuOWMtMC4xLTEuMS0wLjctMS42LTEuNC0yLjJjMC43LDAuNCwxLjQsMS4xLDEuNSwyLjFjMC4xLDEuNC0wLjUsMi40LTEuMywzLjFjLTAuOSwwLjgtMi4yLDEuMy0zLjcsMC45YzIuNCwwLjgsNC43LTEuMSw1LTMuMWMwLjItMS41LTAuNS0yLjQtMS4zLTNjLTAuMS0wLjEtMC4xLTAuMS0wLjItMC4yYzEsMC41LDEuOSwxLjcsMS42LDMuNGMtMC40LDItMi40LDMuNi00LjksMy4yYzAuNCwwLjEsMC44LDAuMSwxLjIsMC4xYzEuMi0wLjEsMi4yLTAuNiwyLjgtMS4zYzAuNy0wLjgsMS4yLTEuNywxLjEtMy4xYy0wLjEtMS4yLTAuOC0xLjgtMS42LTIuNWMwLjQsMC4xLDAuNywwLjQsMC45LDAuN2MwLjQsMC41LDAuOCwxLjEsMC44LDEuOWMwLjEsMS40LTAuNiwyLjUtMS4zLDMuMmMtMC44LDAuOC0xLjgsMS4zLTMuMSwxLjNjMi4xLDAuMSwzLjQtMS4yLDQuMS0yLjZjMC40LTAuOCwwLjUtMiwwLjItMi44Yy0wLjMtMC44LTAuOS0xLjQtMS42LTEuOGMxLjEsMC42LDIuMSwxLjcsMS45LDMuNWMtMC4xLDAuNy0wLjMsMS4yLTAuNiwxLjdjLTAuNiwxLTEuNiwxLjgtMi44LDIuMmMwLjgtMC4yLDEuNi0wLjcsMi4yLTEuM2MwLjctMC44LDEuMy0xLjgsMS4yLTMuMmMwLTEuNS0xLTIuNC0xLjktM2MwLDAsMCwwLDAsMGMxLDAuNSwxLjgsMS40LDIsMi44QzIxLjIsMTIuNCwxOS44LDE0LDE4LjUsMTQuOCIvPjxwYXRoIGlkPSJwb2xpLXR4dF8xXyIgY2xhc3M9InN0MzQiIGQ9Ik04LDExLjRjMCwwLDAsMCwwLjEsMGMwLjcsMCwwLjktMC4yLDEtMC4zYzAuMi0wLjIsMC4yLTAuNywwLjItMS4xYzAtMC40LDAtMC43LTAuMy0xQzguOSw4LjgsOC40LDguNyw4LDguN2wwLDAuMUw4LDExLjRMOCwxMS40eiBNNS42LDE1LjRWNy4yaDIuMWMwLjgsMCwxLjUsMCwxLjksMC4xYzAuNCwwLjEsMC45LDAuMiwxLjEsMC40YzAuMywwLjIsMC42LDAuNSwwLjgsMC45YzAuMiwwLjQsMC4zLDAuOSwwLjMsMS41YzAsMC45LTAuMiwxLjctMC43LDIuMWMtMC41LDAuNS0xLjYsMC43LTIuNSwwLjdIOHYyLjVINS42eiBNMjcuNCwxNS4zSDIyVjcuMmgyLjZ2NS43aDIuN1YxNS4zeiBNMzAuNCwxNS40aC0yLjVWMTBoMi41VjE1LjR6IE0zMC40LDkuNGgtMi42VjcuMmgyLjZWOS40eiIvPjwvZz48L3N2Zz4=)}.bg-qiwi{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfMTFfIiBjbGFzcz0ic3QyOCIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTAuOSwxNC44YzAuMSwwLjMsMC4yLDAuNSwwLjQsMC43YzAuMiwwLjIsMC40LDAuNCwwLjYsMC41YzAuMiwwLjEsMC41LDAuMywwLjcsMC4zYzAuMSwwLjEsMC4zLDAuMSwwLjQsMC4xYzAuMSwwLDAuMiwwLjEsMC4zLDAuM2MwLDAuMi0wLjEsMC4zLTAuMywwLjNjLTAuMiwwLTAuMy0wLjEtMC41LTAuMWMtMC45LTAuMS0xLjctMC42LTIuNC0xLjJjLTAuMS0wLjEtMC4yLTAuMi0wLjMtMC40UzkuNiwxNSw5LjUsMTQuOWMtMC42LTAuMS0xLjItMC40LTEuNi0wLjhjLTAuNC0wLjUtMC43LTEuMS0wLjgtMS43QzYuOSwxMS43LDcsMTEsNy4yLDEwLjJDNy40LDksOC42LDgsOS45LDhjMC40LDAsMC44LDAuMSwxLjEsMC4yYzAuMywwLjEsMC43LDAuMywwLjksMC42YzAsMCwwLDAsMCwwQzEyLDguOSwxMi4yLDksMTIuMiw5LjFjMCwwLDAsMC4xLDAsMC4xYzAsMCwwLjEsMC4xLDAuMSwwLjFzMCwwLDAsMC4xczAsMC4xLDAuMSwwLjFjMCwwLDAsMCwwLDBjMCwwLjEsMC4xLDAuMiwwLjEsMC4zczAuMSwwLjIsMC4xLDAuM2MwLjEsMC4zLDAuMiwwLjYsMC4yLDAuOWMwLjEsMC44LTAuMSwxLjctMC40LDIuNGMtMC4yLDAuMy0wLjQsMC42LTAuNywwLjhDMTEuNSwxNC41LDExLjIsMTQuNywxMC45LDE0Ljh6IE05LjcsOC44QzkuNiw4LjksOS40LDguOSw5LjIsOUM5LjEsOS4xLDksOS4yLDguOSw5LjNDOC44LDkuNCw4LjcsOS41LDguNiw5LjdjLTAuMSwwLjMtMC4yLDAuNS0wLjIsMC44Yy0wLjEsMC4zLTAuMSwwLjYtMC4xLDFjMCwwLjcsMC4xLDEuNSwwLjUsMi4xQzksMTMuOCw5LjIsMTQsOS41LDE0LjFjMC4yLDAsMC4zLDAuMSwwLjUsMC4xYzAuMSwwLDAuMiwwLDAuMy0wLjFjMC4xLDAsMC4yLDAsMC4zLTAuMWMwLjEtMC4xLDAuMS0wLjEsMC4yLTAuMmMwLjEtMC4xLDAuMi0wLjIsMC4zLTAuM2MwLTAuMSwwLjEtMC4yLDAuMS0wLjJjMC40LTEsMC41LTIuMSwwLjItMy4yYy0wLjEtMC4zLTAuMi0wLjYtMC40LTAuOGMtMC4yLTAuMi0wLjQtMC4zLTAuNi0wLjVDMTAuMiw4LjgsMTAsOC44LDkuNyw4LjhDOS44LDguOCw5LjgsOC44LDkuNyw4LjhMOS43LDguOEw5LjcsOC44eiBNMTQuNyw4LjJjMC40LDAsMC44LDAsMS4xLDBjMC4xLDAuMSwwLjEsMC4zLDAsMC40YzAsMS43LDAsMy42LDAsNS40YzAsMC4xLDAsMC4zLDAsMC40YzAsMC4xLDAsMC4yLDAsMC40Yy0wLjIsMC0wLjQsMC0wLjYsMGMtMC4yLDAtMC40LDAtMC42LDBDMTQuNiwxMi42LDE0LjYsMTAuNCwxNC43LDguMkMxNC42LDguMiwxNC43LDguMiwxNC43LDguMkwxNC43LDguMnogTTE3LjUsOC4yaDEuMWMwLjEsMC4yLDAuMSwwLjQsMC4yLDAuNWMwLjMsMS4zLDAuNywyLjYsMSwzLjljMC4xLDAsMC0wLjEsMC4xLTAuMXMwLTAuMSwwLTAuMWMwLTAuMSwwLjEtMC4yLDAuMS0wLjNjMC4xLTAuMiwwLjEtMC40LDAuMi0wLjVjMC4xLTAuNCwwLjItMC43LDAuMy0xLjFzMC4yLTAuNywwLjMtMS4xYzAuMi0wLjMsMC4yLTAuOCwwLjQtMS4xaDAuNWMwLjIsMC4zLDAuMiwwLjgsMC40LDEuMWMwLjEsMC40LDAuMiwwLjcsMC4zLDEuMWMwLjIsMC43LDAuNSwxLjUsMC43LDIuMmMwLjEtMC4yLDAuMS0wLjQsMC4yLTAuNWMwLTAuMiwwLjEtMC40LDAuMS0wLjVjMC4yLTAuOCwwLjQtMS41LDAuNi0yLjJjMC4xLTAuNCwwLjItMC43LDAuMy0xLjFjMC4zLDAsMC42LDAsMSwwYzAsMC4zLTAuMSwwLjYtMC4yLDAuOGMwLDAuMy0wLjIsMC41LTAuMiwwLjhjLTAuMiwwLjUtMC4zLDEuMS0wLjUsMS42Yy0wLjEsMC42LTAuMywxLjEtMC40LDEuN2MtMC4xLDAuMy0wLjIsMC42LTAuMiwwLjhjLTAuMSwwLjMtMC4xLDAuNS0wLjMsMC44aC0wLjdjLTAuMi0wLjMtMC4yLTAuNy0wLjQtMWMtMC4zLTEtMC43LTIuMS0xLTMuMWMtMC4xLDAuMi0wLjEsMC4zLTAuMiwwLjVjMCwwLjItMC4xLDAuNC0wLjIsMC41Yy0wLjEsMC40LTAuMiwwLjctMC4zLDFjLTAuMSwwLjMtMC4yLDAuNy0wLjMsMWMtMC4xLDAuMy0wLjIsMC43LTAuNCwxYy0wLjIsMC0wLjQsMC0wLjcsMEMxOS4xLDE0LjUsMTksMTQuMywxOSwxNGMtMC4xLTAuMy0wLjEtMC42LTAuMi0wLjhjLTAuMS0wLjYtMC4zLTEuMS0wLjQtMS43Yy0wLjItMC41LTAuMy0xLjEtMC41LTEuNmMtMC4xLTAuMy0wLjItMC41LTAuMi0wLjhDMTcuNSw4LjgsMTcuNCw4LjUsMTcuNSw4LjJDMTcuNSw4LjIsMTcuNSw4LjIsMTcuNSw4LjJMMTcuNSw4LjJ6IE0yNi44LDguMmMwLjQsMCwwLjgsMCwxLjEsMEMyOCw4LjUsMjgsOC43LDI4LDl2NWMwLDAuMywwLDAuNSwwLDAuOGMtMC4zLDAtMC42LDAtMC45LDBjLTAuMSwwLTAuMiwwLTAuMywwYy0wLjEtMC4zLTAuMS0wLjUsMC0wLjhWOUMyNi42LDguNywyNi43LDguNSwyNi44LDguMkMyNi43LDguMiwyNi44LDguMiwyNi44LDguMnoiLz48L3N2Zz4=)}.bg-safetypay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfMTBfIiBjbGFzcz0ic3QyOSIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTgsNGwtNyw3bDcsN2w3LTdMMTgsNHogTTE2LjYsMTUuM2wtMi4xLTIuMWwyLjEtMi4xbC0yLjEtMi4xbDIuMS0yLjFMMTguOCw5bDIuMSwyLjFMMTYuNiwxNS4zeiBNMjIuOSwxMS44bC0zLjUsMy41bC0wLjgtMC44bDMuNS0zLjVsLTMuNS0zLjVsMC44LTAuOGw0LjMsNC4zTDIyLjksMTEuOEwyMi45LDExLjhMMjIuOSwxMS44eiIvPjwvc3ZnPg==)}.bg-sepa{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHlfMl8zXyIgY2xhc3M9InN0MjUiIGQ9Ik0zLDBoMzBjMS43LDAsMywxLjMsMywzdjE2YzAsMS43LTEuMywzLTMsM0gzYy0xLjcsMC0zLTEuMy0zLTNWM0MwLDEuMywxLjMsMCwzLDB6Ii8+PGc+PHBhdGggY2xhc3M9InN0MCIgZD0iTTExLjIsOS44SDkuNWMwLTAuMiwwLTAuNC0wLjEtMC42QzkuMyw5LjEsOSw5LDguNiw5QzguMyw5LDgsOSw3LjcsOS4xQzcuNSw5LjMsNy40LDkuNSw3LjUsOS43YzAsMC4yLDAsMC40LDAuMiwwLjVjMC4xLDAuMSwwLjIsMC4xLDAuNCwwLjFsMC4zLDBjMC43LDAsMS4yLDAuMSwxLjQsMC4xYzAuNSwwLDAuOSwwLjIsMS4zLDAuNWMwLjIsMC4yLDAuMywwLjUsMC40LDAuOGMwLDAuMiwwLDAuNCwwLDAuNmMwLDAuNCwwLDAuOC0wLjIsMS4yYy0wLjIsMC41LTAuNiwwLjgtMS4zLDAuOWMtMC40LDAuMS0wLjgsMC4xLTEuMywwLjFjLTAuNywwLTEuMywwLTItMC4yYy0wLjQtMC4xLTAuOC0wLjQtMC45LTAuOGMtMC4xLTAuNC0wLjEtMC44LTAuMS0xLjJoMS43YzAsMC4xLDAsMC4xLDAsMC4xYzAsMC4yLDAuMSwwLjQsMC4yLDAuNkM3LjgsMTMsNy45LDEzLDgsMTNoMC42YzAuMiwwLDAuNCwwLDAuNi0wLjFjMC4xLDAsMC4zLTAuMiwwLjMtMC4zYzAtMC4xLDAtMC4yLDAtMC4zYzAtMC4yLTAuMS0wLjUtMC4zLTAuNWMtMC40LTAuMS0wLjctMC4xLTEuMS0wLjFjLTAuNSwwLTAuOS0wLjEtMS4xLTAuMWMtMC40LDAtMC44LTAuMy0xLjEtMC42Yy0wLjItMC40LTAuMy0wLjgtMC4yLTEuMmMwLTAuMywwLTAuNywwLjEtMWMwLjEtMC4yLDAuMi0wLjQsMC40LTAuNkM2LjYsNy45LDcsNy43LDcuMyw3LjdjMC40LDAsMC44LDAsMS4yLDBjMC41LDAsMSwwLDEuNSwwLjFjMC43LDAuMiwxLjEsMC43LDEuMSwxLjdDMTEuMiw5LjUsMTEuMiw5LjYsMTEuMiw5Ljh6IE0xOC42LDE0LjRWNy42aDMuNGMwLjQsMCwwLjcsMCwxLjEsMC4xYzAuNSwwLjEsMC45LDAuNSwxLjEsMS4xYzAuMSwwLjQsMC4yLDAuOCwwLjEsMS4zYzAsMC41LDAsMS0wLjIsMS41Yy0wLjIsMC42LTAuNywxLTEuMywxYy0wLjEsMC0wLjQsMC0xLDBsLTAuMywwaC0xLjF2MS43SDE4LjZ6IE0yMC40LDExLjFoMS4xYzAuMiwwLDAuNCwwLDAuNy0wLjFjMC4xLTAuMSwwLjItMC4yLDAuMi0wLjRjMC0wLjIsMC0wLjQsMC0wLjVjMC0wLjIsMC0wLjQtMC4xLTAuNmMtMC4xLTAuMi0wLjMtMC4zLTAuNS0wLjRjLTAuMSwwLTAuMiwwLTAuNCwwaC0xLjFMMjAuNCwxMS4xTDIwLjQsMTEuMXogTTI4LjEsMTMuMmgtMi40bC0wLjMsMS4yaC0xLjlsMi02LjdoMi43bDIsNi43aC0xLjhMMjguMSwxMy4yeiBNMjcuOCwxMS45TDI2LjksOWwtMC44LDIuOUgyNy44eiIvPjxwYXRoIGNsYXNzPSJzdDM2IiBkPSJNMTQsOS44aDMuN2wwLDBsLTAuNCwxbDAsMGgtMy42bDAsMGMwLDAuMSwwLDAuMiwwLDAuMmMwLDAuMSwwLDAuMiwwLDAuNGwwLDBIMTdsMCwwbC0wLjUsMWwwLDBIMTRsMCwwYzAuNywxLjEsMi4yLDEuNCwzLjMsMC43YzAuMi0wLjEsMC40LTAuMywwLjUtMC40bC0wLjEsMHYxLjJsMCwwYy0xLjYsMS0zLjcsMC42LTQuNy0wLjljLTAuMS0wLjItMC4yLTAuMy0wLjMtMC41bDAsMGgtMS4ybDAsMGwwLjQtMWwwLDBoMC41bDAsMGMwLTAuMSwwLTAuMiwwLTAuM2MwLTAuMSwwLTAuMiwwLTAuM2wwLDBoLTFsMCwwbDAuNS0xbDAsMGgwLjhsMCwwYzAuMi0wLjYsMC43LTEuMSwxLjItMS41YzEuMy0wLjksMy4xLTAuNyw0LjIsMC4zbDAsMGwtMC40LDAuOGwwLDBjLTAuOC0xLTIuNC0xLjItMy40LTAuNEMxNC4zLDkuMywxNC4xLDkuNSwxNCw5LjhMMTQsOS44TDE0LDkuOEwxNCw5Ljh6Ii8+PC9nPjwvc3ZnPg==)}.bg-sofort{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHlfMV8iIGNsYXNzPSJzdDMwIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yMC43LDVjLTEuMS0wLjEtMi4yLDAuMS0zLjMsMC41Yy0xLjMsMC43LTIuMiwxLjktMi42LDMuNGMtMC4xLDAuMy0wLjIsMC43LTAuMiwxLjFjMCwwLjMsMCwwLjYsMC4yLDAuOGMwLjIsMC4zLDAuNCwwLjYsMC43LDAuOGMwLjMsMC4yLDAuNywwLjQsMS4xLDAuNWwwLjUsMC4xYzAuMywwLjEsMC42LDAuMiwwLjcsMC4yYzAuMSwwLDAuMiwwLjEsMC4zLDAuMWMwLjEsMC4xLDAuMiwwLjEsMC4zLDAuM2MwLDAuMSwwLjEsMC4yLDAuMSwwLjJjMCwwLjEsMCwwLjItMC4xLDAuM2MtMC4xLDAuMi0wLjMsMC40LTAuNSwwLjVjLTAuNCwwLjEtMC44LDAuMi0xLjMsMC4xSDkuMkw4LDE3aDhjMS4yLDAsMi40LTAuMSwzLjUtMC41YzEuNi0wLjYsMi44LTIsMy4xLTMuN2MwLjItMC43LDAuMS0xLjQtMC4yLTJjLTAuNC0wLjYtMS4xLTEtMS44LTEuMWwtMC40LTAuMWwtMC42LTAuMmMtMC4yLDAtMC40LTAuMi0wLjUtMC4zQzE5LDguOSwxOC45LDguNywxOSw4LjVjMC4xLTAuMiwwLjItMC40LDAuNC0wLjVjMC4zLTAuMSwwLjUtMC4yLDAuOC0wLjJoNC43YzAsMCwwLjEtMC4xLDAuMS0wLjFjMC44LTEuMSwxLjgtMiwzLTIuN0gyMC43TDIwLjcsNXoiLz48L3N2Zz4=)}.bg-tenpay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfOF8iIGNsYXNzPSJzdDMyIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGlkPSJUZW5wYXktMl8xXyIgY2xhc3M9InN0MCIgZD0iTTcuNCwxMy42aDFWOS45aDEuNFY5SDZ2MC45aDEuNFYxMy42eiBNMTAuNiwxMi42YzAuMSwwLjIsMC4yLDAuNCwwLjQsMC42YzAuMiwwLjIsMC40LDAuMywwLjYsMC40YzAuMiwwLjEsMC41LDAuMSwwLjgsMC4xYzAuMiwwLDAuNSwwLDAuNy0wLjFjMC4yLTAuMSwwLjUtMC4yLDAuNy0wLjNsLTAuMy0wLjZjLTAuMSwwLjEtMC4zLDAuMS0wLjQsMC4yYy0wLjEsMC0wLjMsMC4xLTAuNSwwLjFjLTAuMiwwLTAuNS0wLjEtMC43LTAuMmMtMC4yLTAuMS0wLjMtMC4zLTAuNC0wLjZoMi40YzAtMC4xLDAtMC4xLDAtMC4yYzAtMC4xLDAtMC4yLDAtMC4zYzAtMC4yLDAtMC41LTAuMS0wLjdjLTAuMS0wLjItMC4yLTAuNC0wLjMtMC41Yy0wLjEtMC4yLTAuMy0wLjMtMC41LTAuNGMtMC41LTAuMi0wLjktMC4yLTEuNCwwYy0wLjIsMC4xLTAuNCwwLjItMC42LDAuNGMtMC4yLDAuMi0wLjMsMC40LTAuNCwwLjZjLTAuMSwwLjItMC4yLDAuNS0wLjIsMC44QzEwLjQsMTIuMSwxMC41LDEyLjQsMTAuNiwxMi42TDEwLjYsMTIuNnogTTExLjUsMTEuNWMwLTAuMiwwLjEtMC40LDAuMy0wLjVjMC4xLTAuMSwwLjMtMC4yLDAuNS0wLjJjMC4yLDAsMC40LDAuMSwwLjUsMC4yYzAuMSwwLjEsMC4yLDAuMywwLjIsMC41TDExLjUsMTEuNUwxMS41LDExLjV6IE0xNC44LDEzLjZoMXYtMi4zYzAuMS0wLjEsMC4yLTAuMiwwLjMtMC4zYzAuMS0wLjEsMC4yLTAuMSwwLjQtMC4xYzAuMiwwLDAuMywwLDAuNCwwLjJjMC4xLDAuMiwwLjEsMC4zLDAuMSwwLjV2Mmgxdi0yLjJjMC0wLjQtMC4xLTAuNy0wLjMtMUMxNy43LDEwLjEsMTcuMywxMCwxNywxMGMtMC4yLDAtMC41LDAuMS0wLjcsMC4yYy0wLjIsMC4xLTAuNCwwLjItMC41LDAuNGgwbC0wLjEtMC41aC0wLjlMMTQuOCwxMy42TDE0LjgsMTMuNnogTTIwLjEsMTMuM2MwLjIsMC4yLDAuNSwwLjQsMC45LDAuNGMwLjIsMCwwLjQsMCwwLjYtMC4xYzAuMi0wLjEsMC40LTAuMiwwLjUtMC40YzAuMS0wLjIsMC4zLTAuNCwwLjMtMC42YzAuMS0wLjMsMC4xLTAuNSwwLjEtMC44YzAtMC4yLDAtMC41LTAuMS0wLjdjLTAuMS0wLjItMC4yLTAuNC0wLjMtMC42Yy0wLjEtMC4yLTAuMy0wLjMtMC40LTAuNGMtMC4yLTAuMS0wLjQtMC4xLTAuNi0wLjFjLTAuMiwwLTAuNCwwLTAuNiwwLjFjLTAuMiwwLjEtMC4zLDAuMi0wLjUsMC4zaDBsLTAuMS0wLjRoLTAuOXY0LjhoMXYtMUwyMC4xLDEzLjN6IE0yMC4xLDExLjJjMC4yLTAuMiwwLjQtMC4zLDAuNy0wLjNjMC40LDAsMC42LDAuMywwLjYsMC45YzAsMC4zLDAsMC42LTAuMiwwLjhjLTAuMSwwLjItMC4zLDAuMi0wLjUsMC4yYy0wLjIsMC0wLjQtMC4xLTAuNi0wLjJMMjAuMSwxMS4yTDIwLjEsMTEuMnogTTIzLjMsMTMuMWMwLjEsMC4xLDAuMSwwLjIsMC4yLDAuM2MwLjEsMC4xLDAuMiwwLjIsMC40LDAuMmMwLjIsMC4xLDAuMywwLjEsMC41LDAuMWMwLjIsMCwwLjUsMCwwLjctMC4xYzAuMi0wLjEsMC40LTAuMiwwLjYtMC4zaDBsMC4xLDAuNGgwLjl2LTJjMC0wLjQtMC4xLTAuOS0wLjQtMS4yQzI1LjksMTAuMSwyNS41LDEwLDI1LDEwYy0wLjMsMC0wLjYsMC0wLjksMC4xYy0wLjMsMC4xLTAuNSwwLjItMC44LDAuM2wwLjQsMC43YzAuMi0wLjEsMC40LTAuMiwwLjYtMC4yYzAuMi0wLjEsMC4zLTAuMSwwLjUtMC4xYzAuMiwwLDAuNCwwLDAuNSwwLjFjMC4xLDAuMSwwLjIsMC4yLDAuMiwwLjRjLTAuNCwwLTAuNywwLjEtMS4xLDAuMWMtMC4zLDAtMC41LDAuMS0wLjcsMC4zYy0wLjIsMC4xLTAuMywwLjItMC40LDAuNGMtMC4xLDAuMi0wLjEsMC4zLTAuMSwwLjVDMjMuMywxMi44LDIzLjMsMTIuOSwyMy4zLDEzLjFMMjMuMywxMy4xeiBNMjQuMywxMi40YzAuMS0wLjEsMC4xLTAuMSwwLjItMC4yYzAuMS0wLjEsMC4zLTAuMSwwLjQtMC4xYzAuMiwwLDAuNC0wLjEsMC42LTAuMXYwLjZjLTAuMSwwLjEtMC4zLDAuMi0wLjQsMC4yYy0wLjEsMC4xLTAuMywwLjEtMC40LDAuMWMtMC4xLDAtMC4yLDAtMC40LTAuMWMtMC4xLTAuMS0wLjEtMC4xLTAuMS0wLjNDMjQuMywxMi41LDI0LjMsMTIuNCwyNC4zLDEyLjRMMjQuMywxMi40eiBNMjcuNywxNC4xbC0wLjIsMC44YzAuMSwwLDAuMiwwLDAuMiwwLjFjMC4xLDAsMC4yLDAsMC4zLDBjMC4yLDAsMC40LDAsMC42LTAuMWMwLjItMC4xLDAuMy0wLjEsMC40LTAuM2MwLjEtMC4xLDAuMy0wLjMsMC4zLTAuNGMwLjEtMC4yLDAuMi0wLjQsMC4zLTAuNmwxLjQtMy42aC0xbC0wLjUsMS41Yy0wLjEsMC4yLTAuMSwwLjQtMC4yLDAuNWMtMC4xLDAuMi0wLjEsMC40LTAuMiwwLjVoMGMtMC4xLTAuMi0wLjEtMC40LTAuMi0wLjVDMjksMTIsMjksMTEuOCwyOC45LDExLjZsLTAuNi0xLjVoLTFsMS41LDMuNGwtMC4xLDAuMmMtMC4xLDAuMS0wLjEsMC4yLTAuMywwLjNjLTAuMSwwLjEtMC4zLDAuMS0wLjUsMC4xQzI3LjksMTQuMiwyNy44LDE0LjIsMjcuNywxNC4xTDI3LjcsMTQuMUwyNy43LDE0LjF6Ii8+PC9zdmc+)}.bg-trustpay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfNV8iIGNsYXNzPSJzdDIxIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnIGlkPSJ0cnVzdHBheSI+PHBhdGggaWQ9IlhNTElEXzY4NV8iIGQ9Ik0yMC44LDEzLjRjLTAuNCwwLTAuNywwLTEuMSwwYzAuNC0xLjgsMC43LTMuNiwxLjEtNS40YzAuOSwwLDEuOCwwLDIuNywwYzAuMiwwLDAuNCwwLjEsMC42LDAuMWMwLjMsMC4xLDAuNiwwLjQsMC42LDAuN2MwLjEsMC43LTAuMSwxLjMtMC41LDEuOWMtMC40LDAuNS0wLjksMC42LTEuNCwwLjZjLTAuNCwwLTAuOSwwLTEuMywwYy0wLjEsMC0wLjIsMC0wLjIsMC4xQzIxLjEsMTIuMiwyMC45LDEyLjgsMjAuOCwxMy40eiBNMjEuNCwxMC41YzAuNCwwLDAuNywwLDEuMSwwYzAuNiwwLDAuOC0wLjIsMS0wLjhjMC0wLjEsMC0wLjEsMC0wLjJjMC0wLjItMC4xLTAuNC0wLjMtMC40Yy0wLjUtMC4xLTEtMC4xLTEuNS0wLjFDMjEuNiw5LjUsMjEuNSwxMCwyMS40LDEwLjV6IE0yNy40LDEzLjRjLTAuMywwLTAuNiwwLTEsMGMwLTAuMSwwLTAuMSwwLTAuMmMtMC4yLDAuMS0wLjUsMC4yLTAuNywwLjJjLTAuMywwLTAuNywwLjEtMSwwYy0wLjUtMC4xLTAuNy0wLjUtMC42LTEuMWMwLjEtMC43LDAuNy0xLjIsMS40LTEuM2MwLjQtMC4xLDAuOC0wLjEsMS4yLTAuMmMwLjEsMCwwLjIsMCwwLjItMC4yYzAtMC4xLDAtMC4xLDAtMC4yYzAtMC4yLDAtMC40LTAuMy0wLjRjLTAuMiwwLTAuMywwLTAuNSwwYy0wLjMsMC0wLjUsMC4xLTAuNiwwLjRjLTAuMywwLTAuNiwwLTEsMGMwLTAuNCwwLjQtMC45LDAuOC0xLjFjMC41LTAuMiwxLTAuMiwxLjQtMC4yYzAuMiwwLDAuNCwwLjEsMC42LDAuMWMwLjQsMC4xLDAuNSwwLjQsMC41LDAuOUMyNy44LDExLjQsMjcuNiwxMi4zLDI3LjQsMTMuNEMyNy40LDEzLjMsMjcuNCwxMy40LDI3LjQsMTMuNHogTTI2LjcsMTEuNmMtMC40LDAuMS0wLjgsMC4xLTEuMSwwLjJjLTAuMywwLjEtMC41LDAuMy0wLjUsMC42YzAsMC4xLDAsMC4yLDAuMiwwLjNjMC40LDAuMiwxLDAsMS4yLTAuNEMyNi42LDEyLDI2LjcsMTEuOCwyNi43LDExLjZ6IE0zMCwxMi4zYzAuMy0wLjUsMC41LTEsMC44LTEuNmMwLjItMC40LDAuNC0wLjgsMC42LTEuMWMwLTAuMSwwLjEtMC4xLDAuMi0wLjFjMC4zLDAsMC42LDAsMSwwYy0wLjEsMC4yLTAuMiwwLjQtMC4zLDAuNmMtMC43LDEuMy0xLjUsMi42LTIuMiwzLjljMCwwLDAsMCwwLDAuMUMyOS40LDE0LjksMjksMTUsMjgsMTVjMCwwLDAsMC0wLjEsMGMwLjEtMC4zLDAuMS0wLjUsMC4yLTAuOGMwLjEsMCwwLjMsMCwwLjQsMGMwLjMsMCwwLjYtMC4zLDAuNy0wLjZjMCwwLDAtMC4xLDAtMC4xYy0wLjMtMS4xLTAuNS0yLjMtMC42LTMuNGMwLTAuMiwwLTAuNCwwLTAuNmMwLjQsMCwwLjgsMCwxLjEsMEMyOS43LDEwLjQsMjkuOCwxMS4zLDMwLDEyLjNDMjkuOSwxMi4zLDMwLDEyLjMsMzAsMTIuM3oiLz48cGF0aCBpZD0iWE1MSURfNjc4XyIgY2xhc3M9InN0MCIgZD0iTTE3LDEwLjZjLTAuMywwLTAuNywwLTEsMGMwLTAuMSwwLTAuMSwwLTAuMWMwLTAuMi0wLjEtMC4zLTAuMi0wLjNjLTAuMiwwLTAuNSwwLTAuNywwYy0wLjEsMC0wLjIsMC0wLjIsMC4xYy0wLjEsMC4xLTAuMSwwLjItMC4xLDAuM2MwLDAuMSwwLjEsMC4yLDAuMiwwLjJjMC40LDAuMSwwLjcsMC4yLDEuMSwwLjNjMC4xLDAsMC4yLDAuMSwwLjMsMC4xYzAuNSwwLjIsMC43LDAuNiwwLjUsMS4yYy0wLjIsMC42LTAuNywwLjktMS4zLDFjLTAuNSwwLjEtMSwwLjEtMS41LTAuMWMtMC41LTAuMS0wLjgtMC41LTAuOC0xLjFjMC0wLjEsMC0wLjIsMC4yLTAuMmMwLjMsMCwwLjUsMCwwLjgsMGMwLjEsMCwwLjEsMCwwLjEsMC4xYzAsMC4zLDAuMSwwLjQsMC40LDAuNGMwLjIsMCwwLjQsMCwwLjcsMGMwLjEsMCwwLjIsMCwwLjItMC4xYzAuMi0wLjEsMC4yLTAuMiwwLjItMC40YzAtMC4yLTAuMS0wLjItMC4zLTAuM2MtMC40LTAuMS0wLjctMC4yLTEuMS0wLjNjLTAuMSwwLTAuMi0wLjEtMC4zLTAuMWMtMC40LTAuMi0wLjUtMC40LTAuNS0wLjhjMC4xLTAuOSwwLjYtMS4zLDEuNC0xLjRjMC40LDAsMC44LDAsMS4xLDBjMC4yLDAsMC40LDAuMSwwLjUsMC4yQzE3LDkuNywxNy4xLDEwLjIsMTcsMTAuNnogTTEzLjEsOS40Yy0wLjEsMC40LTAuMSwwLjgtMC4yLDEuMWMtMC4yLDAuOS0wLjQsMS44LTAuNSwyLjdjMCwwLjEtMC4xLDAuMS0wLjEsMC4xYy0wLjMsMC0wLjYsMC0wLjksMGMwLTAuMSwwLTAuMiwwLTAuM2MtMC4yLDAuMS0wLjQsMC4yLTAuNiwwLjNjLTAuNCwwLjEtMC45LDAuMS0xLjMsMEM5LjEsMTMuMyw5LDEzLjEsOSwxMi44YzAtMC40LDAuMS0wLjgsMC4xLTEuMmMwLjEtMC42LDAuMy0xLjMsMC40LTEuOWMwLTAuMSwwLjEtMC4yLDAuMi0wLjJjMC4zLDAsMC42LDAsMC45LDBjLTAuMSwwLjMtMC4xLDAuNi0wLjIsMC45Yy0wLjEsMC42LTAuMiwxLjEtMC4zLDEuN2MtMC4xLDAuNCwwLjEsMC42LDAuNSwwLjZjMC43LDAsMC45LTAuMywxLTAuOGMwLjEtMC43LDAuMy0xLjUsMC40LTIuMmMwLTAuMSwwLjEtMC4yLDAuMi0wLjJDMTIuNSw5LjUsMTIuOCw5LjQsMTMuMSw5LjR6IE0xMS40LDEzLjFMMTEuNCwxMy4xTDExLjQsMTMuMUwxMS40LDEzLjF6IE00LjYsMTMuNGMtMC40LDAtMC43LDAtMS4xLDBDMy44LDExLjksNCwxMC40LDQuMyw5QzMuOCw5LDMuMyw5LDIuNyw5YzAuMS0wLjMsMC4xLTAuNiwwLjItMC45QzIuOSw4LjEsMyw4LDMsOGMwLjQsMCwwLjgsMCwxLjIsMGMwLjUsMCwwLjksMCwxLjQsMGMwLjUsMCwxLDAsMS41LDBjMCwwLDAuMSwwLDAuMSwwQzcuMiw4LjMsNy4yLDguNiw3LjEsOC45QzcuMSw4LjksNyw5LDYuOSw5QzYuNSw5LDYuMSw5LDUuNiw5QzUuNSw5LDUuNSw5LDUuNCw5LjFDNS4yLDEwLjUsNC45LDExLjksNC42LDEzLjRDNC42LDEzLjMsNC42LDEzLjQsNC42LDEzLjR6IE0xOS4zLDguNWMtMC4xLDAuMy0wLjEsMC42LTAuMiwxYzAuMiwwLDAuNCwwLDAuNywwYy0wLjEsMC4zLTAuMSwwLjYtMC4yLDAuOWMtMC4yLDAtMC40LDAtMC43LDBjLTAuMSwwLjUtMC4yLDAuOS0wLjMsMS4zYzAsMC4yLTAuMSwwLjQtMC4xLDAuNmMtMC4xLDAuMywwLDAuNCwwLjMsMC40YzAuMSwwLDAuMiwwLDAuMywwYzAsMC4zLTAuMSwwLjUtMC4xLDAuN2MwLDAtMC4xLDAuMS0wLjEsMC4xYy0wLjMsMC0wLjcsMC0xLDBjLTAuMywwLTAuNS0wLjItMC40LTAuNmMwLjEtMC41LDAuMi0xLDAuMy0xLjVjMC4xLTAuNCwwLjEtMC43LDAuMi0xLjFjLTAuMiwwLTAuMywwLTAuNSwwYzAuMS0wLjMsMC4xLTAuNSwwLjItMC44YzAsMCwwLjEtMC4xLDAuMS0wLjFjMC40LDAsMC40LDAsMC41LTAuNGMwLTAuMSwwLTAuMSwwLTAuMmMwLjEtMC40LDAuMS0wLjQsMC41LTAuNEMxOC45LDguNSwxOS4xLDguNSwxOS4zLDguNXogTTcuNyw5LjRjMCwwLjEsMCwwLjMtMC4xLDAuNEM4LDkuNCw4LjUsOS4zLDksOS40QzksOS43LDguOSwxMCw4LjksMTAuNGMtMC4yLDAtMC40LDAtMC42LDBjLTAuNCwwLjEtMC42LDAuMy0wLjcsMC43Yy0wLjEsMC41LTAuMiwwLjktMC40LDEuNGMtMC4xLDAuMy0wLjEsMC41LTAuMiwwLjhjMCwwLTAuMSwwLjEtMC4xLDAuMWMtMC4zLDAtMC42LDAtMSwwYzAuMS0wLjUsMC4yLTEsMC4zLTEuNWMwLjItMC44LDAuMy0xLjUsMC41LTIuM2MwLTAuMSwwLjEtMC4yLDAuMi0wLjJDNy4yLDkuNSw3LjUsOS40LDcuNyw5LjR6Ii8+PC9nPjwvc3ZnPg==)}.bg-unionpay{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzUyXzNfIiBjbGFzcz0ic3QxNCIgZD0iTTMsMGgzMGMxLjcsMCwzLDEuMywzLDN2MTZjMCwxLjctMS4zLDMtMywzSDNjLTEuNywwLTMtMS4zLTMtM1YzQzAsMS4zLDEuMywwLDMsMHoiLz48Zz48Zz48cGF0aCBjbGFzcz0ic3QxNiIgZD0iTTI0LjksMTZoLTAuM2wxLTMuNkgyNmwwLjEtMC40djAuNGMwLDAuMiwwLjIsMC41LDAuNywwLjRoMC42bDAuMi0wLjdoLTAuMmMtMC4xLDAtMC4yLDAtMC4yLTAuMXYtMC40aC0xLjFsMCwwYy0wLjMsMC0xLjQsMC0xLjYsMC4xQzI0LjMsMTEuOSwyNCwxMiwyNCwxMmwwLjEtMC40aC0xbC0wLjIsMC43bC0xLDMuNmgtMC4ybC0wLjIsMC43aDJsLTAuMSwwLjJoMWwwLjEtMC4yaDAuM0wyNC45LDE2eiBNMjMuNywxNmgtMC44bDAuMi0wLjhoMC44TDIzLjcsMTZ6IE0yNC4xLDE0LjVjMCwwLTAuMiwwLTAuNCwwLjFjLTAuMiwwLjEtMC41LDAuMi0wLjUsMC4ybDAuMy0wLjloMC44TDI0LjEsMTQuNXogTTI0LjEsMTMuMmMtMC4yLDAuMS0wLjUsMC4yLTAuNSwwLjJsMC4zLTAuOWgwLjhsLTAuMiwwLjdDMjQuNSwxMy4xLDI0LjMsMTMuMSwyNC4xLDEzLjJ6IE0yNS42LDEzLjhoMS4ybC0wLjIsMC42aC0xLjJMMjUuMiwxNWgxbC0wLjgsMS4xYy0wLjEsMC4xLTAuMSwwLjEtMC4yLDAuMWMtMC4xLDAtMC4xLDAuMS0wLjIsMC4xaC0wLjNMMjQuNiwxN2gwLjhjMC40LDAsMC42LTAuMiwwLjgtMC40bDAuNS0wLjhsMC4xLDAuOGMwLDAuMSwwLjEsMC4yLDAuMiwwLjNjMC4xLDAsMC4yLDAuMSwwLjMsMC4xczAuMiwwLDAuMywwaDAuNGwwLjItMC44SDI4Yy0wLjEsMC0wLjIsMC0wLjItMC4xczAtMC4xLDAtMC4ybC0wLjEtMC44aC0wLjVsMC4yLTAuM2gxLjJsMC4yLTAuNmgtMS4xbDAuMi0wLjZoMS4xbDAuMi0wLjdoLTMuMkwyNS42LDEzLjh6IE0xNS44LDE2LjJsMC4zLTAuOWgxLjFsMC4yLTAuN2gtMS4xbDAuMi0wLjZoMS4xbDAuMi0wLjdIMTVMMTQuOCwxNGgwLjZsLTAuMiwwLjZoLTAuNmwtMC4yLDAuN0gxNWwtMC4zLDEuMmMtMC4xLDAuMiwwLDAuMiwwLjEsMC4zYzAuMSwwLjEsMC4xLDAuMSwwLjIsMC4yYzAuMSwwLDAuMiwwLjEsMC4zLDAuMWgxLjNsMC4yLTAuOGwtMC42LDAuMUMxNi4xLDE2LjMsMTUuOCwxNi4zLDE1LjgsMTYuMnogTTE1LjksMTEuN2wtMC4zLDAuNWMtMC4xLDAuMS0wLjEsMC4yLTAuMiwwLjJjLTAuMSwwLTAuMSwwLTAuMiwwaC0wLjFsLTAuMiwwLjdoMC41YzAuMiwwLDAuNC0wLjEsMC41LTAuMWMwLjEtMC4xLDAuMSwwLDAuMi0wLjFsMC4yLTAuMmgxLjVsMC4yLTAuN2gtMS4xbDAuMi0wLjRIMTUuOXogTTE4LjIsMTYuMmMwLDAsMC0wLjEsMC0wLjJsMC40LTEuNGgxLjVjMC4yLDAsMC40LDAsMC41LDBjMC4xLDAsMC4yLTAuMSwwLjMtMC4xYzAuMS0wLjEsMC4yLTAuMiwwLjMtMC4yYzAuMS0wLjEsMC4yLTAuMywwLjMtMC42bDAuNS0xLjhoLTEuNmMwLDAtMC41LDAuMS0wLjcsMC4ycy0wLjUsMC4zLTAuNSwwLjNsMC4xLTAuNWgtMWwtMS4zLDQuNkMxNywxNi41LDE3LDE2LjYsMTcsMTYuN3MwLjEsMC4yLDAuMiwwLjJjMC4xLDAuMSwwLjIsMC4xLDAuMywwLjFjMC4xLDAsMC4zLDAsMC41LDBoMC43bDAuMi0wLjhsLTAuNiwwQzE4LjMsMTYuMiwxOC4yLDE2LjIsMTguMiwxNi4yeiBNMTkuMiwxMi41aDEuNmwtMC4xLDAuNGMwLDAtMC44LDAtMC45LDBDMTkuMywxMywxOSwxMy4yLDE5LDEzLjJMMTkuMiwxMi41eiBNMTguOSwxMy41aDEuNmwtMC4xLDAuM2MwLDAtMC4xLDAtMC4yLDBoLTEuM0wxOC45LDEzLjV6IE0yMC40LDE0LjljMCwwLjEsMCwwLjEtMC4xLDAuMWMwLDAtMC4xLDAtMC4yLDBIMjB2LTAuNGgtMC45bDAsMS45YzAsMC4xLDAsMC4yLDAuMSwwLjNjMC4xLDAuMSwwLjQsMC4xLDAuOCwwLjFoMC42bDAuMi0wLjdsLTAuNSwwaC0wLjJjMCwwLTAuMSwwLTAuMS0wLjFjMCwwLTAuMSwwLTAuMS0wLjF2LTAuNWwwLjUsMGMwLjMsMCwwLjQtMC4xLDAuNS0wLjJzMC4xLTAuMiwwLjItMC4zbDAuMS0wLjRoLTAuN0wyMC40LDE0Ljl6IE05LjIsNS4xYy0wLjksMC0xLjEsMC0xLjIsMGMwLDAuMi0wLjYsMy0wLjYsM0M3LjMsOC42LDcuMiw5LDYuOSw5LjNDNi43LDkuNCw2LjUsOS41LDYuMiw5LjVjLTAuNCwwLTAuNi0wLjItMC42LTAuNlY4LjhMNS43LDhjMCwwLDAuNi0yLjYsMC43LTIuOWMwLDAsMCwwLDAsMEM1LjIsNSw1LDUsNSw1YzAsMCwwLDAuMiwwLDAuMkw0LjMsOC4xTDQuMiw4LjNMNC4xLDkuMWMwLDAuMiwwLjEsMC40LDAuMSwwLjZjMC4zLDAuNSwxLjEsMC42LDEuNiwwLjZjMC42LDAsMS4yLTAuMSwxLjYtMC40YzAuNy0wLjQsMC44LTEsMS0xLjZsMC4xLTAuM0M4LjUsOC4xLDkuMSw1LjQsOS4yLDUuMUM5LjIsNS4xLDkuMiw1LjEsOS4yLDUuMXogTTExLjQsNy4yYy0wLjIsMC0wLjQsMC0wLjcsMC4yYy0wLjEsMC4xLTAuMiwwLjEtMC4zLDAuMmwwLjEtMC4zbC0wLjEtMC4xQzkuOSw3LjMsOS44LDcuNCw5LjMsNy40bC0wLjEsMEM5LjIsNy45LDkuMiw4LjMsOC45LDkuM0M4LjksOS42LDguOCwxMCw4LjcsMTAuM2wwLDAuMWMwLjUsMCwwLjcsMCwxLjEsMGwwLTAuMWMwLjEtMC4zLDAuMS0wLjQsMC4yLTFjMC4xLTAuMywwLjItMC45LDAuMi0xLjFjMC4xLTAuMSwwLjItMC4xLDAuMy0wLjFjMC4yLDAsMC4yLDAuMiwwLjIsMC4zYzAsMC4yLTAuMSwwLjYtMC4yLDFsLTAuMSwwLjNjLTAuMSwwLjItMC4xLDAuNC0wLjEsMC42bDAsMGMwLjUsMCwwLjYsMCwxLjEsMGwwLjEtMC4xYzAuMS0wLjUsMC4xLTAuNiwwLjItMS4zbDAuMS0wLjNjMC4xLTAuNiwwLjItMC45LDAuMS0xLjJDMTEuOSw3LjMsMTEuNyw3LjIsMTEuNCw3LjJ6IE0xMy45LDcuOUMxMy42LDcuOSwxMy40LDgsMTMuMiw4Yy0wLjIsMC0wLjMsMC4xLTAuNiwwLjFsMCwwbDAsMGMwLDAuMi0wLjEsMC40LTAuMSwwLjZjMCwwLjItMC4xLDAuNS0wLjIsMC44Yy0wLjEsMC4zLTAuMSwwLjMtMC4xLDAuNGMwLDAuMS0wLjEsMC4yLTAuMSwwLjRsMCwwdjBjMC4yLDAsMC40LDAsMC42LDBzMC4zLDAsMC42LDBsMCwwbDAsMGMwLTAuMiwwLjEtMC4zLDAuMS0wLjRjMC0wLjEsMC4xLTAuMywwLjItMC43YzAuMS0wLjIsMC4xLTAuNCwwLjEtMC42QzEzLjcsOC4zLDEzLjgsOC4xLDEzLjksNy45TDEzLjksNy45TDEzLjksNy45eiBNMTUuMywxMC41YzAuNSwwLDEtMC4xLDEuNC0wLjZjMC4zLTAuMywwLjQtMC44LDAuNS0xYzAuMi0wLjcsMC0xLTAuMS0xLjJjLTAuMi0wLjMtMC42LTAuNC0xLTAuNGMtMC4yLDAtMC44LDAtMS4zLDAuNWMtMC4zLDAuMy0wLjUsMC44LTAuNiwxLjJjLTAuMSwwLjQtMC4yLDEuMiwwLjUsMS40QzE0LjgsMTAuNCwxNS4xLDEwLjUsMTUuMywxMC41eiBNMTUuMyw4LjlDMTUuNCw4LjQsMTUuNSw4LDE1LjksOGMwLjMsMCwwLjMsMC4zLDAuMiwwLjhjMCwwLjEtMC4xLDAuNS0wLjIsMC43Yy0wLjEsMC4xLTAuMiwwLjItMC4zLDAuMmMwLDAtMC4yLDAtMC4yLTAuM0MxNS4yLDkuMywxNS4yLDkuMSwxNS4zLDguOXogTTI0LjksOC45Yy0wLjEsMC40LTAuMiwxLjIsMC41LDEuNGMwLjIsMC4xLDAuNCwwLjEsMC42LDAuMWMwLjIsMCwwLjQtMC4xLDAuNi0wLjNjMCwwLjEsMCwwLjEtMC4xLDAuMmwwLDBjMC41LDAsMC42LDAsMS4yLDBsMC4xLDBjMC4xLTAuNSwwLjEtMC45LDAuMy0xLjhjMC4xLTAuNCwwLjItMC44LDAuMy0xLjNsMC0wLjFjLTAuNSwwLjEtMC43LDAuMS0xLjIsMC4ybDAsMGMwLDAuMSwwLDAuMSwwLDAuMWMtMC4xLTAuMS0wLjItMC4yLTAuNC0wLjNjLTAuMi0wLjEtMC44LDAtMS4yLDAuNUMyNS4yLDguMSwyNSw4LjUsMjQuOSw4Ljl6IE0yNiw5QzI2LjIsOC40LDI2LjMsOCwyNi42LDhjMC4yLDAsMC4zLDAuMiwwLjMsMC42YzAsMC4xLDAsMC4yLTAuMSwwLjNjMCwwLjItMC4xLDAuMy0wLjEsMC41YzAsMC4xLTAuMSwwLjItMC4xLDAuM2MtMC4xLDAuMS0wLjMsMC4yLTAuNCwwLjJjMCwwLTAuMiwwLTAuMi0wLjNDMjYsOS4zLDI2LDkuMSwyNiw5eiBNMTguNCwxMC40TDE4LjQsMTAuNGMwLjEtMC4zLDAuMS0wLjQsMC4yLTFjMC4xLTAuMywwLjItMC45LDAuMi0xLjFjMC4xLTAuMSwwLjItMC4xLDAuMy0wLjFjMC4yLDAsMC4yLDAuMiwwLjIsMC4zYzAsMC4yLTAuMSwwLjYtMC4yLDFsLTAuMSwwLjNjLTAuMSwwLjItMC4xLDAuNC0wLjEsMC42bDAsMGMwLjUsMCwwLjYsMCwxLjEsMGwwLjEtMC4xYzAuMS0wLjUsMC4xLTAuNiwwLjItMS4zbDAuMS0wLjNjMC4xLTAuNiwwLjItMC45LDAuMS0xLjJjLTAuMS0wLjMtMC40LTAuMy0wLjYtMC4zYy0wLjIsMC0wLjQsMC0wLjcsMC4yYy0wLjEsMC4xLTAuMiwwLjEtMC4zLDAuMmwwLjEtMC4zTDE5LDcuMmMtMC41LDAuMS0wLjcsMC4xLTEuMiwwLjJsMCwwYy0wLjEsMC41LTAuMSwwLjktMC4zLDEuOGMtMC4xLDAuMy0wLjIsMC43LTAuMiwxLjFsMCwwLjFDMTcuOCwxMC40LDE4LDEwLjQsMTguNCwxMC40eiBNMjIuMSwxMC40YzAtMC4yLDAuMi0xLjEsMC4yLTEuMXMwLjItMC43LDAuMi0wLjdjMCwwLDAuMS0wLjEsMC4xLTAuMWgwLjFjMC43LDAsMS41LDAsMi4xLTAuNWMwLjQtMC4zLDAuNy0wLjgsMC44LTEuNGMwLTAuMSwwLjEtMC4zLDAuMS0wLjVjMC0wLjItMC4xLTAuNC0wLjItMC42Yy0wLjMtMC41LTAuOS0wLjUtMS43LTAuNWgtMC4zYy0wLjksMC0xLjMsMC0xLjQsMGMwLDAuMSwwLDAuMiwwLDAuMmwtMC4zLDEuNmMwLDAtMC44LDMuNC0wLjgsMy41QzIxLjYsMTAuNCwyMS45LDEwLjQsMjIuMSwxMC40eiBNMjIuNyw3LjZMMjMuMSw2VjUuOVY1LjlsMC4xLDBjMCwwLDAuNywwLjEsMC44LDAuMWMwLjMsMC4xLDAuNCwwLjQsMC4zLDAuOGMtMC4xLDAuMy0wLjMsMC42LTAuNiwwLjhjLTAuMiwwLjEtMC41LDAuMS0wLjgsMC4xaC0wLjJMMjIuNyw3LjZ6IE0zMS45LDcuM0wzMS45LDcuM2MtMC42LDAuMS0wLjcsMC4xLTEuMiwwLjFsMCwwdjBsMCwwYy0wLjQsMC45LTAuMywwLjctMC42LDEuNGMwLDAsMC0wLjEsMC0wLjFMMzAsNy4zbC0wLjEtMC4xYy0wLjYsMC4xLTAuNiwwLjEtMS4xLDAuMmwwLDBjMCwwLDAsMCwwLDAuMWwwLDBjMC4xLDAuMywwLjEsMC4zLDAuMSwwLjhjMCwwLjMsMC4xLDAuNSwwLjEsMC44YzAuMSwwLjQsMC4xLDAuNiwwLjEsMS4zYy0wLjMsMC42LTAuNCwwLjgtMC44LDEuM2wwLDBsLTAuMiwwLjRjMCwwLjEtMC4xLDAuMS0wLjEsMC4xYzAsMC0wLjEsMC0wLjIsMGgtMC4xbC0wLjIsMC43aDAuN2MwLjQsMCwwLjYtMC4yLDAuOC0wLjRsMC40LTAuOGwwLDBsMC4xLTAuMUMyOS44LDExLjEsMzEuOSw3LjMsMzEuOSw3LjN6IE0xMy45LDdjLTAuMi0wLjItMC43LTAuMS0xLDAuMWMtMC4zLDAuMi0wLjMsMC41LTAuMSwwLjZjMC4yLDAuMSwwLjcsMC4xLDAuOS0wLjFDMTQuMSw3LjUsMTQuMSw3LjIsMTMuOSw3eiIvPjwvZz48L2c+PC9zdmc+)}.bg-visa{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzUyXzJfIiBjbGFzcz0ic3QxIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwxNUg4LjlMNy40LDguN0M3LjMsOC41LDcuMSw4LjIsNi45LDguMUM2LjMsNy44LDUuNyw3LjUsNSw3LjRWNy4yaDMuM2MwLjQsMCwwLjgsMC4zLDAuOSwwLjhsMC44LDQuNWwyLjEtNS4zaDJMMTEsMTV6IE0xNS4zLDE1aC0ybDEuNi03LjhoMkwxNS4zLDE1eiBNMTkuNCw5LjNjMC4xLTAuNCwwLjQtMC43LDAuOC0wLjdjMC43LTAuMSwxLjMsMC4xLDEuOSwwLjRsMC4zLTEuN0MyMS45LDcuMSwyMS4zLDcsMjAuNyw3Yy0xLjksMC0zLjMsMS4xLTMuMywyLjZjMC4xLDEsMC44LDEuOCwxLjcsMi4xYzAuOCwwLjQsMSwwLjYsMSwxYy0wLjEsMC41LTAuNiwwLjktMS4xLDAuOGMwLDAsMCwwLDAsMGMtMC43LDAtMS40LTAuMi0yLTAuNWwtMC4zLDEuN2MwLjcsMC4zLDEuNCwwLjQsMi4xLDAuNGMyLjEsMC4xLDMuNS0xLDMuNS0yLjZDMjIuMSwxMC4zLDE5LjQsMTAuMiwxOS40LDkuM0wxOS40LDkuM0wxOS40LDkuM3ogTTI5LDE1bC0xLjYtNy44aC0xLjdjLTAuNCwwLTAuNywwLjItMC44LDAuNkwyMi4xLDE1aDJsMC40LTEuMUgyN2wwLjIsMS4xTDI5LDE1TDI5LDE1eiBNMjYuMSw5LjNsMC42LDIuOUgyNUwyNi4xLDkuM3oiLz48L3N2Zz4=)}.bg-webmoney{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU2X2NvcHkiIGNsYXNzPSJzdDIyIiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxwYXRoIGlkPSJDb21iaW5lZC1TaGFwZSIgY2xhc3M9InN0MCIgZD0iTTE4LDQuM2MxLjEsMCwyLjEsMC4yLDMsMC43YzAuMSwwLjEsMC4zLDAuMSwwLjQsMC4ybC0wLjYsMC42bC0wLjktMWwtMS42LDEuNGwtMS0xbC0zLDIuNmwxLjksMi4xbC0wLjcsMC42bDEuOSwyLjFsLTAuNywwLjZsMi43LDIuOWwxLjYtMS40bDEuNCwxLjVjLTAuMywwLjItMC42LDAuNC0wLjksMC42Yy0xLDAuNi0yLjEsMC45LTMuNCwwLjljLTMuOCwwLTYuOC0zLTYuOC02LjdDMTEuMSw3LjMsMTQuMiw0LjMsMTgsNC4zeiBNMTYuNywxMC42bDEuNi0xLjRsMS41LDEuNmwtMS42LDEuNEwxNi43LDEwLjZMMTYuNywxMC42eiBNMTcuOSwxMy40bDEuNi0xLjVsMS41LDEuNkwxOS4zLDE1TDE3LjksMTMuNEwxNy45LDEzLjR6IE0xNS42LDcuOGwxLjYtMS40TDE4LjYsOEwxNyw5LjRMMTUuNiw3Ljh6IE0xOC41LDcuMUwxOS44LDZsMS4xLDEuMmwtMS4yLDEuMUwxOC41LDcuMXogTTIwLjcsMTJsMS4yLTEuMWwxLjEsMS4ybC0xLjIsMS4xTDIwLjcsMTJ6IE0yMS44LDE0LjVsMS4yLTEuMWwxLjEsMS4ybC0xLjIsMS4xTDIxLjgsMTQuNUwyMS44LDE0LjV6IE0yMi4zLDguOWwwLjgtMC43TDIzLjgsOUwyMyw5LjdMMjIuMyw4Ljl6IE0yMS4yLDYuNUwyMiw1LjhsMC43LDAuOEwyMiw3LjNMMjEuMiw2LjV6IE0yMy4zLDExLjNsMC44LTAuN2wwLjcsMC44TDI0LDEyLjFMMjMuMywxMS4zTDIzLjMsMTEuM3ogTTE5LjcsOS41bDEuMi0xLjFMMjIsOS42bC0xLjIsMS4xTDE5LjcsOS41eiIvPjwvc3ZnPg==)}.bg-yandex{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZpc2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMzYgMjIiIHdpZHRoPSIzNnB4IiBoZWlnaHQ9IjIycHgiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGRkZGRkY7fS5zdDF7ZmlsbDojMjI0REJBO30uc3Qye2ZpbGw6IzAwN0VDRDt9LnN0M3tmaWxsOiMzNTNBNDg7fS5zdDR7ZmlsbDojMzEzMTU5O30uc3Q1e2ZpbGw6I0U4MkMzMDt9LnN0NntmaWxsOiNFQ0EyMUQ7fS5zdDd7ZmlsbDojRjM2RDFFO30uc3Q4e2ZpbGw6I0Q5MkUyODt9LnN0OXtmaWxsOiM0Mjk5REE7fS5zdDEwe2ZpbGw6IzZDNkRCOTt9LnN0MTF7ZmlsbDojRjE5RTBDO30uc3QxMntmaWxsOiMyMTgzQ0I7fS5zdDEze2ZpbGw6IzI0NjRCNDt9LnN0MTR7ZmlsbDojMzM3QTgzO30uc3QxNXtmaWxsOiNENDQ2M0Q7fS5zdDE2e2ZpbGw6I0ZERkRGRjt9LnN0MTd7ZmlsbDojMDA5RkUzO30uc3QxOHtmaWxsOiNGNUY2RkE7fS5zdDE5e2ZpbGw6I0M1MkI3MTt9LnN0MjB7ZmlsbDojMDAwMjY4O30uc3QyMXtmaWxsOiMxOUFFRkY7fS5zdDIye2ZpbGw6IzEwNkRCMzt9LnN0MjN7ZmlsbDojNDI4NUY0O30uc3QyNHtmaWxsOiNFMjM0NDI7fS5zdDI1e2ZpbGw6IzA3MjY5NDt9LnN0MjZ7ZmlsbDojNzUzMDc5O30uc3QyN3tmaWxsOiNCQTMwMkM7fS5zdDI4e2ZpbGw6IzNCNjZBRDt9LnN0Mjl7ZmlsbDojMDA5RkM5O30uc3QzMHtmaWxsOiNGRjk1MDA7fS5zdDMxe2ZpbGw6IzQwNTc4Nzt9LnN0MzJ7ZmlsbDojMDA1NkFEO30uc3QzM3tmaWxsOiNGRjAwMDc7fS5zdDM0e2ZpbGw6IzEzMTQxMzt9LnN0MzV7ZmlsbDojMDIwMjAyO30uc3QzNntmaWxsOiNGRkJDMDA7fTwvc3R5bGU+PHBhdGggaWQ9IlJvdW5kZWRfUmVjdGFuZ2xlXzU5X2NvcHlfNl8iIGNsYXNzPSJzdDI0IiBkPSJNMywwaDMwYzEuNywwLDMsMS4zLDMsM3YxNmMwLDEuNy0xLjMsMy0zLDNIM2MtMS43LDAtMy0xLjMtMy0zVjNDMCwxLjMsMS4zLDAsMywweiIvPjxnPjxwYXRoIGlkPSJzdmdfMyIgY2xhc3M9InN0MCIgZD0iTTEwLjMsNi40YzAuMSwwLDAuMywwLDAuNCwwYzAuMiwwLDAuNCwwLDAuNSwwYzAsMC4xLDAsMC4xLDAsMC4yYy0wLjcsMS45LTEuNCwzLjgtMi4xLDUuN2MwLDAuMSwwLDAuMSwwLDAuMmMwLDEsMCwxLjksMCwyLjljLTAuMSwwLTAuMiwwLTAuMiwwYy0wLjIsMC0wLjQsMC0wLjYsMGMwLTEsMC0yLjEsMC0zLjFDNy42LDEwLjgsNyw5LjIsNi40LDcuNmMwLTAuMS0wLjEtMC4zLTAuMS0wLjRjMC4yLDAsMC41LDAsMC43LDBjMC4xLDAsMC4yLDAsMC4yLDAuMWMwLjMsMSwwLjcsMiwxLDNjMC4xLDAuNCwwLjMsMC44LDAuNCwxLjJjMC4xLTAuNSwwLjMtMS4xLDAuNS0xLjZDOS41LDguNyw5LjksNy41LDEwLjMsNi40eiIvPjxwYXRoIGlkPSJYTUxJRF8xMzYwXyIgY2xhc3M9InN0MzUiIGQ9Ik0xNy43LDExYzAsMS41LDAsMywwLDQuNWMwLDAtMC4xLDAtMC4xLDAuMWMtMC4zLDAtMC41LDAtMC44LDBjMC0xLjUsMC0yLjksMC00LjRjLTAuMS0wLjItMC4yLTAuNC0wLjQtMC40Yy0wLjMtMC4xLTAuNywwLTEsMC4yYzAsMS40LDAsMi44LDAsNC4yYzAsMC4yLDAsMC4zLDAsMC41Yy0wLjMsMC0wLjUsMC0wLjgsMGMwLDAtMC4xLDAtMC4xLTAuMWMwLTEuOCwwLTMuNiwwLTUuNGMwLjEsMCwwLjEsMCwwLjIsMGMwLjIsMCwwLjUsMCwwLjcsMGMwLDAuMSwwLDAuMiwwLDAuM2MwLjEtMC4xLDAuMi0wLjEsMC4zLTAuMmMwLDAsMC4xLDAsMC4xLDBsMCwwYzAuNC0wLjIsMC45LTAuMiwxLjMtMC4xQzE3LjUsMTAuMSwxNy44LDEwLjYsMTcuNywxMXogTTEzLjYsMTUuNGMwLDAuMS0wLjEsMC4xLTAuMSwwLjFjLTAuMSwwLTAuMywwLTAuNCwwYzAtMC4xLTAuMS0wLjEtMC4xLTAuMmMwLTAuMS0wLjEtMC4yLTAuMS0wLjJjLTAuMiwwLjMtMC41LDAuNS0wLjksMC41Yy0wLjMsMC4xLTAuNy0wLjEtMC45LTAuM2MtMC4yLTAuMi0wLjQtMC41LTAuNS0wLjdjMC0wLjEsMC0wLjEtMC4xLTAuMmMwLDAsMC0wLjEsMC0wLjFjMC0wLjEsMC0wLjEsMC0wLjJjMC0wLjIsMC0wLjUsMC0wLjdjMC0wLjIsMC4xLTAuNCwwLjEtMC41YzAuMS0wLjMsMC4zLTAuNiwwLjYtMC44YzAuNC0wLjQsMS4xLTAuMywxLjYtMC4xYzAtMC4zLDAtMC41LDAtMC41YzAtMC4xLDAtMC4zLTAuMS0wLjRjMCwwLDAtMC4xLDAtMC4xYy0wLjEtMC4yLTAuMi0wLjQtMC4zLTAuNGMtMC4yLTAuMS0wLjQsMC0wLjYsMGMwLDAtMC4xLDAtMC4xLDBjMCwwLTAuMSwwLTAuMSwwLjFjLTAuMSwwLjEtMC4zLDAuMi0wLjQsMC4xYzAtMC4xLTAuMS0wLjItMC4xLTAuMmMtMC4xLTAuMS0wLjItMC4zLTAuMi0wLjRjMCwwLDAuMSwwLDAuMS0wLjFjMC4yLTAuMSwwLjMtMC4xLDAuNS0wLjJsMCwwdjBjMC4yLTAuMSwwLjUtMC4xLDAuOC0wLjFjMC4xLDAsMC4zLDAsMC40LDAuMWMwLjMsMC4xLDAuNSwwLjMsMC43LDAuNWMwLDAsMCwwLjEsMC4xLDAuMWMwLDAuMSwwLjEsMC4xLDAuMSwwLjJjMCwwLDAsMC4xLDAsMC4xYzAsMCwwLDAuMSwwLDAuMWMwLDAuMSwwLDAuMSwwLDAuMmMwLDAuMiwwLDAuNCwwLjEsMC41QzEzLjYsMTIuOSwxMy42LDE0LjIsMTMuNiwxNS40eiBNMTIuNywxMi43Yy0wLjEtMC4xLTAuNy0wLjQtMS0wLjFjLTAuNCwwLjQtMC40LDEtMC40LDEuM2MwLDAuMiwwLjIsMSwwLjcsMWMwLjUsMCwwLjctMC4zLDAuNy0wLjNDMTIuNywxNC41LDEyLjcsMTMuNSwxMi43LDEyLjd6IE0xMi43LDEyLjdDMTIuNywxMi43LDEyLjcsMTIuNywxMi43LDEyLjdDMTIuNywxMi43LDEyLjcsMTIuNywxMi43LDEyLjd6IE0yNiwxMS42QzI2LDEyLDI2LDEyLjUsMjYsMTIuOWMtMC4yLDAtMS44LDAtMi4zLTAuMWMwLDAuMiwwLDAuNCwwLDAuN2MwLDAuMSwwLDAuMSwwLDAuMmMwLDAsMCwwLjEsMCwwLjFjMCwwLDAsMC4xLDAsMC4xYzAsMC4xLDAuMSwwLjIsMC4xLDAuMmMwLjEsMC4zLDAuNCwwLjUsMC43LDAuNmMwLjQsMC4xLDAuOCwwLDEuMi0wLjFjMCwwLDAsMC4xLDAsMC4xYzAsMC4xLDAsMC4xLDAsMC4yYzAsMC4xLDAsMC4xLDAuMSwwLjJjMCwwLDAsMC4xLDAsMC4xYy0wLjMsMC4yLTAuNywwLjMtMSwwLjNjLTAuNCwwLjEtMC44LDAtMS4xLTAuM2MtMC4zLTAuMi0wLjQtMC40LTAuNi0wLjdjMCwwLDAtMC4xLDAtMC4xYzAtMC4xLTAuMS0wLjEtMC4xLTAuMmMwLTAuMSwwLTAuMS0wLjEtMC4yYzAsMCwwLTAuMSwwLTAuMWMtMC4xLTAuMy0wLjEtMC42LTAuMS0wLjljMC0wLjMsMC0wLjYsMC0xYzAtMC4yLDAuMS0wLjQsMC4xLTAuNmMwLTAuMSwwLTAuMiwwLjEtMC4zYzAsMCwwLTAuMSwwLTAuMWMwLDAsMC0wLjEsMC0wLjFjMC0wLjEsMC0wLjEsMC4xLTAuMmMwLTAuMSwwLjEtMC4xLDAuMS0wLjJjMC4xLTAuMiwwLjMtMC41LDAuNS0wLjZsMCwwYzAuNC0wLjMsMC45LTAuMywxLjMtMC4xYzAuMiwwLjEsMC4zLDAuMiwwLjQsMC40YzAuMSwwLjEsMC4yLDAuMywwLjIsMC41YzAsMC4xLDAuMSwwLjIsMC4xLDAuNGMwLDAuMSwwLDAuMSwwLDAuMkMyNS45LDExLjQsMjUuOSwxMS41LDI2LDExLjZ6IE0yNC41LDEwLjVjLTAuNS0wLjEtMC43LDAuOC0wLjcsMS44YzAuMy0wLjEsMS4yLTAuMSwxLjMtMC4xQzI1LjEsMTAuNiwyNC42LDEwLjUsMjQuNSwxMC41eiBNMjkuNSwxNC44YzAtMC4xLTAuMS0wLjItMC4xLTAuM2MtMC4xLTAuMy0wLjMtMC42LTAuNC0xYzAtMC4xLTAuMS0wLjItMC4xLTAuM2MtMC4xLTAuMi0wLjEtMC4zLTAuMi0wLjVjMC0wLjEtMC4xLTAuMS0wLjEtMC4yYzAuMS0wLjEsMC4xLTAuMywwLjItMC40YzAuMS0wLjEsMC4xLTAuMiwwLjItMC40YzAuMS0wLjEsMC4xLTAuMiwwLjItMC40YzAuMS0wLjEsMC4xLTAuMywwLjItMC40YzAuMS0wLjEsMC4xLTAuMiwwLjEtMC4zYzAuMS0wLjEsMC4xLTAuMiwwLjItMC40YzAtMC4xLDAuMS0wLjIsMC4xLTAuNGMwLDAsMCwwLDAsMGMtMC4yLDAtMC40LDAtMC43LDBjLTAuMSwwLTAuMSwwLjEtMC4yLDAuMmMwLDAsMCwwLjEtMC4xLDAuMWMwLDAuMSwwLDAuMS0wLjEsMC4yYzAsMCwwLDAuMS0wLjEsMC4xYzAsMC4xLDAsMC4xLTAuMSwwLjJjMCwwLDAsMC4xLTAuMSwwLjFjLTAuMSwwLjItMC4xLDAuMy0wLjIsMC41YzAsMCwwLDAuMSwwLDAuMWMwLDAsMCwwLjEtMC4xLDAuMWMwLDAuMS0wLjEsMC4yLTAuMSwwLjNjLTAuMS0wLjEtMC4xLTAuMi0wLjEtMC40YzAsMCwwLTAuMS0wLjEtMC4xYzAtMC4xLDAtMC4xLTAuMS0wLjJjMCwwLDAtMC4xLTAuMS0wLjFjMC0wLjEtMC4xLTAuMi0wLjEtMC4zYzAtMC4xLTAuMS0wLjItMC4xLTAuM2MwLDAsMC0wLjEtMC4xLTAuMWMwLTAuMS0wLjEtMC4yLTAuMS0wLjNjLTAuMS0wLjEtMC4zLDAtMC41LDBjLTAuMSwwLTAuMywwLTAuNCwwLjFsMCwwYzAuMSwwLjEsMC4xLDAuMiwwLjEsMC4zYzAsMC4xLDAuMSwwLjIsMC4xLDAuM2MwLDAuMSwwLjEsMC4yLDAuMSwwLjNjMC4xLDAuMSwwLjEsMC4zLDAuMiwwLjRjMCwwLjEsMC4xLDAuMiwwLjEsMC4zYzAuMSwwLjMsMC4yLDAuNSwwLjQsMC44YzAuMSwwLjEsMCwwLjIsMCwwLjNjMCwwLjEtMC4xLDAuMS0wLjEsMC4yYzAsMC4xLTAuMSwwLjItMC4xLDAuM2MwLDAuMS0wLjEsMC4yLTAuMSwwLjNjMCwwLjEtMC4xLDAuMi0wLjEsMC4yYzAsMC4xLTAuMSwwLjEtMC4xLDAuMmMwLDAuMS0wLjEsMC4yLTAuMSwwLjNjMCwwLjEtMC4xLDAuMi0wLjEsMC4zYzAsMC4xLTAuMSwwLjItMC4xLDAuMmMwLDAuMS0wLjEsMC4yLTAuMSwwLjNjMCwwLjEtMC4xLDAuMi0wLjEsMC4zYzAsMC4xLDAsMC4xLTAuMSwwLjJjMCwwLDAuMSwwLDAuMSwwLjFjMC4yLDAsMC41LDAsMC43LDBjMC0wLjEsMC4xLTAuMiwwLjEtMC4zYzAtMC4xLDAtMC4xLDAuMS0wLjJjMCwwLDAtMC4xLDAuMS0wLjFjMCwwLDAtMC4xLDAtMC4xYzAtMC4xLDAtMC4xLDAuMS0wLjJjMCwwLDAtMC4xLDAuMS0wLjFjMCwwLDAtMC4xLDAtMC4xYzAuMS0wLjMsMC4yLTAuNSwwLjMtMC44YzAtMC4xLDAtMC4xLDAuMS0wLjJjMCwwLDAsMCwwLjEsMGMwLDAuMSwwLjEsMC4zLDAuMSwwLjRjMCwwLDAsMC4xLDAuMSwwLjFjMCwwLDAsMC4xLDAsMC4xYzAsMC4xLDAsMC4xLDAuMSwwLjJjMCwwLDAsMC4xLDAuMSwwLjFjMCwwLjEsMCwwLjEsMC4xLDAuMmMwLDAuMSwwLjEsMC4yLDAuMSwwLjNjMCwwLjEsMC4xLDAuMiwwLjEsMC4zYzAsMC4xLDAsMC4xLDAuMSwwLjJjMCwwLDAsMC4xLDAsMC4xYzAsMCwwLjEsMC4xLDAuMiwwLjFjMC4yLDAsMC40LDAsMC43LDBjMCwwLDAtMC4xLDAuMS0wLjFjLTAuMS0wLjEtMC4xLTAuMy0wLjItMC40QzI5LjUsMTQuOSwyOS41LDE0LjksMjkuNSwxNC44eiBNMjIsNy4zYzAsMi43LDAsNS40LDAsOC4xYzAsMC0wLjEsMC0wLjEsMC4xYy0wLjIsMC0wLjMsMC0wLjUsMGMtMC4xLTAuMS0wLjEtMC4yLTAuMi0wLjNjLTAuMywwLjMtMC43LDAuNS0xLjIsMC40Yy0wLjMsMC0wLjctMC4yLTAuOS0wLjVjLTAuMS0wLjEtMC4yLTAuMy0wLjMtMC41YzAtMC4xLTAuMS0wLjItMC4xLTAuMmMwLDAsMC0wLjEsMC0wLjFjMCwwLDAtMC4xLDAtMC4xYzAsMCwwLTAuMSwwLTAuMWMwLTAuMSwwLTAuMSwwLTAuMmMtMC4xLTAuNC0wLjEtMC44LTAuMS0xLjNjMC0wLjMsMC0wLjYsMC4xLTAuOWMwLTAuMSwwLTAuMSwwLTAuMmMwLDAsMC0wLjEsMC0wLjFjMCwwLDAtMC4xLDAtMC4xYzAtMC4xLDAtMC4xLDAuMS0wLjJjMC0wLjEsMC4xLTAuMiwwLjEtMC4zYzAtMC4xLDAuMS0wLjEsMC4xLTAuMmMwLjEtMC4zLDAuNC0wLjQsMC42LTAuNmMwLjQtMC4yLDAuOS0wLjIsMS40LDBjMC0wLjksMC0xLjgsMC0yLjhDMjEuNCw3LjIsMjEuNyw3LjIsMjIsNy4zQzIyLDcuMiwyMiw3LjIsMjIsNy4zeiBNMjEuMSwxNC43YzAtMC4yLDAtMi43LDAtNGMwLDAsMCwwLDAsMGMtMC4yLTAuMS0wLjUtMC4zLTAuOS0wLjJjLTEsMC4zLTEuMiw0LjEsMC4xLDQuM0MyMC40LDE0LjksMjAuOCwxNC45LDIxLjEsMTQuN3ogTTIxLjIsNy4yTDIxLjIsNy4yQzIxLjIsNy4yLDIxLjIsNy4yLDIxLjIsNy4yTDIxLjIsNy4yeiIvPjwvZz48L3N2Zz4=)}.bg-klarna{background-image:url(data:image/svg+xml;base64,PHN2ZyBpZD0nS2xhcm5hJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSczNicgaGVpZ2h0PScyMic+PHN0eWxlPi5zdDF7ZmlsbDojZmZmfTwvc3R5bGU+PHBhdGggaWQ9J1JvdW5kZWRfUmVjdGFuZ2xlXzUyXzZfJyBkPSdNMyAwaDMwYzEuNyAwIDMgMS4zIDMgM3YxNmMwIDEuNy0xLjMgMy0zIDNIM2MtMS43IDAtMy0xLjMtMy0zVjNjMC0xLjcgMS4zLTMgMy0zeicgZmlsbD0nI2ViNmY5MycvPjxnIHRyYW5zZm9ybT0ndHJhbnNsYXRlKDIwIDQ0KSc+PHBhdGggaWQ9J1NoYXBlXzFfJyBjbGFzcz0nc3QxJyBkPSdNLTEwLjEtMzYuMWgtMS40YzAgMS4xLS41IDIuMi0xLjQgMi44bC0uNS40IDIuMSAyLjloMS43bC0xLjktMi42Yy45LTEgMS40LTIuMiAxLjQtMy41eicvPjxwYXRoIGlkPSdSZWN0YW5nbGUtcGF0aF8xXycgY2xhc3M9J3N0MScgZD0nTS0xNS0zNi4xaDEuNHY2LjFILTE1eicvPjxwYXRoIGNsYXNzPSdzdDEnIGQ9J00tOS4yLTM2LjFoMS4zdjYuMWgtMS4zek0zLjgtMzQuNGMtLjUgMC0xIC4yLTEuMy42di0uNUgxLjN2NC4yaDEuM3YtMi4yYzAtLjYuNC0xIDEtMXMuOS4zLjkuOXYyLjJoMS4zdi0yLjdjLS4yLS44LS45LTEuNS0yLTEuNXpNLTMuOC0zNC4ydi4zYy0uNC0uMi0uOC0uNC0xLjMtLjQtMS4yIDAtMi4yIDEtMi4yIDIuMiAwIDEuMiAxIDIuMiAyLjIgMi4yLjUgMCAuOS0uMSAxLjMtLjR2LjNoMS4zdi00LjJoLTEuM3pNLTUtMzEuMWMtLjYgMC0xLjEtLjUtMS4xLTEuMSAwLS42LjUtMS4xIDEuMS0xLjFzMS4xLjUgMS4xIDEuMWMuMS43LS40IDEuMS0xLjEgMS4xek0tLjYtMzMuN3YtLjVoLTEuM3Y0LjJoMS4zdi0yYzAtLjcuNy0xIDEuMi0xdi0xLjJjLS40IDAtLjkuMi0xLjIuNXpNOS42LTM0LjJ2LjNjLS40LS4yLS44LS40LTEuMy0uNC0xLjIgMC0yLjIgMS0yLjIgMi4yIDAgMS4yIDEgMi4yIDIuMiAyLjIuNSAwIC45LS4xIDEuMy0uNHYuM2gxLjN2LTQuMkg5LjZ6bS0xLjIgMy4xYy0uNiAwLTEuMS0uNS0xLjEtMS4xIDAtLjYuNS0xLjEgMS4xLTEuMS42IDAgMS4xLjUgMS4xIDEuMS4xLjctLjQgMS4xLTEuMSAxLjF6TTEyLjItMzEuNWMtLjQgMC0uOC40LS44LjhzLjQuOC44LjguOC0uNC44LS44YzAtLjUtLjQtLjgtLjgtLjh6Jy8+PC9nPjwvc3ZnPg==)}.bg-eps{background-image:url(data:image/svg+xml;base64,PHN2ZyBpZD0iS2xhcm5hIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNiIgaGVpZ2h0PSIyMiIgdmlld0JveD0iMCAwIDM2IDIyIj4gIDx0aXRsZT5pY29uLWVwczwvdGl0bGU+ICA8cGF0aCBpZD0iUm91bmRlZF9SZWN0YW5nbGVfNTIiIGRhdGEtbmFtZT0iUm91bmRlZCBSZWN0YW5nbGUgNTIiIGQ9Ik0zLDBIMzNhMywzLDAsMCwxLDMsM1YxOWEzLDMsMCwwLDEtMywzSDNhMywzLDAsMCwxLTMtM1YzQTMsMywwLDAsMSwzLDBaIiBmaWxsPSIjZjFmMGYyIi8+ICA8Zz4gICAgPGc+ICAgICAgPHBhdGggZD0iTTI3LjYzLDExLjM3SDI1LjU3YS40OC40OCwwLDAsMSwwLS45NWgzLjMyVjguODRIMjUuNDdhMi4wNSwyLjA1LDAsMCwwLTIsMi4wNWgwYTIuMDUsMi4wNSwwLDAsMCwyLDIuMDZoMi4yMWEuNDcuNDcsMCwxLDEsMCwuOTRIMjNhNCw0LDAsMCwxLTEuNDcsMS42OWg2LjA2YTIuMTEsMi4xMSwwLDAsMCwyLjEtMi4xMWgwQTIuMSwyLjEsMCwwLDAsMjcuNjMsMTEuMzdaIiBmaWxsPSIjNzE3MDZmIi8+ICAgICAgPHBhdGggZD0iTTIyLjY4LDEyLjIxaDBhMy4zNywzLjM3LDAsMCwwLTMuMzctMy4zN2gwYTMuMjksMy4yOSwwLDAsMC0zLjI2LDMuMzd2Ni45NGgxLjU4VjE1LjU4aDEuNjhBMy4zNywzLjM3LDAsMCwwLDIyLjY4LDEyLjIxWm0tMS41OC0uMDVhMS43MiwxLjcyLDAsMCwxLTEuNzMsMS43M0gxNy42M1YxMi4xNmExLjc0LDEuNzQsMCwxLDEsMy40NywwWiIgZmlsbD0iIzcxNzA2ZiIvPiAgICA8L2c+ICAgIDxnPiAgICAgIDxwYXRoIGQ9Ik05LjIyLDUuNzlhMS40NywxLjQ3LDAsMCwxLDIuOTQsMHYuODRoMS4zN1Y1LjY5YTIuODQsMi44NCwwLDAsMC01LjY4LDB2Ljk0SDkuMjJaIiBmaWxsPSIjYzgwMjZlIi8+ICAgICAgPHBhdGggZD0iTTE1LjIxLDEzLjg5VjkuMTNhMS40MywxLjQzLDAsMCwwLTEuNDQtMS40NEg3LjcxQTEuNDQsMS40NCwwLDAsMCw2LjI3LDkuMTN2Ni4wNmExLjQ1LDEuNDUsMCwwLDAsMS40NCwxLjQ0aDYuMDZhMS40NSwxLjQ1LDAsMCwwLDEuMzktMUgxMC42OWEzLjM3LDMuMzcsMCwwLDEtMy4zNy0zLjM3aDBhMy4zNywzLjM3LDAsMCwxLDMuMzctMy4zN2gwYTMuMzcsMy4zNywwLDAsMSwzLjM3LDMuMzdWMTNIOS4yYTEuNzIsMS43MiwwLDAsMCwxLjU0Ljk0aDQuNDdaIiBmaWxsPSIjYzgwMjZlIi8+ICAgICAgPHBhdGggZD0iTTEwLjc0LDEwLjQyYTEuNzMsMS43MywwLDAsMC0xLjU0Ljk1aDMuMDlBMS43NCwxLjc0LDAsMCwwLDEwLjc0LDEwLjQyWiIgZmlsbD0iI2M4MDI2ZSIvPiAgICA8L2c+ICA8L2c+PC9zdmc+)}.bg-bancontact{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNiIgaGVpZ2h0PSIxNiI+ICAgIDxwYXRoIGQ9Ik0yIDBoMjJjMS4xIDAgMiAuOSAyIDJ2MTJjMCAxLjEtLjkgMi0yIDJIMmMtMS4xIDAtMi0uOS0yLTJWMkMwIC45LjkgMCAyIDB6IiBmaWxsPSIjZjBmM2Y1Ij48L3BhdGg+ICAgIDxwYXRoIGQ9Ik0yMS4zIDZoLTYuNmwtMy41IDRINC43bDEuNi0xLjloLTNjLS41IDAtMSAuNS0xIDF2Mi4xYzAgLjYuNCAxIDEgMWgxMS40Yy41IDAgMS4zLS4zIDEuNy0uOEwyMS4zIDZ6IiBmaWxsPSIjMDA0ZTkxIj48L3BhdGg+ICAgIDxwYXRoIGQ9Ik0yMi42IDMuN2MuNSAwIDEgLjUgMSAxdjIuMWMwIC42LS40IDEtMSAxaC0zTDIxLjMgNmgtNi42bC0zLjUgNEg0LjdsNC44LTUuNWMuNC0uNCAxLjEtLjggMS43LS44aDExLjR6IiBmaWxsPSIjZmQwIj48L3BhdGg+PC9zdmc+)}.bg-knet{background-image:url(data:image/svg+xml;base64,PHN2ZyBpZD0nS2xhcm5hLXNtYWxsJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScyNicgaGVpZ2h0PScxNic+ICAgIDxzdHlsZT4uc3Qye2ZpbGw6I2ZmZn08L3N0eWxlPiAgICA8cGF0aCBkPSdNMiAwaDIyYzEuMSAwIDIgLjkgMiAydjEyYzAgMS4xLS45IDItMiAySDJjLTEuMSAwLTItLjktMi0yVjJDMCAuOS45IDAgMiAweicgZmlsbD0nIzAwNzhkYycvPiAgICA8cGF0aCBmaWxsPScjZmZlMTAwJyBkPSdNMjEuNiA3LjRsLTMuOS0yLjkgMy44LTIuM2gtNy42bC0zLjIgMi4xVjIuMkg1LjZ2NS4yaDUuMVY0LjhsMy4yIDIuNnonLz4gICAgPHBhdGggY2xhc3M9J3N0MicgZD0nTTYuMyAxMi44djEuNWgtLjR2LTEuNGMwLS41LS4yLS43LS43LS43LS4yIDAtLjMuMS0uNS4yLS4xLjEtLjIuMy0uMi41djEuNEg0di0yLjRoLjR2LjRjLjEtLjEuMi0uMi40LS4zLjEtLjEuMy0uMS41LS4xLjYtLjEgMSAuMiAxIC45ek0xMy43IDEyLjJjLjIuMi4zLjYuMyAxaC0yLjFjMCAuMy4xLjUuMi42LjEuMS4zLjIuNi4yLjIgMCAuNC0uMS41LS4xLjEtLjEuMi0uMi4zLS40aC41Yy0uMS4yLS4yLjQtLjQuNi0uMi4yLS41LjMtLjkuM3MtLjctLjEtLjktLjMtLjQtLjUtLjQtLjkuMS0uNi4zLS45Yy4yLS4yLjUtLjQuOS0uNC42LS4xLjkgMCAxLjEuM3ptLTEuNS4xYy0uMS4xLS4yLjMtLjMuNmgxLjdjLS4xLS41LS4zLS44LS44LS44LS4zIDAtLjUuMS0uNi4yek0yMC45IDExLjloLjV2LjNoLS41djEuNWMwIC4xIDAgLjIuMS4yIDAgMCAuMS4xLjIuMWguM3YuM2gtLjRjLS4yIDAtLjQtLjEtLjUtLjItLjEtLjEtLjEtLjItLjEtLjR2LTEuNWgtLjN2LS4zaC4zdi0uNmwuNC0uMnYuOHpNMCA5LjRoMjZ2LjRIMHonLz48L3N2Zz4=)}.bg-fawry{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSczNicgaGVpZ2h0PScyMic+ICAgIDxzdHlsZT4uc3Qye2ZpbGw6IzAxNmQ5Yn08L3N0eWxlPiAgICA8cGF0aCBpZD0nUm91bmRlZF9SZWN0YW5nbGVfNTJfNl8nIGQ9J00zIDBoMzBjMS43IDAgMyAxLjMgMyAzdjE2YzAgMS43LTEuMyAzLTMgM0gzYy0xLjcgMC0zLTEuMy0zLTNWM2MwLTEuNyAxLjMtMyAzLTN6JyBmaWxsPScjZmVkMzAxJy8+ICAgIDxnIGlkPSd5eEFZeXkudGlmJz48cGF0aCBkPSdNMy4xIDEzLjRjLS41LS44LS44LTEuNy0uNy0yLjYuMS0xLjYuOS0yLjkgMi40LTMuNy44LS40IDEuNi0uNiAyLjQtLjUuOCAwIDEuNS4yIDIuMS43IDAgLjIuMS40IDAgLjUgMCAuNS0uMi45LS41IDEuMy0uMS4zLS4zLjUtLjUuOC0uMS4xLS4xLjIgMCAuM2guMmMuMyAwIC41IDAgLjgtLjEuMSAwIC4xIDAgLjEuMSAwIC4yIDAgLjMtLjEuNSAwIC4xIDAgLjIuMS4ycy4yIDAgLjItLjFjLjUtLjcuOS0xLjMgMS0yLjEuMy40LjQuOS41IDEuNC4zIDEuNS0uMSAyLjktMS4yIDQtLjguOC0xLjcgMS4yLTIuOCAxLjMtMSAuMS0xLjktLjEtMi44LS43LjQgMCAuNy0uMSAxLS4zLjgtLjMgMS40LS44IDIuMS0xLjMuMyAwIC40LS4xLjUtLjEuMSAwIC4yLjIuMy4zLjEuMS4xLjIuMy4xLjIgMCAuMS0uMi4xLS4zbC4zLTIuMWMwLS4yIDAtLjMtLjMtLjMtLjUgMC0xLjEuMS0xLjYuMS0uMiAwLS40IDAtLjYuMS0uMSAwLS4yIDAtLjIuMS0uMS4xIDAgLjIuMS4zbC4zLjNjLjEuMS4xLjEgMCAuMi0uNi41LTEuMi45LTEuOSAxLjItLjMuMi0uNy4zLTEgLjRoLS42eicgZmlsbD0nI2ZkZmRmZCcvPiAgICAgICAgPHBhdGggY2xhc3M9J3N0MicgZD0nTTIyLjYgMTAuN2MtLjIuNi0uNCAxLjItLjYgMS45LS4xLjMtLjIuNC0uNS40aC0uNGMtLjMgMC0uNC0uMS0uNS0uNC0uMy0uOS0uNi0xLjctLjktMi42LS4xLS4yLS4xLS4zLS4yLS41di0uMmMwLS4xIDAtLjIuMS0uMmguOGMuMiAwIC4zLjIuNC40LjEuNS4zIDEgLjQgMS40IDAgLjEgMCAuMi4xLjMuMi0uNi4zLTEuMS41LTEuNy4yLS4yLjItLjMuNi0uM2guNWMuMyAwIC40LjEuNS4zLjEuNS4zIDEgLjQgMS40IDAgLjEgMCAuMi4xLjMuMS0uNS4zLS45LjQtMS40IDAtLjEuMS0uMy4xLS40LjEtLjIuMi0uMy40LS4zaC43Yy4xIDAgLjIuMS4yLjJ2LjJjLS4zIDEtLjcgMi0xIDMtLjEuMy0uMi40LS41LjRoLS40Yy0uMyAwLS40LS4xLS41LS40LS4zLS41LS41LTEuMS0uNy0xLjggMCAuMSAwIDAgMCAwek0zLjEgMTMuNGguNmMuNC0uMS43LS4yIDEtLjQuNy0uMyAxLjMtLjggMS44LTEuMi4xLS4xLjEtLjEgMC0uMmwtLjMtLjNjLS4xLS4xLS4yLS4xLS4xLS4zIDAtLjEuMi0uMS4yLS4xLjIgMCAuNCAwIC42LS4xLjUgMCAxLjEtLjEgMS42LS4xLjIgMCAuMy4xLjMuM2wtLjMgMi4xYzAgLjEgMCAuMy0uMS4zcy0uMi0uMS0uMy0uMWMwLS4xLS4xLS4zLS4yLS4zcy0uMi4yLS4zLjNjLS42LjUtMS4zIDEtMi4xIDEuMy0uMy4xLS43LjItMSAuMy0uNi0uNS0xLS45LTEuNC0xLjV6TTI5LjkgOS4yaC4zYy4yIDAgLjMuMS4zLjMuMS4zLjIuNy4zIDEgLjEuMy4yLjUuMy44LjEuMi4xLjMuMy41bC4xLjFjLjIuMS4yLjEuMi0uMS4yLS43LjQtMS40LjYtMi4yLjEtLjMuMS0uMy40LS4zaC41Yy4yIDAgLjMuMS4yLjMtLjIuNy0uNCAxLjQtLjYgMi0uMS41LS4zLjktLjQgMS40LS4xLjMtLjIuNS0uNC44LS4yLjQtLjYuNS0xIC42aC0uOGMtLjEgMC0uMiAwLS4yLS4xLS4yLS4xLS4yLS42IDAtLjdIMzAuNmMuMy4xLjUtLjEuNi0uMyAwIDAgLjEtLjEuMS0uMi4xLS4yLjEtLjItLjEtLjItLjQtLjEtLjgtLjMtMS0uNi0uMi0uNC0uNC0uNy0uNS0xLjEtLjEtLjUtLjMtLjktLjQtMS40di0uMmMwLS4xLjEtLjIuMi0uMi4xLS4yLjMtLjIuNC0uMnpNMTIuNCAxMS4xVjkuNmMwLS4yIDAtLjUuMS0uNy4yLS41LjUtLjggMS4xLS45LjUtLjEgMS0uMSAxLjYgMCAuNCAwIC40LjEuNC41di4yYzAgLjEtLjEuMi0uMi4yaC0xLjFjLS40LjEtLjUuMi0uNS42LS4xLjQtLjEuNC4zLjRoLjhjLjIgMCAuMy4xLjMuM3YuMmMwIC4yLS4xLjMtLjMuM2gtMWMtLjEgMC0uMiAwLS4yLjJ2MS45YzAgLjMgMCAuMy0uMy4zaC0uNmMtLjMgMC0uMy0uMS0uMy0uMy0uMS0uNi0uMS0xLjItLjEtMS43ek0yNi4xIDExLjFWOS41YzAtLjMgMC0uMy4zLS4zaC42Yy4yIDAgLjMgMCAuMy4zIDAgLjEgMCAuMS4xLjEuNC0uMy44LS40IDEuMy0uNC4zLS4xLjMgMCAuMy4ydi40YzAgLjItLjEuMi0uMy4yaC0uNmMtLjQgMC0uNi4yLS44LjUtLjEuMSAwIC4xIDAgLjJ2Mi4xYzAgLjEtLjEuMS0uMi4xaC0uN2MtLjIgMC0uMy0uMS0uMy0uM3YtMS41ek0xMC43IDguOGMtLjEuOC0uNSAxLjUtMSAyLjEgMCAuMS0uMS4xLS4yLjFzLS4xLS4yLS4xLS4yYzAtLjIgMC0uMy4xLS41IDAtLjEgMC0uMS0uMS0uMS0uMyAwLS41IDAtLjguMWgtLjJjLS4xLS4xLS4xLS4yIDAtLjMuMi0uMi40LS41LjUtLjguMi0uNC40LS44LjUtMS4zdi0uNWMuNS4yIDEgLjcgMS4zIDEuNHpNMTguMiA5LjJjLS42LS4yLTEuMi0uMS0xLjkgMC0uMSAwLS4zLjEtLjQuMi0uMi4yLS4zLjQtLjMuNiAwIC4yLjEuMy4yLjNoLjRjLjIgMCAuNC0uMS41LS4yLjItLjEuMy0uMS41LS4yaC40Yy4zIDAgLjUuMi41LjYgMCAuMSAwIC4xLS4xLjFoLS45Yy0uMyAwLS42IDAtLjguMS0uMy4xLS42LjItLjguNS0uNC42LS4xIDEuMy41IDEuNi43LjMgMS4zLjMgMiAwbC4xLS4xaC4xYy4xLjIuMS4yLjMuMmguNWMuMyAwIC4zIDAgLjMtLjN2LTEtMWMwLS43LS4zLTEuMi0xLjEtMS40em0tLjQgMi45Yy0uMi4xLS40LjEtLjYuMWgtLjNjLS4yLS4xLS4zLS4yLS4zLS40cy4yLS4zLjQtLjRoMWMuMSAwIC4xIDAgLjEuMSAwIC41LjEuNC0uMy42eicvPiAgICA8L2c+PC9zdmc+)} From 380d515ad582546da16f09e6081d36ead3148c2f Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 9 Jul 2024 08:56:26 +0200 Subject: [PATCH 119/147] Bump composer version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index cfe2fd99..adcfca76 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "6.2.0", + "version": "6.2.1", "autoload": { "files": [ "registration.php" From d97d3074b371f0d8cfac2c384dcb34d8213be56a Mon Sep 17 00:00:00 2001 From: Typhaine Demangeon Date: Wed, 10 Jul 2024 11:37:57 +0200 Subject: [PATCH 120/147] CHECMAG2003-236: Reformat file before working on functions --- .../method-renderer/checkoutcom_klarna.js | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index a07589a1..6f55ea5a 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -24,8 +24,8 @@ define([ 'Magento_Checkout/js/model/quote', 'mage/translate', 'mage/url', -], function($, ko, Component, Utilities, CheckoutUtilities, FullScreenLoader, - AdditionalValidators, Quote, __, Url) { +], function ($, ko, Component, Utilities, CheckoutUtilities, FullScreenLoader, + AdditionalValidators, Quote, __, Url) { 'use strict'; window.checkoutConfig.reloadOnBillingAddress = true; @@ -46,7 +46,8 @@ define([ /** * @return {void} */ - initialize: function() { + initialize: function () { + console.log('init klara') this._super(); CheckoutUtilities.initSubscribers(this); this.getKlarnaContextDatas(); @@ -55,7 +56,7 @@ define([ /** * @return {string} */ - getCode: function() { + getCode: function () { return METHOD_ID; }, @@ -63,29 +64,32 @@ define([ * @param {string} field * @return {string} */ - getValue: function(field) { + getValue: function (field) { return Utilities.getValue(METHOD_ID, field); }, /** * @return {void} */ - checkLastPaymentMethod: function() { + checkLastPaymentMethod: function () { return Utilities.checkLastPaymentMethod(); }, /** * @return {Promise} */ - getKlarnaContextDatas: function() { - let self = this; + getKlarnaContextDatas: function () { + const self = this; + fetch(Url.build('checkout_com/klarna/context'), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest', }, - }).then(response => response.json()).then(response => { + }) + .then(response => response.json()) + .then(response => { // Store given token this.chkKlarnaClientToken = response.content.partner_metadata.client_token; this.chkKlarnaContextId = response.content.id; @@ -101,14 +105,13 @@ define([ container: '#klarna-payments-container', }, {}, - function(res) { + function (res) { if (res.show_form === true) { // Display method self.placeOrderEnable(true); } else { Utilities.showMessage('error', - __('Something went wrong with klarna method. Please choose another method.'), - METHOD_ID); + __('Something went wrong with klarna method. Please choose another method.'), METHOD_ID); } }, ); @@ -116,16 +119,15 @@ define([ // Here we know that klarna is disallowed for this context Utilities.log(response); Utilities.showMessage('error', - __('Something went wrong with klarna method. Please choose another method.'), - METHOD_ID); + __('Something went wrong with klarna method. Please choose another method.'), METHOD_ID); }); }, /** * Display the Klarna popin */ - authorizePayment: function() { - let self = this; + authorizePayment: function () { + const self = this; // Retrieve current quote datas in order to give billing informations to Klarna $.ajax({ @@ -136,7 +138,7 @@ define([ form_key: window.checkoutConfig.formKey, store_id: window.checkoutConfig.quoteData.store_id, }, - success: function(data) { + success: function (data) { // Launch klarna popin with retrieved customer datas Klarna.Payments.authorize( @@ -154,7 +156,7 @@ define([ country: data.billing.country_id.toLowerCase(), }, }, - function(res) { + function (res) { if (res.approved === true) { self.placeOrder(); } else { @@ -172,12 +174,11 @@ define([ /** * @return {void} */ - placeOrder: function() { + placeOrder: function () { FullScreenLoader.startLoader(); - if (Utilities.methodIsSelected(METHOD_ID) && - this.chkKlarnaContextId) { - let data = { + if (Utilities.methodIsSelected(METHOD_ID) && this.chkKlarnaContextId) { + const data = { methodId: METHOD_ID, contextPaymentId: this.chkKlarnaContextId, }; @@ -187,10 +188,10 @@ define([ Utilities.placeOrder( data, METHOD_ID, - function() { + function () { Utilities.log(__('Success')); }, - function() { + function () { Utilities.log(__('Fail')); }, ); From afb4d65961fb92c1e6ba5b828b8c3b6f855fd649 Mon Sep 17 00:00:00 2001 From: Typhaine Demangeon Date: Wed, 10 Jul 2024 11:51:59 +0200 Subject: [PATCH 121/147] CHECMAG2003-236: Remove console.log --- .../web/js/view/payment/method-renderer/checkoutcom_klarna.js | 1 - 1 file changed, 1 deletion(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index 6f55ea5a..6e77caee 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -47,7 +47,6 @@ define([ * @return {void} */ initialize: function () { - console.log('init klara') this._super(); CheckoutUtilities.initSubscribers(this); this.getKlarnaContextDatas(); From 9714297f509f21098ce744e78e7357825c6f1cef Mon Sep 17 00:00:00 2001 From: Typhaine Demangeon Date: Thu, 11 Jul 2024 16:01:51 +0200 Subject: [PATCH 122/147] Move api call in javascript file with promise instead of phtml --- view/frontend/layout/checkout_index_index.xml | 7 --- .../templates/script/klarna-script.phtml | 18 ------- .../method-renderer/checkoutcom_klarna.js | 53 ++++++++++++++++++- 3 files changed, 51 insertions(+), 27 deletions(-) delete mode 100644 view/frontend/templates/script/klarna-script.phtml diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml index 2417413a..478838d6 100755 --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -19,13 +19,6 @@ - - - - diff --git a/view/frontend/templates/script/klarna-script.phtml b/view/frontend/templates/script/klarna-script.phtml deleted file mode 100644 index 544d25d3..00000000 --- a/view/frontend/templates/script/klarna-script.phtml +++ /dev/null @@ -1,18 +0,0 @@ - - * @copyright 2010-present Checkout.com - * @license https://opensource.org/licenses/mit-license.html MIT License - * @link https://docs.checkout.com/ - */ - -?> - diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index 6e77caee..83671306 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -42,14 +42,63 @@ define([ buttonId: METHOD_ID + '_btn', chkKlarnaClientToken: null, chkKlarnaContextId: null, + chkKlarnaApiUrl: 'https://x.klarnacdn.net/kp/lib/v1/api.js', /** * @return {void} */ initialize: function () { this._super(); - CheckoutUtilities.initSubscribers(this); - this.getKlarnaContextDatas(); + + const scriptPromise = this.klarnaScriptLoader(); + + scriptPromise.then(() => { + CheckoutUtilities.initSubscribers(this); + this.getKlarnaContextDatas(); + }).catch((error) => { + Utilities.log(error); + }); + }, + + /** + * Load klarna script witch promise + * @returns {Promise} + * @constructor + */ + klarnaScriptLoader: function () { + return new Promise((resolve, reject) => { + const klarnaScript = document.querySelector(`script[src*="${this.chkKlarnaApiUrl}"]`); + + if (klarnaScript) { + resolve(); + return; + } + + const script = document.createElement('script'); + + script.addEventListener('load', () => { + resolve(); + }); + + script.addEventListener('error', () => { + reject('Something wrong happened with Klarna script load'); + }); + + this.buildScript(script); + }); + }, + + /** + * Build Klarna script + * @param script + */ + buildScript: function (script) { + const scriptUrl = new URL(this.chkKlarnaApiUrl); + + script.type = 'text/javascript'; + script.src = scriptUrl; + + document.head.appendChild(script); }, /** From b02aeac092bdfc8d506faf6a10fdb28fa2e56069 Mon Sep 17 00:00:00 2001 From: Arnaud Savoye Date: Thu, 18 Jul 2024 09:13:21 +0200 Subject: [PATCH 123/147] CHECMAG2003-241 Remove properties not existing in SDK --- Model/Service/ApiHandlerService.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/Model/Service/ApiHandlerService.php b/Model/Service/ApiHandlerService.php index 40c46044..6a7c1b92 100644 --- a/Model/Service/ApiHandlerService.php +++ b/Model/Service/ApiHandlerService.php @@ -479,10 +479,7 @@ public function createItems(CartInterface $entity): array $product->name = $shipping->getShippingDescription(); $product->quantity = 1; $product->unit_price = $shipping->getShippingInclTax() * 100; - $product->tax_rate = $shipping->getTaxPercent() * 100; $product->total_amount = $shipping->getShippingAmount() * 100; - $product->total_tax_amount = $shipping->getTaxAmount() * 100; - $product->type = 'shipping_fee'; $items[] = $product; } From b3779b27875d594b160e505c895fc613199530da Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 22 Jul 2024 17:15:04 +0200 Subject: [PATCH 124/147] Bump composer version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index adcfca76..71db88b6 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "6.2.1", + "version": "6.2.2", "autoload": { "files": [ "registration.php" From fc03532a9b4d6cd4a96ab1f538b0136c5fc2b7f1 Mon Sep 17 00:00:00 2001 From: Arnaud Savoye Date: Wed, 24 Jul 2024 16:12:57 +0200 Subject: [PATCH 125/147] CHECMAG2003-242 Get config method from SCOPE STORE --- Gateway/Config/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index 2eef81a6..460c9419 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -314,7 +314,7 @@ public function getMethodsConfig(): array { $output = []; /** @var array $paymentMethodsConfig */ - $paymentMethodsConfig = $this->scopeConfig->getValue(Loader::KEY_PAYMENT, ScopeInterface::SCOPE_WEBSITE); + $paymentMethodsConfig = $this->scopeConfig->getValue(Loader::KEY_PAYMENT, ScopeInterface::SCOPE_STORE); /** * Get only the active CheckoutCom methods From 636957ca43a7fd5951119afe026ef70d9f7b37c1 Mon Sep 17 00:00:00 2001 From: Arnaud Savoye Date: Thu, 25 Jul 2024 14:40:03 +0200 Subject: [PATCH 126/147] CHECMAG2003-243 Store code is a string remove int type hint and replace by string to get correct config --- Gateway/Config/Config.php | 5 +++-- Model/Service/ApiHandlerService.php | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index 2eef81a6..d8df8205 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -483,6 +483,7 @@ public function getStoreCountry(): string */ public function isLive(): bool { + $live = $this->getValue('environment'); return $this->getValue('environment') === 1; } @@ -568,12 +569,12 @@ public function isAbcRefundAfterNasMigrationActive($storeCode = null): bool } /** - * @param int $storeCode + * @param string $storeCode * @param string $scope * * @return Environment */ - public function getEnvironment(int $storeCode, string $scope): Environment + public function getEnvironment(string $storeCode, string $scope): Environment { if ((int)$this->getValue('environment', null, $storeCode, $scope) === 1) { return Environment::sandbox(); diff --git a/Model/Service/ApiHandlerService.php b/Model/Service/ApiHandlerService.php index 6a7c1b92..bd532878 100644 --- a/Model/Service/ApiHandlerService.php +++ b/Model/Service/ApiHandlerService.php @@ -181,7 +181,7 @@ public function init( } $service = $this->scopeConfig->getValue(ConfigService::SERVICE_CONFIG_PATH, $scope, $storeCode); - $environment = $this->config->getEnvironment((int)$storeCode, $scope); + $environment = $this->config->getEnvironment($storeCode, $scope); $api = CheckoutSdk::builder(); if ($service === ConfigService::SERVICE_ABC) { @@ -208,7 +208,7 @@ public function initAbcForRefund( $publicKey = $this->config->getValue('abc_refund_public_key', null, $storeCode, $scope); $api = CheckoutSdk::builder(); - $environment = $this->config->getEnvironment((int)$storeCode, $scope); + $environment = $this->config->getEnvironment($storeCode, $scope); $this->checkoutApi = $api ->previous()->staticKeys() From b7ca9c73e55af9e4941b138c2e8c3739d0290b0d Mon Sep 17 00:00:00 2001 From: Arnaud Savoye Date: Fri, 26 Jul 2024 08:22:42 +0200 Subject: [PATCH 127/147] CHECMAG2003-243 Remove unused variable --- Gateway/Config/Config.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Gateway/Config/Config.php b/Gateway/Config/Config.php index d8df8205..b3912889 100755 --- a/Gateway/Config/Config.php +++ b/Gateway/Config/Config.php @@ -483,7 +483,6 @@ public function getStoreCountry(): string */ public function isLive(): bool { - $live = $this->getValue('environment'); return $this->getValue('environment') === 1; } From 9807bbe7c30df351c7a29c641d79aeeea4a7af7d Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Fri, 26 Jul 2024 12:14:35 +0200 Subject: [PATCH 128/147] CHECMAG2003-236 - Add currencies and country options --- Controller/Klarna/Context.php | 41 ++++--- Model/Methods/KlarnaMethod.php | 10 ++ Model/Methods/PaypalMethod.php | 2 +- etc/config.xml | 10 ++ .../method-renderer/checkoutcom_klarna.js | 100 +++++++++++++----- 5 files changed, 125 insertions(+), 38 deletions(-) diff --git a/Controller/Klarna/Context.php b/Controller/Klarna/Context.php index 45f2da2e..c6dd2494 100644 --- a/Controller/Klarna/Context.php +++ b/Controller/Klarna/Context.php @@ -22,8 +22,10 @@ use Checkout\Common\Address; use Checkout\Payments\Request\Source\AbstractRequestSource; use Checkout\Payments\Request\Source\Contexts\PaymentContextsKlarnaSource; +use CheckoutCom\Magento2\Helper\Logger; use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; use CheckoutCom\Magento2\Model\Service\QuoteHandlerService; +use Exception; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\Result\Json; @@ -35,17 +37,20 @@ class Context implements HttpPostActionInterface protected PaymentContextRequestService $paymentContextRequestService; protected RequestInterface $request; protected QuoteHandlerService $quoteHandlerService; + protected Logger $logger; public function __construct( JsonFactory $resultJsonFactory, PaymentContextRequestService $paymentContextRequestService, RequestInterface $request, - QuoteHandlerService $quoteHandlerService + QuoteHandlerService $quoteHandlerService, + Logger $logger ) { $this->resultJsonFactory = $resultJsonFactory; $this->paymentContextRequestService = $paymentContextRequestService; $this->request = $request; $this->quoteHandlerService = $quoteHandlerService; + $this->logger = $logger; } /** @@ -54,17 +59,29 @@ public function __construct( public function execute(): Json { $resultJson = $this->resultJsonFactory->create(); - $resultJson->setData( - [ - 'content' => $this->paymentContextRequestService - ->setShippingFeesAsItem(true) - ->collectDiscountAmountOnItemUnitPrice(false) - ->setForceAuthorizeMode((bool)$this->request->getParam('forceAuthorizeMode')) - ->makePaymentContextRequests( - $this->getKlarnaContextSource() - ), - ] - ); + + try { + $resultJson->setData( + [ + 'content' => $this->paymentContextRequestService + ->setShippingFeesAsItem(true) + ->collectDiscountAmountOnItemUnitPrice(false) + ->setForceAuthorizeMode((bool)$this->request->getParam('forceAuthorizeMode')) + ->makePaymentContextRequests( + $this->getKlarnaContextSource() + ), + ] + ); + } catch (Exception $e) { + $this->logger->write(sprintf('Error happen while requesting klarna context: %s', $e->getMessage())); + $resultJson->setData( + [ + 'content' => [ + 'error' => __('Error happen while requesting context, please see logs'), + ], + ] + ); + } return $resultJson; } diff --git a/Model/Methods/KlarnaMethod.php b/Model/Methods/KlarnaMethod.php index 97cf40f6..735f0914 100755 --- a/Model/Methods/KlarnaMethod.php +++ b/Model/Methods/KlarnaMethod.php @@ -488,4 +488,14 @@ public function isAvailable(CartInterface $quote = null): bool return false; } + + public function canUseForCurrency($currencyCode): bool + { + $availableCurrencies = array_filter(explode(',', $this->getConfigData('specificcurrencies') ?? '')); + if (!empty($availableCurrencies) && !in_array($currencyCode, $availableCurrencies)) { + return false; + } + + return true; + } } diff --git a/Model/Methods/PaypalMethod.php b/Model/Methods/PaypalMethod.php index 46dcbc0d..d873e355 100755 --- a/Model/Methods/PaypalMethod.php +++ b/Model/Methods/PaypalMethod.php @@ -496,7 +496,7 @@ public function isAvailable(CartInterface $quote = null): bool public function canUseForCurrency($currencyCode): bool { $availableCurrencies = array_filter(explode(',', $this->getConfigData('specificcurrencies') ?? '')); - if (!empty($availableCountries) && !in_array($currencyCode, $availableCurrencies)) { + if (!empty($availableCurrencies) && !in_array($currencyCode, $availableCurrencies)) { return false; } diff --git a/etc/config.xml b/etc/config.xml index 37d0ab05..add7cbd3 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -190,6 +190,16 @@ 0 1 1 + 1 + AT,DK,ES,FI,DE,NL,NO,SE,GB + EUR,DKK,GBP,NOK,SEK + + AT,ES,FI,DE,NL,DK,NO,SE + DK + GB + NO + SE + CheckoutCom\Magento2\Model\Methods\PaypalMethod diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index 83671306..cf23e000 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -24,8 +24,8 @@ define([ 'Magento_Checkout/js/model/quote', 'mage/translate', 'mage/url', -], function ($, ko, Component, Utilities, CheckoutUtilities, FullScreenLoader, - AdditionalValidators, Quote, __, Url) { +], function($, ko, Component, Utilities, CheckoutUtilities, FullScreenLoader, + AdditionalValidators, Quote, __, Url) { 'use strict'; window.checkoutConfig.reloadOnBillingAddress = true; @@ -47,27 +47,62 @@ define([ /** * @return {void} */ - initialize: function () { + initialize: function() { this._super(); const scriptPromise = this.klarnaScriptLoader(); scriptPromise.then(() => { CheckoutUtilities.initSubscribers(this); + + // Manage billing address change + let self = this; + let prevAddress; + Quote.billingAddress.subscribe( + function (newAddress) { + if (!newAddress || !prevAddress || newAddress.getKey() !== prevAddress.getKey()) { + prevAddress = newAddress; + if (newAddress) { + self.getKlarnaContextDatas(Quote.billingAddress().countryId); + } + } + } + ); + this.getKlarnaContextDatas(); }).catch((error) => { Utilities.log(error); }); }, + canCurrencyForCountry: function(countryId = '') { + let klarnaCurrencyMapping = window.checkoutConfig.payment.checkoutcom_magento2.checkoutcom_klarna.currency_mapping; + let currencyCode = window.checkoutConfig.quoteData.base_currency_code; + let countryCode = countryId; + if (!countryId && window.checkoutConfig.billingAddressFromData) { + countryCode = window.checkoutConfig.billingAddressFromData.country_id; + } + + if (countryCode && currencyCode) { + if (typeof klarnaCurrencyMapping[currencyCode] !== 'undefined') { + return klarnaCurrencyMapping[currencyCode].indexOf(countryCode) !== -1; + } else { + this.placeOrderEnable(false); + return false; + } + } + return true; + }, + /** * Load klarna script witch promise * @returns {Promise} * @constructor */ - klarnaScriptLoader: function () { + klarnaScriptLoader: function() { return new Promise((resolve, reject) => { - const klarnaScript = document.querySelector(`script[src*="${this.chkKlarnaApiUrl}"]`); + const klarnaScript = document.querySelector( + `script[src*="${this.chkKlarnaApiUrl}"]`); if (klarnaScript) { resolve(); @@ -92,9 +127,9 @@ define([ * Build Klarna script * @param script */ - buildScript: function (script) { + buildScript: function(script) { const scriptUrl = new URL(this.chkKlarnaApiUrl); - + script.type = 'text/javascript'; script.src = scriptUrl; @@ -104,7 +139,7 @@ define([ /** * @return {string} */ - getCode: function () { + getCode: function() { return METHOD_ID; }, @@ -112,32 +147,43 @@ define([ * @param {string} field * @return {string} */ - getValue: function (field) { + getValue: function(field) { return Utilities.getValue(METHOD_ID, field); }, /** * @return {void} */ - checkLastPaymentMethod: function () { + checkLastPaymentMethod: function() { return Utilities.checkLastPaymentMethod(); }, /** * @return {Promise} */ - getKlarnaContextDatas: function () { + getKlarnaContextDatas: function(countryId = '') { const self = this; + // Check currency mapping + if (!this.canCurrencyForCountry(countryId)) { + alert('on ne peut pas'); + self.placeOrderEnable(false); + return; + } + fetch(Url.build('checkout_com/klarna/context'), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest', }, - }) - .then(response => response.json()) - .then(response => { + }).then(response => response.json()).then(response => { + // Error on context request + if (response.content.error) { + self.placeOrderEnable(false); + return; + } + // Store given token this.chkKlarnaClientToken = response.content.partner_metadata.client_token; this.chkKlarnaContextId = response.content.id; @@ -153,13 +199,14 @@ define([ container: '#klarna-payments-container', }, {}, - function (res) { + function(res) { if (res.show_form === true) { // Display method self.placeOrderEnable(true); } else { Utilities.showMessage('error', - __('Something went wrong with klarna method. Please choose another method.'), METHOD_ID); + __('Something went wrong with klarna method. Please choose another method.'), + METHOD_ID); } }, ); @@ -167,14 +214,15 @@ define([ // Here we know that klarna is disallowed for this context Utilities.log(response); Utilities.showMessage('error', - __('Something went wrong with klarna method. Please choose another method.'), METHOD_ID); + __('Something went wrong with klarna method. Please choose another method.'), + METHOD_ID); }); }, /** * Display the Klarna popin */ - authorizePayment: function () { + authorizePayment: function() { const self = this; // Retrieve current quote datas in order to give billing informations to Klarna @@ -186,7 +234,7 @@ define([ form_key: window.checkoutConfig.formKey, store_id: window.checkoutConfig.quoteData.store_id, }, - success: function (data) { + success: function(data) { // Launch klarna popin with retrieved customer datas Klarna.Payments.authorize( @@ -195,7 +243,8 @@ define([ billing_address: { given_name: data.billing.firstname, family_name: data.billing.lastname, - email: data.billing.email || Utilities.getEmail(), + email: data.billing.email || + Utilities.getEmail(), street_address: data.billing.street, postal_code: data.billing.postcode, city: data.billing.city, @@ -204,7 +253,7 @@ define([ country: data.billing.country_id.toLowerCase(), }, }, - function (res) { + function(res) { if (res.approved === true) { self.placeOrder(); } else { @@ -222,10 +271,11 @@ define([ /** * @return {void} */ - placeOrder: function () { + placeOrder: function() { FullScreenLoader.startLoader(); - if (Utilities.methodIsSelected(METHOD_ID) && this.chkKlarnaContextId) { + if (Utilities.methodIsSelected(METHOD_ID) && + this.chkKlarnaContextId) { const data = { methodId: METHOD_ID, contextPaymentId: this.chkKlarnaContextId, @@ -236,10 +286,10 @@ define([ Utilities.placeOrder( data, METHOD_ID, - function () { + function() { Utilities.log(__('Success')); }, - function () { + function() { Utilities.log(__('Fail')); }, ); From 3f4b8570678c6594bddd46a65e206b4fa5cf58d0 Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Tue, 30 Jul 2024 09:02:01 +0200 Subject: [PATCH 129/147] CHECMAG2003-236 - Manage country change - let api say us if context is ok --- Controller/Klarna/Context.php | 15 ++++++++-- etc/config.xml | 11 +------ .../method-renderer/checkoutcom_klarna.js | 30 +++---------------- .../template/payment/checkoutcom_klarna.html | 2 +- 4 files changed, 19 insertions(+), 39 deletions(-) diff --git a/Controller/Klarna/Context.php b/Controller/Klarna/Context.php index c6dd2494..716e6c88 100644 --- a/Controller/Klarna/Context.php +++ b/Controller/Klarna/Context.php @@ -30,6 +30,7 @@ use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\Serialize\SerializerInterface; class Context implements HttpPostActionInterface { @@ -38,12 +39,14 @@ class Context implements HttpPostActionInterface protected RequestInterface $request; protected QuoteHandlerService $quoteHandlerService; protected Logger $logger; + protected SerializerInterface $serializer; public function __construct( JsonFactory $resultJsonFactory, PaymentContextRequestService $paymentContextRequestService, RequestInterface $request, QuoteHandlerService $quoteHandlerService, + SerializerInterface $serializer, Logger $logger ) { $this->resultJsonFactory = $resultJsonFactory; @@ -51,6 +54,7 @@ public function __construct( $this->request = $request; $this->quoteHandlerService = $quoteHandlerService; $this->logger = $logger; + $this->serializer = $serializer; } /** @@ -91,11 +95,18 @@ private function getKlarnaContextSource(): AbstractRequestSource $klarnaRequestSource = new PaymentContextsKlarnaSource(); $accountHolder = new AccountHolder(); $billingAddress = new Address(); - $billingAddress->country = - $this->quoteHandlerService->getBillingAddress()->getCountry() ?: $this->quoteHandlerService->getQuote()->getShippingAddress()->getCountry(); + $billingAddress->country = $this->getCountryId(); $accountHolder->billing_address = $billingAddress; $klarnaRequestSource->account_holder = $accountHolder; return $klarnaRequestSource; } + + /** + * If a country id is given on request parameters give it first, if no use the quote one + */ + private function getCountryId(): string + { + return (string)$this->serializer->unserialize((string)$this->request->getContent())['country'] ?: $this->quoteHandlerService->getBillingAddress()->getCountry(); + } } diff --git a/etc/config.xml b/etc/config.xml index add7cbd3..65f0b709 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -190,16 +190,7 @@ 0 1 1 - 1 - AT,DK,ES,FI,DE,NL,NO,SE,GB - EUR,DKK,GBP,NOK,SEK - - AT,ES,FI,DE,NL,DK,NO,SE - DK - GB - NO - SE - + 0 CheckoutCom\Magento2\Model\Methods\PaypalMethod diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index cf23e000..656a0044 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -75,25 +75,6 @@ define([ }); }, - canCurrencyForCountry: function(countryId = '') { - let klarnaCurrencyMapping = window.checkoutConfig.payment.checkoutcom_magento2.checkoutcom_klarna.currency_mapping; - let currencyCode = window.checkoutConfig.quoteData.base_currency_code; - let countryCode = countryId; - if (!countryId && window.checkoutConfig.billingAddressFromData) { - countryCode = window.checkoutConfig.billingAddressFromData.country_id; - } - - if (countryCode && currencyCode) { - if (typeof klarnaCurrencyMapping[currencyCode] !== 'undefined') { - return klarnaCurrencyMapping[currencyCode].indexOf(countryCode) !== -1; - } else { - this.placeOrderEnable(false); - return false; - } - } - return true; - }, - /** * Load klarna script witch promise * @returns {Promise} @@ -164,19 +145,15 @@ define([ getKlarnaContextDatas: function(countryId = '') { const self = this; - // Check currency mapping - if (!this.canCurrencyForCountry(countryId)) { - alert('on ne peut pas'); - self.placeOrderEnable(false); - return; - } - fetch(Url.build('checkout_com/klarna/context'), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest', }, + body: JSON.stringify({ + country: countryId + }), }).then(response => response.json()).then(response => { // Error on context request if (response.content.error) { @@ -204,6 +181,7 @@ define([ // Display method self.placeOrderEnable(true); } else { + self.placeOrderEnable(false); Utilities.showMessage('error', __('Something went wrong with klarna method. Please choose another method.'), METHOD_ID); diff --git a/view/frontend/web/template/payment/checkoutcom_klarna.html b/view/frontend/web/template/payment/checkoutcom_klarna.html index 8cb52f59..13a8ebe0 100755 --- a/view/frontend/web/template/payment/checkoutcom_klarna.html +++ b/view/frontend/web/template/payment/checkoutcom_klarna.html @@ -63,4 +63,4 @@
-
+
From 80443a677620361eac1538edb4d364e2d73deddb Mon Sep 17 00:00:00 2001 From: Tommy Chausson Date: Tue, 30 Jul 2024 14:26:52 +0200 Subject: [PATCH 130/147] CHECMAG2003-236 - Keep klarna method visible only disallow ordering and display message --- Controller/Klarna/Context.php | 22 +++++++++++++++---- .../method-renderer/checkoutcom_klarna.js | 3 ++- .../template/payment/checkoutcom_klarna.html | 4 ++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Controller/Klarna/Context.php b/Controller/Klarna/Context.php index 716e6c88..dfa18f39 100644 --- a/Controller/Klarna/Context.php +++ b/Controller/Klarna/Context.php @@ -18,6 +18,7 @@ namespace CheckoutCom\Magento2\Controller\Klarna; +use Checkout\CheckoutApiException; use Checkout\Common\AccountHolder; use Checkout\Common\Address; use Checkout\Payments\Request\Source\AbstractRequestSource; @@ -25,11 +26,11 @@ use CheckoutCom\Magento2\Helper\Logger; use CheckoutCom\Magento2\Model\Service\PaymentContextRequestService; use CheckoutCom\Magento2\Model\Service\QuoteHandlerService; -use Exception; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\Phrase; use Magento\Framework\Serialize\SerializerInterface; class Context implements HttpPostActionInterface @@ -76,12 +77,12 @@ public function execute(): Json ), ] ); - } catch (Exception $e) { - $this->logger->write(sprintf('Error happen while requesting klarna context: %s', $e->getMessage())); + } catch (CheckoutApiException $apiException) { + $this->logger->write(sprintf('Error happen while requesting klarna context: %s', $apiException->getMessage())); $resultJson->setData( [ 'content' => [ - 'error' => __('Error happen while requesting context, please see logs'), + 'error' => $this->resolveExceptionErrorMessage($apiException), ], ] ); @@ -90,6 +91,19 @@ public function execute(): Json return $resultJson; } + private function resolveExceptionErrorMessage(CheckoutApiException $apiException): Phrase + { + $errorDetails = !$apiException->error_details ? [] : $apiException->error_details; + $errorCodes = $errorDetails['error_codes'] ?? []; + + return in_array('billing_country_invalid', $errorCodes) ? + __('This payment method is not available in your country') : + ( + in_array('currency_not_supported', $errorCodes) ? + __('Currency is not supported for your country') : __('This payment method is not available') + ); + } + private function getKlarnaContextSource(): AbstractRequestSource { $klarnaRequestSource = new PaymentContextsKlarnaSource(); diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js index 656a0044..be0db9fa 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_klarna.js @@ -144,7 +144,7 @@ define([ */ getKlarnaContextDatas: function(countryId = '') { const self = this; - + Utilities.clearMessages(METHOD_ID); fetch(Url.build('checkout_com/klarna/context'), { method: 'POST', headers: { @@ -158,6 +158,7 @@ define([ // Error on context request if (response.content.error) { self.placeOrderEnable(false); + Utilities.showMessage('error', response.content.error, METHOD_ID); return; } diff --git a/view/frontend/web/template/payment/checkoutcom_klarna.html b/view/frontend/web/template/payment/checkoutcom_klarna.html index 13a8ebe0..689d4504 100755 --- a/view/frontend/web/template/payment/checkoutcom_klarna.html +++ b/view/frontend/web/template/payment/checkoutcom_klarna.html @@ -14,7 +14,7 @@ -->
+ data-bind="css: {'_active': (getCode() == isChecked())}, attr: {'id': getCode() + '_container'}">
@@ -54,7 +54,7 @@ type="submit" data-bind=" click: authorizePayment, - css: {disabled: !isPlaceOrderActionAllowed()}, + css: {disabled: !placeOrderEnable()}, attr: {title: $t('Place Order'), 'id': buttonId} "> From 9371ad798350488bab92ada315d3a09d89cbc35a Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 6 Aug 2024 15:22:22 +0200 Subject: [PATCH 131/147] Bump composer version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 71db88b6..d66ae9ef 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "6.2.2", + "version": "6.3.0", "autoload": { "files": [ "registration.php" From 6fee32c70a33197c3df4464d4686af5f17db0153 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Wed, 14 Aug 2024 11:36:58 +0200 Subject: [PATCH 132/147] Bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d66ae9ef..0b8d91fd 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "6.3.0", + "version": "6.3.1", "autoload": { "files": [ "registration.php" From 4349f39da74eea93f87f67824877a457ce2027e1 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Wed, 28 Aug 2024 16:42:39 +0200 Subject: [PATCH 133/147] CHECMAG2003-246: remove KNET mandate info message --- Controller/Payment/Fail.php | 11 +---------- Controller/Payment/Verify.php | 12 +----------- etc/frontend/di.xml | 14 -------------- view/base/templates/ui/knetInfo.phtml | 25 ------------------------- 4 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 view/base/templates/ui/knetInfo.phtml diff --git a/Controller/Payment/Fail.php b/Controller/Payment/Fail.php index 43a45c27..f07d2f16 100644 --- a/Controller/Payment/Fail.php +++ b/Controller/Payment/Fail.php @@ -207,19 +207,10 @@ public function execute(): ResponseInterface $order ); - // Display error message and knet mandate info + // Display error message $this->messageManager->addErrorMessage( __('The transaction could not be processed.') ); - $this->messageManager->addComplexNoticeMessage('knetInfoMessage', [ - 'postDate' => $response['source']['post_date'] ?? null, - 'amount' => $amount ?? null, - 'paymentId' => $response['source']['knet_payment_id'] ?? null, - 'transactionId' => $response['source']['knet_transaction_id'] ?? null, - 'authCode' => $response['source']['auth_code'] ?? null, - 'reference' => $response['source']['bank_reference'] ?? null, - 'resultCode' => $response['source']['knet_result'] ?? null, - ]); } else { $this->messageManager->addErrorMessage( $errorMessage ? $errorMessage->getText() : __('The transaction could not be processed.') diff --git a/Controller/Payment/Verify.php b/Controller/Payment/Verify.php index bbc4af89..2d4c4dde 100644 --- a/Controller/Payment/Verify.php +++ b/Controller/Payment/Verify.php @@ -161,16 +161,6 @@ public function execute(): ResponseInterface $response['amount'] ?? null, $order ); - - $this->messageManager->addComplexNoticeMessage('knetInfoMessage', [ - 'postDate' => $response['source']['post_date'] ?? null, - 'amount' => $amount ?? null, - 'paymentId' => $response['source']['knet_payment_id'] ?? null, - 'transactionId' => $response['source']['knet_transaction_id'] ?? null, - 'authCode' => $response['source']['auth_code'] ?? null, - 'reference' => $response['source']['bank_reference'] ?? null, - 'resultCode' => $response['source']['knet_result'] ?? null, - ]); } if (isset($response['metadata']['successUrl']) && @@ -215,7 +205,7 @@ public function execute(): ResponseInterface $this->messageManager->addErrorMessage( __('An error has occurred, please select another payment method or retry in a few minutes') ); - + $this->logger->write($e->getMessage()); return $this->_redirect('checkout/cart', ['_secure' => true]); diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml index 929031e2..f563d089 100755 --- a/etc/frontend/di.xml +++ b/etc/frontend/di.xml @@ -50,20 +50,6 @@ - - - - - - \Magento\Framework\View\Element\Message\Renderer\BlockRenderer::CODE - - CheckoutCom_Magento2::ui/knetInfo.phtml - - - - - - diff --git a/view/base/templates/ui/knetInfo.phtml b/view/base/templates/ui/knetInfo.phtml deleted file mode 100644 index 027d9a4a..00000000 --- a/view/base/templates/ui/knetInfo.phtml +++ /dev/null @@ -1,25 +0,0 @@ - - * @copyright 2010-present Checkout.com - * @license https://opensource.org/licenses/mit-license.html MIT License - * @link https://docs.checkout.com/ - */ -?> - -%1 ; ', $block->escapeHtml($block->getData('postDate'))) ?> -%1 ; ', $block->escapeHtml($block->getData('amount'))) ?> -%1 ; ', $block->escapeHtml($block->getData('resultCode'))) ?> -%1 ; ', $block->escapeHtml($block->getData('paymentId'))) ?> -%1 ; ', $block->escapeHtml($block->getData('transactionId'))) ?> -%1 ; ', $block->escapeHtml($block->getData('authCode'))) ?> -%1 ; ', $block->escapeHtml($block->getData('reference'))) ?> From af869567a44755e66b35dcdea3300de6290d1e7c Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Fri, 30 Aug 2024 10:22:54 +0200 Subject: [PATCH 134/147] CHECMAG2003-249: adjust cps whitelist --- etc/csp_whitelist.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/csp_whitelist.xml b/etc/csp_whitelist.xml index aa7f7d6c..bcaf333a 100644 --- a/etc/csp_whitelist.xml +++ b/etc/csp_whitelist.xml @@ -27,7 +27,7 @@ - https://cdn.checkout.com + https://*.checkout.com *.klarnacdn.net @@ -49,4 +49,4 @@ - \ No newline at end of file + From 216c9952b1f549abc3c16a4e265df24a6b412bd4 Mon Sep 17 00:00:00 2001 From: Benoit ALIX Date: Tue, 3 Sep 2024 15:22:05 +0200 Subject: [PATCH 135/147] Fix credit cards inputs Frame loading --- view/frontend/web/js/view/payment/utilities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/frontend/web/js/view/payment/utilities.js b/view/frontend/web/js/view/payment/utilities.js index 5ffcfe19..1c511ae7 100755 --- a/view/frontend/web/js/view/payment/utilities.js +++ b/view/frontend/web/js/view/payment/utilities.js @@ -399,7 +399,7 @@ define( methodIsSelected: function (idSelector) { var id = idSelector.replace('#', ''); var selected = CheckoutData.getSelectedPaymentMethod(); - return id === selected; + return id === selected || selected === null; }, /** From 5817bfe6434f4c8bc2ae6aa8f5eb9bb143bd53c8 Mon Sep 17 00:00:00 2001 From: Laurent Clouet Date: Mon, 30 Sep 2024 16:10:50 +0200 Subject: [PATCH 136/147] CHECMAG2003-252: Add support of multi-region support for api call --- Model/Service/ApiHandlerService.php | 14 +++++++++++--- composer.json | 2 +- etc/adminhtml/system.xml | 6 ++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Model/Service/ApiHandlerService.php b/Model/Service/ApiHandlerService.php index bd532878..a73c2acc 100644 --- a/Model/Service/ApiHandlerService.php +++ b/Model/Service/ApiHandlerService.php @@ -37,6 +37,7 @@ use CheckoutCom\Magento2\Gateway\Config\Config; use CheckoutCom\Magento2\Helper\Logger; use CheckoutCom\Magento2\Helper\Utilities; +use CheckoutCom\Magento2\Model\Config\Backend\Source\ConfigRegion; use CheckoutCom\Magento2\Model\Config\Backend\Source\ConfigService; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\ProductMetadataInterface; @@ -172,6 +173,8 @@ public function init( string $secretKey = null, string $publicKey = null ): ApiHandlerService { + $region = $this->config->getValue('region', null, $storeCode, $scope); + if (!$secretKey) { $secretKey = $this->config->getValue('secret_key', null, $storeCode, $scope); } @@ -190,11 +193,16 @@ public function init( $api = $api->staticKeys(); } - $this->checkoutApi = $api + $sdkBuilder = $api ->publicKey($publicKey) ->secretKey($secretKey) - ->environment($environment) - ->build(); + ->environment($environment); + + if ($region != ConfigRegion::REGION_GLOBAL) { // do not set subdomain when global region is used + $sdkBuilder->environmentSubdomain($region); + } + + $this->checkoutApi = $sdkBuilder->build(); return $this; } diff --git a/composer.json b/composer.json index 0b8d91fd..961bbb70 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "checkoutcom/magento2", "description": "Checkout.com Payment Gateway for Magento 2", "require": { - "checkout/checkout-sdk-php": "3.2.0", + "checkout/checkout-sdk-php": "3.2.4", "php": "~7.4.0||~8.1.0||~8.2.0", "magento/framework": ">=100.0.1" }, diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 9c2bb46e..2be5d8bf 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -176,6 +176,12 @@ + + + CheckoutCom\Magento2\Model\Config\Backend\Source\ConfigRegion + settings/checkoutcom_configuration/region + required-entry + CheckoutCom\Magento2\Model\Config\Backend\Source\ConfigService From f126d480f12bd90d6d932e274f3f476845f39583 Mon Sep 17 00:00:00 2001 From: Loubna Fattouh Date: Wed, 9 Oct 2024 16:10:35 +0100 Subject: [PATCH 137/147] CHECMAG2003-249: fix canceled request --- .../js/view/payment/method-renderer/checkoutcom_card_payment.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index 0cc2f866..fdd8af45 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -126,8 +126,6 @@ define( } ); - self.getCkoPaymentForm(); - // Option click event $('.payment-method input[type="radio"]').on('click', function () { self.allowPlaceOrder(false); From 6b519a1324639a767c38694418679c8b1b14a4e9 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Thu, 10 Oct 2024 09:38:06 +0200 Subject: [PATCH 138/147] CHECMAG2003-256: fix success result on REST API --- Model/Api/V3.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Model/Api/V3.php b/Model/Api/V3.php index f4b255a3..adab3e7a 100644 --- a/Model/Api/V3.php +++ b/Model/Api/V3.php @@ -336,8 +336,9 @@ private function processPayment(): array // Get the payment $response = $this->getPaymentResponse($amount, $currency, $reference); + $isValidResponse = $this->api->isValidResponse($response); - if ($this->api->isValidResponse($response)) { + if ($isValidResponse) { // Process the payment response $is3ds = property_exists($response, '_links') && isset($response->_links['redirect']) @@ -357,7 +358,7 @@ private function processPayment(): array } // Update the result - $this->result['success'] = $response->isSuccessful(); + $this->result['success'] = $isValidResponse; } else { // Payment failed if (isset($response->response_code)) { From 42e834786a9fcd7923189a2345818fecdc763a3f Mon Sep 17 00:00:00 2001 From: Benjamin HOUILLON Date: Fri, 11 Oct 2024 09:43:12 +0000 Subject: [PATCH 139/147] Bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0b8d91fd..9cfc3b9e 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "6.3.1", + "version": "6.3.2", "autoload": { "files": [ "registration.php" From 5ad815058ccf5f51a0c27afbe9ba27d507457b9a Mon Sep 17 00:00:00 2001 From: Benjamin HOUILLON Date: Fri, 11 Oct 2024 11:27:34 +0000 Subject: [PATCH 140/147] Bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9cfc3b9e..0a5a6779 100755 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Checkout.com Payment Gateway for Magento 2", "require": { "checkout/checkout-sdk-php": "3.2.0", - "php": "~7.4.0||~8.1.0||~8.2.0", + "php": "~7.4.0||~8.1.0||~8.2.0||~8.3.0", "magento/framework": ">=100.0.1" }, "type": "magento2-module", From b577785506c3068f9804e47d68724c0c947349df Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Fri, 18 Oct 2024 16:56:10 +0200 Subject: [PATCH 141/147] CHECMAG2003-252: fix missing source model --- Model/Config/Backend/Source/ConfigRegion.php | 47 ++++++++++++++++++++ Model/Service/ApiHandlerService.php | 8 ++-- 2 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 Model/Config/Backend/Source/ConfigRegion.php diff --git a/Model/Config/Backend/Source/ConfigRegion.php b/Model/Config/Backend/Source/ConfigRegion.php new file mode 100644 index 00000000..262c3999 --- /dev/null +++ b/Model/Config/Backend/Source/ConfigRegion.php @@ -0,0 +1,47 @@ + + * @copyright 2010-present Checkout.com + * @license https://opensource.org/licenses/mit-license.html MIT License + * @link https://docs.checkout.com/ + */ + +declare(strict_types=1); + +namespace CheckoutCom\Magento2\Model\Config\Backend\Source; + +use Magento\Framework\Data\OptionSourceInterface; + +class ConfigRegion implements OptionSourceInterface +{ + public const REGION_GLOBAL = ''; + public const REGION_KSA = 'ksa'; + + /** + * Options getter + * + * @return string[][] + */ + public function toOptionArray(): array + { + return [ + [ + 'value' => '', + 'label' => __('--') + ], + [ + 'value' => self::REGION_KSA, + 'label' => __('KSA') + ] + ]; + } +} diff --git a/Model/Service/ApiHandlerService.php b/Model/Service/ApiHandlerService.php index a73c2acc..34b0fbcc 100644 --- a/Model/Service/ApiHandlerService.php +++ b/Model/Service/ApiHandlerService.php @@ -184,7 +184,7 @@ public function init( } $service = $this->scopeConfig->getValue(ConfigService::SERVICE_CONFIG_PATH, $scope, $storeCode); - $environment = $this->config->getEnvironment($storeCode, $scope); + $environment = $this->config->getEnvironment((string)$storeCode, $scope); $api = CheckoutSdk::builder(); if ($service === ConfigService::SERVICE_ABC) { @@ -197,8 +197,8 @@ public function init( ->publicKey($publicKey) ->secretKey($secretKey) ->environment($environment); - - if ($region != ConfigRegion::REGION_GLOBAL) { // do not set subdomain when global region is used + + if ($region !== ConfigRegion::REGION_GLOBAL) { // do not set subdomain when global region is used $sdkBuilder->environmentSubdomain($region); } @@ -216,7 +216,7 @@ public function initAbcForRefund( $publicKey = $this->config->getValue('abc_refund_public_key', null, $storeCode, $scope); $api = CheckoutSdk::builder(); - $environment = $this->config->getEnvironment($storeCode, $scope); + $environment = $this->config->getEnvironment((string)$storeCode, $scope); $this->checkoutApi = $api ->previous()->staticKeys() From e9f45777ee29a8d9e79c624ed6caa7fd0916539c Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 21 Oct 2024 10:09:36 +0200 Subject: [PATCH 142/147] CHECMAG2003-252: fix global region config value --- Model/Config/Backend/Source/ConfigRegion.php | 4 ++-- Model/Service/ApiHandlerService.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Model/Config/Backend/Source/ConfigRegion.php b/Model/Config/Backend/Source/ConfigRegion.php index 262c3999..84653c13 100644 --- a/Model/Config/Backend/Source/ConfigRegion.php +++ b/Model/Config/Backend/Source/ConfigRegion.php @@ -23,7 +23,7 @@ class ConfigRegion implements OptionSourceInterface { - public const REGION_GLOBAL = ''; + public const REGION_GLOBAL = 'global'; public const REGION_KSA = 'ksa'; /** @@ -35,7 +35,7 @@ public function toOptionArray(): array { return [ [ - 'value' => '', + 'value' => self::REGION_GLOBAL, 'label' => __('--') ], [ diff --git a/Model/Service/ApiHandlerService.php b/Model/Service/ApiHandlerService.php index 34b0fbcc..03b62a6c 100644 --- a/Model/Service/ApiHandlerService.php +++ b/Model/Service/ApiHandlerService.php @@ -198,7 +198,8 @@ public function init( ->secretKey($secretKey) ->environment($environment); - if ($region !== ConfigRegion::REGION_GLOBAL) { // do not set subdomain when global region is used + // Do not set subdomain when global region is used + if ($region !== ConfigRegion::REGION_GLOBAL) { $sdkBuilder->environmentSubdomain($region); } From 3271b45ff36a12c376da31416e61aad115c30fee Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Mon, 21 Oct 2024 10:28:20 +0200 Subject: [PATCH 143/147] CHECMAG2003-252: add region default configuration --- etc/config.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/config.xml b/etc/config.xml index 65f0b709..7b02ff57 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -27,6 +27,7 @@ 0 1 + global ABC From 44d69570cdf85061683307d8d344060c2d37d56d Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Tue, 22 Oct 2024 14:31:10 +0200 Subject: [PATCH 144/147] CHECMAG2003-252: Add region configuration field translation --- i18n/en_GB.csv | 2 ++ i18n/en_US.csv | 2 ++ 2 files changed, 4 insertions(+) diff --git a/i18n/en_GB.csv b/i18n/en_GB.csv index 06f0b4da..bd713ff6 100644 --- a/i18n/en_GB.csv +++ b/i18n/en_GB.csv @@ -1,3 +1,4 @@ +"--","Others" " for an amount of %1. Action ID: %2. Event ID: %3. Payment ID: %4. Error: %5 %6"," for an amount of %1. Action ID: %2. Event ID: %3. Payment ID: %4. Error: %5 %6" "3DS authorization code","3DS authorization code" "3DS has expired or authentication failed, please try again","3DS has expired or authentication failed, please try again" @@ -63,6 +64,7 @@ "Invalid request. No session ID found.","Invalid request. No session ID found." "It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method","It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method" "It looks like your card is invalid or blocked, please try with another card","It looks like your card is invalid or blocked, please try with another card" +"KSA","KSA" "Learn More","Learn More" "Match Not Capable","Match Not Capable" "Mismatched Address (fraud check)","Mismatched Address (fraud check)" diff --git a/i18n/en_US.csv b/i18n/en_US.csv index 06f0b4da..bd713ff6 100644 --- a/i18n/en_US.csv +++ b/i18n/en_US.csv @@ -1,3 +1,4 @@ +"--","Others" " for an amount of %1. Action ID: %2. Event ID: %3. Payment ID: %4. Error: %5 %6"," for an amount of %1. Action ID: %2. Event ID: %3. Payment ID: %4. Error: %5 %6" "3DS authorization code","3DS authorization code" "3DS has expired or authentication failed, please try again","3DS has expired or authentication failed, please try again" @@ -63,6 +64,7 @@ "Invalid request. No session ID found.","Invalid request. No session ID found." "It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method","It looks like this transaction has been blocked due to account holder action, please contact your bank or use another card or payment method" "It looks like your card is invalid or blocked, please try with another card","It looks like your card is invalid or blocked, please try with another card" +"KSA","KSA" "Learn More","Learn More" "Match Not Capable","Match Not Capable" "Mismatched Address (fraud check)","Mismatched Address (fraud check)" From ce1fa3c39370917c24a7717720591683b3a5e116 Mon Sep 17 00:00:00 2001 From: Benjamin HOUILLON Date: Tue, 22 Oct 2024 12:44:40 +0000 Subject: [PATCH 145/147] Bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c0a3bff2..bf34db5c 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "6.3.2", + "version": "6.4.0", "autoload": { "files": [ "registration.php" From 8c2604bccff508a968938d71f9909da5cca47bb8 Mon Sep 17 00:00:00 2001 From: Benjamin Houillon Date: Thu, 14 Nov 2024 14:52:39 +0100 Subject: [PATCH 146/147] CHECMAG2003-260: fix preferred scheme for payment cards --- Model/Methods/CardPaymentMethod.php | 2 +- .../payment/method-renderer/checkoutcom_card_payment.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Model/Methods/CardPaymentMethod.php b/Model/Methods/CardPaymentMethod.php index 6da889b2..fc176dd5 100755 --- a/Model/Methods/CardPaymentMethod.php +++ b/Model/Methods/CardPaymentMethod.php @@ -360,7 +360,7 @@ public function sendPaymentRequest( } // Preferred scheme - if (isset($data['preferredScheme']) && in_array((string) $data['preferredScheme'], self::PREFERRED_SCHEMES)) { + if (isset($data['preferredScheme']) && in_array((string) strtoupper($data['preferredScheme']), self::PREFERRED_SCHEMES)) { $request->processing = ['preferred_scheme' => strtolower($data['preferredScheme'])]; } diff --git a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js index fdd8af45..02e726d1 100755 --- a/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js +++ b/view/frontend/web/js/view/payment/method-renderer/checkoutcom_card_payment.js @@ -296,7 +296,7 @@ define( // Store the card token and the card bin self.cardToken = event.token; self.cardBin = event.bin; - self.preferredScheme = event.scheme; + self.preferredScheme = event.preferred_scheme; // Enable the submit form Frames.enableSubmitForm(); @@ -307,7 +307,7 @@ define( Frames.addEventHandler( Frames.Events.CARD_BIN_CHANGED, function (event) { - self.preferredScheme = event.scheme; + self.preferredScheme = event.preferred_scheme; self.isCoBadged(event.isCoBadged); } ); @@ -329,7 +329,7 @@ define( cardToken: response.token, cardBin: response.bin, saveCard: this.saveCard, - preferredScheme: response.scheme, + preferredScheme: response.preferred_scheme, source: METHOD_ID }; From 3c714e614f1cc3bf8dc40abd6cfb8a6adf468e92 Mon Sep 17 00:00:00 2001 From: Julien TRAJMAN Date: Tue, 31 Dec 2024 10:49:29 +0100 Subject: [PATCH 147/147] Bump composer.json version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bf34db5c..ae858e3e 100755 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "magento/framework": ">=100.0.1" }, "type": "magento2-module", - "version": "6.4.0", + "version": "6.4.1", "autoload": { "files": [ "registration.php"