/**
  * @param WC_Subscription $wc_subscription
  * @param string          $new_status
  **/
 public function filter_pre_cancelled_status($wc_subscription, $new_status)
 {
     if ('pending-cancel' === $new_status) {
         $wc_subscription->update_status('cancelled');
     }
 }
/**
 * Checks if the user can be granted the permission to remove a line item from the subscription.
 *
 * @param WC_Subscription $subscription An instance of a WC_Subscription object
 * @since 2.0
 */
function wcs_can_items_be_removed($subscription)
{
    $allow_remove = false;
    if (sizeof($subscription->get_items()) > 1 && $subscription->payment_method_supports('subscription_amount_changes') && $subscription->has_status(array('active', 'on-hold', 'pending'))) {
        $allow_remove = true;
    }
    return apply_filters('wcs_can_items_be_removed', $allow_remove, $subscription);
}
 /**
  * Make sure the sign-up fee on a subscription line item takes into account sign-up fees paid for switching.
  *
  * @param WC_Subscription $subscription
  * @return array $cart_item Details of an item in WC_Cart for a switch
  * @since 2.0
  */
 public static function subscription_items_sign_up_fee($sign_up_fee, $line_item, $subscription)
 {
     // This item has never been switched, no need to add anything
     if (!isset($line_item['switched_subscription_item_id'])) {
         return $sign_up_fee;
     }
     // First add any sign-up fees for previously switched items
     $switched_line_items = $subscription->get_items('line_item_switched');
     foreach ($switched_line_items as $switched_line_item_id => $switched_line_item) {
         if ($line_item['switched_subscription_item_id'] == $switched_line_item_id) {
             $sign_up_fee += $subscription->get_items_sign_up_fee($switched_line_item);
             // Recursion: get the sign up fee for this item's old item and the sign up fee for that item's old item and the sign up fee for that item's old item and the sign up fee for that item's old item ...
             break;
             // Each item can only be switched once
         }
     }
     // Now add any sign-up fees paid in switch orders
     foreach (wcs_get_switch_orders_for_subscription($subscription->id) as $order) {
         foreach ($order->get_items() as $order_item_id => $order_item) {
             if (wcs_get_canonical_product_id($line_item) == wcs_get_canonical_product_id($order_item)) {
                 // We only want to add the amount of the line total which was for a prorated sign-up fee, not the amount for a prorated recurring amount
                 if (isset($order_item['switched_subscription_sign_up_fee_prorated'])) {
                     if ($order_item['switched_subscription_sign_up_fee_prorated'] > 0) {
                         $sign_up_proportion = $order_item['switched_subscription_sign_up_fee_prorated'] / ($order_item['switched_subscription_price_prorated'] + $order_item['switched_subscription_sign_up_fee_prorated']);
                     } else {
                         $sign_up_proportion = 0;
                     }
                 } else {
                     $sign_up_proportion = 1;
                 }
                 $sign_up_fee += round($order_item['line_total'] * $sign_up_proportion, 2);
             }
         }
     }
     return $sign_up_fee;
 }
 /**
  * Render the payment method used for a subscription in the "My Subscriptions" table
  *
  * @since 4.1.0
  * @param string $payment_method_to_display the default payment method text to display
  * @param \WC_Subscription $subscription
  * @return string the subscription payment method
  */
 public function maybe_render_payment_method($payment_method_to_display, $subscription)
 {
     // bail for other payment methods
     if ($this->get_gateway()->get_id() !== $subscription->payment_method) {
         return $payment_method_to_display;
     }
     $token = $this->get_gateway()->get_payment_token($subscription->get_user_id(), $this->get_gateway()->get_order_meta($subscription->id, 'payment_token'));
     if ($token instanceof SV_WC_Payment_Gateway_Payment_Token) {
         $payment_method_to_display = sprintf(_x('Via %s ending in %s', 'Supports direct payment method subscriptions', $this->get_gateway()->get_text_domain()), $token->get_type_full(), $token->get_last_four());
     }
     return $payment_method_to_display;
 }
 /**
  * Stores shipping info on the subscription
  *
  * @param WC_Subscription $subscription instance of a subscriptions object
  * @param WC_Cart $cart A cart with recurring items in it
  */
 public static function add_shipping($subscription, $cart)
 {
     // We need to make sure we only get recurring shipping packages
     WC_Subscriptions_Cart::set_calculation_type('recurring_total');
     foreach ($cart->get_shipping_packages() as $package_index => $base_package) {
         $package = WC_Subscriptions_Cart::get_calculated_shipping_for_package($base_package);
         $recurring_shipping_package_key = WC_Subscriptions_Cart::get_recurring_shipping_package_key($cart->recurring_cart_key, $package_index);
         $shipping_method_id = isset(WC()->checkout()->shipping_methods[$package_index]) ? WC()->checkout()->shipping_methods[$package_index] : '';
         if (isset(WC()->checkout()->shipping_methods[$recurring_shipping_package_key])) {
             $shipping_method_id = WC()->checkout()->shipping_methods[$recurring_shipping_package_key];
             $package_key = $recurring_shipping_package_key;
         } else {
             $package_key = $package_index;
         }
         if (isset($package['rates'][$shipping_method_id])) {
             $item_id = $subscription->add_shipping($package['rates'][$shipping_method_id]);
             if (!$item_id) {
                 throw new Exception(__('Error: Unable to create subscription. Please try again.', 'woocommerce-subscriptions'));
             }
             // Allows plugins to add order item meta to shipping
             do_action('woocommerce_add_shipping_order_item', $subscription->id, $item_id, $package_key);
             do_action('woocommerce_subscriptions_add_recurring_shipping_order_item', $subscription->id, $item_id, $package_key);
         }
     }
     WC_Subscriptions_Cart::set_calculation_type('none');
 }
 /**
  * Render the payment method used for a subscription in the "My Subscriptions" table
  *
  * @since 4.1.0
  * @param string $payment_method_to_display the default payment method text to display
  * @param \WC_Subscription $subscription
  * @return string the subscription payment method
  */
 public function maybe_render_payment_method($payment_method_to_display, $subscription)
 {
     // bail for other payment methods
     if ($this->get_gateway()->get_id() !== $subscription->payment_method) {
         return $payment_method_to_display;
     }
     $token = $this->get_gateway()->get_payment_tokens_handler()->get_token($subscription->get_user_id(), $this->get_gateway()->get_order_meta($subscription->id, 'payment_token'));
     if ($token instanceof SV_WC_Payment_Gateway_Payment_Token) {
         $payment_method_to_display = sprintf(__('Via %s ending in %s', 'woocommerce-plugin-framework'), $token->get_type_full(), $token->get_last_four());
     }
     return $payment_method_to_display;
 }
 /**
  * If the subscription has expired since upgrading and the end date is not the original expiration date,
  * we need to unexpire it, which in the case of a previously active subscription means activate it, and
  * in any other case, leave it as on-hold (a cancelled subscription wouldn't have been expired, so the
  * status must be on-hold or active).
  *
  * @param  WC_Subscription $subscription data about the subscription
  * @return bool true if the trial date was repaired, otherwise false
  */
 protected static function maybe_repair_status($subscription, $former_order_item_meta, $dates_to_update)
 {
     if ($subscription->has_status('expired') && 'expired' != $former_order_item_meta['_wcs_migrated_subscription_status'][0] && isset($dates_to_update['end'])) {
         try {
             // we need to bypass the update_status() method here because normally an expired subscription can't have it's status changed, we also don't want normal status change hooks to be fired
             wp_update_post(array('ID' => $subscription->id, 'post_status' => 'wc-on-hold'));
             // if the payment method doesn't support date changes, we still want to reactivate the subscription but we also need to process a special failed payment at the next renewal to fix up the payment method so we'll set a special flag in post meta to handle that
             if (!$subscription->payment_method_supports('subscription_date_changes') && $subscription->get_total() > 0) {
                 update_post_meta($subscription->id, '_wcs_repaired_2_0_2_needs_failed_payment', 'true');
                 WCS_Upgrade_Logger::add(sprintf('For subscription %d: payment method does not support "subscription_date_changes" and total > 0, setting "_wcs_repaired_2_0_2_needs_failed_payment" post meta flag.', $subscription->id));
             }
             if ('active' == $former_order_item_meta['_wcs_migrated_subscription_status'][0] && $subscription->can_be_updated_to('active')) {
                 $subscription->update_status('active');
             }
             WCS_Upgrade_Logger::add(sprintf('For subscription %d: repaired status. Status was "expired", it is now "%s".', $subscription->id, $subscription->get_status()));
             $repair_status = true;
         } catch (Exception $e) {
             WCS_Upgrade_Logger::add(sprintf('!!! For subscription %d: unable to repair status, exception "%s"', $subscription->id, $e->getMessage()));
             $repair_status = false;
         }
     } else {
         WCS_Upgrade_Logger::add(sprintf('For subscription %d: no need to repair status, current status: %s; former status: %s.', $subscription->id, $subscription->get_status(), $former_order_item_meta['_wcs_migrated_subscription_status'][0]));
         $repair_status = false;
     }
     return $repair_status;
 }
