/** * Uses the a subscription's combined price total calculated by WooCommerce to determine the * total price that should be charged per period. * * @since 1.2 */ public static function set_calculated_total($total) { global $woocommerce; if ('none' == self::$calculation_type || !self::cart_contains_subscription() && !self::cart_contains_subscription_renewal()) { return $total; } // We've requested totals be recalculated with sign up fee only or free trial, we need to remove anything shipping related from the totals if ('sign_up_fee_total' == self::$calculation_type || 'free_trial_total' == self::$calculation_type) { $total = $total - $woocommerce->cart->shipping_tax_total - $woocommerce->cart->shipping_total; $woocommerce->cart->shipping_taxes = array(); $woocommerce->cart->shipping_tax_total = 0; $woocommerce->cart->shipping_total = 0; } self::$calculation_type = 'none'; return $total; }
/** * Display the recurring totals for items in the cart * * @since 2.0 */ public static function display_recurring_totals() { if (self::cart_contains_subscription()) { // We only want shipping for recurring amounts, and they need to be calculated again here self::$calculation_type = 'recurring_total'; $shipping_methods = array(); $carts_with_multiple_payments = 0; // Create new subscriptions for each subscription product in the cart (that is not a renewal) foreach (WC()->cart->recurring_carts as $recurring_cart_key => $recurring_cart) { // Cart contains more than one payment if (0 != $recurring_cart->next_payment_date) { $carts_with_multiple_payments++; // Create shipping packages for each subscription item if (self::cart_contains_subscriptions_needing_shipping()) { $chosen_shipping_methods = WC()->session->get('chosen_shipping_methods', array()); // Don't remove any subscriptions with a free trial from the shipping packages foreach ($recurring_cart->get_shipping_packages() as $base_package) { $package = WC()->shipping->calculate_shipping_for_package($base_package); // Only display the costs for the chosen shipping method foreach ($chosen_shipping_methods as $package_key) { if (isset($package['rates'][$package_key])) { $shipping_methods[$recurring_cart_key] = $package['rates'][$package_key]; } } } } } } if ($carts_with_multiple_payments >= 1) { wc_get_template('checkout/recurring-totals.php', array('shipping_methods' => $shipping_methods, 'recurring_carts' => WC()->cart->recurring_carts, 'carts_with_multiple_payments' => $carts_with_multiple_payments), '', plugin_dir_path(WC_Subscriptions::$plugin_file) . 'templates/'); } self::$calculation_type = 'none'; } }
/** * Display the recurring totals for items in the cart * * @since 2.0 */ public static function display_recurring_totals() { if (self::cart_contains_subscription()) { // We only want shipping for recurring amounts, and they need to be calculated again here self::$calculation_type = 'recurring_total'; $shipping_methods = array(); $carts_with_multiple_payments = 0; // Create new subscriptions for each subscription product in the cart (that is not a renewal) foreach (WC()->cart->recurring_carts as $recurring_cart_key => $recurring_cart) { // Cart contains more than one payment if (0 != $recurring_cart->next_payment_date) { $carts_with_multiple_payments++; } } if ($carts_with_multiple_payments >= 1) { wc_get_template('checkout/recurring-totals.php', array('shipping_methods' => $shipping_methods, 'recurring_carts' => WC()->cart->recurring_carts, 'carts_with_multiple_payments' => $carts_with_multiple_payments), '', plugin_dir_path(WC_Subscriptions::$plugin_file) . 'templates/'); } self::$calculation_type = 'none'; } }
/** * 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; 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); }
/** * Validate the chosen recurring shipping methods for each recurring shipping package. * Ensures there is at least one chosen shipping method and that the chosen method is valid considering the available * package rates. * * @since 2.0.14 */ public static function validate_recurring_shipping_methods() { $shipping_methods = WC()->checkout()->shipping_methods; $added_invalid_notice = false; $standard_packages = WC()->shipping->get_packages(); // temporarily store the current calculation type so we can restore it later $calculation_type = self::$calculation_type; self::$calculation_type = 'recurring_total'; foreach (WC()->cart->recurring_carts as $recurring_cart_key => $recurring_cart) { if (false === $recurring_cart->needs_shipping() || 0 == $recurring_cart->next_payment_date) { continue; } $packages = $recurring_cart->get_shipping_packages(); foreach ($packages as $package_index => $base_package) { $package = self::get_calculated_shipping_for_package($base_package); if (isset($standard_packages[$package_index]) && $package['rates'] == $standard_packages[$package_index]['rates'] && apply_filters('wcs_cart_totals_shipping_html_price_only', true, $package, WC()->cart->recurring_carts[$recurring_cart_key])) { // the recurring package rates match the initial package rates, there won't be a selected shipping method for this recurring cart package // move on to the next package continue; } $recurring_shipping_package_key = WC_Subscriptions_Cart::get_recurring_shipping_package_key($recurring_cart_key, $package_index); if (!isset($package['rates'][$shipping_methods[$recurring_shipping_package_key]])) { if (!$added_invalid_notice) { wc_add_notice(__('Invalid recurring shipping method.', 'woocommerce-subscriptions'), 'error'); $added_invalid_notice = true; } WC()->checkout()->shipping_methods[$recurring_shipping_package_key] = ''; } } } self::$calculation_type = $calculation_type; }