/**
  * Returns a string representing the details of the subscription. 
  *
  * For example "$20 per Month for 3 Months with a $10 sign-up fee".
  *
  * @param WC_Product|int $product A WC_Product object or ID of a WC_Product.
  * @param array $inclusions An associative array of flags to indicate how to calculate the price and what to include, values:
  *			'tax_calculation'     => false to ignore tax, 'include_tax' or 'exclude_tax' To indicate that tax should be added or excluded respectively
  *			'subscription_length' => true to include subscription's length (default) or false to exclude it
  *			'sign_up_fee'         => true to include subscription's sign up fee (default) or false to exclude it
  *			'price'               => string a price to short-circuit the price calculations and use in a string for the product
  * @since 1.0
  */
 public static function get_price_string($product, $include = array())
 {
     global $wp_locale;
     if (!is_object($product)) {
         $product = WC_Subscriptions::get_product($product);
     }
     if (!self::is_subscription($product)) {
         return;
     }
     $include = wp_parse_args($include, array('tax_calculation' => get_option('woocommerce_tax_display_shop'), 'subscription_price' => true, 'subscription_period' => true, 'subscription_length' => true, 'sign_up_fee' => true, 'trial_length' => true));
     $include = apply_filters('woocommerce_subscriptions_product_price_string_inclusions', $include, $product);
     $base_price = self::get_price($product);
     if (true === $include['sign_up_fee']) {
         $sign_up_fee = self::get_sign_up_fee($product);
     } elseif (false !== $include['sign_up_fee']) {
         // Allow override of product's sign-up fee
         $sign_up_fee = $include['sign_up_fee'];
     } else {
         $sign_up_fee = 0;
     }
     if ($include['tax_calculation'] != false) {
         if (in_array($include['tax_calculation'], array('exclude_tax', 'excl'))) {
             // Subtract Tax
             if (isset($include['price'])) {
                 $price = $include['price'];
             } else {
                 $price = $product->get_price_excluding_tax(1, $include['price']);
             }
             if (true === $include['sign_up_fee']) {
                 $sign_up_fee = $product->get_sign_up_fee_excluding_tax();
             }
         } else {
             // Add Tax
             if (isset($include['price'])) {
                 $price = $include['price'];
             } else {
                 $price = $product->get_price_including_tax();
             }
             if (true === $include['sign_up_fee']) {
                 $sign_up_fee = $product->get_sign_up_fee_including_tax();
             }
         }
     } else {
         if (isset($include['price'])) {
             $price = $include['price'];
         } else {
             $price = woocommerce_price($base_price);
         }
     }
     $price .= ' <span class="subscription-details">';
     $billing_interval = self::get_interval($product);
     $billing_period = self::get_period($product);
     $subscription_length = self::get_length($product);
     $trial_length = self::get_trial_length($product);
     $trial_period = self::get_trial_period($product);
     if (is_numeric($sign_up_fee)) {
         $sign_up_fee = woocommerce_price($sign_up_fee);
     }
     if ($include['subscription_length']) {
         $ranges = WC_Subscriptions_Manager::get_subscription_ranges($billing_period);
     }
     if ($include['subscription_length'] && $subscription_length != 0) {
         $include_length = true;
     } else {
         $include_length = false;
     }
     $subscription_string = '';
     if ($include['subscription_price'] && $include['subscription_period']) {
         // Allow extensions to not show price or billing period e.g. Name Your Price
         if ($include_length && $subscription_length == $billing_interval) {
             $subscription_string = $price;
             // Only for one billing period so show "$5 for 3 months" instead of "$5 every 3 months for 3 months"
         } elseif (WC_Subscriptions_Synchroniser::is_product_synced($product) && in_array($billing_period, array('week', 'month', 'year'))) {
             $payment_day = WC_Subscriptions_Synchroniser::get_products_payment_day($product);
             switch ($billing_period) {
                 case 'week':
                     $payment_day_of_week = WC_Subscriptions_Synchroniser::get_weekday($payment_day);
                     if (1 == $billing_interval) {
                         // e.g. $5 every Wednesday
                         $subscription_string = sprintf(__('%s every %s', 'woocommerce-subscriptions'), $price, $payment_day_of_week);
                     } else {
                         // e.g. $5 every 2 weeks on Wednesday
                         $subscription_string = sprintf(__('%s every %s on %s', 'woocommerce-subscriptions'), $price, WC_Subscriptions_Manager::get_subscription_period_strings($billing_interval, $billing_period), $payment_day_of_week);
                     }
                     break;
                 case 'month':
                     if (1 == $billing_interval) {
                         // e.g. $15 on the 15th of each month
                         if ($payment_day > 27) {
                             $subscription_string = sprintf(__('%s on the last day of each month', 'woocommerce-subscriptions'), $price);
                         } else {
                             $subscription_string = sprintf(__('%s on the %s of each month', 'woocommerce-subscriptions'), $price, WC_Subscriptions::append_numeral_suffix($payment_day));
                         }
                     } else {
                         // e.g. $15 on the 15th of every 3rd month
                         if ($payment_day > 27) {
                             $subscription_string = sprintf(__('%s on the last day of every %s month', 'woocommerce-subscriptions'), $price, WC_Subscriptions::append_numeral_suffix($billing_interval));
                         } else {
                             $subscription_string = sprintf(__('%s on the %s day of every %s month', 'woocommerce-subscriptions'), $price, WC_Subscriptions::append_numeral_suffix($payment_day), WC_Subscriptions::append_numeral_suffix($billing_interval));
                         }
                     }
                     break;
                 case 'year':
                     if (1 == $billing_interval) {
                         // e.g. $15 on March 15th each year
                         $subscription_string = sprintf(__('%s on %s %s each year', 'woocommerce-subscriptions'), $price, $wp_locale->month[$payment_day['month']], WC_Subscriptions::append_numeral_suffix($payment_day['day']));
                     } else {
                         // e.g. $15 on March 15th every 3rd year
                         $subscription_string = sprintf(__('%s on %s %s every %s year', 'woocommerce-subscriptions'), $price, $wp_locale->month[$payment_day['month']], WC_Subscriptions::append_numeral_suffix($payment_day['day']), WC_Subscriptions::append_numeral_suffix($billing_interval));
                     }
                     break;
             }
         } else {
             $subscription_string = sprintf(_n('%s / %s', ' %s every %s', $billing_interval, 'woocommerce-subscriptions'), $price, WC_Subscriptions_Manager::get_subscription_period_strings($billing_interval, $billing_period));
         }
     } elseif ($include['subscription_price']) {
         $subscription_string = $price;
     } elseif ($include['subscription_period']) {
         $subscription_string = sprintf(_n('%s', 'every %s', $billing_interval, 'woocommerce-subscriptions'), WC_Subscriptions_Manager::get_subscription_period_strings($billing_interval, $billing_period));
     }
     // Add the length to the end
     if ($include_length) {
         $subscription_string = sprintf(__('%s for %s', 'woocommerce-subscriptions'), $subscription_string, $ranges[$subscription_length]);
     }
     if ($include['trial_length'] && $trial_length != 0) {
         $trial_string = WC_Subscriptions_Manager::get_subscription_trial_period_strings($trial_length, $trial_period);
         $subscription_string = sprintf(__('%s with %s free trial', 'woocommerce-subscriptions'), $subscription_string, $trial_string);
     }
     if ($include['sign_up_fee'] && self::get_sign_up_fee($product) > 0) {
         $subscription_string = sprintf(__('%s and a %s sign-up fee', 'woocommerce-subscriptions'), $subscription_string, $sign_up_fee);
     }
     $subscription_string .= '</span>';
     return apply_filters('woocommerce_subscriptions_product_price_string', $subscription_string, $product, $include);
 }
 /**
  * Returns a string representing the details of the subscription.
  *
  * For example "$20 per Month for 3 Months with a $10 sign-up fee".
  *
  * @param WC_Product|int $product A WC_Product object or ID of a WC_Product.
  * @param array $inclusions An associative array of flags to indicate how to calculate the price and what to include, values:
  *			'tax_calculation'     => false to ignore tax, 'include_tax' or 'exclude_tax' To indicate that tax should be added or excluded respectively
  *			'subscription_length' => true to include subscription's length (default) or false to exclude it
  *			'sign_up_fee'         => true to include subscription's sign up fee (default) or false to exclude it
  *			'price'               => string a price to short-circuit the price calculations and use in a string for the product
  * @since 1.0
  */
 public static function get_price_string($product, $include = array())
 {
     global $wp_locale;
     if (!is_object($product)) {
         $product = WC_Subscriptions::get_product($product);
     }
     if (!self::is_subscription($product)) {
         return;
     }
     $include = wp_parse_args($include, array('tax_calculation' => get_option('woocommerce_tax_display_shop'), 'subscription_price' => true, 'subscription_period' => true, 'subscription_length' => true, 'sign_up_fee' => true, 'trial_length' => true));
     $include = apply_filters('woocommerce_subscriptions_product_price_string_inclusions', $include, $product);
     $base_price = self::get_price($product);
     if (true === $include['sign_up_fee']) {
         $sign_up_fee = self::get_sign_up_fee($product);
     } elseif (false !== $include['sign_up_fee']) {
         // Allow override of product's sign-up fee
         $sign_up_fee = $include['sign_up_fee'];
     } else {
         $sign_up_fee = 0;
     }
     if (false != $include['tax_calculation']) {
         if (in_array($include['tax_calculation'], array('exclude_tax', 'excl'))) {
             // Subtract Tax
             if (isset($include['price'])) {
                 $price = $include['price'];
             } else {
                 $price = $product->get_price_excluding_tax(1, $include['price']);
             }
             if (true === $include['sign_up_fee']) {
                 $sign_up_fee = self::get_sign_up_fee_excluding_tax($product);
             }
         } else {
             // Add Tax
             if (isset($include['price'])) {
                 $price = $include['price'];
             } else {
                 $price = $product->get_price_including_tax();
             }
             if (true === $include['sign_up_fee']) {
                 $sign_up_fee = self::get_sign_up_fee_including_tax($product);
             }
         }
     } else {
         if (isset($include['price'])) {
             $price = $include['price'];
         } else {
             $price = wc_price($base_price);
         }
     }
     $price .= ' <span class="subscription-details">';
     $billing_interval = self::get_interval($product);
     $billing_period = self::get_period($product);
     $subscription_length = self::get_length($product);
     $trial_length = self::get_trial_length($product);
     $trial_period = self::get_trial_period($product);
     if (is_numeric($sign_up_fee)) {
         $sign_up_fee = wc_price($sign_up_fee);
     }
     if ($include['subscription_length']) {
         $ranges = wcs_get_subscription_ranges($billing_period);
     }
     if ($include['subscription_length'] && 0 != $subscription_length) {
         $include_length = true;
     } else {
         $include_length = false;
     }
     $subscription_string = '';
     if ($include['subscription_price'] && $include['subscription_period']) {
         // Allow extensions to not show price or billing period e.g. Name Your Price
         if ($include_length && $subscription_length == $billing_interval) {
             $subscription_string = $price;
             // Only for one billing period so show "$5 for 3 months" instead of "$5 every 3 months for 3 months"
         } elseif (WC_Subscriptions_Synchroniser::is_product_synced($product) && in_array($billing_period, array('week', 'month', 'year'))) {
             $payment_day = WC_Subscriptions_Synchroniser::get_products_payment_day($product);
             switch ($billing_period) {
                 case 'week':
                     $payment_day_of_week = WC_Subscriptions_Synchroniser::get_weekday($payment_day);
                     if (1 == $billing_interval) {
                         // translators: 1$: recurring amount string, 2$: day of the week (e.g. "$10 every Wednesday")
                         $subscription_string = sprintf(__('%1$s every %2$s', 'woocommerce-subscriptions'), $price, $payment_day_of_week);
                     } else {
                         // translators: 1$: recurring amount string, 2$: period, 3$: day of the week (e.g. "$10 every 2nd week on Wednesday")
                         $subscription_string = sprintf(__('%1$s every %2$s on %3$s', 'woocommerce-subscriptions'), $price, wcs_get_subscription_period_strings($billing_interval, $billing_period), $payment_day_of_week);
                     }
                     break;
                 case 'month':
                     if (1 == $billing_interval) {
                         if ($payment_day > 27) {
                             // translators: placeholder is recurring amount
                             $subscription_string = sprintf(__('%s on the last day of each month', 'woocommerce-subscriptions'), $price);
                         } else {
                             // translators: 1$: recurring amount, 2$: day of the month (e.g. "23rd") (e.g. "$5 every 23rd of each month")
                             $subscription_string = sprintf(__('%1$s on the %2$s of each month', 'woocommerce-subscriptions'), $price, WC_Subscriptions::append_numeral_suffix($payment_day));
                         }
                     } else {
                         if ($payment_day > 27) {
                             // translators: 1$: recurring amount, 2$: interval (e.g. "3rd") (e.g. "$10 on the last day of every 3rd month")
                             $subscription_string = sprintf(__('%1$s on the last day of every %2$s month', 'woocommerce-subscriptions'), $price, WC_Subscriptions::append_numeral_suffix($billing_interval));
                         } else {
                             // translators: 1$: <price> on the, 2$: <date> day of every, 3$: <interval> month (e.g. "$10 on the 23rd day of every 2nd month")
                             $subscription_string = sprintf(__('%1$s on the %2$s day of every %3$s month', 'woocommerce-subscriptions'), $price, WC_Subscriptions::append_numeral_suffix($payment_day), WC_Subscriptions::append_numeral_suffix($billing_interval));
                         }
                     }
                     break;
                 case 'year':
                     if (1 == $billing_interval) {
                         // translators: 1$: <price> on, 2$: <date>, 3$: <month> each year (e.g. "$15 on March 15th each year")
                         $subscription_string = sprintf(__('%1$s on %2$s %3$s each year', 'woocommerce-subscriptions'), $price, $wp_locale->month[$payment_day['month']], WC_Subscriptions::append_numeral_suffix($payment_day['day']));
                     } else {
                         // translators: 1$: recurring amount, 2$: month (e.g. "March"), 3$: day of the month (e.g. "23rd") (e.g. "$15 on March 15th every 3rd year")
                         $subscription_string = sprintf(__('%1$s on %2$s %3$s every %4$s year', 'woocommerce-subscriptions'), $price, $wp_locale->month[$payment_day['month']], WC_Subscriptions::append_numeral_suffix($payment_day['day']), WC_Subscriptions::append_numeral_suffix($billing_interval));
                     }
                     break;
             }
         } else {
             // translators: 1$: recurring amount, 2$: subscription period (e.g. "month" or "3 months") (e.g. "$15 / month" or "$15 every 2nd month")
             $subscription_string = sprintf(_n('%1$s / %2$s', ' %1$s every %2$s', $billing_interval, 'woocommerce-subscriptions'), $price, wcs_get_subscription_period_strings($billing_interval, $billing_period));
         }
     } elseif ($include['subscription_price']) {
         $subscription_string = $price;
     } elseif ($include['subscription_period']) {
         // translators: billing period (e.g. "every week")
         $subscription_string = sprintf(__('every %s', 'woocommerce-subscriptions'), wcs_get_subscription_period_strings($billing_interval, $billing_period));
     }
     // Add the length to the end
     if ($include_length) {
         // translators: 1$: subscription string (e.g. "$10 up front then $5 on March 23rd every 3rd year"), 2$: length (e.g. "4 years")
         $subscription_string = sprintf(__('%1$s for %2$s', 'woocommerce-subscriptions'), $subscription_string, $ranges[$subscription_length]);
     }
     if ($include['trial_length'] && 0 != $trial_length) {
         $trial_string = wcs_get_subscription_trial_period_strings($trial_length, $trial_period);
         // translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years"), 2$: trial length (e.g.: "with 4 months free trial")
         $subscription_string = sprintf(__('%1$s with %2$s free trial', 'woocommerce-subscriptions'), $subscription_string, $trial_string);
     }
     if ($include['sign_up_fee'] && self::get_sign_up_fee($product) > 0) {
         // translators: 1$: subscription string (e.g. "$15 on March 15th every 3 years for 6 years with 2 months free trial"), 2$: signup fee price (e.g. "and a $30 sign-up fee")
         $subscription_string = sprintf(__('%1$s and a %2$s sign-up fee', 'woocommerce-subscriptions'), $subscription_string, $sign_up_fee);
     }
     $subscription_string .= '</span>';
     return apply_filters('woocommerce_subscriptions_product_price_string', $subscription_string, $product, $include);
 }
 /**
  * Records the initial payment against a subscription.
  *
  * This function is called when an orders status is changed to completed or processing
  * for those gateways which never call @see WC_Order::payment_complete(), like the core
  * WooCommerce Cheque and Bank Transfer gateways.
  *
  * It will also set the start date on the subscription to the time the payment is completed.
  *
  * @param $order_id int|WC_Order
  * @param $old_order_status
  * @param $new_order_status
  * @since 2.0
  */
 public static function maybe_record_subscription_payment($order_id, $old_order_status, $new_order_status)
 {
     if (wcs_order_contains_subscription($order_id)) {
         $subscriptions = wcs_get_subscriptions_for_order($order_id);
         $was_activated = false;
         $order_completed = in_array($new_order_status, array(apply_filters('woocommerce_payment_complete_order_status', 'processing', $order_id), 'processing', 'completed')) && in_array($old_order_status, apply_filters('woocommerce_valid_order_statuses_for_payment', array('pending', 'on-hold', 'failed')));
         foreach ($subscriptions as $subscription) {
             // Do we need to activate a subscription?
             if ($order_completed && !$subscription->has_status(wcs_get_subscription_ended_statuses()) && !$subscription->has_status('active')) {
                 $new_start_date_offset = current_time('timestamp', true) - $subscription->get_time('start');
                 $dates = array('start' => current_time('mysql', true));
                 if (0 != $subscription->get_time('trial_end')) {
                     $dates['trial_end'] = gmdate('Y-m-d H:i:s', $subscription->get_time('trial_end') + $new_start_date_offset);
                 }
                 if (0 != $subscription->get_time('next_payment')) {
                     if (WC_Subscriptions_Synchroniser::subscription_contains_synced_product($subscription)) {
                         $prior_date = isset($dates['trial_end']) ? $dates['trial_end'] : $dates['start'];
                         if ($subscription->get_time('next_payment') < strtotime($prior_date)) {
                             foreach ($subscription->get_items() as $item) {
                                 $product_id = wcs_get_canonical_product_id($item);
                                 if (WC_Subscriptions_Synchroniser::is_product_synced($product_id)) {
                                     $dates['next_payment'] = WC_Subscriptions_Synchroniser::calculate_first_payment_date($product_id);
                                     break;
                                 }
                             }
                         }
                     } else {
                         $dates['next_payment'] = gmdate('Y-m-d H:i:s', $subscription->get_time('next_payment') + $new_start_date_offset);
                     }
                 }
                 if (0 != $subscription->get_time('end')) {
                     $dates['end'] = gmdate('Y-m-d H:i:s', $subscription->get_time('end') + $new_start_date_offset);
                 }
                 $subscription->update_dates($dates);
                 $subscription->payment_complete();
                 $was_activated = true;
             } elseif ('failed' == $new_order_status) {
                 $subscription->payment_failed();
             }
         }
         if ($was_activated) {
             do_action('subscriptions_activated_for_order', $order_id);
         }
     }
 }
 /**
  * Records the initial payment against a subscription.
  *
  * This function is called when an orders status is changed to completed or processing
  * for those gateways which never call @see WC_Order::payment_complete(), like the core
  * WooCommerce Cheque and Bank Transfer gateways.
  *
  * It will also set the start date on the subscription to the time the payment is completed.
  *
  * @param $order_id int|WC_Order
  * @param $old_order_status
  * @param $new_order_status
  * @since 2.0
  */
 public static function maybe_record_subscription_payment($order_id, $old_order_status, $new_order_status)
 {
     if (wcs_order_contains_subscription($order_id)) {
         $subscriptions = wcs_get_subscriptions_for_order($order_id);
         $was_activated = false;
         $order_completed = in_array($new_order_status, array(apply_filters('woocommerce_payment_complete_order_status', 'processing', $order_id), 'processing', 'completed')) && in_array($old_order_status, apply_filters('woocommerce_valid_order_statuses_for_payment', array('pending', 'on-hold', 'failed')));
         foreach ($subscriptions as $subscription) {
             // Do we need to activate a subscription?
             if ($order_completed && !$subscription->has_status(wcs_get_subscription_ended_statuses()) && !$subscription->has_status('active')) {
                 $new_start_date_offset = current_time('timestamp', true) - $subscription->get_time('start');
                 // if the payment has been processed more than an hour after the order was first created, let's update the dates on the subscription to account for that, because it may have even been processed days after it was first placed
                 if ($new_start_date_offset > HOUR_IN_SECONDS) {
                     $dates = array('start' => current_time('mysql', true));
                     if (WC_Subscriptions_Synchroniser::subscription_contains_synced_product($subscription)) {
                         $trial_end = $subscription->get_time('trial_end');
                         $next_payment = $subscription->get_time('next_payment');
                         // if either there is a free trial date or a next payment date that falls before now, we need to recalculate all the sync'd dates
                         if ($trial_end > 0 && $trial_end < strtotime($dates['start']) || $next_payment > 0 && $next_payment < strtotime($dates['start'])) {
                             foreach ($subscription->get_items() as $item) {
                                 $product_id = wcs_get_canonical_product_id($item);
                                 if (WC_Subscriptions_Synchroniser::is_product_synced($product_id)) {
                                     $dates['trial_end'] = WC_Subscriptions_Product::get_trial_expiration_date($product_id, $dates['start']);
                                     $dates['next_payment'] = WC_Subscriptions_Synchroniser::calculate_first_payment_date($product_id, 'mysql', $dates['start']);
                                     $dates['end'] = WC_Subscriptions_Product::get_expiration_date($product_id, $dates['start']);
                                     break;
                                 }
                             }
                         }
                     } else {
                         // No sync'ing to mess about with, just add the offset to the existing dates
                         foreach (array('trial_end', 'next_payment', 'end') as $date_type) {
                             if (0 != $subscription->get_time($date_type)) {
                                 $dates[$date_type] = gmdate('Y-m-d H:i:s', $subscription->get_time($date_type) + $new_start_date_offset);
                             }
                         }
                     }
                     $subscription->update_dates($dates);
                 }
                 $subscription->payment_complete();
                 $was_activated = true;
             } elseif ('failed' == $new_order_status) {
                 $subscription->payment_failed();
             }
         }
         if ($was_activated) {
             do_action('subscriptions_activated_for_order', $order_id);
         }
     }
 }