/**
 * Return an associative array of a given subscriptions details (if it exists) in the pre v2.0 data structure.
 *
 * @param WC_Subscription $subscription An instance of WC_Subscription
 * @return array Subscription details
 * @since 2.0
 */
function wcs_get_subscription_in_deprecated_structure(WC_Subscription $subscription)
{
    $completed_payments = array();
    if ($subscription->get_completed_payment_count()) {
        if (!empty($subscription->order) && $subscription->order->has_status($subscription->get_paid_order_statuses())) {
            $completed_payments[] = $subscription->order->post->post_date_gmt;
        }
        $paid_renewal_order_ids = get_posts(array('posts_per_page' => -1, 'post_status' => $subscription->get_paid_order_statuses(), 'post_type' => 'shop_order', 'orderby' => 'date', 'order' => 'desc', 'fields' => 'ids', 'meta_query' => array(array('key' => '_subscription_renewal', 'compare' => '=', 'value' => $subscription->id, 'type' => 'numeric'))));
        foreach ($paid_renewal_order_ids as $paid_renewal_order_id) {
            $completed_payments[] = get_post_field('post_date_gmt', $paid_renewal_order_id);
        }
    }
    $items = $subscription->get_items();
    $item = array_pop($items);
    if (!empty($item)) {
        $deprecated_subscription_object = array('order_id' => $subscription->order->id, 'product_id' => isset($item['product_id']) ? $item['product_id'] : 0, 'variation_id' => isset($item['variation_id']) ? $item['variation_id'] : 0, 'status' => $subscription->get_status(), 'period' => $subscription->billing_period, 'interval' => $subscription->billing_interval, 'length' => wcs_estimate_periods_between(0 == $subscription->get_time('trial_end') ? $subscription->get_time('start') : $subscription->get_time('trial_end'), $subscription->get_time('end') + 120, $subscription->billing_period, 'floor') / $subscription->billing_interval, 'start_date' => $subscription->get_date('start'), 'expiry_date' => $subscription->get_date('end'), 'end_date' => $subscription->has_status(wcs_get_subscription_ended_statuses()) ? $subscription->get_date('end') : 0, 'trial_expiry_date' => $subscription->get_date('trial_end'), 'failed_payments' => $subscription->failed_payment_count, 'completed_payments' => $completed_payments, 'suspension_count' => $subscription->suspension_count, 'last_payment_date' => $subscription->get_date('last_payment'));
    } else {
        $deprecated_subscription_object = array();
    }
    return $deprecated_subscription_object;
}
 /**
  * Stores shipping info on the subscription
  *
  * @param WC_Subscription $subscription instance of a subscriptions object
  * @param WC_Cart $cart A cart with recurring items in it
  */
 public static function add_shipping($subscription, $cart)
 {
     foreach ($cart->get_shipping_packages() as $base_package) {
         $package = WC()->shipping->calculate_shipping_for_package($base_package);
         foreach (WC()->shipping->get_packages() as $package_key => $package_to_ignore) {
             if (isset($package['rates'][WC()->checkout()->shipping_methods[$package_key]])) {
                 $item_id = $subscription->add_shipping($package['rates'][WC()->checkout()->shipping_methods[$package_key]]);
                 if (!$item_id) {
                     throw new Exception(__('Error: Unable to create subscription. Please try again.', 'woocommerce-subscriptions'));
                 }
                 // Allows plugins to add order item meta to shipping
                 do_action('woocommerce_add_shipping_order_item', $subscription->id, $item_id, $package_key);
                 do_action('woocommerce_subscriptions_add_recurring_shipping_order_item', $subscription->id, $item_id, $package_key);
             }
         }
     }
 }
 /**
  * Handles subscriptions put on hold; does the same thing as for
  * cancelled subscriptions; keep as separate implementations though.
  * 
  * @param WC_Subscription $subscription
  * @since 1.9.0
  */
 private static function subscription_status_on_hold($subscription)
 {
     if (!empty($subscription->order)) {
         $order_id = $subscription->order->id;
     } else {
         $order_id = $subscription->id;
     }
     $user_id = $subscription->user_id;
     $items = $subscription->get_items();
     foreach ($items as $item) {
         $product_id = $item['product_id'];
         $groups_product_groups = get_user_meta($user_id, '_groups_product_groups', true);
         if (isset($groups_product_groups[$order_id]) && isset($groups_product_groups[$order_id][$product_id]) && isset($groups_product_groups[$order_id][$product_id]['groups'])) {
             foreach ($groups_product_groups[$order_id][$product_id]['groups'] as $group_id) {
                 self::maybe_delete($user_id, $group_id, $order_id);
             }
         }
     }
 }
 /**
  * Make sure the sign-up fee on a subscription line item takes into account sign-up fees paid for switching.
  *
  * @param WC_Subscription $subscription
  * @param string $tax_inclusive_or_exclusive Defaults to the value tax setting stored on the subscription.
  * @return array $cart_item Details of an item in WC_Cart for a switch
  * @since 2.0
  */
 public static function subscription_items_sign_up_fee($sign_up_fee, $line_item, $subscription, $tax_inclusive_or_exclusive = '')
 {
     // This item has never been switched, no need to add anything
     if (!isset($line_item['switched_subscription_item_id'])) {
         return $sign_up_fee;
     }
     // First add any sign-up fees for previously switched items
     $switched_line_items = $subscription->get_items('line_item_switched');
     // Default tax inclusive or exclusive to the value set on the subscription. This is for backwards compatibility
     if (empty($tax_inclusive_or_exclusive)) {
         $tax_inclusive_or_exclusive = 'yes' == $subscription->prices_include_tax ? 'inclusive_of_tax' : 'exclusive_of_tax';
     }
     foreach ($switched_line_items as $switched_line_item_id => $switched_line_item) {
         if ($line_item['switched_subscription_item_id'] == $switched_line_item_id) {
             $sign_up_fee += $subscription->get_items_sign_up_fee($switched_line_item, $tax_inclusive_or_exclusive);
             // Recursion: get the sign up fee for this item's old item and the sign up fee for that item's old item and the sign up fee for that item's old item and the sign up fee for that item's old item ...
             break;
             // Each item can only be switched once
         }
     }
     // Now add any sign-up fees paid in switch orders
     foreach (wcs_get_switch_orders_for_subscription($subscription->id) as $order) {
         foreach ($order->get_items() as $order_item_id => $order_item) {
             if (wcs_get_canonical_product_id($line_item) == wcs_get_canonical_product_id($order_item)) {
                 // We only want to add the amount of the line total which was for a prorated sign-up fee, not the amount for a prorated recurring amount
                 if (isset($order_item['switched_subscription_sign_up_fee_prorated'])) {
                     if ($order_item['switched_subscription_sign_up_fee_prorated'] > 0) {
                         $sign_up_proportion = $order_item['switched_subscription_sign_up_fee_prorated'] / ($order_item['switched_subscription_price_prorated'] + $order_item['switched_subscription_sign_up_fee_prorated']);
                     } else {
                         $sign_up_proportion = 0;
                     }
                 } else {
                     $sign_up_proportion = 1;
                 }
                 $order_total = $order_item['line_total'];
                 if ('inclusive_of_tax' == $tax_inclusive_or_exclusive && 'yes' == $order->prices_include_tax) {
                     $order_total += $order_item['line_tax'];
                 }
                 $sign_up_fee += round($order_total * $sign_up_proportion, 2);
             }
         }
     }
     return $sign_up_fee;
 }
 /**
  * Function to manage payment method for renewal orders based on availability of store credit (WCS 2.0+)
  *
  * @param WC_Subscription $subscription
  * @return WC_Subscription $subscription
  */
 public function sc_wcs_modify_subscription($subscription = null)
 {
     if (!empty($subscription) && $subscription instanceof WC_Subscription) {
         $pay_from_credit_of_original_order = get_option('pay_from_smart_coupon_of_original_order', 'yes');
         if ($pay_from_credit_of_original_order != 'yes') {
             return $subscription;
         }
         $original_order_id = !empty($subscription->order->id) ? $subscription->order->id : 0;
         if (empty($original_order_id)) {
             return $subscription;
         }
         $renewal_total = $subscription->get_total();
         $original_order = $this->get_order($original_order_id);
         $coupon_used_in_original_order = $original_order->get_used_coupons();
         if (sizeof($coupon_used_in_original_order) > 0) {
             foreach ($coupon_used_in_original_order as $coupon_code) {
                 $coupon = new WC_Coupon($coupon_code);
                 if (!empty($coupon->discount_type) && $coupon->discount_type == 'smart_coupon' && !empty($coupon->amount)) {
                     if ($coupon->amount >= $renewal_total) {
                         $subscription->set_payment_method('');
                     } else {
                         $payment_gateways = $this->global_wc()->payment_gateways->get_available_payment_gateways();
                         if (!empty($payment_gateways[$original_order->payment_method])) {
                             $payment_method = $payment_gateways[$original_order->payment_method];
                             $subscription->set_payment_method($payment_method);
                         }
                     }
                 }
             }
         }
     }
     return $subscription;
 }
 /**
  * Validate the incoming request to either remove an item or add and item back to a subscription that was previously removed.
  * Add an descriptive notice to the page whether or not the request was validated or not.
  *
  * @since 2.0
  * @param WC_Subscription $subscription
  * @param int $order_item_id
  * @param bool $undo_request bool
  * @return bool
  */
 private static function validate_remove_items_request($subscription, $order_item_id, $undo_request = false)
 {
     $subscription_items = $subscription->get_items();
     $response = false;
     if (!wp_verify_nonce($_GET['_wpnonce'], $_GET['subscription_id'])) {
         wc_add_notice(__('Security error. Please contact us if you need assistance.', 'woocommerce-subscriptions'), 'error');
     } elseif (!current_user_can('edit_shop_subscription_line_items', $subscription->id)) {
         wc_add_notice(__('You cannot modify a subscription that does not belong to you.', 'woocommerce-subscriptions'), 'error');
     } elseif (!$undo_request && !isset($subscription_items[$order_item_id])) {
         // only need to validate the order item id when removing
         wc_add_notice(__('You cannot remove an item that does not exist. ', 'woocommerce-subscriptions'), 'error');
     } elseif (!$subscription->payment_method_supports('subscription_amount_changes')) {
         wc_add_notice(__('The item was not removed because this Subscription\'s payment method does not support removing an item.', 'woocommerce-subscriptions'));
     } else {
         $response = true;
     }
     return $response;
 }