Working on subscriptions (WIP)

This commit is contained in:
Emili Castells Guasch 2023-06-21 15:42:18 +02:00
parent 157dd41b7c
commit 06bfe33db2
5 changed files with 165 additions and 59 deletions

View file

@ -4,7 +4,7 @@ export const isChangePaymentPage = () => {
}
export const subscriptionHasPlan = () => {
if (PayPalCommerceGateway.data_client_id.has_subscriptions) {
if (PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled && PayPalCommerceGateway.data_client_id.has_subscriptions) {
if (PayPalCommerceGateway.subscription_plan_id !== '') {
return true;
}

View file

@ -15,6 +15,8 @@ document.addEventListener(
subscriptionTrial.style.display = 'none';
}
console.log('testing')
const unlinkBtn = document.getElementById('ppcp_unlink_sub_plan');
unlinkBtn?.addEventListener('click', (event)=>{
event.preventDefault();

View file

@ -176,10 +176,8 @@ class SubscriptionHelper {
* @throws NotFoundException If setting is not found.
*/
public function checkout_subscription_product_allowed(): bool {
$subscription_mode = $this->settings->has( 'subscriptions_mode' ) ? $this->settings->get( 'subscriptions_mode' ) : '';
if (
$subscription_mode !== 'subscriptions_api'
|| ! $this->paypal_subscription_id()
! $this->paypal_subscription_id()
|| ! $this->cart_contains_only_one_item()
) {
return false;

View file

@ -11,6 +11,7 @@ namespace WooCommerce\PayPalCommerce\Subscription;
use Exception;
use WC_Product;
use WC_Product_Subscription_Variation;
use WC_Subscriptions_Product;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
@ -178,7 +179,7 @@ class SubscriptionModule implements ModuleInterface {
//phpcs:disable WordPress.Security.NonceVerification.Recommended
$post_id = wc_clean( wp_unslash( $_GET['post'] ?? '' ) );
$product = wc_get_product( $post_id );
if ( ! is_a( $product, WC_Product::class ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) {
if ( ! ( is_a( $product, WC_Product::class) || is_a( $product, WC_Product_Subscription_Variation::class) ) || ! WC_Subscriptions_Product::is_subscription( $product ) ) {
return;
}
@ -463,40 +464,28 @@ class SubscriptionModule implements ModuleInterface {
return;
}
$enable_subscription_product = wc_clean( wp_unslash( $_POST['_ppcp_enable_subscription_product'] ?? '' ) );
$product->update_meta_data( '_ppcp_enable_subscription_product', $enable_subscription_product );
$product->save();
if ( $product->get_type() === 'subscription' && $enable_subscription_product === 'yes' ) {
$subscriptions_api_handler = $c->get( 'subscription.api-handler' );
assert( $subscriptions_api_handler instanceof SubscriptionsApiHandler );
if ( $product->meta_exists( 'ppcp_subscription_product' ) && $product->meta_exists( 'ppcp_subscription_plan' ) ) {
$subscriptions_api_handler->update_product( $product );
$subscriptions_api_handler->update_plan( $product );
return;
}
if ( ! $product->meta_exists( 'ppcp_subscription_product' ) ) {
$subscriptions_api_handler->create_product( $product );
}
if ( $product->meta_exists( 'ppcp_subscription_product' ) && ! $product->meta_exists( 'ppcp_subscription_plan' ) ) {
$subscription_plan_name = wc_clean( wp_unslash( $_POST['_ppcp_subscription_plan_name'] ?? '' ) );
if ( ! is_string( $subscription_plan_name ) ) {
return;
}
$product->update_meta_data( '_ppcp_subscription_plan_name', $subscription_plan_name );
$product->save();
$subscriptions_api_handler->create_plan( $subscription_plan_name, $product );
}
}
$subscriptions_api_handler = $c->get('subscription.api-handler');
assert($subscriptions_api_handler instanceof SubscriptionsApiHandler);
$this->update_subscription_product_meta($product, $subscriptions_api_handler);
},
12
);
add_action('woocommerce_save_product_variation', function($variation_id) use($c){
if ( ! WC_Subscriptions_Product::is_subscription( $variation_id ) || empty( $_POST['_wcsnonce_save_variations'] ) || ! wp_verify_nonce( $_POST['_wcsnonce_save_variations'], 'wcs_subscription_variations' ) ) {
return;
}
$product = wc_get_product( $variation_id );
if ( ! is_a( $product, WC_Product_Subscription_Variation::class ) ) {
return;
}
$subscriptions_api_handler = $c->get('subscription.api-handler');
assert($subscriptions_api_handler instanceof SubscriptionsApiHandler);
$this->update_subscription_product_meta($product, $subscriptions_api_handler);
});
add_action(
'woocommerce_process_shop_subscription_meta',
/**
@ -705,6 +694,32 @@ class SubscriptionModule implements ModuleInterface {
}
);
add_action(
'woocommerce_variation_options_pricing',
function( $loop, $variation_data, $variation ) use ( $c ) {
$settings = $c->get( 'wcgateway.settings' );
assert( $settings instanceof Settings );
try {
$subscriptions_mode = $settings->get( 'subscriptions_mode' );
if ( $subscriptions_mode === 'subscriptions_api' ) {
$product = wc_get_product( $variation->ID );
if ( ! is_a( $product, WC_Product_Subscription_Variation::class ) ) {
return;
}
$environment = $c->get( 'onboarding.environment' );
$this->render_paypal_subscription_fields( $product, $environment );
}
} catch ( NotFoundException $exception ) {
return;
}
},
10,
3
);
add_action(
'woocommerce_product_options_general_product_data',
function() use ( $c ) {
@ -725,29 +740,8 @@ class SubscriptionModule implements ModuleInterface {
return;
}
$enable_subscription_product = $product->get_meta( '_ppcp_enable_subscription_product' );
$subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' );
echo '<div class="options_group subscription_pricing show_if_subscription hidden">';
echo '<p class="form-field"><label for="_ppcp_enable_subscription_product">Connect to PayPal</label><input type="checkbox" id="ppcp_enable_subscription_product" name="_ppcp_enable_subscription_product" value="yes" ' . checked( $enable_subscription_product, 'yes', false ) . '/><span class="description">Connect Product to PayPal Subscriptions Plan</span>';
echo wc_help_tip( esc_html__( 'Create a subscription product and plan to bill customers at regular intervals. Be aware that certain subscription settings cannot be modified once the PayPal Subscription is linked to this product. Unlink the product to edit disabled fields.', 'woocommerce-paypal-payments' ) );
echo '</p>';
$subscription_product = $product->get_meta( 'ppcp_subscription_product' );
$subscription_plan = $product->get_meta( 'ppcp_subscription_plan' );
if ( $subscription_product && $subscription_plan ) {
if ( $enable_subscription_product !== 'yes' ) {
echo '<p class="form-field" id="ppcp-enable-subscription"><label></label><button class="button" id="ppcp_unlink_sub_plan">' . esc_html__( 'Unlink PayPal Subscription Plan', 'woocommerce-paypal-payments' ) . '</button><span class="spinner is-active" id="spinner-unlink-plan" style="float: none; display:none;"></span></p>';
echo '<p class="form-field" id="pcpp-plan-unlinked" style="display: none;">Plan unlinked successfully ✔️</p>';
}
$environment = $c->get( 'onboarding.environment' );
$host = $environment->current_environment_is( Environment::SANDBOX ) ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com';
echo '<p class="form-field" id="pcpp-product"><label>' . esc_html__( 'Product', 'woocommerce-paypal-payments' ) . '</label><a href="' . esc_url( $host . '/billing/plans/products/' . $subscription_product['id'] ) . '" target="_blank">' . esc_attr( $subscription_product['id'] ) . '</a></p>';
echo '<p class="form-field" id="pcpp-plan"><label>' . esc_html__( 'Plan', 'woocommerce-paypal-payments' ) . '</label><a href="' . esc_url( $host . '/billing/plans/' . $subscription_plan['id'] ) . '" target="_blank">' . esc_attr( $subscription_plan['id'] ) . '</a></p>';
} else {
echo '<p class="form-field"><label for="_ppcp_subscription_plan_name">' . esc_html__( 'Plan Name', 'woocommerce-paypal-payments' ) . '</label><input type="text" class="short" id="ppcp_subscription_plan_name" name="_ppcp_subscription_plan_name" value="' . esc_attr( $subscription_plan_name ) . '"></p>';
}
echo '</div>';
$environment = $c->get( 'onboarding.environment' );
$this->render_paypal_subscription_fields( $product, $environment );
}
} catch ( NotFoundException $exception ) {
return;
@ -832,4 +826,115 @@ class SubscriptionModule implements ModuleInterface {
}
);
}
/**
* Render PayPal Subscriptions fields.
*
* @param WC_Product $product WC Product.
* @param Environment $environment The environment.
* @return void
*/
private function render_paypal_subscription_fields( WC_Product $product, Environment $environment ): void {
$enable_subscription_product = $product->get_meta( '_ppcp_enable_subscription_product' );
$subscription_plan_name = $product->get_meta( '_ppcp_subscription_plan_name' );
//echo '<div class="options_group subscription_pricing show_if_subscription hidden">';
echo '<p class="form-field">';
echo sprintf(
// translators: %1$s and %2$s are label open and close tags.
esc_html__( '%1$sConnect to PayPal%2$s', 'woocommerce-paypal-payments' ),
'<label for="_ppcp_enable_subscription_product">',
'</label>'
);
echo '<input type="checkbox" id="ppcp_enable_subscription_product" name="_ppcp_enable_subscription_product" value="yes" ' . checked( $enable_subscription_product, 'yes', false ) . '/>';
echo sprintf(
// translators: %1$s and %2$s are label open and close tags.
esc_html__( '%1$sConnect Product to PayPal Subscriptions Plan%2$s', 'woocommerce-paypal-payments' ),
'<span class="description">',
'</span>'
);
echo wc_help_tip( esc_html__( 'Create a subscription product and plan to bill customers at regular intervals. Be aware that certain subscription settings cannot be modified once the PayPal Subscription is linked to this product. Unlink the product to edit disabled fields.', 'woocommerce-paypal-payments' ) );
echo '</p>';
$subscription_product = $product->get_meta( 'ppcp_subscription_product' );
$subscription_plan = $product->get_meta( 'ppcp_subscription_plan' );
if ( $subscription_product && $subscription_plan ) {
if ( $enable_subscription_product !== 'yes' ) {
echo sprintf(
// translators: %1$s and %2$s are button and wrapper html tags.
esc_html__( '%1$sUnlink PayPal Subscription Plan%2$s', 'woocommerce-paypal-payments' ),
'<p class="form-field" id="ppcp-enable-subscription"><label></label><button class="button" id="ppcp_unlink_sub_plan">',
'</button><span class="spinner is-active" id="spinner-unlink-plan" style="float: none; display:none;"></span></p>'
);
echo sprintf(
// translators: %1$s and %2$s is open and closing paragraph tag.
esc_html__( 'Plan unlinked successfully ✔️', 'woocommerce-paypal-payments' ),
'<p class="form-field" id="pcpp-plan-unlinked" style="display: none;">',
'</p>'
);
}
$host = $environment->current_environment_is( Environment::SANDBOX ) ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com';
echo sprintf(
// translators: %1$s and %2$s are wrapper html tags.
esc_html__( '%1$sProduct%2$s', 'woocommerce-paypal-payments' ),
'<p class="form-field" id="pcpp-product"><label>',
'</label><a href="' . esc_url( $host . '/billing/plans/products/' . $subscription_product['id'] ) . '" target="_blank">' . esc_attr( $subscription_product['id'] ) . '</a></p>'
);
echo sprintf(
// translators: %1$s and %2$s are wrapper html tags.
esc_html__( '%1$sPlan%2$s', 'woocommerce-paypal-payments' ),
'<p class="form-field" id="pcpp-plan"><label>',
'</label><a href="' . esc_url( $host . '/billing/plans/' . $subscription_plan['id'] ) . '" target="_blank">' . esc_attr( $subscription_plan['id'] ) . '</a></p>'
);
} else {
echo sprintf(
// translators: %1$s and %2$s are wrapper html tags.
esc_html__( '%1$sPlan Name%2$s', 'woocommerce-paypal-payments' ),
'<p class="form-field"><label for="_ppcp_subscription_plan_name">',
'</label><input type="text" class="short" id="ppcp_subscription_plan_name" name="_ppcp_subscription_plan_name" value="' . esc_attr( $subscription_plan_name ) . '"></p>'
);
}
//echo '</div>';
}
/**
* Updates subscription product meta.
*
* @param WC_Product $product
* @param SubscriptionsApiHandler $subscriptions_api_handler
* @return void
*/
private function update_subscription_product_meta(WC_Product $product, SubscriptionsApiHandler $subscriptions_api_handler): void
{
$enable_subscription_product = wc_clean(wp_unslash($_POST['_ppcp_enable_subscription_product'] ?? ''));
$product->update_meta_data('_ppcp_enable_subscription_product', $enable_subscription_product);
$product->save();
if (($product->get_type() === 'subscription' || $product->get_type() === 'subscription_variation') && $enable_subscription_product === 'yes') {
if ($product->meta_exists('ppcp_subscription_product') && $product->meta_exists('ppcp_subscription_plan')) {
$subscriptions_api_handler->update_product($product);
$subscriptions_api_handler->update_plan($product);
return;
}
if (!$product->meta_exists('ppcp_subscription_product')) {
$subscriptions_api_handler->create_product($product);
}
if ($product->meta_exists('ppcp_subscription_product') && !$product->meta_exists('ppcp_subscription_plan')) {
$subscription_plan_name = wc_clean(wp_unslash($_POST['_ppcp_subscription_plan_name'] ?? ''));
if (!is_string($subscription_plan_name)) {
return;
}
$product->update_meta_data('_ppcp_subscription_plan_name', $subscription_plan_name);
$product->save();
$subscriptions_api_handler->create_plan($subscription_plan_name, $product);
}
}
}
}

View file

@ -124,8 +124,9 @@ class DisableGateways {
return true;
}
$subscription_mode = $this->settings->has( 'subscriptions_mode' ) ? $this->settings->get( 'subscriptions_mode' ) : '';
if (
is_checkout()
(is_checkout() && $subscription_mode === 'subscriptions_api')
&& $this->subscription_helper->cart_contains_subscription()
&& ! $this->subscription_helper->checkout_subscription_product_allowed()
) {