/** * Check if the cart includes a subscription that needs to be synced. * * @return bool Returns true if any item in the cart is a subscription sync request, otherwise, false. * @since 1.5 */ public static function cart_contains_synced_subscription() { global $woocommerce; $cart_contains_synced_subscription = false; if (self::is_syncing_enabled() && isset($woocommerce->cart) && !WC_Subscriptions_Cart::cart_contains_subscription_renewal('child')) { foreach ($woocommerce->cart->get_cart() as $cart_item_key => $cart_item) { if (!is_array($cart_item['data']->subscription_payment_sync_date) && $cart_item['data']->subscription_payment_sync_date > 0 || is_array($cart_item['data']->subscription_payment_sync_date) && $cart_item['data']->subscription_payment_sync_date['day'] > 0) { $cart_contains_synced_subscription = $cart_item; break; } } } return $cart_contains_synced_subscription; }
/** * For subscription renewal via cart, use original order discount * * @since 1.3 */ public static function before_calculate_totals($cart) { $cart_item = WC_Subscriptions_Cart::cart_contains_subscription_renewal(); if ($cart_item) { $original_order_id = $cart_item['subscription_renewal']['original_order']; $cart->discount_cart = WC_Subscriptions_Order::get_meta($original_order_id, '_order_recurring_discount_cart', 0); $cart->discount_total = WC_Subscriptions_Order::get_meta($original_order_id, '_order_recurring_discount_total', 0); } }
/** * Check is a subscription coupon is valid before applying * * @since 1.2 */ public static function validate_subscription_coupon($valid, $coupon) { self::$coupon_error = ''; // ignore non-subscription coupons if (!in_array($coupon->type, array('recurring_fee', 'sign_up_fee', 'recurring_percent', 'sign_up_fee_percent'))) { // but make sure there is actually something for the coupon to be applied to (i.e. not a free trial) if (WC_Subscriptions_Cart::cart_contains_free_trial() && 0 == WC_Subscriptions_Cart::get_cart_subscription_sign_up_fee()) { self::$coupon_error = __('Sorry, this coupon is only valid for an initial payment and the subscription already has a free trial.', 'woocommerce-subscriptions'); } } else { // prevent subscription coupons from being applied to renewal payments if (WC_Subscriptions_Cart::cart_contains_subscription_renewal()) { self::$coupon_error = __('Sorry, this coupon is only valid for new subscriptions.', 'woocommerce-subscriptions'); } // prevent subscription coupons from being applied to non-subscription products if (!WC_Subscriptions_Cart::cart_contains_subscription_renewal() && !WC_Subscriptions_Cart::cart_contains_subscription()) { self::$coupon_error = __('Sorry, this coupon is only valid for subscription products.', 'woocommerce-subscriptions'); } // prevent sign up fee coupons from being applied to subscriptions without a sign up fee if (0 == WC_Subscriptions_Cart::get_cart_subscription_sign_up_fee() && in_array($coupon->type, array('sign_up_fee', 'sign_up_fee_percent'))) { self::$coupon_error = __('Sorry, this coupon is only valid for subscription products with a sign-up fee.', 'woocommerce-subscriptions'); } } if (!empty(self::$coupon_error)) { $valid = false; add_filter('woocommerce_coupon_error', __CLASS__ . '::add_coupon_error', 10); } return $valid; }
/** * Add each subscription product's details to an order so that the state of the subscription persists even when a product is changed * * @since 1.2.5 */ public static function add_order_item_meta($item_id, $values) { global $woocommerce; if (!WC_Subscriptions_Cart::cart_contains_subscription_renewal('child') && WC_Subscriptions_Product::is_subscription($values['product_id'])) { $cart_item = $values['data']; $product_id = empty($values['variation_id']) ? $values['product_id'] : $values['variation_id']; // Add subscription details so order state persists even when a product is changed $period = isset($cart_item->subscription_period) ? $cart_item->subscription_period : WC_Subscriptions_Product::get_period($product_id); $interval = isset($cart_item->subscription_period_interval) ? $cart_item->subscription_period_interval : WC_Subscriptions_Product::get_interval($product_id); $length = isset($cart_item->subscription_length) ? $cart_item->subscription_length : WC_Subscriptions_Product::get_length($product_id); $trial_length = isset($cart_item->subscription_trial_length) ? $cart_item->subscription_trial_length : WC_Subscriptions_Product::get_trial_length($product_id); $trial_period = isset($cart_item->subscription_trial_period) ? $cart_item->subscription_trial_period : WC_Subscriptions_Product::get_trial_period($product_id); $sign_up_fee = isset($cart_item->subscription_sign_up_fee) ? $cart_item->subscription_sign_up_fee : WC_Subscriptions_Product::get_sign_up_fee($product_id); woocommerce_add_order_item_meta($item_id, '_subscription_period', $period); woocommerce_add_order_item_meta($item_id, '_subscription_interval', $interval); woocommerce_add_order_item_meta($item_id, '_subscription_length', $length); woocommerce_add_order_item_meta($item_id, '_subscription_trial_length', $trial_length); woocommerce_add_order_item_meta($item_id, '_subscription_trial_period', $trial_period); woocommerce_add_order_item_meta($item_id, '_subscription_recurring_amount', $woocommerce->cart->base_recurring_prices[$product_id]); // WC_Subscriptions_Product::get_price() would return a price without filters applied woocommerce_add_order_item_meta($item_id, '_subscription_sign_up_fee', $sign_up_fee); // Calculated recurring amounts for the item woocommerce_add_order_item_meta($item_id, '_recurring_line_total', $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_total']); woocommerce_add_order_item_meta($item_id, '_recurring_line_tax', $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_tax']); woocommerce_add_order_item_meta($item_id, '_recurring_line_subtotal', $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_subtotal']); woocommerce_add_order_item_meta($item_id, '_recurring_line_subtotal_tax', $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_subtotal_tax']); // Add recurring line tax data (for WC 2.2+) $raw_tax_data = $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_tax_data']; $recurring_tax_data = array(); $recurring_tax_data['total'] = array_map('wc_format_decimal', $raw_tax_data['total']); $recurring_tax_data['subtotal'] = array_map('wc_format_decimal', $raw_tax_data['subtotal']); woocommerce_add_order_item_meta($item_id, '_recurring_line_tax_data', $recurring_tax_data); } }
/** * When a subscription is added to the cart, remove other products/subscriptions to * work with PayPal Standard, which only accept one subscription per checkout. * * If multiple purchase flag is set, allow them to be added at the same time. * * @since 1.0 */ public static function maybe_empty_cart($valid, $product_id, $quantity) { global $woocommerce; if (WC_Subscriptions_Product::is_subscription($product_id) && 'yes' != get_option(WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no')) { $woocommerce->cart->empty_cart(); } elseif (WC_Subscriptions_Product::is_subscription($product_id) && WC_Subscriptions_Cart::cart_contains_subscription_renewal('child')) { self::remove_subscriptions_from_cart(); self::add_notice(__('A subscription renewal has been removed from your cart. Multiple subscriptions can not be purchased at the same time.', 'woocommerce-subscriptions'), 'notice'); } elseif (WC_Subscriptions_Product::is_subscription($product_id) && WC_Subscriptions_Cart::cart_contains_subscription()) { self::remove_subscriptions_from_cart(); self::add_notice(__('A subscription has been removed from your cart. Multiple subscriptions can not be purchased at the same time.', 'woocommerce-subscriptions'), 'notice'); } elseif (WC_Subscriptions_Cart::cart_contains_subscription() && 'yes' != get_option(WC_Subscriptions_Admin::$option_prefix . '_multiple_purchase', 'no')) { self::remove_subscriptions_from_cart(); self::add_notice(__('A subscription has been removed from your cart. Products and subscriptions can not be purchased at the same time.', 'woocommerce-subscriptions'), 'notice'); // Redirect to cart page to remove subscription & notify shopper add_filter('add_to_cart_fragments', __CLASS__ . '::redirect_ajax_add_to_cart'); } return $valid; }
/** * Check is a subscription coupon is valid before applying * * @since 1.2 */ public static function validate_subscription_coupon($valid, $coupon) { self::$coupon_error = ''; // ignore non-subscription coupons if (!in_array($coupon->type, array('recurring_fee', 'sign_up_fee', 'recurring_percent', 'sign_up_fee_percent'))) { // make sure there are no other products in the cart which the coupon could be applied to - WC()->cart->get_cart_contents_count() returns the quantity of items in the cart, not the total number of unique items, we need to use WC()->cart->cart_contents for that. if (1 == count(WC()->cart->cart_contents) && 0 == WC_Subscriptions_Cart::get_cart_subscription_sign_up_fee()) { $error_message = __('Sorry, this coupon is only valid for an initial payment and the subscription does not have an initial payment.', 'woocommerce-subscriptions'); // now make sure there is actually something for the coupon to be applied to (i.e. not a free trial or sync'd subscription without any prorated initial amount) if (WC_Subscriptions_Cart::cart_contains_free_trial()) { self::$coupon_error = $error_message; } elseif (WC_Subscriptions_Synchroniser::cart_contains_synced_subscription() && !WC_Subscriptions_Synchroniser::cart_contains_prorated_subscription()) { self::$coupon_error = $error_message; } } } else { // prevent subscription coupons from being applied to renewal payments if (WC_Subscriptions_Cart::cart_contains_subscription_renewal('child')) { self::$coupon_error = __('Sorry, this coupon is only valid for new subscriptions.', 'woocommerce-subscriptions'); } // prevent subscription coupons from being applied to non-subscription products if (!WC_Subscriptions_Cart::cart_contains_subscription_renewal() && !WC_Subscriptions_Cart::cart_contains_subscription()) { self::$coupon_error = __('Sorry, this coupon is only valid for subscription products.', 'woocommerce-subscriptions'); } // prevent sign up fee coupons from being applied to subscriptions without a sign up fee if (0 == WC_Subscriptions_Cart::get_cart_subscription_sign_up_fee() && in_array($coupon->type, array('sign_up_fee', 'sign_up_fee_percent'))) { self::$coupon_error = __('Sorry, this coupon is only valid for subscription products with a sign-up fee.', 'woocommerce-subscriptions'); } } if (!empty(self::$coupon_error)) { $valid = false; add_filter('woocommerce_coupon_error', __CLASS__ . '::add_coupon_error', 10); } return $valid; }
/** * If a product is being marked as not purchasable because it is limited and the customer has a subscription, * but the current request is to switch the subscription, then mark it as purchasable. * * @since 1.5 * @return bool */ public static function is_purchasable($is_purchasable, $product) { global $woocommerce; if (false === $is_purchasable && WC_Subscriptions_Product::is_subscription($product->id) && 'no' != $product->limit_subscriptions && is_user_logged_in() && ('active' == $product->limit_subscriptions && WC_Subscriptions_Manager::user_has_subscription(0, $product->id, 'on-hold') || WC_Subscriptions_Manager::user_has_subscription(0, $product->id, $product->limit_subscriptions))) { // Adding to cart from the product page if (isset($_GET['renew_subscription']) || isset($_GET['manual_subscription_renewal'])) { $is_purchasable = true; // Validating when restoring cart from session } elseif ($cart_item = WC_Subscriptions_Cart::cart_contains_subscription_renewal('parent')) { $is_purchasable = true; // Restoring cart from session, so need to check the cart in the session (WC_Subscriptions_Cart::cart_contains_subscription_renewal() only checks the cart) } elseif (isset($woocommerce->session->cart)) { foreach ($woocommerce->session->cart as $cart_item_key => $cart_item) { if ($product->id == $cart_item['product_id'] && isset($cart_item['subscription_renewal'])) { $is_purchasable = true; break; } } } } return $is_purchasable; }