Skip to content

Instantly share code, notes, and snippets.

@ssx
Created February 7, 2025 15:00
Show Gist options
  • Save ssx/3dfe0575dae8fc97db8bba4f1e5860c9 to your computer and use it in GitHub Desktop.
Save ssx/3dfe0575dae8fc97db8bba4f1e5860c9 to your computer and use it in GitHub Desktop.
diff --git a/vendor/magento/module-payment-services-paypal/Block/SmartButtons.php b/vendor/magento/module-payment-services-paypal/Block/SmartButtons.php
index 60beabb8..d74fa01d 100644
--- a/vendor/magento/module-payment-services-paypal/Block/SmartButtons.php
+++ b/vendor/magento/module-payment-services-paypal/Block/SmartButtons.php
@@ -14,6 +14,7 @@ use Magento\Framework\View\Element\Template\Context;
use Magento\PaymentServicesPaypal\Model\Config;
use Magento\Catalog\Block\ShortcutInterface;
use Magento\Framework\View\Element\Template;
+use Magento\Checkout\Model\Session as CheckoutSession;
/**
* @api
@@ -50,6 +51,11 @@ class SmartButtons extends Template implements ShortcutInterface
*/
private $serializer;
+ /**
+ * @var CheckoutSession
+ */
+ private $checkoutSession;
+
/**
* @param Context $context
* @param Config $config
@@ -59,6 +65,7 @@ class SmartButtons extends Template implements ShortcutInterface
* @param array $data
* @param Json|null $serializer
* @param CompositeConfigProvider|null $compositeConfigProvider
+ * @param CheckoutSession|null $checkoutSession
*/
public function __construct(
Context $context,
@@ -68,7 +75,8 @@ class SmartButtons extends Template implements ShortcutInterface
array $componentConfig = [],
array $data = [],
Json $serializer = null,
- CompositeConfigProvider $compositeConfigProvider = null
+ CompositeConfigProvider $compositeConfigProvider = null,
+ CheckoutSession $checkoutSession = null
) {
$this->config = $config;
$this->componentConfig = $componentConfig;
@@ -82,6 +90,7 @@ class SmartButtons extends Template implements ShortcutInterface
$this->setTemplate($data['template'] ?? $componentConfig[$this->pageType]['template']);
$this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
$this->configProvider = $compositeConfigProvider ?: ObjectManager::getInstance()->get(CompositeConfigProvider::class);
+ $this->checkoutSession = $checkoutSession ?: ObjectManager::getInstance()->get(CheckoutSession::class);
}
/**
@@ -185,4 +194,19 @@ class SmartButtons extends Template implements ShortcutInterface
{
return $this->serializer->serialize($this->configProvider->getConfig());
}
+
+ /**
+ * Check if quote exists
+ *
+ * @return bool
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ public function doesQuoteExist(): bool
+ {
+ try {
+ return $this->checkoutSession->getQuote()->getId() != null;
+ } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ return false;
+ }
+ }
}
diff --git a/vendor/magento/module-payment-services-paypal/Controller/SmartButtons/SetQuoteAsInactive.php b/vendor/magento/module-payment-services-paypal/Controller/SmartButtons/SetQuoteAsInactive.php
index a7b1f0c4..e82abc52 100644
--- a/vendor/magento/module-payment-services-paypal/Controller/SmartButtons/SetQuoteAsInactive.php
+++ b/vendor/magento/module-payment-services-paypal/Controller/SmartButtons/SetQuoteAsInactive.php
@@ -80,8 +80,11 @@ class SetQuoteAsInactive implements HttpPostActionInterface
try {
$quote = $this->getQuote();
- $quote->setIsActive(false);
- $this->quoteRepository->save($quote);
+
+ if ($quote->getIsActive()) {
+ $quote->setIsActive(false);
+ $this->quoteRepository->save($quote);
+ }
$result->setHttpResponseCode(200);
return $result;
@@ -103,7 +106,7 @@ class SetQuoteAsInactive implements HttpPostActionInterface
private function getQuote() : CartInterface
{
if ($this->paypalSession->getQuoteId()) {
- return $this->quoteRepository->getActive($this->paypalSession->getQuoteId());
+ return $this->quoteRepository->get($this->paypalSession->getQuoteId());
}
return $this->checkoutSession->getQuote();
diff --git a/vendor/magento/module-payment-services-paypal/view/frontend/templates/smart_buttons_minicart.phtml b/vendor/magento/module-payment-services-paypal/view/frontend/templates/smart_buttons_minicart.phtml
index 54fb0aad..108b84e8 100644
--- a/vendor/magento/module-payment-services-paypal/view/frontend/templates/smart_buttons_minicart.phtml
+++ b/vendor/magento/module-payment-services-paypal/view/frontend/templates/smart_buttons_minicart.phtml
@@ -13,11 +13,15 @@ declare(strict_types=1);
/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */
?>
-<?php $serializedCheckoutConfig = /* @noEscape */ $block->getSerializedCheckoutConfig();
-
-$scriptString = <<<script
+<?php
+if ($block->isEnabled() && $block->doesQuoteExist()) {
+ $serializedCheckoutConfig = /* @noEscape */ $block->getSerializedCheckoutConfig();
+ $scriptString = <<<script
window.checkoutConfig = {$serializedCheckoutConfig};
+ window.customerData = window.checkoutConfig.customerData;
+ window.isCustomerLoggedIn = window.checkoutConfig.isCustomerLoggedIn;
script;
+}
?>
<?php if ($block->isLocationEnabled('minicart')): ?>
@@ -39,4 +43,8 @@ script;
</div>
<?php endif ?>
-<?= /* @noEscape */ $secureRenderer->renderTag('script', [], $scriptString, false) ?>
+<?php /* @noEscape */
+if ($block->isEnabled() && $block->doesQuoteExist()) {
+ echo $secureRenderer->renderTag('script', [], $scriptString, false);
+}
+?>
diff --git a/vendor/magento/module-payment-services-paypal/view/frontend/web/js/view/payment/apple-pay-cart.js b/vendor/magento/module-payment-services-paypal/view/frontend/web/js/view/payment/apple-pay-cart.js
index 2fe5692d..7eafe4c0 100644
--- a/vendor/magento/module-payment-services-paypal/view/frontend/web/js/view/payment/apple-pay-cart.js
+++ b/vendor/magento/module-payment-services-paypal/view/frontend/web/js/view/payment/apple-pay-cart.js
@@ -15,7 +15,8 @@ define([
'Magento_PaymentServicesPaypal/js/view/payment/methods/apple-pay',
'Magento_Checkout/js/model/quote',
'Magento_Checkout/js/model/cart/totals-processor/default',
-], function (_, $, utils, Component, $t, customerData, ResponseError, ApplePayButton, quote, totalsProcessor) {
+ 'Magento_Customer/js/model/customer',
+], function (_, $, utils, Component, $t, customerData, ResponseError, ApplePayButton, quote, totalsProcessor, customer) {
'use strict';
return Component.extend({
@@ -41,12 +42,6 @@ define([
.then(this.initApplePayButton)
.catch(console.log);
- // Reload quote totals in minicart to have the correct grand_total for the Apple Popup
- if (this.pageType === 'minicart') {
- totalsProcessor.estimateTotals().done(function (result) {
- quote.setTotals(result);
- });
- }
return this;
},
@@ -100,19 +95,27 @@ define([
},
onClick: function () {
- this.isErrorDisplayed = false;
+ // Reload customer data to use correct loggedin/guest urls in the applepay button
+ // See smart_buttons_minicart.phtml:21-22
+ if (this.pageType === 'minicart') {
+ this.fixCustomerData();
+ }
+ // Show popup with initial order amount from window.checkoutConfig
+ // See smart_buttons_minicart.phtml:20
this.applePayButton.showLoaderAsync(true).then(() => {
const data = {
response: {
'paypal-order': {
- currency_code: String(quote.totals().quote_currency_code),
- amount: Number(quote.totals().grand_total).toString(),
+ currency_code: window.checkoutConfig.quoteData.base_currency_code,
+ amount: window.checkoutConfig.quoteData.grand_total.toString(),
}
}
}
this.applePayButton.showPopup(data);
})
+
+ this.isErrorDisplayed = false;
},
/**
@@ -163,5 +166,33 @@ define([
this.applePaySession.begin();
},
+
+ /**
+ * Fix customer data
+ *
+ * Why do we need this?
+ * See: src/app/code/Magento/Customer/view/frontend/web/js/model/customer.js:17
+ *
+ * When we initialise customer data on the page where the minicart was not rendered yet,
+ * the customer data in the "window" object is 'undefined' at first because . This makes this line
+ * var isLoggedIn = ko.observable(window.isCustomerLoggedIn),
+ * to create an observable of undefined variable, that does not work in knockout.
+ * knockout expects an existing variable to create an observable.
+ *
+ * Later, when we render minicart and update "window" object with customer data,
+ * it's not being picked up by customer.js logic and when try to read the data, it's still undefined,
+ * even though it exists in the "window" object.
+ *
+ * This function forces the customer data to be updated from the "window" object.
+ */
+ fixCustomerData: function () {
+ if (customer.isLoggedIn() === undefined && window.isCustomerLoggedIn !== undefined) {
+ customer.setIsLoggedIn(window.isCustomerLoggedIn);
+ }
+
+ if (customer.isLoggedIn() && _.isEmpty(customer.customerData)) {
+ customer.customerData = window.customerData;
+ }
+ }
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment