/**
  * 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 resubscribe to the subscription, then mark it as purchasable.
  *
  * @since 2.0
  * @return bool
  */
 public function is_purchasable($is_purchasable, $product)
 {
     // If the product is being set as not-purchasable by Subscriptions (due to limiting)
     if (false === $is_purchasable && false === WC_Subscriptions_Product::is_purchasable($is_purchasable, $product)) {
         // Validating when restoring cart from session
         if (false !== wcs_cart_contains_resubscribe()) {
             $is_purchasable = true;
             // Restoring cart from session, so need to check the cart in the session (wcs_cart_contains_renewal() only checks the cart)
         } elseif (isset(WC()->session->cart)) {
             foreach (WC()->session->cart as $cart_item_key => $cart_item) {
                 if ($product->id == $cart_item['product_id'] && isset($cart_item[$this->cart_item_key])) {
                     $is_purchasable = true;
                     break;
                 }
             }
         } elseif (isset($_GET['resubscribe'])) {
             // Is a request to resubscribe
             $subscription = wcs_get_subscription(absint($_GET['resubscribe']));
             if (false !== $subscription && $subscription->has_product($product->id) && wcs_can_user_resubscribe_to($subscription)) {
                 $is_purchasable = true;
             }
         }
     }
     return $is_purchasable;
 }
 /**
  * Calculate the initial and recurring totals for all subscription products in the cart.
  *
  * We need to group subscriptions by billing schedule to make the display and creation of recurring totals sane,
  * when there are multiple subscriptions in the cart. To do that, we use an array with keys of the form:
  * '{billing_interval}_{billing_period}_{trial_interval}_{trial_period}_{length}_{billing_period}'. This key
  * is used to reference WC_Cart objects for each recurring billing schedule and these are stored in the master
  * cart with the billing schedule key.
  *
  * After we have calculated and grouped all recurring totals, we need to checks the structure of the subscription
  * product prices to see whether they include sign-up fees and/or free trial periods and then recalculates the
  * appropriate totals by using the @see self::$calculation_type flag and cloning the cart to run @see WC_Cart::calculate_totals()
  *
  * @since 1.3.5
  * @version 2.0
  */
 public static function calculate_subscription_totals($total, $cart)
 {
     if (!self::cart_contains_subscription() && !wcs_cart_contains_resubscribe()) {
         // cart doesn't contain subscription
         return $total;
     } elseif ('none' != self::$calculation_type) {
         // We're in the middle of a recalculation, let it run
         return $total;
     }
     // Save the original cart values/totals, as we'll use this when there is no sign-up fee
     WC()->cart->total = $total < 0 ? 0 : $total;
     do_action('woocommerce_subscription_cart_before_grouping');
     $subscription_groups = array();
     // Group the subscription items by their cart item key based on billing schedule
     foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
         if (WC_Subscriptions_Product::is_subscription($cart_item['data'])) {
             $subscription_groups[self::get_recurring_cart_key($cart_item)][] = $cart_item_key;
         }
     }
     do_action('woocommerce_subscription_cart_after_grouping');
     $recurring_carts = array();
     // Now let's calculate the totals for each group of subscriptions
     self::$calculation_type = 'recurring_total';
     foreach ($subscription_groups as $recurring_cart_key => $subscription_group) {
         // Create a clone cart to calculate and store totals for this group of subscriptions
         $recurring_cart = clone WC()->cart;
         $product = null;
         // Remove any items not in this subscription group
         foreach ($recurring_cart->get_cart() as $cart_item_key => $cart_item) {
             if (!in_array($cart_item_key, $subscription_group)) {
                 unset($recurring_cart->cart_contents[$cart_item_key]);
                 continue;
             }
             if (null === $product) {
                 $product = $cart_item['data'];
             }
         }
         $recurring_cart->start_date = apply_filters('wcs_recurring_cart_start_date', gmdate('Y-m-d H:i:s'), $recurring_cart);
         $recurring_cart->trial_end_date = apply_filters('wcs_recurring_cart_trial_end_date', WC_Subscriptions_Product::get_trial_expiration_date($product, $recurring_cart->start_date), $recurring_cart, $product);
         $recurring_cart->next_payment_date = apply_filters('wcs_recurring_cart_next_payment_date', WC_Subscriptions_Product::get_first_renewal_payment_date($product, $recurring_cart->start_date), $recurring_cart, $product);
         $recurring_cart->end_date = apply_filters('wcs_recurring_cart_end_date', WC_Subscriptions_Product::get_expiration_date($product, $recurring_cart->start_date), $recurring_cart, $product);
         // No fees recur (yet)
         $recurring_cart->fees = array();
         $recurring_cart->fee_total = 0;
         WC()->shipping->reset_shipping();
         self::maybe_recalculate_shipping();
         $recurring_cart->calculate_totals();
         // Store this groups cart details
         $recurring_carts[$recurring_cart_key] = clone $recurring_cart;
         // And remove some other floatsam
         $recurring_carts[$recurring_cart_key]->removed_cart_contents = array();
         $recurring_carts[$recurring_cart_key]->cart_session_data = array();
     }
     self::$calculation_type = 'none';
     // We need to reset the packages and totals stored in WC()->shipping too
     self::maybe_recalculate_shipping();
     WC()->cart->calculate_shipping();
     // If there is no sign-up fee and a free trial, and no products being purchased with the subscription, we need to zero the fees for the first billing period
     if (0 == self::get_cart_subscription_sign_up_fee() && self::all_cart_items_have_free_trial()) {
         foreach (WC()->cart->get_fees() as $fee_index => $fee) {
             WC()->cart->fees[$fee_index]->amount = 0;
             WC()->cart->fees[$fee_index]->tax = 0;
         }
         WC()->cart->fee_total = 0;
     }
     WC()->cart->recurring_carts = $recurring_carts;
     $total = max(0, round(WC()->cart->cart_contents_total + WC()->cart->tax_total + WC()->cart->shipping_tax_total + WC()->cart->shipping_total + WC()->cart->fee_total, WC()->cart->dp));
     if (isset(WC()->cart->discount_total) && 0 !== WC()->cart->discount_total) {
         // WC < 2.3, deduct deprecated after tax discount total
         $total = max(0, round($total - WC()->cart->discount_total, WC()->cart->dp));
     }
     if (!self::charge_shipping_up_front()) {
         $total = max(0, $total - WC()->cart->shipping_tax_total - WC()->cart->shipping_total);
         WC()->cart->shipping_taxes = array();
         WC()->cart->shipping_tax_total = 0;
         WC()->cart->shipping_total = 0;
     }
     return apply_filters('woocommerce_subscriptions_calculated_total', $total);
 }
 /**
  * Checks the cart to see if it contains a subscription resubscribe item.
  *
  * @see wcs_cart_contains_resubscribe()
  * @param WC_Cart $cart The cart object to search in.
  * @return bool | Array The cart item containing the renewal, else false.
  * @since  2.0.10
  */
 protected function cart_contains($cart = '')
 {
     return wcs_cart_contains_resubscribe($cart);
 }