public function test_unschedule()
 {
     $time = time();
     $hook = md5(rand());
     $action_id = wc_schedule_single_action($time, $hook);
     wc_unschedule_action($hook);
     $next = wc_next_scheduled_action($hook);
     $this->assertFalse($next);
     $store = ActionScheduler::store();
     $action = $store->fetch_action($action_id);
     $this->assertNull($action->get_schedule()->next());
     $this->assertEmpty($action->get_hook());
 }
 /**
  * When an order is added or updated from the admin interface, check if a subscription product
  * has been manually added to the order or the details of the subscription have been modified,
  * and create/update the subscription as required.
  *
  * Save subscription order meta items
  *
  * @param int $post_id The ID of the post which is the WC_Order object.
  * @param Object $post The post object of the order.
  * @since 1.1
  */
 public static function pre_process_shop_order_meta($post_id, $post)
 {
     global $woocommerce, $wpdb;
     $order_contains_subscription = false;
     $order = new WC_Order($post_id);
     $existing_product_ids = array();
     foreach ($order->get_items() as $existing_item) {
         $existing_product_ids[] = self::get_items_product_id($existing_item);
     }
     $product_ids = array();
     if (isset($_POST['order_item_id'])) {
         foreach ($_POST['order_item_id'] as $order_item_id) {
             $product_ids[$order_item_id] = woocommerce_get_order_item_meta($order_item_id, '_product_id');
         }
     }
     // Check if there are new subscription products to be added, or the order already has a subscription item
     foreach (array_merge($product_ids, $existing_product_ids) as $order_item_id => $product_id) {
         $is_existing_item = false;
         if (in_array($product_id, $existing_product_ids)) {
             $is_existing_item = true;
         }
         // If this is a new item and it's a subscription product, we have a subscription
         if (!$is_existing_item && WC_Subscriptions_Product::is_subscription($product_id)) {
             $order_contains_subscription = true;
         }
         // If this is an existing item and it's a subscription item, we have a subscription
         if ($is_existing_item && self::is_item_subscription($order, $product_id)) {
             $order_contains_subscription = true;
         }
     }
     if (!$order_contains_subscription) {
         return $post_id;
     }
     $existing_payment_method = get_post_meta($post_id, '_recurring_payment_method', true);
     $chosen_payment_method = isset($_POST['_recurring_payment_method']) ? stripslashes($_POST['_recurring_payment_method']) : '';
     // For subscriptions manually added using paypal, make sure the _paypal_first_ipn_ignored_for_pdt is set so that IPN notifications are never ignored
     if (isset($_POST['_payment_method']) && 'paypal' == $_POST['_payment_method'] && 'true' != get_post_meta($post_id, '_paypal_first_ipn_ignored_for_pdt', true)) {
         update_post_meta($post_id, '_paypal_first_ipn_ignored_for_pdt', 'true');
     }
     // If the recurring payment method is changing, or it isn't set make sure we have correct manual payment flag set
     if (isset($_POST['_recurring_payment_method']) || empty($existing_payment_method) && ($chosen_payment_method != $existing_payment_method || empty($chosen_payment_method))) {
         $payment_gateways = $woocommerce->payment_gateways->payment_gateways();
         // Make sure the subscription is cancelled with the current gateway
         if (!empty($existing_payment_method) && isset($payment_gateways[$existing_payment_method]) && $payment_gateways[$existing_payment_method]->supports('subscriptions')) {
             foreach ($product_ids as $product_id) {
                 WC_Subscriptions_Payment_Gateways::trigger_gateway_cancelled_subscription_hook(absint($_POST['customer_user']), WC_Subscriptions_Manager::get_subscription_key($post_id, $product_id));
             }
         }
         if (!empty($chosen_payment_method) && isset($payment_gateways[$chosen_payment_method]) && $payment_gateways[$chosen_payment_method]->supports('subscriptions')) {
             $manual_renewal = 'false';
         } else {
             $manual_renewal = 'true';
         }
         update_post_meta($post_id, '_wcs_requires_manual_renewal', $manual_renewal);
         if (!empty($chosen_payment_method)) {
             update_post_meta($post_id, '_recurring_payment_method', stripslashes($_POST['_recurring_payment_method']));
         }
     }
     // Make sure the recurring order totals are correct
     update_post_meta($post_id, '_order_recurring_discount_total', WC_Subscriptions::format_total($_POST['_order_recurring_discount_total']));
     update_post_meta($post_id, '_order_recurring_total', WC_Subscriptions::format_total($_POST['_order_recurring_total']));
     // Update fields for WC < 2.1
     if (WC_Subscriptions::is_woocommerce_pre('2.1')) {
         // Also allow updates to the recurring payment method's title
         if (isset($_POST['_recurring_payment_method_title'])) {
             update_post_meta($post_id, '_recurring_payment_method_title', stripslashes($_POST['_recurring_payment_method_title']));
         } else {
             // it's been deleted
             update_post_meta($post_id, '_recurring_payment_method_title', '');
         }
         if (isset($_POST['_order_recurring_discount_cart'])) {
             update_post_meta($post_id, '_order_recurring_discount_cart', stripslashes($_POST['_order_recurring_discount_cart']));
         } else {
             // it's been deleted
             update_post_meta($post_id, '_order_recurring_discount_cart', 0);
         }
         if (isset($_POST['_order_recurring_tax_total'])) {
             // WC < 2.1
             update_post_meta($post_id, '_order_recurring_tax_total', stripslashes($_POST['_order_recurring_tax_total']));
         } else {
             // it's been deleted
             update_post_meta($post_id, '_order_recurring_tax_total', 0);
         }
         if (isset($_POST['_order_recurring_shipping_tax_total'])) {
             update_post_meta($post_id, '_order_recurring_shipping_tax_total', stripslashes($_POST['_order_recurring_shipping_tax_total']));
         } else {
             // it's been deleted
             update_post_meta($post_id, '_order_recurring_shipping_tax_total', 0);
         }
         if (isset($_POST['_order_recurring_shipping_total'])) {
             update_post_meta($post_id, '_order_recurring_shipping_total', stripslashes($_POST['_order_recurring_shipping_total']));
         } else {
             // it's been deleted
             update_post_meta($post_id, '_order_recurring_shipping_total', 0);
         }
     }
     // Save tax rows
     $total_tax = 0;
     $total_shipping_tax = 0;
     if (isset($_POST['recurring_order_taxes_id'])) {
         // WC 2.0+
         $tax_keys = array('recurring_order_taxes_id', 'recurring_order_taxes_rate_id', 'recurring_order_taxes_amount', 'recurring_order_taxes_shipping_amount');
         foreach ($tax_keys as $tax_key) {
             ${$tax_key} = isset($_POST[$tax_key]) ? $_POST[$tax_key] : array();
         }
         foreach ($recurring_order_taxes_id as $item_id => $value) {
             $item_id = absint($item_id);
             $rate_id = absint($recurring_order_taxes_rate_id[$item_id]);
             if ($rate_id) {
                 $rate = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $rate_id));
                 $label = $rate->tax_rate_name ? $rate->tax_rate_name : $woocommerce->countries->tax_or_vat();
                 $compound = $rate->tax_rate_compound ? 1 : 0;
                 $code = array();
                 $code[] = $rate->tax_rate_country;
                 $code[] = $rate->tax_rate_state;
                 $code[] = $rate->tax_rate_name ? $rate->tax_rate_name : 'TAX';
                 $code[] = absint($rate->tax_rate_priority);
                 $code = strtoupper(implode('-', array_filter($code)));
             } else {
                 $code = '';
                 $label = $woocommerce->countries->tax_or_vat();
             }
             $wpdb->update($wpdb->prefix . "woocommerce_order_items", array('order_item_name' => woocommerce_clean($code)), array('order_item_id' => $item_id), array('%s'), array('%d'));
             woocommerce_update_order_item_meta($item_id, 'rate_id', $rate_id);
             woocommerce_update_order_item_meta($item_id, 'label', $label);
             woocommerce_update_order_item_meta($item_id, 'compound', $compound);
             if (isset($recurring_order_taxes_amount[$item_id])) {
                 woocommerce_update_order_item_meta($item_id, 'tax_amount', WC_Subscriptions::format_total($recurring_order_taxes_amount[$item_id]));
                 $total_tax += WC_Subscriptions::format_total($recurring_order_taxes_amount[$item_id]);
             }
             if (isset($recurring_order_taxes_shipping_amount[$item_id])) {
                 woocommerce_update_order_item_meta($item_id, 'shipping_tax_amount', WC_Subscriptions::format_total($recurring_order_taxes_shipping_amount[$item_id]));
                 $total_shipping_tax += WC_Subscriptions::format_total($recurring_order_taxes_shipping_amount[$item_id]);
             }
         }
     }
     if (!isset($_POST['_order_recurring_tax_total']) && function_exists('wc_round_tax_total')) {
         // WC 2.1+
         update_post_meta($post_id, '_order_recurring_tax_total', wc_round_tax_total($total_tax));
     }
     if (!isset($_POST['_order_recurring_shipping_tax_total']) && function_exists('wc_round_tax_total')) {
         // WC 2.1+
         update_post_meta($post_id, '_order_recurring_shipping_tax_total', wc_round_tax_total($total_shipping_tax));
     }
     // And that shipping methods are updated as required
     if (isset($_POST['_recurring_shipping_method']) || isset($_POST['_recurring_shipping_method_title'])) {
         // WC < 2.1
         update_post_meta($post_id, '_recurring_shipping_method', stripslashes($_POST['_recurring_shipping_method']));
         update_post_meta($post_id, '_recurring_shipping_method_title', stripslashes($_POST['_recurring_shipping_method_title']));
     }
     // Shipping Rows
     $recurring_order_shipping = 0;
     if (isset($_POST['recurring_shipping_method_id'])) {
         // WC 2.1+
         $get_values = array('recurring_shipping_method_id', 'recurring_shipping_method_title', 'recurring_shipping_method', 'recurring_shipping_cost');
         foreach ($get_values as $value) {
             ${$value} = isset($_POST[$value]) ? $_POST[$value] : array();
         }
         foreach ($recurring_shipping_method_id as $item_id => $value) {
             if ('new' == $item_id) {
                 foreach ($value as $new_key => $new_value) {
                     $method_id = woocommerce_clean($recurring_shipping_method[$item_id][$new_key]);
                     $method_title = woocommerce_clean($recurring_shipping_method_title[$item_id][$new_key]);
                     $cost = WC_Subscriptions::format_total($recurring_shipping_cost[$item_id][$new_key]);
                     $new_id = woocommerce_add_order_item($post_id, array('order_item_name' => $method_title, 'order_item_type' => 'recurring_shipping'));
                     if ($new_id) {
                         woocommerce_add_order_item_meta($new_id, 'method_id', $method_id);
                         woocommerce_add_order_item_meta($new_id, 'cost', $cost);
                     }
                     $recurring_order_shipping += $cost;
                 }
             } elseif ('old' == $item_id) {
                 // Migrate a WC 2.0.n shipping method to WC 2.1 format
                 $method_id = woocommerce_clean($recurring_shipping_method[$item_id]);
                 $method_title = woocommerce_clean($recurring_shipping_method_title[$item_id]);
                 $cost = WC_Subscriptions::format_total($recurring_shipping_cost[$item_id]);
                 $new_id = woocommerce_add_order_item($post_id, array('order_item_name' => $method_title, 'order_item_type' => 'recurring_shipping'));
                 if ($new_id) {
                     woocommerce_add_order_item_meta($new_id, 'method_id', $method_id);
                     woocommerce_add_order_item_meta($new_id, 'cost', $cost);
                 }
                 $recurring_order_shipping += $cost;
                 delete_post_meta($post_id, '_recurring_shipping_method');
                 delete_post_meta($post_id, '_recurring_shipping_method_title');
             } else {
                 $item_id = absint($item_id);
                 $method_id = woocommerce_clean($recurring_shipping_method[$item_id]);
                 $method_title = woocommerce_clean($recurring_shipping_method_title[$item_id]);
                 $cost = WC_Subscriptions::format_total($recurring_shipping_cost[$item_id]);
                 $wpdb->update($wpdb->prefix . "woocommerce_order_items", array('order_item_name' => $method_title), array('order_item_id' => $item_id), array('%s'), array('%d'));
                 woocommerce_update_order_item_meta($item_id, 'method_id', $method_id);
                 woocommerce_update_order_item_meta($item_id, 'cost', $cost);
                 $recurring_order_shipping += $cost;
             }
         }
     }
     if (!isset($_POST['_order_recurring_shipping_total'])) {
         // WC 2.1+
         update_post_meta($post_id, '_order_recurring_shipping_total', $recurring_order_shipping);
     }
     // Check if all the subscription products on the order have associated subscriptions on the user's account, and if not, add a new one
     foreach ($product_ids as $order_item_id => $product_id) {
         $is_existing_item = false;
         if (in_array($product_id, $existing_product_ids)) {
             $is_existing_item = true;
         }
         // If this is a new item and it's not a subscription product, ignore it
         if (!$is_existing_item && !WC_Subscriptions_Product::is_subscription($product_id)) {
             continue;
         }
         // If this is an existing item and it's not a subscription, ignore it
         if ($is_existing_item && !self::is_item_subscription($order, $product_id)) {
             continue;
         }
         $subscription_key = WC_Subscriptions_Manager::get_subscription_key($post_id, $product_id);
         $subscription = array();
         if (!empty($order->customer_user) && $_POST['customer_user'] != $order->customer_user) {
             $customer_has_changed = true;
             $hook_args = array('user_id' => (int) $order->customer_user, 'subscription_key' => $subscription_key);
             wc_unschedule_action('scheduled_subscription_trial_end', $hook_args);
             wc_unschedule_action('scheduled_subscription_payment', $hook_args);
             wc_unschedule_action('scheduled_subscription_expiration', $hook_args);
         } else {
             $customer_has_changed = false;
         }
         // In case it's a new order or the customer has changed
         $order->customer_user = $order->user_id = (int) $_POST['customer_user'];
         $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
         if (empty($subscription)) {
             // Add a new subscription
             // The order may not exist yet, so we need to set a few things ourselves
             if (empty($order->order_key)) {
                 $order->order_key = uniqid('order_');
                 add_post_meta($post_id, '_order_key', $order->order_key, true);
             }
             if (empty($_POST['order_date'])) {
                 $start_date = gmdate('Y-m-d H:i:s');
             } else {
                 $start_date = get_gmt_from_date($_POST['order_date'] . ' ' . (int) $_POST['order_date_hour'] . ':' . (int) $_POST['order_date_minute'] . ':00');
             }
             WC_Subscriptions_Manager::create_pending_subscription_for_order($order, $product_id, array('start_date' => $start_date));
             // Add the subscription meta for this item to the order
             $functions_and_meta = array('get_period' => '_order_subscription_periods', 'get_interval' => '_order_subscription_intervals', 'get_length' => '_order_subscription_lengths');
             foreach ($functions_and_meta as $function_name => $meta_key) {
                 $subscription_meta = self::get_meta($order, $meta_key, array());
                 $subscription_meta[$product_id] = WC_Subscriptions_Product::$function_name($product_id);
                 update_post_meta($order->id, $meta_key, $subscription_meta);
             }
             // This works because meta is added when the item is added via Ajax
             self::process_shop_order_item_meta($post_id, $post);
             // If the order's existing status is something other than pending and the order status is not being changed, manually set the subscription's status (otherwise, it will be handled when WC transitions the order's status)
             if ($order->status == $_POST['order_status'] && 'pending' != $order->status) {
                 switch ($order->status) {
                     case 'completed':
                     case 'processing':
                         WC_Subscriptions_Manager::activate_subscription($order->customer_user, $subscription_key);
                         break;
                     case 'cancelled':
                         WC_Subscriptions_Manager::cancel_subscription($order->customer_user, $subscription_key);
                         break;
                     case 'failed':
                         WC_Subscriptions_Manager::failed_subscription_signup($order->customer_user, $subscription_key);
                         break;
                 }
             }
         }
     }
     // Determine whether we need to update any subscription dates for existing subscriptions (before the item meta is updated)
     if (!empty($product_ids)) {
         $start_date = $_POST['order_date'] . ' ' . (int) $_POST['order_date_hour'] . ':' . (int) $_POST['order_date_minute'] . date(':s', strtotime($order->order_date));
         // Order's customer or start date changed for an existing order
         if ($customer_has_changed || !empty($order->order_date) && $order->order_date != $start_date) {
             self::$requires_update['expiration_date'] = array_values($product_ids);
             self::$requires_update['trial_expiration'] = array_values($product_ids);
             self::$requires_update['next_billing_date'] = array_values($product_ids);
         } elseif (isset($_POST['meta_key'])) {
             $item_meta_keys = isset($_POST['meta_key']) ? $_POST['meta_key'] : array();
             $new_meta_values = isset($_POST['meta_value']) ? $_POST['meta_value'] : array();
             foreach ($item_meta_keys as $item_meta_id => $meta_key) {
                 $meta_data = self::get_item_meta_data($item_meta_id);
                 $product_id = woocommerce_get_order_item_meta($meta_data->order_item_id, '_product_id');
                 // Set flags to update payment dates if required
                 switch ($meta_key) {
                     case '_subscription_period':
                     case '_subscription_interval':
                         if ($new_meta_values[$item_meta_id] != $meta_data->meta_value) {
                             self::$requires_update['next_billing_date'][] = $product_id;
                         }
                         break;
                     case '_subscription_start_date':
                     case '_subscription_trial_length':
                     case '_subscription_trial_period':
                         if ($new_meta_values[$item_meta_id] != $meta_data->meta_value) {
                             self::$requires_update['expiration_date'][] = $product_id;
                             self::$requires_update['trial_expiration'][] = $product_id;
                             self::$requires_update['next_billing_date'][] = $product_id;
                         }
                         break;
                     case '_subscription_length':
                         if ($new_meta_values[$item_meta_id] != $meta_data->meta_value) {
                             self::$requires_update['expiration_date'][] = $product_id;
                             self::$requires_update['next_billing_date'][] = $product_id;
                         }
                         break;
                     case '_subscription_trial_expiry_date':
                         if ($new_meta_values[$item_meta_id] != $meta_data->meta_value) {
                             self::$requires_update['trial_expiration'][] = $product_id;
                         }
                         break;
                     case '_subscription_expiry_date':
                         if ($new_meta_values[$item_meta_id] != $meta_data->meta_value) {
                             self::$requires_update['expiration_date'][] = $product_id;
                         }
                         break;
                 }
             }
         }
     }
 }
 public function test_canceled_action_comments()
 {
     $action_id = wc_schedule_single_action(time(), 'a hook');
     wc_unschedule_action('a hook');
     $logger = ActionScheduler::logger();
     $logs = $logger->get_logs($action_id);
     $expected = new ActionScheduler_LogEntry($action_id, 'action canceled');
     $this->assertTrue(in_array($expected, $logs));
 }
 /**
  * WP-Cron occasionally gets itself into an infinite loop on scheduled events, this function is
  * designed to create a non-cron related safeguard against payments getting caught up in such a loop.
  *
  * When the scheduled subscription payment hook is fired by WP-Cron, this function is attached before
  * any other to make sure the hook hasn't already fired for this period.
  *
  * A transient is used to keep a record of any payment for each period. The transient expiration is
  * set to one billing period in the future, minus 1 hour, if there is a future payment due, otherwise,
  * it is set to 23 hours in the future. This later option provides a safeguard in case a subscription's
  * data is corrupted and the @see self::calculate_next_payment_date() is returning an
  * invalid value. As no subscription can charge a payment more than once per day, the 23 hours is a safe
  * throttle period for billing that still removes the possibility of a catastrophic failure (payments
  * firing every few seconds until a credit card is maxed out).
  *
  * The transient keys use both the user ID and subscription key to ensure it is unique per subscription
  * (even on multisite)
  *
  * @param int $user_id The id of the user who purchased the subscription
  * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key()
  * @since 1.1.2
  */
 public static function safeguard_scheduled_payments($user_id, $subscription_key)
 {
     global $wp_filter, $wpdb;
     $subscription = self::get_subscription($subscription_key);
     $lock_key = 'wcs_blocker_' . $user_id . '_' . $subscription_key;
     // Bypass options API
     $payments_blocked_until = $wpdb->get_var($wpdb->prepare("SELECT option_value FROM {$wpdb->options} WHERE option_name = %s", $lock_key));
     if ($payments_blocked_until > gmdate('U') || in_array($subscription['status'], array('suspended', 'on-hold', 'cancelled', 'expired', 'failed'))) {
         // Short-circuit for debugging
         if (defined('WCS_DEBUG') && true === WCS_DEBUG) {
             return;
         }
         // Clear the schedule for this hook
         wc_unschedule_action('scheduled_subscription_payment', array('user_id' => (int) $user_id, 'subscription_key' => $subscription_key));
         // But now that we've cleared the schedule, make sure the next subscription payment is correctly scheduled
         self::maybe_reschedule_subscription_payment($user_id, $subscription_key);
         // Make sure nothing else fires for this duplicated hook, except for this function: we can't use remove_all_actions here because we need to keep a record of the actions which were removed in case we need to add them for another hook in the same request
         foreach ($wp_filter['scheduled_subscription_payment'] as $priority => $filters) {
             foreach ($filters as $filter_id => $filter_details) {
                 if (__CLASS__ . '::' . __FUNCTION__ == $filter_details['function']) {
                     continue;
                 }
                 self::$removed_filter_cache[] = array('filter_id' => $filter_id, 'function' => $filter_details['function'], 'priority' => $priority, 'accepted_args' => $filter_details['accepted_args']);
                 remove_action('scheduled_subscription_payment', $filter_details['function'], $priority, $filter_details['accepted_args']);
             }
         }
     } else {
         $next_billing_timestamp = self::calculate_next_payment_date($subscription_key, $user_id, 'timestamp', gmdate('Y-m-d H:i:s'));
         // If there are future payments, block until then, otherwise block for 23 hours
         $transient_timeout = $next_billing_timestamp > 0 ? $next_billing_timestamp - 60 * 60 - gmdate('U') : 60 * 60 * 23;
         self::update_wp_cron_lock($subscription_key, $transient_timeout, $user_id);
         // If the payment hook is fired for more than one subscription in the same request, and the actions associated with the hook were removed because a prevous instance was a duplicate, re-add the actions for this instance of the hook
         if (!empty(self::$removed_filter_cache)) {
             foreach (self::$removed_filter_cache as $key => $filter) {
                 add_action('scheduled_subscription_payment', $filter['function'], $filter['priority'], $filter['accepted_args']);
                 unset(self::$removed_filter_cache[$key]);
             }
         }
     }
 }
 /**
  * When a subscription's status is updated, maybe schedule an event
  *
  * @param object $subscription An instance of a WC_Subscription object
  * @param string $date_type Can be 'start', 'trial_end', 'next_payment', 'last_payment', 'end', 'end_of_prepaid_term' or a custom date type
  * @param string $datetime A MySQL formated date/time string in the GMT/UTC timezone.
  */
 public function update_status($subscription, $new_status, $old_status)
 {
     $action_args = array('subscription_id' => $subscription->id);
     switch ($new_status) {
         case 'active':
             foreach ($this->action_hooks as $action_hook => $date_type) {
                 $next_scheduled = wc_next_scheduled_action($action_hook, $action_args);
                 $event_time = $subscription->get_time($date_type);
                 // Maybe clear the existing schedule for this hook
                 if (false !== $next_scheduled && $next_scheduled != $event_time) {
                     wc_unschedule_action($action_hook, $action_args);
                 }
                 if (0 != $event_time && $event_time > current_time('timestamp', true) && $next_scheduled != $event_time) {
                     wc_schedule_single_action($event_time, $action_hook, $action_args);
                 }
             }
             break;
         case 'pending-cancel':
             $end_time = $subscription->get_time('end');
             // This will have been set to the correct date already
             // Now that we have the current times, clear the scheduled hooks
             foreach ($this->action_hooks as $action_hook => $date_type) {
                 wc_unschedule_action($action_hook, $action_args);
             }
             $next_scheduled = wc_next_scheduled_action('woocommerce_scheduled_subscription_end_of_prepaid_term', $action_args);
             if (false !== $next_scheduled && $next_scheduled != $end_time) {
                 wc_unschedule_action('woocommerce_scheduled_subscription_end_of_prepaid_term', $action_args);
             }
             // The end date was set in WC_Subscriptions::update_dates() to the appropriate value, so we can schedule our action for that time
             if ($end_time > current_time('timestamp', true) && $next_scheduled != $end_time) {
                 wc_schedule_single_action($end_time, 'woocommerce_scheduled_subscription_end_of_prepaid_term', $action_args);
             }
             break;
         case 'on-hold':
         case 'cancelled':
         case 'switched':
         case 'expired':
         case 'trash':
             foreach ($this->action_hooks as $action_hook => $date_type) {
                 wc_unschedule_action($action_hook, $action_args);
             }
             wc_unschedule_action('woocommerce_scheduled_subscription_end_of_prepaid_term', $action_args);
             break;
     }
 }
 /**
  * Listen for changes in payment dates and adjust the sending schedule of matching emails
  *
  * @param bool      $is_set TRUE if a schedule has been set for the new date
  * @param int       $next_payment Timestamp of the new payment date
  * @param string    $subscription_key
  * @param int       $user_id
  * @return bool The unchanged value of $is_set
  */
 public function payment_date_changed($is_set, $next_payment, $subscription_key, $user_id)
 {
     // look for unsent emails in the queue matching this subscription
     $serialized_key = serialize(array('subs_key' => $subscription_key));
     $serialized_key = str_replace('a:1:{', '', $serialized_key);
     $serialized_key = str_replace('}', '', $serialized_key);
     $scheduler = new FUE_Sending_Scheduler(Follow_Up_Emails::instance());
     $items = $scheduler->get_items(array('is_sent' => 0, 'meta' => $serialized_key));
     foreach ($items as $item) {
         $email = new FUE_Email($item->email_id);
         if ($email->trigger == 'subs_before_expire' || $email->trigger == 'subs_before_renewal') {
             // unschedule the email first
             $param = array('email_order_id' => $item->id);
             wc_unschedule_action('sfn_followup_emails', $param, 'fue');
             // get the new sending schedule
             $new_timestamp = 0;
             if ($email->trigger == 'subs_before_expire') {
                 $expiry_date = WC_Subscriptions_Manager::get_subscription_expiration_date($subscription_key, $user_id);
                 if ($expiry_date) {
                     // convert to local time
                     $new_timestamp = get_date_from_gmt($expiry_date, 'U');
                 }
             } else {
                 $renewal_date = WC_Subscriptions_Manager::get_next_payment_date($subscription_key, $user_id);
                 if ($renewal_date) {
                     // convert to local time
                     $new_timestamp = get_date_from_gmt($renewal_date, 'U');
                 }
             }
             if ($new_timestamp) {
                 // add this email to the queue
                 $interval = (int) $email->interval_num;
                 $add = FUE_Sending_Scheduler::get_time_to_add($interval, $email->interval_duration);
                 $send_on = $new_timestamp - $add;
                 // update the send_on value of the queue item
                 $item->send_on = $send_on;
                 $item->save();
                 // set a schedule using the new timestamp
                 $scheduler->schedule_email($item->id, $send_on);
             }
         }
     }
     return $is_set;
 }
