/**
  * Find all subscription with a given billing agreement ID and cancel them becasue that billing agreement has been
  * cancelled at PayPal, and therefore, no future payments can be charged.
  *
  * @since 2.0
  */
 protected function cancel_subscriptions($billing_agreement_id)
 {
     $subscription_ids = get_posts(array('posts_per_page' => -1, 'post_type' => 'shop_subscription', 'post_status' => 'any', 'fields' => 'ids', 'orderby' => 'date', 'order' => 'DESC', 'meta_query' => array(array('key' => '_paypal_subscription_id', 'compare' => '=', 'value' => $billing_agreement_id))));
     if (empty($subscription_ids)) {
         return;
     }
     $note = esc_html__('Billing agreement cancelled at PayPal.', 'woocommerce-subscriptions');
     foreach ($subscription_ids as $subscription_id) {
         $subscription = wcs_get_subscription($subscription_id);
         try {
             if (false !== $subscription && !$subscription->has_status(wcs_get_subscription_ended_statuses())) {
                 $subscription->cancel_order($note);
                 WC_Gateway_Paypal::log(sprintf('Subscription %s Cancelled: %s', $subscription_id, $note));
             }
         } catch (Exception $e) {
             WC_Gateway_Paypal::log(sprintf('Unable to cancel subscription %s: %s', $subscription_id, $e->getMessage()));
         }
     }
 }
 /**
  * Whenever a renewal order's status is changed, check if a corresponding subscription's status should be changed
  *
  * This function is hooked to 'woocommerce_order_status_changed', rather than 'woocommerce_payment_complete', to ensure
  * subscriptions are updated even if payment is processed by a manual payment gateways (which would never trigger the
  * 'woocommerce_payment_complete' hook) or by some other means that circumvents that hook.
  *
  * @since 2.0
  */
 public static function maybe_record_subscription_payment($order_id, $orders_old_status, $orders_new_status)
 {
     if (!wcs_order_contains_renewal($order_id)) {
         return;
     }
     $subscriptions = wcs_get_subscriptions_for_renewal_order($order_id);
     $was_activated = false;
     $order_completed = in_array($orders_new_status, array(apply_filters('woocommerce_payment_complete_order_status', 'processing', $order_id), 'processing', 'completed'));
     $order_needed_payment = in_array($orders_old_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')) {
             if ($order_needed_payment) {
                 $subscription->payment_complete();
                 $was_activated = true;
             }
             if ('failed' === $orders_old_status) {
                 do_action('woocommerce_subscriptions_paid_for_failed_renewal_order', wc_get_order($order_id), $subscription);
             }
         } elseif ('failed' == $orders_new_status) {
             $subscription->payment_failed();
         }
     }
     if ($was_activated) {
         do_action('subscriptions_activated_for_order', $order_id);
     }
 }
 /**
  * Marks all the subscriptions in an order as expired
  *
  * @param WC_Order|int $order The order or ID of the order for which subscriptions should be marked as expired.
  * @since 1.0
  */
 public static function expire_subscriptions_for_order($order)
 {
     $subscriptions = wcs_get_subscriptions_for_order($order);
     if (!empty($subscriptions)) {
         foreach ($subscriptions as $subscription) {
             try {
                 if (!$subscription->has_status(wcs_get_subscription_ended_statuses())) {
                     $subscription->update_status('expired');
                 }
             } catch (Exception $e) {
                 // translators: $1: order number, $2: error message
                 $subscription->add_order_note(sprintf(__('Failed to set subscription as expired for order #%1$s: %2$s', 'woocommerce-subscriptions'), is_object($order) ? $order->get_order_number() : $order, $e->getMessage()));
             }
         }
         do_action('subscriptions_expired_for_order', $order);
     }
 }
 /**
  * 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);
         }
     }
 }
 /**
  * Check if a given date type can be updated for this subscription.
  *
  * @param string $date_type 'start', 'trial_end', 'next_payment', 'last_payment' or 'end'
  */
 public function can_date_be_updated($date_type)
 {
     switch ($date_type) {
         case 'start':
             if ($this->has_status(array('auto-draft', 'pending'))) {
                 $can_date_be_updated = true;
             } else {
                 $can_date_be_updated = false;
             }
             break;
         case 'trial_end':
             if ($this->get_completed_payment_count() < 2 && !$this->has_status(wcs_get_subscription_ended_statuses()) && ($this->has_status('pending') || $this->payment_method_supports('subscription_date_changes'))) {
                 $can_date_be_updated = true;
             } else {
                 $can_date_be_updated = false;
             }
             break;
         case 'next_payment':
         case 'end':
             if (!$this->has_status(wcs_get_subscription_ended_statuses()) && ($this->has_status('pending') || $this->payment_method_supports('subscription_date_changes'))) {
                 $can_date_be_updated = true;
             } else {
                 $can_date_be_updated = false;
             }
             break;
         case 'last_payment':
             $can_date_be_updated = true;
             break;
         default:
             $can_date_be_updated = false;
             break;
     }
     return apply_filters('woocommerce_subscription_can_date_be_updated', $can_date_be_updated, $date_type, $this);
 }
 /**
  * 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);
         }
     }
 }
 /**
  * Adds actions to the admin edit subscriptions page, if the subscription hasn't ended and the payment method supports them.
  *
  * @param array $actions An array of available actions
  * @return array An array of updated actions
  * @since 2.0
  */
 public static function add_subscription_actions($actions)
 {
     global $theorder;
     if (wcs_is_subscription($theorder) && !$theorder->has_status(wcs_get_subscription_ended_statuses())) {
         if ($theorder->payment_method_supports('subscription_date_changes') && $theorder->has_status('active')) {
             $actions['wcs_process_renewal'] = esc_html__('Process renewal', 'woocommerce-subscriptions');
         }
         $actions['wcs_create_pending_renewal'] = esc_html__('Create pending renewal order', 'woocommerce-subscriptions');
     }
     return $actions;
 }
/**
 * 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;
}
 /**
  * Make sure a subscription is cancelled before it is trashed or deleted
  *
  * @param int $post_id
  * @since 2.0
  */
 public static function maybe_cancel_subscription($post_id)
 {
     if ('shop_subscription' == get_post_type($post_id)) {
         $subscription = wcs_get_subscription($post_id);
         if (!$subscription->has_status(wcs_get_subscription_ended_statuses())) {
             $subscription->update_status('cancelled');
         }
     }
 }
 /**
  * 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')) {
                 $subscription->update_dates(array('start' => current_time('mysql', true)));
                 $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);
         }
     }
 }