From 88f7a1a085e3a1278e40107fbdc3985bc8f362e8 Mon Sep 17 00:00:00 2001 From: Michel Bade Date: Tue, 9 Jul 2024 16:21:23 +0200 Subject: [PATCH 1/2] PPI-807 - Improved script loading in storefront --- CHANGELOG.md | 1 + CHANGELOG_de-DE.md | 1 + .../ExpressCheckoutButtonData.php | 127 ++++++++++- .../PayPalExpressCheckoutDataService.php | 48 ++-- .../swag-paypal.abstract-standalone.js | 45 +--- .../src/checkout/swag-paypal.acdc-fields.js | 3 + .../swag-paypal.smart-payment-buttons.js | 42 ---- .../src/page/swag-paypal.express-checkout.js | 56 +---- .../page/swag-paypal.funding-eligibility.js | 51 +---- .../page/swag-paypal.installment-banner.js | 40 +--- .../src/swag-paypal.abstract-buttons.js | 94 +------- .../storefront/src/swag-paypal.script-base.js | 210 ++++++++++++++++++ .../src/swag-paypal.script-loading.js | 3 + .../Service/AbstractCheckoutDataService.php | 35 +-- .../Service/AbstractScriptDataService.php | 57 +++++ .../Service/FundingEligibilityDataService.php | 50 +---- .../Data/Struct/AbstractCheckoutData.php | 63 +----- .../Data/Struct/AbstractScriptData.php | 87 ++++++++ .../Data/Struct/FundingEligibilityData.php | 69 +----- 19 files changed, 561 insertions(+), 521 deletions(-) create mode 100644 src/Resources/app/storefront/src/swag-paypal.script-base.js create mode 100644 src/Storefront/Data/Service/AbstractScriptDataService.php create mode 100644 src/Storefront/Data/Struct/AbstractScriptData.php diff --git a/CHANGELOG.md b/CHANGELOG.md index c9a81132c..c6a18b187 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # 9.4.0 +- PPI-807 - Improved script loading performance in the Storefront - PPI-951 - Fixes an issue, where only generic error messages were displayed during checkout without Smart Payment Buttons - PPI-953 - Fixes an issue, where shipping tracking codes were not synced with an invalid carrier diff --git a/CHANGELOG_de-DE.md b/CHANGELOG_de-DE.md index 386dce3b1..aa9c2f7e1 100644 --- a/CHANGELOG_de-DE.md +++ b/CHANGELOG_de-DE.md @@ -1,4 +1,5 @@ # 9.4.0 +- PPI-807 - Verbessert die Ladezeit der Scripte in der Storefront - PPI-951 - Behebt ein Problem, bei dem ohne Smart Payment Buttons nur generische Fehlermeldungen während des Bestellprozesses angezeigt wurden - PPI-953 - Behebt ein Problem, bei dem Sendungsverfolgungsdaten bei invaliden Versanddienstleister nicht an PayPal übermittelt wurden diff --git a/src/Checkout/ExpressCheckout/ExpressCheckoutButtonData.php b/src/Checkout/ExpressCheckout/ExpressCheckoutButtonData.php index 81507d4ac..bf6a7b659 100644 --- a/src/Checkout/ExpressCheckout/ExpressCheckoutButtonData.php +++ b/src/Checkout/ExpressCheckout/ExpressCheckoutButtonData.php @@ -8,10 +8,10 @@ namespace Swag\PayPal\Checkout\ExpressCheckout; use Shopware\Core\Framework\Log\Package; -use Swag\PayPal\Storefront\Data\Struct\AbstractCheckoutData; +use Swag\PayPal\Storefront\Data\Struct\AbstractScriptData; #[Package('checkout')] -class ExpressCheckoutButtonData extends AbstractCheckoutData +class ExpressCheckoutButtonData extends AbstractScriptData { protected bool $productDetailEnabled; @@ -23,16 +23,29 @@ class ExpressCheckoutButtonData extends AbstractCheckoutData protected bool $cartEnabled; + protected string $buttonColor; + + protected string $buttonShape; + protected bool $addProductToCart; protected string $contextSwitchUrl; protected ?string $payPalPaymentMethodId = null; + protected string $createOrderUrl; + protected string $prepareCheckoutUrl; protected string $checkoutConfirmUrl; + /** + * @deprecated tag:v10.0.0 - Will be removed, use {@link handleErrorUrl} instead + */ + protected string $addErrorUrl; + + protected string $handleErrorUrl; + protected string $cancelRedirectUrl; protected bool $showPayLater; @@ -42,24 +55,39 @@ public function getProductDetailEnabled(): bool return $this->productDetailEnabled; } + public function setProductDetailEnabled(bool $productDetailEnabled): void + { + $this->productDetailEnabled = $productDetailEnabled; + } + public function getOffCanvasEnabled(): bool { return $this->offCanvasEnabled; } + public function setOffCanvasEnabled(bool $offCanvasEnabled): void + { + $this->offCanvasEnabled = $offCanvasEnabled; + } + public function getLoginEnabled(): bool { return $this->loginEnabled; } + public function setLoginEnabled(bool $loginEnabled): void + { + $this->loginEnabled = $loginEnabled; + } + public function getListingEnabled(): bool { return $this->listingEnabled; } - public function getButtonColor(): string + public function setListingEnabled(bool $listingEnabled): void { - return $this->buttonColor; + $this->listingEnabled = $listingEnabled; } public function getCartEnabled(): bool @@ -67,36 +95,127 @@ public function getCartEnabled(): bool return $this->cartEnabled; } + public function setCartEnabled(bool $cartEnabled): void + { + $this->cartEnabled = $cartEnabled; + } + + public function getButtonColor(): string + { + return $this->buttonColor; + } + + public function setButtonColor(string $buttonColor): void + { + $this->buttonColor = $buttonColor; + } + + public function getButtonShape(): string + { + return $this->buttonShape; + } + + public function setButtonShape(string $buttonShape): void + { + $this->buttonShape = $buttonShape; + } + public function getAddProductToCart(): bool { return $this->addProductToCart; } + public function setAddProductToCart(bool $addProductToCart): void + { + $this->addProductToCart = $addProductToCart; + } + public function getContextSwitchUrl(): string { return $this->contextSwitchUrl; } + public function setContextSwitchUrl(string $contextSwitchUrl): void + { + $this->contextSwitchUrl = $contextSwitchUrl; + } + public function getPayPalPaymentMethodId(): ?string { return $this->payPalPaymentMethodId; } + public function setPayPalPaymentMethodId(?string $payPalPaymentMethodId): void + { + $this->payPalPaymentMethodId = $payPalPaymentMethodId; + } + + public function getCreateOrderUrl(): string + { + return $this->createOrderUrl; + } + + public function setCreateOrderUrl(string $createOrderUrl): void + { + $this->createOrderUrl = $createOrderUrl; + } + public function getPrepareCheckoutUrl(): string { return $this->prepareCheckoutUrl; } + public function setPrepareCheckoutUrl(string $prepareCheckoutUrl): void + { + $this->prepareCheckoutUrl = $prepareCheckoutUrl; + } + public function getCheckoutConfirmUrl(): string { return $this->checkoutConfirmUrl; } + public function setCheckoutConfirmUrl(string $checkoutConfirmUrl): void + { + $this->checkoutConfirmUrl = $checkoutConfirmUrl; + } + + /** + * @deprecated tag:v10.0.0 - Will be removed, use {@link handleErrorUrl} instead + */ + public function getAddErrorUrl(): string + { + return $this->addErrorUrl; + } + + /** + * @deprecated tag:v10.0.0 - Will be removed, use {@link handleErrorUrl} instead + */ + public function setAddErrorUrl(string $addErrorUrl): void + { + $this->addErrorUrl = $addErrorUrl; + } + + public function getHandleErrorUrl(): string + { + return $this->handleErrorUrl; + } + + public function setHandleErrorUrl(string $handleErrorUrl): void + { + $this->handleErrorUrl = $handleErrorUrl; + } + public function getCancelRedirectUrl(): string { return $this->cancelRedirectUrl; } + public function setCancelRedirectUrl(string $cancelRedirectUrl): void + { + $this->cancelRedirectUrl = $cancelRedirectUrl; + } + public function isShowPayLater(): bool { return $this->showPayLater; diff --git a/src/Checkout/ExpressCheckout/Service/PayPalExpressCheckoutDataService.php b/src/Checkout/ExpressCheckout/Service/PayPalExpressCheckoutDataService.php index 8330e37e8..0fbbdca85 100644 --- a/src/Checkout/ExpressCheckout/Service/PayPalExpressCheckoutDataService.php +++ b/src/Checkout/ExpressCheckout/Service/PayPalExpressCheckoutDataService.php @@ -9,7 +9,6 @@ use Shopware\Core\Checkout\Cart\SalesChannel\CartService; use Shopware\Core\Checkout\Customer\CustomerEntity; -use Shopware\Core\Framework\Context; use Shopware\Core\Framework\Log\Package; use Shopware\Core\System\SalesChannel\SalesChannelContext; use Shopware\Core\System\SystemConfig\SystemConfigService; @@ -18,46 +17,27 @@ use Swag\PayPal\Checkout\Payment\PayPalPaymentHandler; use Swag\PayPal\Setting\Service\CredentialsUtilInterface; use Swag\PayPal\Setting\Settings; +use Swag\PayPal\Storefront\Data\Service\AbstractScriptDataService; use Swag\PayPal\Util\LocaleCodeProvider; use Swag\PayPal\Util\PaymentMethodUtil; use Symfony\Component\Routing\RouterInterface; #[Package('checkout')] -class PayPalExpressCheckoutDataService implements ExpressCheckoutDataServiceInterface +class PayPalExpressCheckoutDataService extends AbstractScriptDataService implements ExpressCheckoutDataServiceInterface { - private CartService $cartService; - - private LocaleCodeProvider $localeCodeProvider; - - private RouterInterface $router; - - private PaymentMethodUtil $paymentMethodUtil; - - private SystemConfigService $systemConfigService; - - private CredentialsUtilInterface $credentialsUtil; - - private CartPriceService $cartPriceService; - /** * @internal */ public function __construct( - CartService $cartService, + private readonly CartService $cartService, LocaleCodeProvider $localeCodeProvider, - RouterInterface $router, - PaymentMethodUtil $paymentMethodUtil, + private readonly RouterInterface $router, + private readonly PaymentMethodUtil $paymentMethodUtil, SystemConfigService $systemConfigService, CredentialsUtilInterface $credentialsUtil, - CartPriceService $cartPriceService + private readonly CartPriceService $cartPriceService ) { - $this->cartService = $cartService; - $this->localeCodeProvider = $localeCodeProvider; - $this->router = $router; - $this->paymentMethodUtil = $paymentMethodUtil; - $this->systemConfigService = $systemConfigService; - $this->credentialsUtil = $credentialsUtil; - $this->cartPriceService = $cartPriceService; + parent::__construct($localeCodeProvider, $systemConfigService, $credentialsUtil); } public function buildExpressCheckoutButtonData( @@ -87,6 +67,7 @@ public function buildExpressCheckoutButtonData( $salesChannelId = $salesChannelContext->getSalesChannelId(); return (new ExpressCheckoutButtonData())->assign([ + ...parent::getBaseData($salesChannelContext), 'productDetailEnabled' => $this->systemConfigService->getBool(Settings::ECS_DETAIL_ENABLED, $salesChannelId), 'offCanvasEnabled' => $this->systemConfigService->getBool(Settings::ECS_OFF_CANVAS_ENABLED, $salesChannelId), 'loginEnabled' => $this->systemConfigService->getBool(Settings::ECS_LOGIN_ENABLED, $salesChannelId), @@ -94,10 +75,6 @@ public function buildExpressCheckoutButtonData( 'listingEnabled' => $this->systemConfigService->getBool(Settings::ECS_LISTING_ENABLED, $salesChannelId), 'buttonColor' => $this->systemConfigService->getString(Settings::ECS_BUTTON_COLOR, $salesChannelId), 'buttonShape' => $this->systemConfigService->getString(Settings::ECS_BUTTON_SHAPE, $salesChannelId), - 'clientId' => $this->credentialsUtil->getClientId($salesChannelId), - 'languageIso' => $this->getInContextButtonLanguage($salesChannelId, $context), - 'currency' => $salesChannelContext->getCurrency()->getIsoCode(), - 'intent' => \mb_strtolower($this->systemConfigService->getString(Settings::INTENT, $salesChannelId)), 'addProductToCart' => $addProductToCart, 'contextSwitchUrl' => $this->router->generate('frontend.paypal.express.prepare_cart'), 'payPalPaymentMethodId' => $this->paymentMethodUtil->getPayPalPaymentMethodId($context), @@ -108,21 +85,22 @@ public function buildExpressCheckoutButtonData( [PayPalPaymentHandler::PAYPAL_EXPRESS_CHECKOUT_ID => true], RouterInterface::ABSOLUTE_URL ), + /** @deprecated tag:v10.0.0 - Will be removed, use handleErrorUrl instead */ 'addErrorUrl' => $this->router->generate('frontend.paypal.error'), + 'handleErrorUrl' => $this->router->generate('frontend.paypal.handle-error'), 'cancelRedirectUrl' => $this->router->generate($addProductToCart ? 'frontend.checkout.cart.page' : 'frontend.checkout.register.page'), 'showPayLater' => $this->systemConfigService->getBool(Settings::ECS_SHOW_PAY_LATER, $salesChannelId), - 'merchantPayerId' => $this->credentialsUtil->getMerchantPayerId($salesChannelId), ]); } - private function getInContextButtonLanguage(string $salesChannelId, Context $context): string + protected function getButtonLanguage(SalesChannelContext $context): string { - if ($settingsLocale = $this->systemConfigService->getString(Settings::ECS_BUTTON_LANGUAGE_ISO, $salesChannelId)) { + if ($settingsLocale = $this->systemConfigService->getString(Settings::ECS_BUTTON_LANGUAGE_ISO, $context->getSalesChannelId())) { return $this->localeCodeProvider->getFormattedLocaleCode($settingsLocale); } return $this->localeCodeProvider->getFormattedLocaleCode( - $this->localeCodeProvider->getLocaleCodeFromContext($context) + $this->localeCodeProvider->getLocaleCodeFromContext($context->getContext()) ); } } diff --git a/src/Resources/app/storefront/src/checkout/swag-paypal.abstract-standalone.js b/src/Resources/app/storefront/src/checkout/swag-paypal.abstract-standalone.js index e743f469e..c8b7619de 100644 --- a/src/Resources/app/storefront/src/checkout/swag-paypal.abstract-standalone.js +++ b/src/Resources/app/storefront/src/checkout/swag-paypal.abstract-standalone.js @@ -6,26 +6,15 @@ import SwagPaypalAbstractButtons from '../swag-paypal.abstract-buttons'; import SwagPayPalScriptLoading from '../swag-paypal.script-loading'; export default class SwagPaypalAbstractStandalone extends SwagPaypalAbstractButtons { + /** + * @deprecated tag:v10.0.0 - will be removed without replacement + */ static scriptLoading = new SwagPayPalScriptLoading(); static product = 'spb'; static options = { ...super.options, - /** - * This option holds the client id specified in the settings - * - * @type string - */ - clientId: '', - - /** - * This option holds the merchant id specified in the settings - * - * @type string - */ - merchantPayerId: '', - /** * This option holds the client token required for field rendering * @@ -33,34 +22,6 @@ export default class SwagPaypalAbstractStandalone extends SwagPaypalAbstractButt */ clientToken: '', - /** - * This options specifies the currency of the PayPal button - * - * @type string - */ - currency: 'EUR', - - /** - * This options defines the payment intent - * - * @type string - */ - intent: 'capture', - - /** - * This option toggles the PayNow/Login text at PayPal - * - * @type boolean - */ - commit: true, - - /** - * This option specifies the language of the PayPal button - * - * @type string - */ - languageIso: 'en_GB', - /** * This option specifies the PayPal button color * diff --git a/src/Resources/app/storefront/src/checkout/swag-paypal.acdc-fields.js b/src/Resources/app/storefront/src/checkout/swag-paypal.acdc-fields.js index af192a132..d6074787f 100644 --- a/src/Resources/app/storefront/src/checkout/swag-paypal.acdc-fields.js +++ b/src/Resources/app/storefront/src/checkout/swag-paypal.acdc-fields.js @@ -6,6 +6,9 @@ import SwagPaypalAbstractStandalone from './swag-paypal.abstract-standalone'; import SwagPayPalScriptLoading from '../swag-paypal.script-loading'; export default class SwagPaypalAcdcFields extends SwagPaypalAbstractStandalone { + /** + * @deprecated tag:v10.0.0 - will be removed without replacement + */ static scriptLoading = new SwagPayPalScriptLoading(); static options = { diff --git a/src/Resources/app/storefront/src/checkout/swag-paypal.smart-payment-buttons.js b/src/Resources/app/storefront/src/checkout/swag-paypal.smart-payment-buttons.js index c9ed4d1ab..fc6928be3 100644 --- a/src/Resources/app/storefront/src/checkout/swag-paypal.smart-payment-buttons.js +++ b/src/Resources/app/storefront/src/checkout/swag-paypal.smart-payment-buttons.js @@ -29,48 +29,6 @@ export default class SwagPayPalSmartPaymentButtons extends SwagPaypalAbstractBut */ buttonSize: 'small', - /** - * This option specifies the language of the PayPal button - * - * @type string - */ - languageIso: 'en_GB', - - /** - * This option holds the client id specified in the settings - * - * @type string - */ - clientId: '', - - /** - * This option holds the merchant id specified in the settings - * - * @type string - */ - merchantPayerId: '', - - /** - * This options specifies the currency of the PayPal button - * - * @type string - */ - currency: 'EUR', - - /** - * This options defines the payment intent - * - * @type string - */ - intent: 'capture', - - /** - * This option toggles the PayNow/Login text at PayPal - * - * @type boolean - */ - commit: true, - /** * This option toggles if credit card and ELV should be shown * diff --git a/src/Resources/app/storefront/src/page/swag-paypal.express-checkout.js b/src/Resources/app/storefront/src/page/swag-paypal.express-checkout.js index 4975a19fb..688ec8bbe 100644 --- a/src/Resources/app/storefront/src/page/swag-paypal.express-checkout.js +++ b/src/Resources/app/storefront/src/page/swag-paypal.express-checkout.js @@ -5,9 +5,13 @@ import SwagPaypalAbstractButtons from '../swag-paypal.abstract-buttons'; import SwagPayPalScriptLoading from '../swag-paypal.script-loading'; export default class SwagPayPalExpressCheckoutButton extends SwagPaypalAbstractButtons { + /** + * @deprecated tag:v10.0.0 - will be removed without replacement + */ static scriptLoading = new SwagPayPalScriptLoading(); static options = { + ...super.options, /** * This option defines the class name which will be added when the button gets disabled. @@ -44,48 +48,6 @@ export default class SwagPayPalExpressCheckoutButton extends SwagPaypalAbstractB */ buttonSize: 'small', - /** - * This option specifies the language of the PayPal button - * - * @type string - */ - languageIso: 'en_GB', - - /** - * This option holds the client id specified in the settings - * - * @type string - */ - clientId: '', - - /** - * This option holds the merchant id specified in the settings - * - * @type string - */ - merchantPayerId: '', - - /** - * This options specifies the currency of the PayPal button - * - * @type string - */ - currency: 'EUR', - - /** - * This options defines the payment intent - * - * @type string - */ - intent: 'capture', - - /** - * This option toggles the PayNow/Login text at PayPal - * - * @type boolean - */ - commit: false, - /** * This option toggles the text below the PayPal Express button * @@ -161,12 +123,14 @@ export default class SwagPayPalExpressCheckoutButton extends SwagPaypalAbstractB */ showPayLater: true, - /** - * Show no other buttons - * - * @type boolean + /* + * Streamline options for listing pages, overriding the ones + * from swag-paypal.script-loading.js */ useAlternativePaymentMethods: false, + commit: false, + scriptAwaitVisibility: true, + partOfDomContentLoading: false, }; init() { diff --git a/src/Resources/app/storefront/src/page/swag-paypal.funding-eligibility.js b/src/Resources/app/storefront/src/page/swag-paypal.funding-eligibility.js index e1b2495f4..61978c4a3 100644 --- a/src/Resources/app/storefront/src/page/swag-paypal.funding-eligibility.js +++ b/src/Resources/app/storefront/src/page/swag-paypal.funding-eligibility.js @@ -10,47 +10,7 @@ export default class SwagPayPalFundingEligibility extends SwagPaypalAbstractButt ] static options = { - /** - * This option holds the client id specified in the settings - * - * @type string - */ - clientId: '', - - /** - * This option holds the merchant id specified in the settings - * - * @type string - */ - merchantPayerId: '', - - /** - * This option specifies the language of the PayPal button - * - * @type string - */ - languageIso: 'en_GB', - - /** - * This options specifies the currency of the PayPal button - * - * @type string - */ - currency: 'EUR', - - /** - * This options defines the payment intent - * - * @type string - */ - intent: 'capture', - - /** - * This option toggles the PayNow/Login text at PayPal - * - * @type boolean - */ - commit: true, + ...super.options, /** * Previously filtered payment methods @@ -65,6 +25,15 @@ export default class SwagPayPalFundingEligibility extends SwagPaypalAbstractButt * @type string */ methodEligibilityUrl: '', + + /* + * Streamline options for listing pages, overriding the ones + * from swag-paypal.script-loading.js + */ + useAlternativePaymentMethods: false, + commit: false, + scriptAwaitVisibility: true, + partOfDomContentLoading: false, }; init() { diff --git a/src/Resources/app/storefront/src/page/swag-paypal.installment-banner.js b/src/Resources/app/storefront/src/page/swag-paypal.installment-banner.js index 799c96799..492f7b440 100644 --- a/src/Resources/app/storefront/src/page/swag-paypal.installment-banner.js +++ b/src/Resources/app/storefront/src/page/swag-paypal.installment-banner.js @@ -2,26 +2,7 @@ import SwagPaypalAbstractButtons from '../swag-paypal.abstract-buttons'; export default class SwagPayPalInstallmentBanner extends SwagPaypalAbstractButtons { static options = { - /** - * This option holds the client id specified in the settings - * - * @type string - */ - clientId: '', - - /** - * This option holds the merchant id specified in the settings - * - * @type string - */ - merchantPayerId: '', - - /** - * This option toggles the PayNow/Login text at PayPal - * - * @type boolean - */ - commit: true, + ...super.options, /** * This option holds the buyer country for Pay Later localization @@ -37,13 +18,6 @@ export default class SwagPayPalInstallmentBanner extends SwagPaypalAbstractButto */ amount: 0, - /** - * Currency used for the examples - * - * @type string - */ - currency: 'EUR', - /** * Layout of the installment banner * Available layouts: @@ -100,12 +74,14 @@ export default class SwagPayPalInstallmentBanner extends SwagPaypalAbstractButto */ textColor: 'black', - /** - * This option holds the partner attribution id - * - * @type string + /* + * Streamline options for listing pages, overriding the ones + * from swag-paypal.script-loading.js */ - partnerAttributionId: '', + useAlternativePaymentMethods: false, + commit: false, + scriptAwaitVisibility: true, + partOfDomContentLoading: false, }; init() { diff --git a/src/Resources/app/storefront/src/swag-paypal.abstract-buttons.js b/src/Resources/app/storefront/src/swag-paypal.abstract-buttons.js index 52c26e78e..fb7a33a16 100644 --- a/src/Resources/app/storefront/src/swag-paypal.abstract-buttons.js +++ b/src/Resources/app/storefront/src/swag-paypal.abstract-buttons.js @@ -1,24 +1,9 @@ -import Plugin from 'src/plugin-system/plugin.class'; -import {loadScript} from '@paypal/paypal-js'; -import SwagPayPalScriptLoading from './swag-paypal.script-loading'; - -const availableAPMs = [ - 'card', - 'bancontact', - 'blik', - 'eps', - 'giropay', - 'ideal', - 'mybank', - 'p24', - 'sepa', - 'sofort', - 'venmo', -]; - -export default class SwagPaypalAbstractButtons extends Plugin { - static scriptLoading = new SwagPayPalScriptLoading(); +import SwagPayPalScriptBase from './swag-paypal.script-base'; + +export default class SwagPaypalAbstractButtons extends SwagPayPalScriptBase { static options = { + ...super.options, + /** * URL for adding flash error message * @@ -41,76 +26,7 @@ export default class SwagPaypalAbstractButtons extends Plugin { USER_CANCELLED = 'SWAG_PAYPAL__USER_CANCELLED'; BROWSER_UNSUPPORTED = 'SWAG_PAYPAL__BROWSER_UNSUPPORTED'; - createScript(callback) { - if (this.constructor.scriptLoading.paypal !== null) { - callback.call(this, this.constructor.scriptLoading.paypal); - return; - } - - this.constructor.scriptLoading.callbacks.push(callback); - - if (this.constructor.scriptLoading.loadingScript) { - return; - } - - this.constructor.scriptLoading.loadingScript = true; - - loadScript(this.getScriptOptions()).then(this.callCallbacks.bind(this)); - } - - callCallbacks() { - if (this.constructor.scriptLoading.paypal === null) { - this.constructor.scriptLoading.paypal = window.paypal; - delete window.paypal; - } - - this.constructor.scriptLoading.callbacks.forEach((callback) => { - callback.call(this, this.constructor.scriptLoading.paypal); - }); - } - /** - * @return {Object} - */ - getScriptOptions() { - const config = { - components: 'buttons,messages,card-fields,funding-eligibility,applepay,googlepay', - 'client-id': this.options.clientId, - commit: !!this.options.commit, - locale: this.options.languageIso, - currency: this.options.currency, - intent: this.options.intent, - 'enable-funding': 'paylater,venmo', - }; - - if (this.options.disablePayLater || this.options.showPayLater === false) { - config['enable-funding'] = 'venmo'; - } - - if (this.options.useAlternativePaymentMethods === false) { - config['disable-funding'] = availableAPMs.join(','); - } else if (Array.isArray(this.options.disabledAlternativePaymentMethods)) { - config['disable-funding'] = this.options.disabledAlternativePaymentMethods.join(','); - } - - if (this.options.merchantPayerId) { - config['merchant-id'] = this.options.merchantPayerId; - } - - if (this.options.clientToken) { - config['data-client-token'] = this.options.clientToken; - } - - if (this.options.userIdToken) { - config['data-user-id-token'] = this.options.userIdToken; - } - - if (this.options.partnerAttributionId) { - config['data-partner-attribution-id'] = this.options.partnerAttributionId; - } - - return config; - } /** * @param {String} code - The error code. Will be replaced by an extracted error code from {@link error} if available diff --git a/src/Resources/app/storefront/src/swag-paypal.script-base.js b/src/Resources/app/storefront/src/swag-paypal.script-base.js new file mode 100644 index 000000000..31c76522d --- /dev/null +++ b/src/Resources/app/storefront/src/swag-paypal.script-base.js @@ -0,0 +1,210 @@ +import Plugin from 'src/plugin-system/plugin.class'; +import { loadScript } from '@paypal/paypal-js'; +import SwagPayPalScriptLoading from './swag-paypal.script-loading'; + +const availableAPMs = [ + 'card', + 'bancontact', + 'blik', + 'eps', + 'giropay', + 'ideal', + 'mybank', + 'p24', + 'sepa', + 'sofort', + 'venmo', +]; + +export default class SwagPayPalScriptBase extends Plugin { + /** + * @deprecated tag:v10.0.0 - will be removed without replacement + */ + static scriptLoading = new SwagPayPalScriptLoading(); + + static options = { + /** + * This option holds the client id specified in the settings + * + * @type string + */ + clientId: '', + + /** + * This option holds the merchant id specified in the settings + * + * @type string + */ + merchantPayerId: '', + + /** + * This option holds the partner attribution id + * + * @type string + */ + partnerAttributionId: '', + + /** + * This options specifies the currency of the PayPal button + * + * @type string + */ + currency: 'EUR', + + /** + * This options defines the payment intent + * + * @type string + */ + intent: 'capture', + + /** + * This option toggles the PayNow/Login text at PayPal + * + * @type boolean + */ + commit: true, + + /** + * This option specifies the language of the PayPal button + * + * @type string + */ + languageIso: 'en_GB', + + /** + * This option will await the visibility of the element before continue loading the script. + * Useful for listing pages to not load all express buttons at once. + * + * @type boolean + */ + scriptAwaitVisibility: false, + + /** + * This option toggles when the script should be loaded. + * If false, the script will be loaded on 'load' instead of 'DOMContentLoaded' event. + * See 'DOMContentLoaded' and 'load' event for more information. + * + * @type boolean + */ + partOfDomContentLoading: true, + } + + static scriptPromises = {}; + + static paypal = {}; + + _init() { + if (this.options.partOfDomContentLoading || document.readyState === 'complete') { + super._init(); + } else { + window.addEventListener('load', () => { + super._init(); + }); + } + } + + get scriptOptionsHash() { + return JSON.stringify(this.getScriptOptions()); + } + + async createScript(callback) { + SwagPayPalScriptBase.scriptPromises[this.scriptOptionsHash] ??= this._loadScript(); + + const wrapper = async () => { + callback(await SwagPayPalScriptBase.scriptPromises[this.scriptOptionsHash]); + }; + + if (this.options.scriptAwaitVisibility) { + await this._awaitVisibility(wrapper); + } else { + await wrapper(); + } + + this._createScriptLegacy(callback); + } + + async _awaitVisibility(callback) { + const observer = new IntersectionObserver(([entry]) => { + if (entry.isIntersecting) { + observer.disconnect(); + callback(); + } + }, { + rootMargin: '200px', // Load the buttons before they become visible + }); + + observer.observe(this.el); + } + + async _loadScript() { + await loadScript(this.getScriptOptions()); + + SwagPayPalScriptBase.paypal[this.scriptOptionsHash] = window.paypal; + delete window.paypal; + + return SwagPayPalScriptBase.paypal[this.scriptOptionsHash]; + } + + /** + * The options the PayPal script will be loaded with. + * Make sure to not create a flaky order of options, as this will + * mess up the `scriptOptionsHash` and therefore affects script caching. + */ + getScriptOptions() { + const config = { + components: 'buttons,messages,card-fields,funding-eligibility,applepay,googlepay', + 'client-id': this.options.clientId, + commit: !!this.options.commit, + locale: this.options.languageIso, + currency: this.options.currency, + intent: this.options.intent, + 'enable-funding': 'paylater,venmo', + }; + + if (this.options.disablePayLater || this.options.showPayLater === false) { + config['enable-funding'] = 'venmo'; + } + + if (this.options.useAlternativePaymentMethods === false) { + config['disable-funding'] = availableAPMs.join(','); + } else if (Array.isArray(this.options.disabledAlternativePaymentMethods)) { + config['disable-funding'] = this.options.disabledAlternativePaymentMethods.join(','); + } + + if (this.options.merchantPayerId) { + config['merchant-id'] = this.options.merchantPayerId; + } + + if (this.options.clientToken) { + config['data-client-token'] = this.options.clientToken; + } + + if (this.options.userIdToken) { + config['data-user-id-token'] = this.options.userIdToken; + } + + if (this.options.partnerAttributionId) { + config['data-partner-attribution-id'] = this.options.partnerAttributionId; + } + + return config; + } + + /** + * @deprecated tag:v10.0.0 - will be removed without replacement + */ + callCallbacks() { + this.constructor.scriptLoading.callbacks.forEach((callback) => { + SwagPayPalScriptBase.scriptPromises[this.scriptOptionsHash] + .then((paypal) => callback.call(this, paypal)); + }); + } + + /** + * @deprecated tag:v10.0.0 - will be removed without replacement + */ + _createScriptLegacy(callback) { + this.constructor.scriptLoading.callbacks.push(callback); + } +} diff --git a/src/Resources/app/storefront/src/swag-paypal.script-loading.js b/src/Resources/app/storefront/src/swag-paypal.script-loading.js index e3099cd9b..5ab84b50d 100644 --- a/src/Resources/app/storefront/src/swag-paypal.script-loading.js +++ b/src/Resources/app/storefront/src/swag-paypal.script-loading.js @@ -1,3 +1,6 @@ +/** + * @deprecated tag:v10.0.0 - will be removed without replacement + */ export default class SwagPayPalScriptLoading { loadingScript = false; diff --git a/src/Storefront/Data/Service/AbstractCheckoutDataService.php b/src/Storefront/Data/Service/AbstractCheckoutDataService.php index 7c306fc1e..e495bb358 100644 --- a/src/Storefront/Data/Service/AbstractCheckoutDataService.php +++ b/src/Storefront/Data/Service/AbstractCheckoutDataService.php @@ -23,7 +23,7 @@ use Symfony\Component\Routing\RouterInterface; #[Package('checkout')] -abstract class AbstractCheckoutDataService +abstract class AbstractCheckoutDataService extends AbstractScriptDataService { public const PAYPAL_ERROR = 'isPayPalError'; @@ -32,11 +32,12 @@ abstract class AbstractCheckoutDataService */ public function __construct( private readonly PaymentMethodDataRegistry $paymentMethodDataRegistry, - private readonly LocaleCodeProvider $localeCodeProvider, + LocaleCodeProvider $localeCodeProvider, private readonly RouterInterface $router, - protected readonly SystemConfigService $systemConfigService, - protected readonly CredentialsUtilInterface $credentialsUtil + SystemConfigService $systemConfigService, + CredentialsUtilInterface $credentialsUtil ) { + parent::__construct($localeCodeProvider, $systemConfigService, $credentialsUtil); } abstract public function buildCheckoutData(SalesChannelContext $context, ?Cart $cart = null, ?OrderEntity $order = null): ?AbstractCheckoutData; @@ -48,24 +49,19 @@ abstract public function getMethodDataClass(): string; protected function getBaseData(SalesChannelContext $context, ?OrderEntity $order = null): array { + if ($context->getCustomer() === null) { + throw CartException::customerNotLoggedIn(); + } + $paymentMethodId = $this->paymentMethodDataRegistry->getEntityIdFromData( $this->paymentMethodDataRegistry->getPaymentMethod($this->getMethodDataClass()), $context->getContext() ); $salesChannelId = $context->getSalesChannelId(); - $customer = $context->getCustomer(); - - if ($customer === null) { - throw CartException::customerNotLoggedIn(); - } $data = [ - 'clientId' => $this->credentialsUtil->getClientId($salesChannelId), - 'merchantPayerId' => $this->credentialsUtil->getMerchantPayerId($salesChannelId), - 'languageIso' => $this->getButtonLanguage($context), - 'currency' => $context->getCurrency()->getIsoCode(), - 'intent' => \mb_strtolower($this->systemConfigService->getString(Settings::INTENT, $salesChannelId)), + ...parent::getBaseData($context, $order), 'buttonShape' => $this->systemConfigService->getString(Settings::SPB_BUTTON_SHAPE, $salesChannelId), 'paymentMethodId' => $paymentMethodId, 'createOrderUrl' => $context->hasExtension('subscription') @@ -103,15 +99,4 @@ protected function getBaseData(SalesChannelContext $context, ?OrderEntity $order return $data; } - - private function getButtonLanguage(SalesChannelContext $context): string - { - if ($settingsLocale = $this->systemConfigService->getString(Settings::SPB_BUTTON_LANGUAGE_ISO, $context->getSalesChannelId())) { - return $this->localeCodeProvider->getFormattedLocaleCode($settingsLocale); - } - - return $this->localeCodeProvider->getFormattedLocaleCode( - $this->localeCodeProvider->getLocaleCodeFromContext($context->getContext()) - ); - } } diff --git a/src/Storefront/Data/Service/AbstractScriptDataService.php b/src/Storefront/Data/Service/AbstractScriptDataService.php new file mode 100644 index 000000000..42bf74454 --- /dev/null +++ b/src/Storefront/Data/Service/AbstractScriptDataService.php @@ -0,0 +1,57 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Swag\PayPal\Storefront\Data\Service; + +use Shopware\Core\Checkout\Order\OrderEntity; +use Shopware\Core\Framework\Log\Package; +use Shopware\Core\System\SalesChannel\SalesChannelContext; +use Shopware\Core\System\SystemConfig\SystemConfigService; +use Swag\PayPal\RestApi\PartnerAttributionId; +use Swag\PayPal\Setting\Service\CredentialsUtilInterface; +use Swag\PayPal\Setting\Settings; +use Swag\PayPal\Util\LocaleCodeProvider; + +#[Package('checkout')] +abstract class AbstractScriptDataService +{ + /** + * @internal + */ + public function __construct( + protected readonly LocaleCodeProvider $localeCodeProvider, + protected readonly SystemConfigService $systemConfigService, + protected readonly CredentialsUtilInterface $credentialsUtil + ) { + } + + protected function getBaseData(SalesChannelContext $context, ?OrderEntity $order = null): array + { + $salesChannelId = $context->getSalesChannelId(); + $merchantPayerId = $this->credentialsUtil->getMerchantPayerId($salesChannelId); + + return [ + 'clientId' => $this->credentialsUtil->getClientId($salesChannelId), + 'merchantPayerId' => $merchantPayerId, + 'languageIso' => $this->getButtonLanguage($context), + 'currency' => $context->getCurrency()->getIsoCode(), + 'intent' => \mb_strtolower($this->systemConfigService->getString(Settings::INTENT, $salesChannelId)), + 'partnerAttributionId' => $merchantPayerId ? PartnerAttributionId::PAYPAL_PPCP : PartnerAttributionId::PAYPAL_CLASSIC, + ]; + } + + protected function getButtonLanguage(SalesChannelContext $context): string + { + if ($settingsLocale = $this->systemConfigService->getString(Settings::SPB_BUTTON_LANGUAGE_ISO, $context->getSalesChannelId())) { + return $this->localeCodeProvider->getFormattedLocaleCode($settingsLocale); + } + + return $this->localeCodeProvider->getFormattedLocaleCode( + $this->localeCodeProvider->getLocaleCodeFromContext($context->getContext()) + ); + } +} diff --git a/src/Storefront/Data/Service/FundingEligibilityDataService.php b/src/Storefront/Data/Service/FundingEligibilityDataService.php index 678af21fb..7bc0bd6e5 100644 --- a/src/Storefront/Data/Service/FundingEligibilityDataService.php +++ b/src/Storefront/Data/Service/FundingEligibilityDataService.php @@ -12,25 +12,14 @@ use Shopware\Core\System\SystemConfig\SystemConfigService; use Swag\PayPal\Checkout\SalesChannel\MethodEligibilityRoute; use Swag\PayPal\Setting\Service\CredentialsUtilInterface; -use Swag\PayPal\Setting\Settings; use Swag\PayPal\Storefront\Data\Struct\FundingEligibilityData; use Swag\PayPal\Util\LocaleCodeProvider; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\RouterInterface; #[Package('checkout')] -class FundingEligibilityDataService +class FundingEligibilityDataService extends AbstractScriptDataService { - private CredentialsUtilInterface $credentialsUtil; - - private SystemConfigService $systemConfigService; - - private LocaleCodeProvider $localeCodeProvider; - - private RouterInterface $router; - - private RequestStack $requestStack; - /** * @internal */ @@ -38,40 +27,19 @@ public function __construct( CredentialsUtilInterface $credentialsUtil, SystemConfigService $systemConfigService, LocaleCodeProvider $localeCodeProvider, - RouterInterface $router, - RequestStack $requestStack + private readonly RouterInterface $router, + private readonly RequestStack $requestStack ) { - $this->credentialsUtil = $credentialsUtil; - $this->systemConfigService = $systemConfigService; - $this->localeCodeProvider = $localeCodeProvider; - $this->router = $router; - $this->requestStack = $requestStack; + parent::__construct($localeCodeProvider, $systemConfigService, $credentialsUtil); } public function buildData(SalesChannelContext $context): ?FundingEligibilityData { - return (new FundingEligibilityData())->assign( - [ - 'clientId' => $this->credentialsUtil->getClientId($context->getSalesChannelId()), - 'merchantPayerId' => $this->credentialsUtil->getMerchantPayerId($context->getSalesChannelId()), - 'languageIso' => $this->getButtonLanguage($context), - 'currency' => $context->getCurrency()->getIsoCode(), - 'intent' => \mb_strtolower($this->systemConfigService->getString(Settings::INTENT, $context->getSalesChannelId())), - 'methodEligibilityUrl' => $this->router->generate('frontend.paypal.payment-method-eligibility'), - 'filteredPaymentMethods' => $this->getFilteredPaymentMethods(), - ] - ); - } - - private function getButtonLanguage(SalesChannelContext $context): string - { - if ($settingsLocale = $this->systemConfigService->getString(Settings::SPB_BUTTON_LANGUAGE_ISO, $context->getSalesChannelId())) { - return $this->localeCodeProvider->getFormattedLocaleCode($settingsLocale); - } - - return $this->localeCodeProvider->getFormattedLocaleCode( - $this->localeCodeProvider->getLocaleCodeFromContext($context->getContext()) - ); + return (new FundingEligibilityData())->assign([ + ...parent::getBaseData($context), + 'methodEligibilityUrl' => $this->router->generate('frontend.paypal.payment-method-eligibility'), + 'filteredPaymentMethods' => $this->getFilteredPaymentMethods(), + ]); } private function getFilteredPaymentMethods(): array diff --git a/src/Storefront/Data/Struct/AbstractCheckoutData.php b/src/Storefront/Data/Struct/AbstractCheckoutData.php index 91772eb6e..1f54a950a 100644 --- a/src/Storefront/Data/Struct/AbstractCheckoutData.php +++ b/src/Storefront/Data/Struct/AbstractCheckoutData.php @@ -8,21 +8,10 @@ namespace Swag\PayPal\Storefront\Data\Struct; use Shopware\Core\Framework\Log\Package; -use Shopware\Core\Framework\Struct\Struct; #[Package('checkout')] -class AbstractCheckoutData extends Struct +class AbstractCheckoutData extends AbstractScriptData { - protected string $clientId; - - protected string $merchantPayerId; - - protected string $languageIso; - - protected string $currency; - - protected string $intent; - protected string $buttonShape; protected string $buttonColor; @@ -50,56 +39,6 @@ class AbstractCheckoutData extends Struct protected string $brandName; - public function getClientId(): string - { - return $this->clientId; - } - - public function setClientId(string $clientId): void - { - $this->clientId = $clientId; - } - - public function getMerchantPayerId(): string - { - return $this->merchantPayerId; - } - - public function setMerchantPayerId(string $merchantPayerId): void - { - $this->merchantPayerId = $merchantPayerId; - } - - public function getLanguageIso(): string - { - return $this->languageIso; - } - - public function setLanguageIso(string $languageIso): void - { - $this->languageIso = $languageIso; - } - - public function getCurrency(): string - { - return $this->currency; - } - - public function setCurrency(string $currency): void - { - $this->currency = $currency; - } - - public function getIntent(): string - { - return $this->intent; - } - - public function setIntent(string $intent): void - { - $this->intent = $intent; - } - public function getUserIdToken(): ?string { return $this->userIdToken; diff --git a/src/Storefront/Data/Struct/AbstractScriptData.php b/src/Storefront/Data/Struct/AbstractScriptData.php new file mode 100644 index 000000000..983e857c1 --- /dev/null +++ b/src/Storefront/Data/Struct/AbstractScriptData.php @@ -0,0 +1,87 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Swag\PayPal\Storefront\Data\Struct; + +use Shopware\Core\Framework\Log\Package; +use Shopware\Core\Framework\Struct\Struct; + +#[Package('checkout')] +class AbstractScriptData extends Struct +{ + protected string $clientId; + + protected string $merchantPayerId; + + protected string $partnerAttributionId; + + protected string $languageIso; + + protected string $currency; + + protected string $intent; + + public function getClientId(): string + { + return $this->clientId; + } + + public function setClientId(string $clientId): void + { + $this->clientId = $clientId; + } + + public function getMerchantPayerId(): string + { + return $this->merchantPayerId; + } + + public function setMerchantPayerId(string $merchantPayerId): void + { + $this->merchantPayerId = $merchantPayerId; + } + + public function getPartnerAttributionId(): string + { + return $this->partnerAttributionId; + } + + public function setPartnerAttributionId(string $partnerAttributionId): void + { + $this->partnerAttributionId = $partnerAttributionId; + } + + public function getLanguageIso(): string + { + return $this->languageIso; + } + + public function setLanguageIso(string $languageIso): void + { + $this->languageIso = $languageIso; + } + + public function getCurrency(): string + { + return $this->currency; + } + + public function setCurrency(string $currency): void + { + $this->currency = $currency; + } + + public function getIntent(): string + { + return $this->intent; + } + + public function setIntent(string $intent): void + { + $this->intent = $intent; + } +} diff --git a/src/Storefront/Data/Struct/FundingEligibilityData.php b/src/Storefront/Data/Struct/FundingEligibilityData.php index ff9da9b4a..6b159aa81 100644 --- a/src/Storefront/Data/Struct/FundingEligibilityData.php +++ b/src/Storefront/Data/Struct/FundingEligibilityData.php @@ -8,21 +8,10 @@ namespace Swag\PayPal\Storefront\Data\Struct; use Shopware\Core\Framework\Log\Package; -use Shopware\Core\Framework\Struct\Struct; #[Package('checkout')] -class FundingEligibilityData extends Struct +class FundingEligibilityData extends AbstractScriptData { - protected string $clientId; - - protected string $merchantPayerId; - - protected string $languageIso; - - protected string $currency; - - protected string $intent; - /** * @var string[] */ @@ -30,61 +19,17 @@ class FundingEligibilityData extends Struct protected string $methodEligibilityUrl; - public function getClientId(): string - { - return $this->clientId; - } - - public function setClientId(string $clientId): void - { - $this->clientId = $clientId; - } - - public function getMerchantPayerId(): string - { - return $this->merchantPayerId; - } - - public function setMerchantPayerId(string $merchantPayerId): void - { - $this->merchantPayerId = $merchantPayerId; - } - - public function getLanguageIso(): string - { - return $this->languageIso; - } - - public function setLanguageIso(string $languageIso): void - { - $this->languageIso = $languageIso; - } - - public function getCurrency(): string - { - return $this->currency; - } - - public function setCurrency(string $currency): void - { - $this->currency = $currency; - } - - public function getIntent(): string - { - return $this->intent; - } - - public function setIntent(string $intent): void - { - $this->intent = $intent; - } - + /** + * @return string[] + */ public function getFilteredPaymentMethods(): array { return $this->filteredPaymentMethods; } + /** + * @param string[] $filteredPaymentMethods + */ public function setFilteredPaymentMethods(array $filteredPaymentMethods): void { $this->filteredPaymentMethods = $filteredPaymentMethods; From f63b4ae5d64ae26443a70b66953dd74413449110 Mon Sep 17 00:00:00 2001 From: Michel Bade Date: Tue, 16 Jul 2024 10:42:49 +0200 Subject: [PATCH 2/2] PPI-924 - Fixed error handling for express checkout --- CHANGELOG.md | 3 ++- CHANGELOG_de-DE.md | 1 + .../swag-paypal.smart-payment-buttons.js | 6 ++++++ .../src/page/swag-paypal.express-checkout.js | 20 ++++++++++++------- .../src/swag-paypal.abstract-buttons.js | 16 +++++++++++++-- .../snippet/storefront/paypal.de-DE.json | 2 ++ .../snippet/storefront/paypal.en-GB.json | 2 ++ 7 files changed, 40 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6a18b187..006634460 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 9.4.0 - PPI-807 - Improved script loading performance in the Storefront -- PPI-951 - Fixes an issue, where only generic error messages were displayed during checkout without Smart Payment Buttons +- PPI-924 - Added more explicit error messages for errors happening during express checkout +- PPI-951 - Fixes an issue, where only generic error messages were displayed during checkout without Smart Payment Buttons - PPI-953 - Fixes an issue, where shipping tracking codes were not synced with an invalid carrier # 9.3.1 diff --git a/CHANGELOG_de-DE.md b/CHANGELOG_de-DE.md index aa9c2f7e1..9875c9bb2 100644 --- a/CHANGELOG_de-DE.md +++ b/CHANGELOG_de-DE.md @@ -1,5 +1,6 @@ # 9.4.0 - PPI-807 - Verbessert die Ladezeit der Scripte in der Storefront +- PPI-924 - Fügt genauere Fehlermeldungen für Fehler während des Express Checkouts hinzu - PPI-951 - Behebt ein Problem, bei dem ohne Smart Payment Buttons nur generische Fehlermeldungen während des Bestellprozesses angezeigt wurden - PPI-953 - Behebt ein Problem, bei dem Sendungsverfolgungsdaten bei invaliden Versanddienstleister nicht an PayPal übermittelt wurden diff --git a/src/Resources/app/storefront/src/checkout/swag-paypal.smart-payment-buttons.js b/src/Resources/app/storefront/src/checkout/swag-paypal.smart-payment-buttons.js index fc6928be3..bbcb00efa 100644 --- a/src/Resources/app/storefront/src/checkout/swag-paypal.smart-payment-buttons.js +++ b/src/Resources/app/storefront/src/checkout/swag-paypal.smart-payment-buttons.js @@ -67,6 +67,8 @@ export default class SwagPayPalSmartPaymentButtons extends SwagPaypalAbstractBut /** * URL to the after order edit page, as the payment has failed * + * @deprecated tag:v10.0.0 - Will be removed, use {@link handleErrorUrl} instead + * * @type string|null */ accountOrderEditFailedUrl: '', @@ -74,6 +76,8 @@ export default class SwagPayPalSmartPaymentButtons extends SwagPaypalAbstractBut /** * URL to the after order edit page, as the user has cancelled * + * @deprecated tag:v10.0.0 - Will be removed, use {@link handleErrorUrl} instead + * * @type string|null */ accountOrderEditCancelledUrl: '', @@ -95,6 +99,8 @@ export default class SwagPayPalSmartPaymentButtons extends SwagPaypalAbstractBut /** * URL for adding flash error message * + * @deprecated tag:v10.0.0 - Will be removed, use {@link handleErrorUrl} instead + * * @type string */ addErrorUrl: '', diff --git a/src/Resources/app/storefront/src/page/swag-paypal.express-checkout.js b/src/Resources/app/storefront/src/page/swag-paypal.express-checkout.js index 688ec8bbe..e170e7f00 100644 --- a/src/Resources/app/storefront/src/page/swag-paypal.express-checkout.js +++ b/src/Resources/app/storefront/src/page/swag-paypal.express-checkout.js @@ -105,6 +105,8 @@ export default class SwagPayPalExpressCheckoutButton extends SwagPaypalAbstractB /** * URL for adding flash error message * + * @deprecated tag:v10.0.0 - Will be removed, use {@link handleErrorUrl} instead + * * @type string */ addErrorUrl: '', @@ -133,6 +135,9 @@ export default class SwagPayPalExpressCheckoutButton extends SwagPaypalAbstractB partOfDomContentLoading: false, }; + GENERIC_ERROR = 'SWAG_PAYPAL__EXPRESS_GENERIC_ERROR'; + USER_CANCELLED = 'SWAG_PAYPAL__EXPRESS_USER_CANCELLED'; + init() { this._client = new HttpClient(); this.createButton(); @@ -341,16 +346,17 @@ export default class SwagPayPalExpressCheckoutButton extends SwagPaypalAbstractB return actions.redirect(this.options.checkoutConfirmUrl); } - return this.createError('error', response, this.options.cancelRedirectUrl); + return this.onError(); }, ); } - onError(error) { - this.createError('error', error); - } - - onCancel(error) { - this.createError('cancel', error, this.options.cancelRedirectUrl); + onErrorHandled(code, fatal, error) { + if (code === this.GENERIC_ERROR || code === this.USER_CANCELLED) { + window.scrollTo(0, 0); + window.location = this.options.cancelRedirectUrl; + } else { + super.onErrorHandled(code, fatal, error); + } } } diff --git a/src/Resources/app/storefront/src/swag-paypal.abstract-buttons.js b/src/Resources/app/storefront/src/swag-paypal.abstract-buttons.js index fb7a33a16..b19148302 100644 --- a/src/Resources/app/storefront/src/swag-paypal.abstract-buttons.js +++ b/src/Resources/app/storefront/src/swag-paypal.abstract-buttons.js @@ -53,11 +53,23 @@ export default class SwagPaypalAbstractButtons extends SwagPayPalScriptBase { error, fatal, }), () => { - window.onbeforeunload = () => { window.scrollTo(0, 0); }; - window.location.reload(); + this.onErrorHandled(code, fatal, error); }); } + /** + * Will be called after the handleErrorUrl was called. See {@link handleError}. + * + * @param {String} code - The error code. Will be replaced by an extracted error code from {@link error} if available + * @param {Boolean} [fatal=false] - A fatal error will not allow a rerender of the PayPal buttons + * @param {*} [error=undefined] - The error. Can be any type, but will be converted to a string + */ + // eslint-disable-next-line no-unused-vars + onErrorHandled(code, fatal, error) { + window.scrollTo(0, 0); + window.location.reload(); + } + /** * Stop payment process with a generic __fatal__ error. * Will prevent rendering the button through the render function. diff --git a/src/Resources/snippet/storefront/paypal.de-DE.json b/src/Resources/snippet/storefront/paypal.de-DE.json index 367363f73..5cc6f2f79 100644 --- a/src/Resources/snippet/storefront/paypal.de-DE.json +++ b/src/Resources/snippet/storefront/paypal.de-DE.json @@ -6,6 +6,8 @@ "browserUnsupported": "Ihr aktueller Browser wird von der gewählten Zahlungsart nicht unterstützt. Bitte versuchen Sie es mit einem anderen Browser oder wählen Sie eine andere Zahlungsmethode aus." }, "error": { + "SWAG_PAYPAL__EXPRESS_GENERIC_ERROR": "Während des Bestellvorgangs mit PayPal ist ein Fehler aufgetreten. Bitte versuchen Sie es später noch einmal oder verwenden Sie den normalen Bestellprozess.", + "SWAG_PAYPAL__EXPRESS_USER_CANCELLED": "Der Bestellvorgang mit PayPal wurde abgebrochen. Bitte versuchen Sie es noch einmal oder verwenden Sie den normalen Bestellprozess.", "SWAG_PAYPAL__GENERIC_ERROR": "Während des Zahlungsvorgangs ist ein Fehler aufgetreten. Bitte versuchen Sie es später noch einmal oder wählen Sie eine andere Zahlungsart.", "SWAG_PAYPAL__USER_CANCELLED": "Der Zahlungsvorgang wurde abgebrochen. Bitte versuchen Sie es noch einmal oder wählen Sie eine andere Zahlungsart.", "SWAG_PAYPAL__BROWSER_UNSUPPORTED": "Die gewählte Zahlungsart wird von Ihrem aktuellen Browser nicht unterstützt. Bitte versuchen Sie es mit einem anderen Browser oder wählen Sie eine andere Zahlungsart.", diff --git a/src/Resources/snippet/storefront/paypal.en-GB.json b/src/Resources/snippet/storefront/paypal.en-GB.json index b240b98b3..437250965 100644 --- a/src/Resources/snippet/storefront/paypal.en-GB.json +++ b/src/Resources/snippet/storefront/paypal.en-GB.json @@ -6,6 +6,8 @@ "browserUnsupported": "Your current Browser is unsupported by the selected payment method. Please try another Browser or choose another payment method." }, "error": { + "SWAG_PAYPAL__EXPRESS_USER_CANCELLED": "The PayPal order process has been cancelled. Please try again or use the regular checkout.", + "SWAG_PAYPAL__EXPRESS_GENERIC_ERROR": "An error occurred during the PayPal order process. Please try again later or use the regular checkout.", "SWAG_PAYPAL__GENERIC_ERROR": "An error occurred during the payment process. Please try again later or choose another payment method.", "SWAG_PAYPAL__USER_CANCELLED": "The payment process has been cancelled. Please try again or choose another payment method.", "SWAG_PAYPAL__BROWSER_UNSUPPORTED": "The selected payment method does not support your current browser. Please try again with another browser or choose another payment method.",