/**
  * Apply sign up fee or recurring fee discount after tax is calculated
  *
  * @since 1.2
  * @version 1.3.6
  */
 public static function apply_subscription_discount_after_tax($coupon, $cart_item, $price)
 {
     global $woocommerce;
     $calculation_type = WC_Subscriptions_Cart::get_calculation_type();
     if (sizeof($woocommerce->cart->cart_contents) > 0) {
         foreach ($woocommerce->cart->cart_contents as $cart_item_key => $cart_item) {
             if (!WC_Subscriptions_Product::is_subscription($cart_item['product_id'])) {
                 continue;
             }
             if (!$coupon->apply_before_tax() && $coupon->is_valid() && self::is_subscription_discountable($cart_item, $coupon)) {
                 $apply_sign_up_coupon = $apply_sign_up_percent_coupon = $apply_recurring_coupon = $apply_recurring_percent_coupon = $apply_initial_coupon = $apply_initial_percent_coupon = false;
                 if ('sign_up_fee_total' == $calculation_type) {
                     $apply_sign_up_coupon = 'sign_up_fee' == $coupon->type ? true : false;
                     $apply_sign_up_percent_coupon = 'sign_up_fee_percent' == $coupon->type ? true : false;
                 } elseif ('recurring_total' == $calculation_type) {
                     $apply_recurring_coupon = 'recurring_fee' == $coupon->type ? true : false;
                     $apply_recurring_percent_coupon = 'recurring_percent' == $coupon->type ? true : false;
                 }
                 if (in_array($calculation_type, array('combined_total', 'none'))) {
                     if (!WC_Subscriptions_Cart::cart_contains_free_trial()) {
                         // Apply recurring discounts to initial total
                         if ('recurring_fee' == $coupon->type) {
                             $apply_initial_coupon = true;
                         }
                         if ('recurring_percent' == $coupon->type) {
                             $apply_initial_percent_coupon = true;
                         }
                     }
                     if (WC_Subscriptions_Cart::get_cart_subscription_sign_up_fee() > 0) {
                         // Apply sign-up discounts to initial total
                         if ('sign_up_fee' == $coupon->type) {
                             $apply_initial_coupon = true;
                         }
                         if ('sign_up_fee_percent' == $coupon->type) {
                             $apply_initial_percent_coupon = true;
                         }
                     }
                 }
                 // Deduct coupon amounts
                 if ($apply_sign_up_coupon || $apply_recurring_coupon || $apply_initial_coupon) {
                     if ($price < $coupon->amount) {
                         $discount_amount = $price;
                     } else {
                         $discount_amount = $coupon->amount;
                     }
                     $woocommerce->cart->discount_total = $woocommerce->cart->discount_total + $discount_amount * $cart_item['quantity'];
                     WC_Subscriptions_Cart::increase_coupon_discount_amount($coupon->code, $discount_amount * $cart_item['quantity']);
                     // Deduct coupon % discounts from relevant total
                 } elseif ($apply_sign_up_percent_coupon || $apply_recurring_percent_coupon) {
                     $woocommerce->cart->discount_total = $woocommerce->cart->discount_total + round($price / 100 * $coupon->amount, $woocommerce->cart->dp);
                     WC_Subscriptions_Cart::increase_coupon_discount_amount($coupon->code, round($price / 100 * $coupon->amount, $woocommerce->cart->dp));
                     // Deduct coupon % discounts from combined total (we need to calculate percent from base price)
                 } elseif ($apply_initial_percent_coupon) {
                     $product_id = $cart_item['data']->is_type(array('subscription_variation')) ? $cart_item['data']->variation_id : $cart_item['data']->id;
                     // We need to calculate the right amount to discount when the price is the combined sign-up fee and recurring amount
                     if ('combined_total' == $calculation_type && !WC_Subscriptions_Cart::cart_contains_free_trial() && isset($woocommerce->cart->base_sign_up_fees[$product_id]) && $woocommerce->cart->base_sign_up_fees[$product_id] > 0) {
                         $base_total = $woocommerce->cart->base_sign_up_fees[$product_id] + $woocommerce->cart->base_recurring_prices[$product_id];
                         if ('recurring_percent' == $coupon->type) {
                             $portion_of_total = $woocommerce->cart->base_recurring_prices[$product_id] / $base_total;
                         }
                         if ('sign_up_fee_percent' == $coupon->type) {
                             $portion_of_total = $woocommerce->cart->base_sign_up_fees[$product_id] / $base_total;
                         }
                         $amount_to_discount = WC_Subscriptions_Manager::get_amount_from_proportion($price, $portion_of_total);
                     } else {
                         $amount_to_discount = $price;
                     }
                     $discount_amount = round($amount_to_discount / 100 * $coupon->amount, $woocommerce->cart->dp);
                     $woocommerce->cart->discount_total = $woocommerce->cart->discount_total + $discount_amount;
                     WC_Subscriptions_Cart::increase_coupon_discount_amount($coupon->code, $discount_amount);
                 }
             }
         }
     }
 }
 /**
  * Version 1.2 introduced a massive change to the order meta data schema. This function goes
  * through and upgrades the existing data on all orders to the new schema.
  *
  * The upgrade process is timeout safe as it keeps a record of the orders upgraded and only
  * deletes this record once all orders have been upgraded successfully. If operating on a huge
  * number of orders and the upgrade process times out, only the orders not already upgraded
  * will be upgraded in future requests that trigger this function.
  *
  * @since 1.2
  */
 private static function upgrade_database_to_1_2()
 {
     global $wpdb;
     set_transient('wc_subscriptions_is_upgrading', 'true', 60 * 2);
     // Get IDs only and use a direct DB query for efficiency
     $orders_to_upgrade = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type = 'shop_order' AND post_parent = 0");
     $upgraded_orders = get_option('wcs_1_2_upgraded_order_ids', array());
     // Transition deprecated subscription status if we aren't in the middle of updating orders
     if (empty($upgraded_orders)) {
         $wpdb->query($wpdb->prepare("UPDATE {$wpdb->usermeta} SET meta_value = replace( meta_value, 's:9:\"suspended\"', 's:7:\"on-hold\"' ) WHERE meta_key LIKE %s", '%_' . WC_Subscriptions_Manager::$users_meta_key));
         $wpdb->query($wpdb->prepare("UPDATE {$wpdb->usermeta} SET meta_value = replace( meta_value, 's:6:\"failed\"', 's:9:\"cancelled\"' ) WHERE meta_key LIKE %s", '%_' . WC_Subscriptions_Manager::$users_meta_key));
     }
     $orders_to_upgrade = array_diff($orders_to_upgrade, $upgraded_orders);
     // Upgrade all _sign_up_{field} order meta to new order data format
     foreach ($orders_to_upgrade as $order_id) {
         $order = new WC_Order($order_id);
         // Manually check if a product in an order is a subscription, we can't use WC_Subscriptions_Order::order_contains_subscription( $order ) because it relies on the new data structure
         $contains_subscription = false;
         foreach ($order->get_items() as $order_item) {
             if (WC_Subscriptions_Product::is_subscription(WC_Subscriptions_Order::get_items_product_id($order_item))) {
                 $contains_subscription = true;
                 break;
             }
         }
         if (!$contains_subscription) {
             continue;
         }
         $trial_lengths = WC_Subscriptions_Order::get_meta($order, '_order_subscription_trial_lengths', array());
         $trial_length = array_pop($trial_lengths);
         $has_trial = !empty($trial_length) && $trial_length > 0 ? true : false;
         $sign_up_fee_total = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_total', 0);
         // Create recurring_* meta data from existing cart totals
         $cart_discount = $order->get_cart_discount();
         update_post_meta($order_id, '_order_recurring_discount_cart', $cart_discount);
         $order_discount = $order->get_order_discount();
         update_post_meta($order_id, '_order_recurring_discount_total', $order_discount);
         $order_shipping_tax = get_post_meta($order_id, '_order_shipping_tax', true);
         update_post_meta($order_id, '_order_recurring_shipping_tax_total', $order_shipping_tax);
         $order_tax = get_post_meta($order_id, '_order_tax', true);
         // $order->get_total_tax() includes shipping tax
         update_post_meta($order_id, '_order_recurring_tax_total', $order_tax);
         $order_total = $order->get_total();
         update_post_meta($order_id, '_order_recurring_total', $order_total);
         // Set order totals to include sign up fee fields, if there was a sign up fee on the order and a trial period (other wise, the recurring totals are correct)
         if ($sign_up_fee_total > 0) {
             // Order totals need to be changed to be equal to sign up fee totals
             if ($has_trial) {
                 $cart_discount = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_cart', 0);
                 $order_discount = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_total', 0);
                 $order_tax = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_tax_total', 0);
                 $order_total = $sign_up_fee_total;
             } else {
                 // No trial, sign up fees need to be added to order totals
                 $cart_discount += WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_cart', 0);
                 $order_discount += WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_total', 0);
                 $order_tax += WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_tax_total', 0);
                 $order_total += $sign_up_fee_total;
             }
             update_post_meta($order_id, '_order_total', $order_total);
             update_post_meta($order_id, '_cart_discount', $cart_discount);
             update_post_meta($order_id, '_order_discount', $order_discount);
             update_post_meta($order_id, '_order_tax', $order_tax);
         }
         // Make sure we get order taxes in WC 1.x format
         if (false == self::$is_wc_version_2) {
             $order_taxes = $order->get_taxes();
         } else {
             $order_tax_row = $wpdb->get_row($wpdb->prepare("\n\t\t\t\t\tSELECT * FROM {$wpdb->postmeta}\n\t\t\t\t\tWHERE meta_key = '_order_taxes_old'\n\t\t\t\t\tAND post_id = %s\n\t\t\t\t\t", $order_id));
             $order_taxes = (array) maybe_unserialize($order_tax_row->meta_value);
         }
         // Set recurring taxes to order taxes, if using WC 2.0, this will be migrated to the new format in @see self::upgrade_to_latest_wc()
         update_post_meta($order_id, '_order_recurring_taxes', $order_taxes);
         $sign_up_fee_taxes = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_taxes', array());
         // Update order taxes to include sign up fee taxes
         foreach ($sign_up_fee_taxes as $index => $sign_up_tax) {
             if ($has_trial && $sign_up_fee_total > 0) {
                 // Order taxes need to be set to the same as the sign up fee taxes
                 if (isset($sign_up_tax['cart_tax']) && $sign_up_tax['cart_tax'] > 0) {
                     $order_taxes[$index]['cart_tax'] = $sign_up_tax['cart_tax'];
                 }
             } elseif (!$has_trial && $sign_up_fee_total > 0) {
                 // Sign up fee taxes need to be added to order taxes
                 if (isset($sign_up_tax['cart_tax']) && $sign_up_tax['cart_tax'] > 0) {
                     $order_taxes[$index]['cart_tax'] += $sign_up_tax['cart_tax'];
                 }
             }
         }
         if (false == self::$is_wc_version_2) {
             // Doing it right: updated Subs *before* updating WooCommerce, the WooCommerce updater will take care of data migration
             update_post_meta($order_id, '_order_taxes', $order_taxes);
         } else {
             // Doing it wrong: updated Subs *after* updating WooCommerce, need to store in WC2.0 tax structure
             $index = 0;
             $new_order_taxes = $order->get_taxes();
             foreach ($new_order_taxes as $item_id => $order_tax) {
                 $index = $index + 1;
                 if (!isset($order_taxes[$index]['label']) || !isset($order_taxes[$index]['cart_tax']) || !isset($order_taxes[$index]['shipping_tax'])) {
                     continue;
                 }
                 // Add line item meta
                 if ($item_id) {
                     woocommerce_update_order_item_meta($item_id, 'compound', absint(isset($order_taxes[$index]['compound']) ? $order_taxes[$index]['compound'] : 0));
                     woocommerce_update_order_item_meta($item_id, 'tax_amount', woocommerce_clean($order_taxes[$index]['cart_tax']));
                     woocommerce_update_order_item_meta($item_id, 'shipping_tax_amount', woocommerce_clean($order_taxes[$index]['shipping_tax']));
                 }
             }
         }
         /* Upgrade each order item to use new Item Meta schema */
         $order_subscription_periods = WC_Subscriptions_Order::get_meta($order_id, '_order_subscription_periods', array());
         $order_subscription_intervals = WC_Subscriptions_Order::get_meta($order_id, '_order_subscription_intervals', array());
         $order_subscription_lengths = WC_Subscriptions_Order::get_meta($order_id, '_order_subscription_lengths', array());
         $order_subscription_trial_lengths = WC_Subscriptions_Order::get_meta($order_id, '_order_subscription_trial_lengths', array());
         $order_items = $order->get_items();
         foreach ($order_items as $index => $order_item) {
             $product_id = WC_Subscriptions_Order::get_items_product_id($order_item);
             $item_meta = new WC_Order_Item_Meta($order_item['item_meta']);
             $subscription_interval = isset($order_subscription_intervals[$product_id]) ? $order_subscription_intervals[$product_id] : 1;
             $subscription_length = isset($order_subscription_lengths[$product_id]) ? $order_subscription_lengths[$product_id] : 0;
             $subscription_trial_length = isset($order_subscription_trial_lengths[$product_id]) ? $order_subscription_trial_lengths[$product_id] : 0;
             $subscription_sign_up_fee = WC_Subscriptions_Order::get_meta($order, '_cart_contents_sign_up_fee_total', 0);
             if ($sign_up_fee_total > 0) {
                 // Discounted price * Quantity
                 $sign_up_fee_line_total = WC_Subscriptions_Order::get_meta($order, '_cart_contents_sign_up_fee_total', 0);
                 $sign_up_fee_line_tax = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_tax_total', 0);
                 // Base price * Quantity
                 $sign_up_fee_line_subtotal = WC_Subscriptions_Order::get_meta($order, '_cart_contents_sign_up_fee_total', 0) + WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_cart', 0);
                 $sign_up_fee_propotion = $sign_up_fee_line_total > 0 ? $sign_up_fee_line_subtotal / $sign_up_fee_line_total : 0;
                 $sign_up_fee_line_subtotal_tax = WC_Subscriptions_Manager::get_amount_from_proportion(WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_tax_total', 0), $sign_up_fee_propotion);
                 if ($has_trial) {
                     // Set line item totals equal to sign up fee totals
                     $order_item['line_subtotal'] = $sign_up_fee_line_subtotal;
                     $order_item['line_subtotal_tax'] = $sign_up_fee_line_subtotal_tax;
                     $order_item['line_total'] = $sign_up_fee_line_total;
                     $order_item['line_tax'] = $sign_up_fee_line_tax;
                 } else {
                     // No trial period, sign up fees need to be added to order totals
                     $order_item['line_subtotal'] += $sign_up_fee_line_subtotal;
                     $order_item['line_subtotal_tax'] += $sign_up_fee_line_subtotal_tax;
                     $order_item['line_total'] += $sign_up_fee_line_total;
                     $order_item['line_tax'] += $sign_up_fee_line_tax;
                 }
             }
             // Upgrading with WC 1.x
             if (method_exists($item_meta, 'add')) {
                 $item_meta->add('_subscription_period', $order_subscription_periods[$product_id]);
                 $item_meta->add('_subscription_interval', $subscription_interval);
                 $item_meta->add('_subscription_length', $subscription_length);
                 $item_meta->add('_subscription_trial_length', $subscription_trial_length);
                 $item_meta->add('_subscription_recurring_amount', $order_item['line_subtotal']);
                 // WC_Subscriptions_Product::get_price() would return a price without filters applied
                 $item_meta->add('_subscription_sign_up_fee', $subscription_sign_up_fee);
                 // Set recurring amounts for the item
                 $item_meta->add('_recurring_line_total', $order_item['line_total']);
                 $item_meta->add('_recurring_line_tax', $order_item['line_tax']);
                 $item_meta->add('_recurring_line_subtotal', $order_item['line_subtotal']);
                 $item_meta->add('_recurring_line_subtotal_tax', $order_item['line_subtotal_tax']);
                 $order_item['item_meta'] = $item_meta->meta;
                 $order_items[$index] = $order_item;
             } else {
                 // Ignoring all advice, upgrading 4 months after version 1.2 was released, and doing it with WC 2.0 installed
                 woocommerce_add_order_item_meta($index, '_subscription_period', $order_subscription_periods[$product_id]);
                 woocommerce_add_order_item_meta($index, '_subscription_interval', $subscription_interval);
                 woocommerce_add_order_item_meta($index, '_subscription_length', $subscription_length);
                 woocommerce_add_order_item_meta($index, '_subscription_trial_length', $subscription_trial_length);
                 woocommerce_add_order_item_meta($index, '_subscription_trial_period', $order_subscription_periods[$product_id]);
                 woocommerce_add_order_item_meta($index, '_subscription_recurring_amount', $order_item['line_subtotal']);
                 woocommerce_add_order_item_meta($index, '_subscription_sign_up_fee', $subscription_sign_up_fee);
                 // Calculated recurring amounts for the item
                 woocommerce_add_order_item_meta($index, '_recurring_line_total', $order_item['line_total']);
                 woocommerce_add_order_item_meta($index, '_recurring_line_tax', $order_item['line_tax']);
                 woocommerce_add_order_item_meta($index, '_recurring_line_subtotal', $order_item['line_subtotal']);
                 woocommerce_add_order_item_meta($index, '_recurring_line_subtotal_tax', $order_item['line_subtotal_tax']);
                 if ($sign_up_fee_total > 0) {
                     // Order totals have changed
                     woocommerce_update_order_item_meta($index, '_line_subtotal', woocommerce_format_decimal($order_item['line_subtotal']));
                     woocommerce_update_order_item_meta($index, '_line_subtotal_tax', woocommerce_format_decimal($order_item['line_subtotal_tax']));
                     woocommerce_update_order_item_meta($index, '_line_total', woocommerce_format_decimal($order_item['line_total']));
                     woocommerce_update_order_item_meta($index, '_line_tax', woocommerce_format_decimal($order_item['line_tax']));
                 }
             }
         }
         // Save the new meta on the order items for WC 1.x (the API functions already saved the data for WC2.x)
         if (false == self::$is_wc_version_2) {
             update_post_meta($order_id, '_order_items', $order_items);
         }
         $upgraded_orders[] = $order_id;
         update_option('wcs_1_2_upgraded_order_ids', $upgraded_orders);
     }
     // Remove the lock on upgrading
     delete_transient('wc_subscriptions_is_upgrading');
 }
 /**
  * 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 calculate_subscription_totals($total)
 {
     global $woocommerce;
     if (!self::cart_contains_subscription()) {
         return $total;
     } elseif ('sign_up_fee' == self::$recalculation_type) {
         // We've requested totals be recalculated with sign up fee only, we need to remove anything shipping related from the sign-up fee totals
         $total = $total - $woocommerce->cart->shipping_tax_total - $woocommerce->cart->shipping_total;
         $woocommerce->cart->shipping_taxes = array();
         $woocommerce->cart->shipping_tax_total = 0;
         self::$recalculation_type = 'none';
         return $total;
     }
     $base_sign_up_fee = self::get_cart_subscription_sign_up_fee();
     if ($base_sign_up_fee == 0 || self::$recalculation_type == 'base_recurring_fee') {
         // Nothing to fudge here, but we still need to keep a record of recurring totals
         foreach ($woocommerce->cart->get_cart() as $cart_item_key => $values) {
             $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_total'] = $values['line_total'];
             $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_tax'] = $values['line_tax'];
             $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_subtotal'] = $values['line_subtotal'];
             $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_subtotal_tax'] = $values['line_subtotal_tax'];
         }
         $woocommerce->cart->recurring_cart_contents_total = $woocommerce->cart->cart_contents_total;
         $woocommerce->cart->recurring_discount_cart = $woocommerce->cart->discount_cart;
         $woocommerce->cart->recurring_discount_total = $woocommerce->cart->discount_total;
         $woocommerce->cart->recurring_subtotal = $woocommerce->cart->subtotal;
         $woocommerce->cart->recurring_subtotal_ex_tax = $woocommerce->cart->subtotal_ex_tax;
         $woocommerce->cart->recurring_taxes = $woocommerce->cart->get_taxes();
         $woocommerce->cart->recurring_tax_total = $woocommerce->cart->tax_total;
         $woocommerce->cart->recurring_total = $total;
         // after calculating the recurring fee with discount, reset flag
         if (self::$recalculation_type == 'base_recurring_fee') {
             self::$recalculation_type = 'none';
             return $total;
         }
     } else {
         // The $total = price per period + sign up fee, so lets derive each one individually
         $sign_up_fee_proportion = $base_sign_up_fee / ($base_sign_up_fee + self::$base_product_price);
         // self::$base_product_price as set in set_subscription_prices_for_calculation()
         $recurring_proportion = 1 - $sign_up_fee_proportion;
         foreach ($woocommerce->cart->get_cart() as $cart_item_key => $values) {
             $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_total'] = WC_Subscriptions_Manager::get_amount_from_proportion($values['line_total'], $recurring_proportion);
             $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_tax'] = WC_Subscriptions_Manager::get_amount_from_proportion($values['line_tax'], $recurring_proportion);
             $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_subtotal'] = WC_Subscriptions_Manager::get_amount_from_proportion($values['line_subtotal'], $recurring_proportion);
             $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_subtotal_tax'] = WC_Subscriptions_Manager::get_amount_from_proportion($values['line_subtotal_tax'], $recurring_proportion);
         }
         // Calculate recurring totals, required for totals display correctly on cart and order page
         $woocommerce->cart->recurring_cart_contents_total = WC_Subscriptions_Manager::get_amount_from_proportion($woocommerce->cart->cart_contents_total, $recurring_proportion);
         $woocommerce->cart->recurring_discount_cart = WC_Subscriptions_Manager::get_amount_from_proportion($woocommerce->cart->discount_cart, $recurring_proportion);
         $woocommerce->cart->recurring_discount_total = WC_Subscriptions_Manager::get_amount_from_proportion($woocommerce->cart->discount_total, $recurring_proportion);
         $woocommerce->cart->recurring_subtotal = WC_Subscriptions_Manager::get_amount_from_proportion($woocommerce->cart->subtotal, $recurring_proportion);
         $woocommerce->cart->recurring_subtotal_ex_tax = WC_Subscriptions_Manager::get_amount_from_proportion($woocommerce->cart->subtotal_ex_tax, $recurring_proportion);
         $woocommerce->cart->recurring_taxes = array();
         // Add non-shipping taxes
         foreach ($woocommerce->cart->taxes as $tax_id => $tax_amount) {
             $woocommerce->cart->recurring_taxes[$tax_id] = WC_Subscriptions_Manager::get_amount_from_proportion($tax_amount, $recurring_proportion);
         }
         // And shipping taxes
         foreach ($woocommerce->cart->shipping_taxes as $tax_id => $tax_amount) {
             $woocommerce->cart->recurring_taxes[$tax_id] = $tax_amount;
         }
         // Shipping only applies to recurring payments
         // Shipping only applies to recurring amounts, not the sign-up fee, so we'll add it in its entirety to the recurring amount later
         $total_sans_shipping = $total - $woocommerce->cart->shipping_tax_total - $woocommerce->cart->shipping_total;
         $total_ex_tax = $total_sans_shipping - $woocommerce->cart->tax_total;
         $recurring_total_ex_tax = WC_Subscriptions_Manager::get_amount_from_proportion($total_ex_tax, $recurring_proportion) + $woocommerce->cart->shipping_total;
         $woocommerce->cart->recurring_total = WC_Subscriptions_Manager::get_amount_from_proportion($total_sans_shipping, $recurring_proportion) + $woocommerce->cart->shipping_tax_total + $woocommerce->cart->shipping_total;
         $woocommerce->cart->recurring_tax_total = $woocommerce->cart->recurring_total - $recurring_total_ex_tax;
         /** Handle pricing adjustments - Recurring / Sign up fee discounts / trial periods */
         // Recurring discount
         if (WC_Subscriptions_Coupon::cart_contains_recurring_discount()) {
             // save cart with combined totals
             $original_cart = clone $woocommerce->cart;
             // calculate total with sign up fee only first
             self::$recalculation_type = 'sign_up_fee';
             $woocommerce->cart->calculate_totals();
             // save cart with just sign up fee
             $sign_up_fee_cart = clone $woocommerce->cart;
             // now calculate base recurring fee with discount included
             self::$recalculation_type = 'base_recurring_fee';
             $woocommerce->cart->calculate_totals();
             if (self::cart_contains_free_trial()) {
                 // restore sign up fee cart contents & total
                 $woocommerce->cart->cart_contents = $sign_up_fee_cart->cart_contents;
                 $woocommerce->cart->cart_contents_total = $sign_up_fee_cart->cart_contents_total;
                 // restore sign up fee cart sub-totals
                 $woocommerce->cart->subtotal = $sign_up_fee_cart->subtotal;
                 $woocommerce->cart->subtotal_ex_tax = $sign_up_fee_cart->subtotal_ex_tax;
                 // restore sign up fee cart taxes
                 $woocommerce->cart->taxes = $sign_up_fee_cart->taxes;
                 $woocommerce->cart->tax_total = $sign_up_fee_cart->tax_total;
                 // final total is sign up fee cart total only
                 $total = $sign_up_fee_cart->total;
                 // Add sign up fee discounts to cart/total discounts (which already include recurring discounts)
                 $woocommerce->cart->discount_cart = $sign_up_fee_cart->discount_cart > 0 ? $sign_up_fee_cart->discount_cart : 0;
                 $woocommerce->cart->discount_total = $sign_up_fee_cart->discount_total > 0 ? $sign_up_fee_cart->discount_total : 0;
             } else {
                 // restore combined cart contents & total
                 $woocommerce->cart->cart_contents = $original_cart->cart_contents;
                 $woocommerce->cart->cart_contents_total = $original_cart->cart_contents_total;
                 // restore combined cart sub-totals
                 $woocommerce->cart->subtotal = $original_cart->subtotal;
                 $woocommerce->cart->subtotal_ex_tax = $original_cart->subtotal_ex_tax;
                 // combine and total any taxes on sign up fees to the cart total (which already includes taxes on recurring fees)
                 foreach ($woocommerce->cart->taxes as $tax_key => $tax_amount) {
                     $woocommerce->cart->taxes[$tax_key] += $sign_up_fee_cart->taxes[$tax_key];
                 }
                 $woocommerce->cart->tax_total += $sign_up_fee_cart->tax_total;
                 // Add sign up fee discounts to cart/total discounts (which already include recurring discounts)
                 $woocommerce->cart->discount_cart += $sign_up_fee_cart->discount_cart > 0 ? $sign_up_fee_cart->discount_cart : 0;
                 $woocommerce->cart->discount_total += $sign_up_fee_cart->discount_total > 0 ? $sign_up_fee_cart->discount_total : 0;
                 // Final total is sign up fee cart total + recurring fee cart total
                 $total = $sign_up_fee_cart->total + $woocommerce->cart->recurring_total;
             }
             // Sign up fee discount
         } elseif (WC_Subscriptions_Coupon::cart_contains_sign_up_discount()) {
             // save cart with combined totals
             $original_cart = clone $woocommerce->cart;
             // calculate totals with sign up fee only first
             self::$recalculation_type = 'sign_up_fee';
             $woocommerce->cart->calculate_totals();
             if (self::cart_contains_free_trial()) {
                 // only need sign up total for the initial payment
                 $total = $woocommerce->cart->total;
             } else {
                 // restore combined cart contents & total
                 $woocommerce->cart->cart_contents = $original_cart->cart_contents;
                 $woocommerce->cart->cart_contents_total = $original_cart->cart_contents_total;
                 // restore combined cart sub-totals
                 $woocommerce->cart->subtotal = $original_cart->subtotal;
                 $woocommerce->cart->subtotal_ex_tax = $original_cart->subtotal_ex_tax;
                 $total = $woocommerce->cart->total + $woocommerce->cart->recurring_total;
             }
             // Free trial with no discounts - recalculate all the initial payment amounts just for the sign-up fee
         } elseif (self::cart_contains_free_trial()) {
             // only pass sign up fee thru get_price filters
             self::$recalculation_type = 'sign_up_fee';
             $woocommerce->cart->calculate_totals();
             // Make the sign up fee only total persist
             $total = $woocommerce->cart->total;
         }
     }
     return $total;
 }
 /**
  * Version 1.2 introduced a massive change to the order meta data schema. This function goes  
  * through and upgrades the existing data on all orders to the new schema.
  *
  * The upgrade process is timeout safe as it keeps a record of the orders upgraded and only 
  * deletes this record once all orders have been upgraded successfully. If operating on a huge 
  * number of orders and the upgrade process times out, only the orders not already upgraded 
  * will be upgraded in future requests that trigger this function.
  *
  * @since 1.2
  */
 private static function upgrade_database()
 {
     global $wpdb;
     set_transient('wc_subscriptions_is_upgrading', 'true', 60 * 2);
     // Get IDs only and use a direct DB query for efficiency
     $orders_to_upgrade = $wpdb->get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type = 'shop_order' AND post_parent = 0");
     $upgraded_orders = get_option('wcs_1_2_upgraded_order_ids', array());
     // Transition deprecated subscription status if we aren't in the middle of updating orders
     if (empty($upgraded_orders)) {
         $wpdb->query($wpdb->prepare("UPDATE {$wpdb->usermeta} SET meta_value = replace( meta_value, 's:9:\"suspended\"', 's:7:\"on-hold\"' ) WHERE meta_key LIKE %s", '%_' . WC_Subscriptions_Manager::$users_meta_key));
         $wpdb->query($wpdb->prepare("UPDATE {$wpdb->usermeta} SET meta_value = replace( meta_value, 's:6:\"failed\"', 's:9:\"cancelled\"' ) WHERE meta_key LIKE %s", '%_' . WC_Subscriptions_Manager::$users_meta_key));
     }
     $orders_to_upgrade = array_diff($orders_to_upgrade, $upgraded_orders);
     // Upgrade all _sign_up_{field} order meta to new order data format
     foreach ($orders_to_upgrade as $order_id) {
         $order = new WC_Order($order_id);
         // Manually check if a product in an order is a subscription, we can't use WC_Subscriptions_Order::order_contains_subscription( $order ) because it relies on the new data structure
         $contains_subscription = false;
         foreach ($order->get_items() as $order_item) {
             if (WC_Subscriptions_Product::is_subscription($order_item['id'])) {
                 $contains_subscription = true;
                 break;
             }
         }
         if (!$contains_subscription) {
             continue;
         }
         $trial_lengths = WC_Subscriptions_Order::get_meta($order, '_order_subscription_trial_lengths', array());
         $trial_length = array_pop($trial_lengths);
         $has_trial = !empty($trial_length) && $trial_length > 0 ? true : false;
         $sign_up_fee_total = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_total', 0);
         // Create recurring_* meta data from existing cart totals
         $cart_discount = $order->get_cart_discount();
         update_post_meta($order_id, '_order_recurring_discount_cart', $cart_discount);
         $order_discount = $order->get_order_discount();
         update_post_meta($order_id, '_order_recurring_discount_total', $order_discount);
         $order_shipping_tax = get_post_meta($order_id, '_order_shipping_tax', true);
         update_post_meta($order_id, '_order_recurring_shipping_tax_total', $order_shipping_tax);
         $order_tax = get_post_meta($order_id, '_order_tax', true);
         // $order->get_total_tax() includes shipping tax
         update_post_meta($order_id, '_order_recurring_tax_total', $order_tax);
         $order_total = $order->get_total();
         update_post_meta($order_id, '_order_recurring_total', $order_total);
         // Set order totals to include sign up fee fields, if there was a sign up fee on the order and a trial period (other wise, the recurring totals are correct)
         if ($sign_up_fee_total > 0) {
             // Order totals need to be changed to be equal to sign up fee totals
             if ($has_trial) {
                 $cart_discount = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_cart', 0);
                 $order_discount = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_total', 0);
                 $order_tax = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_tax_total', 0);
                 $order_total = $sign_up_fee_total;
             } else {
                 // No trial, sign up fees need to be added to order totals
                 $cart_discount += WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_cart', 0);
                 $order_discount += WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_total', 0);
                 $order_tax += WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_tax_total', 0);
                 $order_total += $sign_up_fee_total;
             }
             update_post_meta($order_id, '_order_total', $order_total);
             update_post_meta($order_id, '_cart_discount', $cart_discount);
             update_post_meta($order_id, '_order_discount', $order_discount);
             update_post_meta($order_id, '_order_tax', $order_tax);
         }
         $order_taxes = $order->get_taxes();
         // Set recurring taxes to order taxes
         update_post_meta($order_id, '_order_recurring_taxes', $order_taxes);
         $sign_up_fee_taxes = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_taxes', array());
         // Update order taxes to include sign up fee taxes
         foreach ($sign_up_fee_taxes as $index => $sign_up_tax) {
             if ($has_trial && $sign_up_fee_total > 0) {
                 // Order taxes need to be set to the same as the sign up fee taxes
                 if (isset($sign_up_tax['cart_tax']) && $sign_up_tax['cart_tax'] > 0) {
                     $order_taxes[$index]['cart_tax'] = $sign_up_tax['cart_tax'];
                 }
             } elseif (!$has_trial && $sign_up_fee_total > 0) {
                 // Sign up fee taxes need to be added to order taxes
                 if (isset($sign_up_tax['cart_tax']) && $sign_up_tax['cart_tax'] > 0) {
                     $order_taxes[$index]['cart_tax'] += $sign_up_tax['cart_tax'];
                 }
             }
         }
         update_post_meta($order_id, '_order_taxes', $order_taxes);
         /* Upgrade each order item to use new Item Meta schema */
         $order_subscription_periods = WC_Subscriptions_Order::get_meta($order_id, '_order_subscription_periods', array());
         $order_subscription_intervals = WC_Subscriptions_Order::get_meta($order_id, '_order_subscription_intervals', array());
         $order_subscription_lengths = WC_Subscriptions_Order::get_meta($order_id, '_order_subscription_lengths', array());
         $order_subscription_trial_lengths = WC_Subscriptions_Order::get_meta($order_id, '_order_subscription_trial_lengths', array());
         $order_items = $order->get_items();
         foreach ($order_items as $index => $order_item) {
             $item_meta = new WC_Order_Item_Meta($order_item['item_meta']);
             $subscription_interval = isset($order_subscription_intervals[$order_item['id']]) ? $order_subscription_intervals[$order_item['id']] : 1;
             $subscription_length = isset($order_subscription_lengths[$order_item['id']]) ? $order_subscription_lengths[$order_item['id']] : 0;
             $subscription_trial_length = isset($order_subscription_trial_lengths[$order_item['id']]) ? $order_subscription_trial_lengths[$order_item['id']] : 0;
             $item_meta->add('_subscription_period', $order_subscription_periods[$order_item['id']]);
             $item_meta->add('_subscription_interval', $subscription_interval);
             $item_meta->add('_subscription_length', $subscription_length);
             $item_meta->add('_subscription_trial_length', $subscription_trial_length);
             $item_meta->add('_subscription_recurring_amount', $order_item['line_subtotal']);
             // WC_Subscriptions_Product::get_price() would return a price without filters applied
             $item_meta->add('_subscription_sign_up_fee', WC_Subscriptions_Order::get_meta($order, '_cart_contents_sign_up_fee_total', 0));
             // Set recurring amounts for the item
             $item_meta->add('_recurring_line_total', $order_item['line_total']);
             $item_meta->add('_recurring_line_tax', $order_item['line_tax']);
             $item_meta->add('_recurring_line_subtotal', $order_item['line_subtotal']);
             $item_meta->add('_recurring_line_subtotal_tax', $order_item['line_subtotal_tax']);
             if ($sign_up_fee_total > 0) {
                 // Discounted price * Quantity
                 $sign_up_fee_line_total = WC_Subscriptions_Order::get_meta($order, '_cart_contents_sign_up_fee_total', 0);
                 $sign_up_fee_line_tax = WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_tax_total', 0);
                 // Base price * Quantity
                 $sign_up_fee_line_subtotal = WC_Subscriptions_Order::get_meta($order, '_cart_contents_sign_up_fee_total', 0) + WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_discount_cart', 0);
                 $sign_up_fee_propotion = $sign_up_fee_line_total > 0 ? $sign_up_fee_line_subtotal / $sign_up_fee_line_total : 0;
                 $sign_up_fee_line_subtotal_tax = WC_Subscriptions_Manager::get_amount_from_proportion(WC_Subscriptions_Order::get_meta($order, '_sign_up_fee_tax_total', 0), $sign_up_fee_propotion);
                 if ($has_trial) {
                     // Set line item totals equal to sign up fee totals
                     $order_item['line_subtotal'] = $sign_up_fee_line_subtotal;
                     $order_item['line_subtotal_tax'] = $sign_up_fee_line_subtotal_tax;
                     $order_item['line_total'] = $sign_up_fee_line_total;
                     $order_item['line_tax'] = $sign_up_fee_line_tax;
                 } else {
                     // No trial period, sign up fees need to be added to order totals
                     $order_item['line_subtotal'] += $sign_up_fee_line_subtotal;
                     $order_item['line_subtotal_tax'] += $sign_up_fee_line_subtotal_tax;
                     $order_item['line_total'] += $sign_up_fee_line_total;
                     $order_item['line_tax'] += $sign_up_fee_line_tax;
                 }
             }
             $order_item['item_meta'] = $item_meta->meta;
             $order_items[$index] = $order_item;
         }
         // Save the new meta on the order items
         update_post_meta($order_id, '_order_items', $order_items);
         $upgraded_orders[] = $order_id;
         update_option('wcs_1_2_upgraded_order_ids', $upgraded_orders);
     }
     // Remove the lock on upgrading
     delete_transient('wc_subscriptions_is_upgrading');
 }