/**
  * 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;
 }