diff --git a/modules/ppcp-blocks/resources/js/Helper/Address.js b/modules/ppcp-blocks/resources/js/Helper/Address.js
index 2c3e9eae1..19ca36fdd 100644
--- a/modules/ppcp-blocks/resources/js/Helper/Address.js
+++ b/modules/ppcp-blocks/resources/js/Helper/Address.js
@@ -63,7 +63,7 @@ export const paypalAddressToWc = (address) => {
* @returns {Object}
*/
export const paypalShippingToWc = (shipping) => {
- const [firstName, lastName] = splitFullName(shipping.name.full_name);
+ const [firstName, lastName] = (shipping.name ? splitFullName(shipping.name.full_name) : ['','']);
return {
...paypalAddressToWc(shipping.address),
first_name: firstName,
@@ -87,6 +87,22 @@ export const paypalPayerToWc = (payer) => {
}
}
+/**
+ * @param {Object} subscriber
+ * @returns {Object}
+ */
+export const paypalSubscriberToWc = (subscriber) => {
+ const firstName = subscriber?.name?.given_name ?? '';
+ const lastName = subscriber?.name?.surname ?? '';
+ const address = subscriber.address ? paypalAddressToWc(subscriber.shipping_address.address) : {};
+ return {
+ ...address,
+ first_name: firstName,
+ last_name: lastName,
+ email: subscriber.email_address,
+ }
+}
+
/**
* @param {Object} order
* @returns {Object}
@@ -130,6 +146,17 @@ export const paypalOrderToWcAddresses = (order) => {
return {billingAddress, shippingAddress};
}
+/**
+ *
+ * @param subscription
+ * @returns {{shippingAddress: Object, billingAddress: Object}}
+ */
+export const paypalSubscriptionToWcAddresses = (subscription) => {
+ const shippingAddress = paypalSubscriberToWc(subscription.subscriber);
+ let billingAddress = shippingAddress;
+ return {billingAddress, shippingAddress};
+}
+
/**
* Merges two WC addresses.
* The objects can contain either the WC form fields or billingAddress, shippingAddress objects.
diff --git a/modules/ppcp-blocks/resources/js/Helper/Subscription.js b/modules/ppcp-blocks/resources/js/Helper/Subscription.js
new file mode 100644
index 000000000..b274fea5e
--- /dev/null
+++ b/modules/ppcp-blocks/resources/js/Helper/Subscription.js
@@ -0,0 +1,16 @@
+/**
+ * @param {Object} scriptData
+ * @returns {Boolean}
+ */
+export const isPayPalSubscription = (scriptData) => {
+ return scriptData.data_client_id.has_subscriptions
+ && scriptData.data_client_id.paypal_subscriptions_enabled;
+}
+
+/**
+ * @param {Object} scriptData
+ * @returns {Boolean}
+ */
+export const cartHasSubscriptionProducts = (scriptData) => {
+ return !! scriptData?.locations_with_subscription_product?.cart;
+}
diff --git a/modules/ppcp-blocks/resources/js/checkout-block.js b/modules/ppcp-blocks/resources/js/checkout-block.js
index 448cbcaed..c6f91bfc6 100644
--- a/modules/ppcp-blocks/resources/js/checkout-block.js
+++ b/modules/ppcp-blocks/resources/js/checkout-block.js
@@ -1,6 +1,15 @@
import {useEffect, useState} from '@wordpress/element';
import {registerExpressPaymentMethod, registerPaymentMethod} from '@woocommerce/blocks-registry';
-import {mergeWcAddress, paypalAddressToWc, paypalOrderToWcAddresses} from "./Helper/Address";
+import {
+ mergeWcAddress,
+ paypalAddressToWc,
+ paypalOrderToWcAddresses,
+ paypalSubscriptionToWcAddresses
+} from "./Helper/Address";
+import {
+ cartHasSubscriptionProducts,
+ isPayPalSubscription
+} from "./Helper/Subscription";
import {
loadPaypalScriptPromise
} from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'
@@ -9,7 +18,6 @@ import {
} from '../../../ppcp-button/resources/js/modules/Helper/Style'
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
import BlockCheckoutMessagesBootstrap from "./Bootstrap/BlockCheckoutMessagesBootstrap";
-
const config = wc.wcSettings.getSetting('ppcp-gateway_data');
window.ppcpFundingSource = config.fundingSource;
@@ -106,6 +114,78 @@ const PayPalComponent = ({
}
};
+ const createSubscription = async (data, actions) => {
+ return actions.subscription.create({
+ 'plan_id': config.scriptData.subscription_plan_id
+ });
+ };
+
+ const handleApproveSubscription = async (data, actions) => {
+ try {
+ const subscription = await actions.subscription.get();
+
+ if (subscription) {
+ const addresses = paypalSubscriptionToWcAddresses(subscription);
+
+ let promises = [
+ // save address on server
+ wp.data.dispatch('wc/store/cart').updateCustomerData({
+ billing_address: addresses.billingAddress,
+ shipping_address: addresses.shippingAddress,
+ }),
+ ];
+ if (!config.finalReviewEnabled) {
+ // set address in UI
+ promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress));
+ if (shippingData.needsShipping) {
+ promises.push(wp.data.dispatch('wc/store/cart').setShippingAddress(addresses.shippingAddress))
+ }
+ }
+ await Promise.all(promises);
+ }
+
+ setPaypalOrder(subscription);
+
+ const res = await fetch(config.scriptData.ajax.approve_subscription.endpoint, {
+ method: 'POST',
+ credentials: 'same-origin',
+ body: JSON.stringify({
+ nonce: config.scriptData.ajax.approve_subscription.nonce,
+ order_id: data.orderID,
+ subscription_id: data.subscriptionID
+ })
+ });
+
+ const json = await res.json();
+
+ if (!json.success) {
+ if (typeof actions !== 'undefined' && typeof actions.restart !== 'undefined') {
+ return actions.restart();
+ }
+ if (json.data?.message) {
+ throw new Error(json.data.message);
+ }
+
+ throw new Error(config.scriptData.labels.error.generic)
+ }
+
+ if (config.finalReviewEnabled) {
+ location.href = getCheckoutRedirectUrl();
+ } else {
+ setGotoContinuationOnError(true);
+ onSubmit();
+ }
+ } catch (err) {
+ console.error(err);
+
+ onError(err.message);
+
+ onClose();
+
+ throw err;
+ }
+ };
+
const getCheckoutRedirectUrl = () => {
const checkoutUrl = new URL(config.scriptData.redirect);
// sometimes some browsers may load some kind of cached version of the page,
@@ -328,6 +408,21 @@ const PayPalComponent = ({
const PayPalButton = paypal.Buttons.driver("react", { React, ReactDOM });
+ if(isPayPalSubscription(config.scriptData)) {
+ return (
+
+ );
+ }
+
return (
;
if (config.placeOrderButtonDescription) {
@@ -360,7 +459,9 @@ if ((config.addPlaceOrderMethod || config.usePlaceOrder) && !config.scriptData.c
edit: descriptionElement,
placeOrderButtonLabel: config.placeOrderButtonText,
ariaLabel: config.title,
- canMakePayment: () => config.enabled,
+ canMakePayment: () => {
+ return config.enabled;
+ },
supports: {
features: features,
},
@@ -374,7 +475,9 @@ if (config.scriptData.continuation) {
content: ,
edit: ,
ariaLabel: config.title,
- canMakePayment: () => true,
+ canMakePayment: () => {
+ return true;
+ },
supports: {
features: [...features, 'ppcp_continuation'],
},