diff --git a/Api/Transaction/Data/DataInterface.php b/Api/Transaction/Data/DataInterface.php old mode 100644 new mode 100755 index 4999ac1..d4fab38 --- a/Api/Transaction/Data/DataInterface.php +++ b/Api/Transaction/Data/DataInterface.php @@ -20,6 +20,7 @@ interface DataInterface extends ExtensibleDataInterface */ public const ENTITY_ID = 'entity_id'; public const QUOTE_ID = 'quote_id'; + public const AMOUNT = 'amount'; public const ORDER_ID = 'order_id'; public const UUID = 'uuid'; public const TOKEN = 'token'; @@ -50,6 +51,21 @@ public function getQuoteId(): ?int; */ public function setQuoteId(int $quoteId): self; + /** + * Returns transaction amount. + * + * @return int quote ID. + */ + public function getAmount(): int; + + /** + * Sets transaction amount. + * + * @param int $amount + * @return $this + */ + public function setAmount(int $amount): self; + /** * Returns the order ID. * diff --git a/Model/Transaction/DataModel.php b/Model/Transaction/DataModel.php old mode 100644 new mode 100755 index a373ffe..7bf493b --- a/Model/Transaction/DataModel.php +++ b/Model/Transaction/DataModel.php @@ -51,6 +51,22 @@ public function setQuoteId(int $quoteId): DataInterface return $this->setData(self::QUOTE_ID, $quoteId); } + /** + * @inheritDoc + */ + public function getAmount(): int + { + return (int)$this->getData(self::AMOUNT); + } + + /** + * @inheritDoc + */ + public function setAmount(int $amount): DataInterface + { + return $this->setData(self::AMOUNT, $amount); + } + /** * @inheritDoc */ diff --git a/Model/Webapi/Checkout.php b/Model/Webapi/Checkout.php old mode 100644 new mode 100755 index c29473c..cdc4b23 --- a/Model/Webapi/Checkout.php +++ b/Model/Webapi/Checkout.php @@ -70,8 +70,8 @@ public function orderRequest(bool $isLoggedIn, string $cartId) //web api can't return first level associative array $return = []; try { - $paymentUrl = $this->orderRequest->execute($token); - $return['response'] = ['success' => true, 'payment_page_url' => $paymentUrl]; + $response = $this->orderRequest->execute($token); + $return['response'] = ['success' => true, 'response' => $response]; return $return; } catch (\Exception $exception) { $this->logRepository->addErrorLog('Checkout endpoint', $exception->getMessage()); diff --git a/Service/Order/MakeRequest.php b/Service/Order/MakeRequest.php index bb13f1b..588538e 100644 --- a/Service/Order/MakeRequest.php +++ b/Service/Order/MakeRequest.php @@ -124,7 +124,7 @@ public function __construct( * Executes TrueLayer Api for Order Request and returns redirect to platform Url * * @param string $token - * @return string + * @return array * @throws AuthenticationException * @throws CouldNotSaveException * @throws InputException @@ -133,7 +133,7 @@ public function __construct( * @throws \TrueLayer\Exceptions\InvalidArgumentException * @throws \TrueLayer\Exceptions\ValidationException */ - public function execute(string $token): string + public function execute(string $token) { $transaction = $this->transactionRepository->getByToken($token); $quote = $this->quoteRepository->get($transaction->getQuoteId()); @@ -163,15 +163,15 @@ public function execute(string $token): string } if ($payment->getId()) { - $transaction->setUuid($payment->getId()); + $transaction->setUuid($payment->getId()) + ->setAmount($paymentData['amount_in_minor']); $this->transactionRepository->save($transaction); - $this->duplicateCurrentQuote($quote); - return $payment->hostedPaymentsPage() - ->returnUri($this->getReturnUrl()) - ->primaryColour($this->configProvider->getPaymentPagePrimaryColor()) - ->secondaryColour($this->configProvider->getPaymentPageSecondaryColor()) - ->tertiaryColour($this->configProvider->getPaymentPageTertiaryColor()) - ->toUrl(); + + return [ + 'payment_id' => $payment->getId(), + 'resource_token' => $payment->getResourceToken(), + 'transaction_id' => $transaction->getUuid(), + ]; } $msg = self::REQUEST_EXCEPTION; @@ -233,7 +233,8 @@ private function prepareData(Quote $quote, string $merchantAccountId): array "type" => "merchant_account", "name" => $this->configProvider->getMerchantAccountName(), "merchant_account_id" => $merchantAccountId - ] + ], + "retry" => [] ], "user" => [ "name" => trim($quote->getBillingAddress()->getFirstname()) . @@ -252,73 +253,4 @@ private function prepareData(Quote $quote, string $merchantAccountId): array return $data; } - - /** - * Duplicate current quote and set this as active session. - * This prevents quotes to change during checkout process - * - * @param Quote $quote - * @throws NoSuchEntityException - * @throws CouldNotSaveException - */ - private function duplicateCurrentQuote(Quote $quote) - { - $quote->setIsActive(false); - $this->quoteRepository->save($quote); - if ($customerId = $quote->getCustomerId()) { - $cartId = $this->cartManagement->createEmptyCartForCustomer($customerId); - } else { - $cartId = $this->cartManagement->createEmptyCart(); - } - $newQuote = $this->quoteRepository->get($cartId); - $newQuote->merge($quote); - - $newQuote->removeAllAddresses(); - if (!$quote->getIsVirtual()) { - $addressData = $this->dataObjectProcessor->buildOutputDataArray( - $quote->getShippingAddress(), - AddressInterface::class - ); - unset($addressData['id']); - $shippingAddress = $this->quoteAddressFactory->create(); - $this->dataObjectHelper->populateWithArray( - $shippingAddress, - $addressData, - AddressInterface::class - ); - $newQuote->setShippingAddress( - $shippingAddress - ); - } - - $addressData = $this->dataObjectProcessor->buildOutputDataArray( - $quote->getBillingAddress(), - AddressInterface::class - ); - unset($addressData['id']); - $billingAddress = $this->quoteAddressFactory->create(); - $this->dataObjectHelper->populateWithArray( - $billingAddress, - $addressData, - AddressInterface::class - ); - $newQuote->setBillingAddress( - $billingAddress - ); - - $newQuote->setTotalsCollectedFlag(false)->collectTotals(); - $this->quoteRepository->save($newQuote); - - $this->checkoutSession->replaceQuote($newQuote); - } - - /** - * Get return url - * - * @return string - */ - private function getReturnUrl(): string - { - return $this->configProvider->getBaseUrl() . 'truelayer/checkout/process/'; - } } diff --git a/Service/Order/ProcessWebhook.php b/Service/Order/ProcessWebhook.php index 3a01e08..2810a8d 100644 --- a/Service/Order/ProcessWebhook.php +++ b/Service/Order/ProcessWebhook.php @@ -9,6 +9,7 @@ use Exception; use Magento\Checkout\Model\Session as CheckoutSession; +use Magento\Framework\Exception\LocalizedException; use Magento\Quote\Api\CartManagementInterface; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\CartInterface; @@ -29,6 +30,7 @@ class ProcessWebhook { public const SUCCESS_MSG = 'Order #%1 successfully captured on TrueLayer'; + /** * @var CheckoutSession */ @@ -127,11 +129,19 @@ public function execute(string $uuid, string $userId) ); if (!$quoteId = $transaction->getQuoteId()) { - $this->logRepository->addDebugLog('webhook', 'no quote id found in transaction'); - return; + $message = 'No quote id found in transaction'; + $this->logRepository->addDebugLog('webhook', $message); + throw new LocalizedException(__($message)); } $quote = $this->quoteRepository->get($quoteId); + + if ($transaction->getAmount() != (int)bcmul((string)$quote->getBaseGrandTotal(), '100')) { + $message = 'Quote amount was changed'; + $this->logRepository->addDebugLog('webhook', $message); + throw new LocalizedException(__($message)); + } + $this->checkoutSession->setQuoteId($quoteId); if (!$this->transactionRepository->isLocked($transaction)) { @@ -150,6 +160,7 @@ public function execute(string $uuid, string $userId) } } catch (Exception $e) { $this->logRepository->addDebugLog('webhook exception', $e->getMessage()); + throw new LocalizedException(__($e->getMessage())); } } @@ -176,7 +187,7 @@ private function placeOrder(CartInterface $quote, $uuid, $userId) $this->sendInvoiceEmail($order); } catch (Exception $e) { $this->logRepository->addDebugLog('place order', $e->getMessage()); - return false; + throw new LocalizedException(__($e->getMessage())); } return $order->getEntityId(); diff --git a/etc/csp_whitelist.xml b/etc/csp_whitelist.xml new file mode 100644 index 0000000..dca2459 --- /dev/null +++ b/etc/csp_whitelist.xml @@ -0,0 +1,10 @@ + + + + + + https://cdn.jsdelivr.net + + + + \ No newline at end of file diff --git a/etc/db_schema.xml b/etc/db_schema.xml old mode 100644 new mode 100755 index 7cbd0df..6c37177 --- a/etc/db_schema.xml +++ b/etc/db_schema.xml @@ -8,6 +8,7 @@ + diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml old mode 100644 new mode 100755 index bbe1509..c153c3c --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -6,9 +6,6 @@ */ --> - - - diff --git a/view/frontend/requirejs-config.js b/view/frontend/requirejs-config.js new file mode 100644 index 0000000..1b7a077 --- /dev/null +++ b/view/frontend/requirejs-config.js @@ -0,0 +1,8 @@ +var config = { + map: { + '*': { + 'Magento_SalesRule/js/action/select-payment-method-mixin': 'TrueLayer_Connect/js/action/select-payment-method-mixin' + } + } +}; + diff --git a/view/frontend/web/css/source/_module.less b/view/frontend/web/css/source/_module.less new file mode 100644 index 0000000..a7be553 --- /dev/null +++ b/view/frontend/web/css/source/_module.less @@ -0,0 +1 @@ +@import 'component/_widget.less'; \ No newline at end of file diff --git a/view/frontend/web/css/source/component/_widget.less b/view/frontend/web/css/source/component/_widget.less new file mode 100644 index 0000000..6c2aec5 --- /dev/null +++ b/view/frontend/web/css/source/component/_widget.less @@ -0,0 +1,63 @@ +// +// Common +// _____________________________________________ + +& when (@media-common = true) { + + // Modify base payment method styles for truelayer method + .truelayer-payment-method { + .payment-method-title { + label { + position: relative; + padding-left: 32px; + + &::before { + content: ''; + + position: absolute; + top: -6px; + left: 0; + + width: 24px; + height: 24px; + background: url("TrueLayer_Connect::images/bank.svg") no-repeat center center; + } + } + } + + .payment-method-content { + iframe { + border: 0; + } + + .small [name="tl-checkout-widget"], + .small .loader { + height: 60px; + margin-bottom: 18px; + } + + .large [name="tl-checkout-widget"], + .large .loader { + min-height: 160px; + margin-bottom: 18px; + } + + .widget-button { + position: relative; + z-index: 10; + max-width: 450px; + } + + .loader { + display: block; + background: url("@{baseDir}images/loader-1.gif") no-repeat center center; + background-size: 36px; + } + } + + .message.success, + .message.info { + margin-bottom: 24px; + } + } +} diff --git a/view/frontend/web/css/styles.css b/view/frontend/web/css/styles.css deleted file mode 100644 index 3dfed2e..0000000 --- a/view/frontend/web/css/styles.css +++ /dev/null @@ -1,17 +0,0 @@ -input#truelayer { - margin-right: 40px; -} - -input#truelayer:before { - content: ''; - display: block; - background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyNTAgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGwtcnVsZTpldmVub2RkO2NsaXAtcnVsZTpldmVub2RkO2ZpbGw6IzA5MzU1NDt9Cgkuc3Qxe2ZpbGw6IzA5MzU1NDt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xNzcuNCwxMDMuN0g0Ny45Yy0yLjQsMC00LjMsMS45LTQuMyw0LjNjMCwyLjQsMS45LDQuMyw0LjMsNC4zSDUwdjc2LjdoLTIuMXYwYy00LjcsMC04LjUsMy44LTguNSw4LjUKCWMwLDQuNywzLjgsOC41LDguNSw4LjVoMTQ5LjJjNC43LDAsOC41LTMuOCw4LjUtOC41YzAtNC43LTMuOC04LjUtOC41LTguNUgxOTV2LTUzLjVsLTE3LjEsMTYuOHYzNi43aC0yNS42di03Ni43aDIyTDE3Ny40LDEwMy43egoJIE0xMzUuMywxMTIuMnY3Ni43aC0yNS42di03Ni43SDEzNS4zeiBNNjcuMSwxMTIuMmgyNS42djc2LjdINjcuMVYxMTIuMnoiLz4KPHBhdGggY2xhc3M9InN0MSIgZD0iTTE1OC4xLDU1LjhsLTIwLjMsMjBjLTEuMywxLjMtMS44LDMuMi0xLjMsNWMwLjUsMS44LDEuOSwzLjQsMy44LDRMMTcxLjIsOTZoLTEzNGMtNCwwLTcuNS0yLjgtOC4zLTYuNwoJYy0wLjgtMy45LDEuMi03LjksNC44LTkuNkwxMTksNDEuM2MyLjItMSw0LjgtMSw3LDBMMTU4LjEsNTUuOHoiLz4KPHBhdGggY2xhc3M9InN0MSIgZD0iTTIwNy43LDIxMS4xSDM3LjJjLTQuNywwLTguNSwzLjgtOC41LDguNWMwLDQuNywzLjgsOC41LDguNSw4LjVoMTcwLjVjNC43LDAsOC41LTMuOCw4LjUtOC41CglDMjE2LjMsMjE0LjksMjEyLjQsMjExLjEsMjA3LjcsMjExLjF6Ii8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0yNDIuNyw3Ny43Yy0wLjYtMS40LTEuOS0yLjUtMy42LTIuOWwtMzQuMi0xMGwxMi4zLTQxLjljMC41LTEuOC0wLjYtMy44LTIuOC00LjljLTIuMi0xLjEtNC43LTAuOC02LjEsMC42CglsLTU5LjIsNTcuMWMtMSwxLTEuMywyLjQtMC43LDMuN2MwLjYsMS4zLDEuOSwyLjUsMy42LDIuOWwzNC4yLDEwbC0xMi4zLDQxLjljLTAuNSwxLjgsMC42LDMuOCwyLjgsNC45YzAuMywwLjIsMC43LDAuMywxLDAuNAoJYzEuOSwwLjYsMy45LDAuMiw1LjEtMUwyNDIsODEuNUMyNDMsODAuNSwyNDMuMyw3OS4xLDI0Mi43LDc3Ljd6Ii8+Cjwvc3ZnPgo="); - background-position: 0px 10px; - background-size: 25px; - background-repeat: no-repeat; - width: 60px; - height: 35px; - float: left; - margin-top: -15px; - margin-left: 25px; -} diff --git a/view/frontend/web/images/bank.svg b/view/frontend/web/images/bank.svg new file mode 100644 index 0000000..8c5ff58 --- /dev/null +++ b/view/frontend/web/images/bank.svg @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/view/frontend/web/js/action/select-payment-method-mixin.js b/view/frontend/web/js/action/select-payment-method-mixin.js new file mode 100644 index 0000000..c2fb586 --- /dev/null +++ b/view/frontend/web/js/action/select-payment-method-mixin.js @@ -0,0 +1,56 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'mage/utils/wrapper', + 'Magento_Checkout/js/model/quote', + 'Magento_SalesRule/js/model/payment/discount-messages', + 'Magento_Checkout/js/action/set-payment-information-extended', + 'Magento_Checkout/js/action/get-totals', + 'Magento_SalesRule/js/model/coupon' +], function ($, wrapper, quote, messageContainer, setPaymentInformationExtended, getTotalsAction, coupon) { + 'use strict'; + + return function (selectPaymentMethodAction) { + + return wrapper.wrap(selectPaymentMethodAction, function (originalSelectPaymentMethodAction, paymentMethod) { + + originalSelectPaymentMethodAction(paymentMethod); + + if (paymentMethod === null) { + return; + } + + $.when( + // Fix: Changed true to false for getting Billing address + setPaymentInformationExtended( + messageContainer, + { + method: paymentMethod.method + }, + false + ) + ).done( + function () { + var deferred = $.Deferred(), + + /** + * Update coupon form. + */ + updateCouponCallback = function () { + if (quote.totals() && !quote.totals()['coupon_code']) { + coupon.setCouponCode(''); + coupon.setIsApplied(false); + } + }; + + getTotalsAction([], deferred); + $.when(deferred).done(updateCouponCallback); + } + ); + }); + }; + +}); diff --git a/view/frontend/web/js/view/payment/method-renderer/truelayer.js b/view/frontend/web/js/view/payment/method-renderer/truelayer.js old mode 100644 new mode 100755 index 71b9164..8cc4785 --- a/view/frontend/web/js/view/payment/method-renderer/truelayer.js +++ b/view/frontend/web/js/view/payment/method-renderer/truelayer.js @@ -1,113 +1,129 @@ -/** - * Copyright © TrueLayer Ltd. All rights reserved. - * See COPYING.txt for license details. - */ -/*browser:true*/ -/*global define*/ -define( - [ - 'jquery', - 'Magento_Checkout/js/view/payment/default', - 'Magento_Checkout/js/model/error-processor', - 'Magento_Checkout/js/model/quote', - 'Magento_Customer/js/model/customer', - 'Magento_Checkout/js/model/url-builder', - 'Magento_Checkout/js/model/full-screen-loader', - 'mage/storage', - 'Magento_Ui/js/model/messageList', - 'Magento_Checkout/js/model/payment/additional-validators', - 'uiRegistry' - ], - function ($, Component, errorProcessor, quote, customer, urlBuilder, fullScreenLoader, storage, messageList, additionalValidators, uiRegistry) { - 'use strict'; - - var payload = ''; - - return Component.extend({ - defaults: { - template: 'TrueLayer_Connect/payment/truelayer' - }, - - getCode: function() { - return 'truelayer'; - }, - - placeOrder: function (data, event) { - if (event) { - event.preventDefault(); - } +define([ + 'ko', + 'Magento_Checkout/js/view/payment/default', + 'Magento_Checkout/js/model/quote', + 'Magento_Customer/js/model/customer', + 'Magento_Checkout/js/model/step-navigator', + 'Magento_Checkout/js/action/set-payment-information', + 'mage/translate', + 'Magento_Ui/js/model/messageList', + 'https://cdn.jsdelivr.net/npm/truelayer-web-sdk/dist/sdk.min.js', +], function (ko, Component, quote, customer, stepNavigator, setPaymentInformation, $t, messageList, truelayerSdk) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'TrueLayer_Connect/payment/truelayer', + successMessage: ko.observable(''), + infoMessage: ko.observable(''), + buttonSize: ko.observable('small'), // 'small' or 'large', + isWidgetInit: ko.observable(false), + orderResult: null, + doneFuncCompletedProtection: ko.observable(0), // Fix: savety against infinite requests + }, + + initialize() { + this._super(); + + this.isPaymentStepLoaded(); + stepNavigator.steps.subscribe(() => this.isPaymentStepLoaded()); + + return this; + }, - this.isPlaceOrderActionAllowed(false); - var _this = this; + isPaymentStepLoaded() { + const steps = stepNavigator.steps(); + const payment = steps.find((step) => step.code === 'payment'); - if (additionalValidators.validate()) { - fullScreenLoader.startLoader(); - _this._placeOrder(); + if (payment && payment.isVisible()) { + // Fix: Correcting a duplicate request "set-payment-information" + // Trigger prompt on page load when no payment method is selected + if (!quote.paymentMethod()) { + setPaymentInformation(messageList, { method: this.getCode() }, false); } - }, + + const timeout = setTimeout(async () => { + this.orderResult = await this.orderRequest(customer.isLoggedIn(), quote.getQuoteId()); + this.initWidget(); - _placeOrder: function () { - return this.setPaymentInformation().done(function () { - this.orderRequest(customer.isLoggedIn(), quote.getQuoteId()); - }.bind(this)); - }, + clearTimeout(timeout); + }, 500); + } + }, - setPaymentInformation: function() { - var serviceUrl, payload; + getCode: () => 'truelayer', - payload = { - cartId: quote.getQuoteId(), - billingAddress: quote.billingAddress(), - paymentMethod: this.getData() - }; + async orderRequest(isLoggedIn, cartId) { + try { + const response = await fetch(`${window.location.origin}/rest/V1/truelayer/order-request`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + isLoggedIn, + cartId, + paymentMethod: this.getData(), + }), + }); + + const result = await response.json(); - if (customer.isLoggedIn()) { - serviceUrl = urlBuilder.createUrl('/carts/mine/set-payment-information', {}); + if (result[0].success) { + return result[0].response; } else { - payload.email = quote.guestEmail; - serviceUrl = urlBuilder.createUrl('/guest-carts/:quoteId/set-payment-information', { - quoteId: quote.getQuoteId() - }); + throw new Error($t('Failed getting order request result.')); } + } catch (error) { + messageList.addErrorMessage({ message: error }); + } + }, - return storage.post( - serviceUrl, JSON.stringify(payload) - ); - }, - - orderRequest: function(isLoggedIn, cartId) { - var url = 'rest/V1/truelayer/order-request'; - - payload = { - isLoggedIn: isLoggedIn, - cartId: cartId, - paymentMethod: this.getData() - }; - - storage.post( - url, - JSON.stringify(payload) - ).done(function (response) { - if (response[0].success) { - fullScreenLoader.stopLoader(); - window.location.replace(response[0].payment_page_url); - } else { - fullScreenLoader.stopLoader(); - this.addError(response[0].message); - } - }.bind(this)); - }, - - /** - * Adds error message - * - * @param {String} message - */ - addError: function (message) { - messageList.addErrorMessage({ - message: message - }); - }, - }); - } -); + initWidget() { + this.isWidgetInit(true); + this.doneFuncCompletedProtection(0); + + truelayerSdk.initWebSdk({ + uiSettings: { + size: this.buttonSize(), + recommendedPaymentMethod: true, + }, + + onError: (error) => messageList.addErrorMessage({ message: $t('Widget error: ') + error }), + onDone: (response) => this.onDone(response), + }) + .mount(document.getElementById('truelayer-widget-iframe')) + .start({ + paymentId: this.orderResult['payment_id'], + resourceToken: this.orderResult['resource_token'], + }); + }, + + async onDone(response) { + this.doneFuncCompletedProtection(this.doneFuncCompletedProtection() + 1); + + if (this.doneFuncCompletedProtection() === 1) { + if (response.resultStatus === 'success') { + this.successMessage($t('Payment success: page will reload.')); + window.location.replace(`/truelayer/checkout/process/payment_id/${this.orderResult['transaction_id']}`); + } + + if (response.resultStatus === 'pending') { + this.infoMessage($t('Payment pending: page will reload.')); + window.location.replace(`/truelayer/checkout/process/payment_id/${this.orderResult['transaction_id']}`); + } + + if (response.resultStatus === 'failed') { + this.isWidgetInit(false); + this.orderResult = await this.orderRequest(customer.isLoggedIn(), quote.getQuoteId()); + + const timeout = setTimeout(() => { + this.initWidget(); + clearTimeout(timeout); + }, 1000); + } + } + }, + }); +}); diff --git a/view/frontend/web/template/payment/truelayer.html b/view/frontend/web/template/payment/truelayer.html old mode 100644 new mode 100755 index 9caf65e..6d31102 --- a/view/frontend/web/template/payment/truelayer.html +++ b/view/frontend/web/template/payment/truelayer.html @@ -4,7 +4,8 @@ * See COPYING.txt for license details. */ --> -
+
+ + +
+ +
+ + + +
+ +
+ + +
+ + + + +
+
+
-
-
- -
-

-
-
-
- - -