Ejemplo n.º 7
0
 /**
  * AJAX handler for toggling an email queue's status
  */
 public static function toggle_queue_status()
 {
     global $wpdb;
     $id = $_POST['id'];
     $status = $wpdb->get_var($wpdb->prepare("SELECT status FROM {$wpdb->prefix}followup_email_orders WHERE id = %d", $id));
     $resp = array('ack' => 'OK');
     if ($status == 0) {
         // activate
         $wpdb->update($wpdb->prefix . 'followup_email_orders', array('status' => 1), array('id' => $id));
         // re-create the task
         $param = array('email_order_id' => $id);
         $send_time = $wpdb->get_var($wpdb->prepare("SELECT send_on FROM {$wpdb->prefix}followup_email_orders WHERE id = %d", $id));
         wc_schedule_single_action($send_time, 'sfn_followup_emails', $param, 'fue');
         $resp['new_status'] = __('Queued', 'follow_up_emails');
         $resp['new_action'] = __('Do not send', 'follow_up_emails');
     } else {
         // deactivate
         $wpdb->update($wpdb->prefix . 'followup_email_orders', array('status' => 0), array('id' => $id));
         // if using action-scheduler, delete the task
         $param = array('email_order_id' => $id);
         wc_unschedule_action('sfn_followup_emails', $param, 'fue');
         $resp['new_status'] = __('Suspended', 'follow_up_emails');
         $resp['new_action'] = __('Re-enable', 'follow_up_emails');
     }
     die(json_encode($resp));
 }
 /**
  * After payment is completed on an order for switching a subscription, complete the switch.
  *
  * @param WC_Order|int $order A WC_Order object or ID of a WC_Order order.
  * @since 1.4
  */
 public static function maybe_complete_switch($order_id)
 {
     $original_subscription_key = get_post_meta($order_id, '_switched_subscription_key', true);
     if (!empty($original_subscription_key)) {
         $original_subscription = WC_Subscriptions_Manager::get_subscription($original_subscription_key);
         $original_order = new WC_Order($original_subscription['order_id']);
         if ('switched' !== $original_subscription['status']) {
             // Don't send "Cancelled Subscription" email to admins
             remove_action('cancelled_subscription', 'WC_Subscriptions_Email::send_subscription_email', 10, 2);
             // Cancel the existing subscription
             WC_Subscriptions_Manager::cancel_subscription($original_order->customer_user, $original_subscription_key);
             add_action('cancelled_subscription', 'WC_Subscriptions_Email::send_subscription_email', 10, 2);
             // Now set a custom status of "switched"
             $original_subscription['status'] = 'switched';
             WC_Subscriptions_Manager::update_subscription($original_subscription_key, $original_subscription);
             wc_unschedule_action('scheduled_subscription_end_of_prepaid_term', array('user_id' => (int) $original_order->customer_user, 'subscription_key' => $original_subscription_key));
             $new_subscriptions_key = WC_Subscriptions_Manager::get_subscription_key($order_id);
             do_action('switched_subscription', $original_order->customer_user, $original_subscription_key, $new_subscriptions_key);
         }
     }
 }
 /**
  * Remove the scheduled action to prevent the email from sending
  *
  * @param int $queue_id
  * @return void
  */
 public function unschedule_email($queue_id)
 {
     $param = $this->get_scheduler_parameters($queue_id);
     wc_unschedule_action('sfn_followup_emails', $param, 'fue');
 }
Ejemplo n.º 10
0
 /**
  * Schedule the daily summary recurring emails
  */
 public function init_daily_summary()
 {
     if (!function_exists('wc_next_scheduled_action')) {
         return;
     }
     if (wc_next_scheduled_action('fue_send_summary')) {
         wc_unschedule_action('fue_send_summary');
     }
     FUE_Sending_Scheduler::queue_daily_summary_email();
     delete_option('fue_init_daily_summary');
 }