/**
  * When creating an order at checkout, if the order is for renewing a subscription from a failed
  * payment, hijack the order creation to make a renewal order - not a vanilla WooCommerce order.
  *
  * @since 1.3
  */
 public static function filter_woocommerce_create_order($order_id, $checkout_object)
 {
     global $woocommerce;
     $cart_item = WC_Subscriptions_Cart::cart_contains_subscription_renewal();
     if ($cart_item && 'child' == $cart_item['subscription_renewal']['role']) {
         $product_id = $cart_item['product_id'];
         $failed_order_id = $cart_item['subscription_renewal']['failed_order'];
         $original_order_id = $cart_item['subscription_renewal']['original_order'];
         $role = $cart_item['subscription_renewal']['role'];
         remove_action('woocommerce_subscriptions_renewal_order_created', 'WC_Subscriptions_Renewal_Order::maybe_send_customer_renewal_order_email', 10, 1);
         $renewal_order_args = array('new_order_role' => $role, 'checkout_renewal' => true, 'failed_order_id' => $failed_order_id);
         $order_id = WC_Subscriptions_Renewal_Order::generate_renewal_order($original_order_id, $product_id, $renewal_order_args);
         if ($checkout_object->posted['payment_method']) {
             $available_gateways = $woocommerce->payment_gateways->get_available_payment_gateways();
             if (isset($available_gateways[$checkout_object->posted['payment_method']])) {
                 $payment_method = $available_gateways[$checkout_object->posted['payment_method']];
                 $payment_method->validate_fields();
                 update_post_meta($order_id, '_payment_method', $payment_method->id);
                 update_post_meta($order_id, '_payment_method_title', $payment_method->get_title());
             }
         }
         if ($checkout_object->posted['shipping_method']) {
             $available_shipping_methods = $woocommerce->shipping->get_available_shipping_methods();
             if (isset($available_shipping_methods[$checkout_object->posted['shipping_method']])) {
                 $shipping_method = $available_shipping_methods[$checkout_object->posted['shipping_method']];
                 update_post_meta($order_id, '_shipping_method', $shipping_method->id);
                 update_post_meta($order_id, '_shipping_method_title', $shipping_method->label);
             }
         }
         if (isset($failed_order_id)) {
             $failed_order = new WC_Order($failed_order_id);
             if ($failed_order->status == 'failed') {
                 update_post_meta($failed_order_id, '_failed_order_replaced_by', $order_id);
             }
         }
     }
     return $order_id;
 }
Ejemplo n.º 2
0
 /**
  * Processes a failed payment on a subscription by recording the failed payment and cancelling the subscription if it exceeds the 
  * maximum number of failed payments allowed on the site. 
  *
  * @param $user_id int The id of the user who owns the expiring subscription. 
  * @param $subscription_key string A subscription key of the form obtained by @see get_subscription_key( $order_id, $product_id )
  * @since 1.0
  */
 public static function process_subscription_payment_failure($user_id, $subscription_key)
 {
     // Store a record of the subscription payment date
     $subscription = self::get_users_subscription($user_id, $subscription_key);
     if (!isset($subscription['failed_payments'])) {
         $subscription['failed_payments'] = 0;
     }
     $subscription['failed_payments'] = $subscription['failed_payments'] + 1;
     self::update_users_subscriptions($user_id, array($subscription_key => $subscription));
     $order = new WC_Order($subscription['order_id']);
     $item = WC_Subscriptions_Order::get_item_by_product_id($order, $subscription['product_id']);
     $max_failed_payments = get_option(WC_Subscriptions_Admin::$option_prefix . '_max_failed_payments', 3);
     // Allow a short circuit for plugins & payment gateways to force max failed payments exceeded
     $failed_payments_exceeded = apply_filters('woocommerce_subscriptions_max_failed_payments_exceeded', false, $user_id, $subscription_key);
     // Have we reached the maximum failed payments allowed on the subscription
     if ($failed_payments_exceeded || $subscription['failed_payments'] >= $max_failed_payments && intval($max_failed_payments) !== 0) {
         self::cancel_subscription($user_id, $subscription_key);
         $order->add_order_note(sprintf(__('Cancelled Subscription "%s". Maximum number of failed subscription payments reached.', WC_Subscriptions::$text_domain), $item['name']));
         if ('yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_generate_renewal_order')) {
             $renewal_order_id = WC_Subscriptions_Renewal_Order::generate_renewal_order($order, $subscription['product_id'], array('new_order_role' => 'parent'));
         }
     } else {
         // Log payment failure on order
         $order->add_order_note(sprintf(__('Payment failed for subscription "%s".', WC_Subscriptions::$text_domain), $item['name']));
         // Place the subscription on-hold
         self::put_subscription_on_hold($user_id, $subscription_key);
     }
     do_action('processed_subscription_payment_failure', $user_id, $subscription_key);
 }
 /**
  * Expires a single subscription on a users account.
  *
  * @param $user_id int The id of the user who owns the expiring subscription. 
  * @param $subscription_key string A subscription key of the form obtained by @see get_subscription_key( $order_id, $product_id )
  * @since 1.0
  */
 public static function process_subscription_payment_failure($user_id, $subscription_key)
 {
     // Store a record of the subscription payment date
     $subscription = self::get_users_subscription($user_id, $subscription_key);
     if (!isset($subscription['failed_payments'])) {
         $subscription['failed_payments'] = 0;
     }
     $subscription['failed_payments'] = $subscription['failed_payments'] + 1;
     self::update_users_subscriptions($user_id, array($subscription_key => $subscription));
     $order = new WC_Order($subscription['order_id']);
     $item = WC_Subscriptions_Order::get_item($order, $subscription['product_id']);
     // We've reached the maximum failed payments allowed on the subscription
     if ($subscription['failed_payments'] >= get_option(WC_Subscriptions_Admin::$option_prefix . '_max_failed_payments')) {
         self::cancel_subscription($user_id, $subscription_key);
         $order->add_order_note(sprintf(__('Cancelled Subscription "%s". Maximum number of failed subscription payments reached.', WC_Subscriptions::$text_domain), $item['name']));
         if ('yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_generate_renewal_order')) {
             $renewal_order_id = WC_Subscriptions_Renewal_Order::generate_renewal_order($order, $subscription['product_id'], 'parent');
         }
     } else {
         // Log payment failure on order
         $order->add_order_note(sprintf(__('Payment failed for subscription "%s".', WC_Subscriptions::$text_domain), $item['name']));
     }
     do_action('processed_subscription_payment_failure', $user_id, $subscription_key);
 }
Ejemplo n.º 4
0
 /**
  * Creates a new order for renewing a subscription product based on the details of a previous order.
  *
  * @param WC_Order|int $order The WC_Order object or ID of the order for which the a new order should be created.
  * @param string $product_id The ID of the subscription product in the order which needs to be added to the new order.
  * @param string $new_order_role A flag to indicate whether the new order should become the master order for the subscription. Accepts either 'parent' or 'child'. Defaults to 'parent' - replace the existing order.
  * @deprecated 1.2
  * @since 1.0
  */
 public static function generate_renewal_order($original_order, $product_id, $new_order_role = 'parent')
 {
     _deprecated_function(__METHOD__, '1.2', 'WC_Subscriptions_Renewal_Order::generate_renewal_order( $original_order, $product_id, array( "new_order_role" => $new_order_role ) )');
     return WC_Subscriptions_Renewal_Order::generate_renewal_order($original_order, $product_id, array('new_order_role' => $new_order_role));
 }
 /**
  * Processes a failed payment on a subscription by recording the failed payment and cancelling the subscription if it exceeds the 
  * maximum number of failed payments allowed on the site. 
  *
  * @param int $user_id The id of the user who owns the expiring subscription. 
  * @param string $subscription_key A subscription key of the form obtained by @see get_subscription_key( $order_id, $product_id )
  * @since 1.0
  */
 public static function process_subscription_payment_failure($user_id, $subscription_key)
 {
     // Store a record of the subscription payment date
     $subscription = self::get_subscription($subscription_key);
     if (!isset($subscription['failed_payments'])) {
         $subscription['failed_payments'] = 0;
     }
     $subscription['failed_payments'] = $subscription['failed_payments'] + 1;
     self::update_users_subscriptions($user_id, array($subscription_key => $subscription));
     $order = new WC_Order($subscription['order_id']);
     $item = WC_Subscriptions_Order::get_item_by_product_id($order, $subscription['product_id']);
     // Allow a short circuit for plugins & payment gateways to force max failed payments exceeded
     if (apply_filters('woocommerce_subscriptions_max_failed_payments_exceeded', false, $user_id, $subscription_key)) {
         self::cancel_subscription($user_id, $subscription_key);
         $order->add_order_note(sprintf(__('Cancelled Subscription "%s". Maximum number of failed subscription payments reached.', 'woocommerce-subscriptions'), $item['name']));
         $renewal_order_id = WC_Subscriptions_Renewal_Order::generate_renewal_order($order, $subscription['product_id'], array('new_order_role' => 'parent'));
     } else {
         // Log payment failure on order
         $order->add_order_note(sprintf(__('Payment failed for subscription "%s".', 'woocommerce-subscriptions'), $item['name']));
         // Place the subscription on-hold
         self::put_subscription_on_hold($user_id, $subscription_key);
     }
     do_action('processed_subscription_payment_failure', $user_id, $subscription_key);
 }
 /**
  * When creating an order at checkout, if the order is for renewing a subscription from a failed
  * payment, hijack the order creation to make a renewal order - not a vanilla WooCommerce order.
  *
  * @since 1.3
  */
 public static function filter_woocommerce_create_order($order_id, $checkout_object)
 {
     global $woocommerce;
     $cart_item = WC_Subscriptions_Cart::cart_contains_subscription_renewal();
     if ($cart_item && 'child' == $cart_item['subscription_renewal']['role']) {
         $product_id = $cart_item['product_id'];
         $failed_order_id = $cart_item['subscription_renewal']['failed_order'];
         $original_order_id = $cart_item['subscription_renewal']['original_order'];
         $role = $cart_item['subscription_renewal']['role'];
         $renewal_order_args = array('new_order_role' => $role, 'checkout_renewal' => true, 'failed_order_id' => $failed_order_id);
         $renewal_order_id = WC_Subscriptions_Renewal_Order::generate_renewal_order($original_order_id, $product_id, $renewal_order_args);
         $original_order = new WC_Order($original_order_id);
         $customer_id = $original_order->customer_user;
         // Save posted billing address fields to both renewal and original order
         if ($checkout_object->checkout_fields['billing']) {
             foreach ($checkout_object->checkout_fields['billing'] as $key => $field) {
                 update_post_meta($renewal_order_id, '_' . $key, $checkout_object->posted[$key]);
                 update_post_meta($original_order->id, '_' . $key, $checkout_object->posted[$key]);
                 // User
                 if ($customer_id && !empty($checkout_object->posted[$key])) {
                     update_user_meta($customer_id, $key, $checkout_object->posted[$key]);
                     // Special fields
                     switch ($key) {
                         case "billing_email":
                             if (!email_exists($checkout_object->posted[$key])) {
                                 wp_update_user(array('ID' => $customer_id, 'user_email' => $checkout_object->posted[$key]));
                             }
                             break;
                         case "billing_first_name":
                             wp_update_user(array('ID' => $customer_id, 'first_name' => $checkout_object->posted[$key]));
                             break;
                         case "billing_last_name":
                             wp_update_user(array('ID' => $customer_id, 'last_name' => $checkout_object->posted[$key]));
                             break;
                     }
                 }
             }
         }
         // Save posted shipping address fields to both renewal and original order
         if ($checkout_object->checkout_fields['shipping'] && ($woocommerce->cart->needs_shipping() || get_option('woocommerce_require_shipping_address') == 'yes')) {
             foreach ($checkout_object->checkout_fields['shipping'] as $key => $field) {
                 $postvalue = false;
                 if (isset($checkout_object->posted['shiptobilling']) && $checkout_object->posted['shiptobilling'] || isset($checkout_object->posted['ship_to_different_address']) && $checkout_object->posted['ship_to_different_address']) {
                     if (isset($checkout_object->posted[str_replace('shipping_', 'billing_', $key)])) {
                         $postvalue = $checkout_object->posted[str_replace('shipping_', 'billing_', $key)];
                         update_post_meta($renewal_order_id, '_' . $key, $postvalue);
                         update_post_meta($original_order->id, '_' . $key, $postvalue);
                     }
                 } elseif (isset($checkout_object->posted[$key])) {
                     $postvalue = $checkout_object->posted[$key];
                     update_post_meta($renewal_order_id, '_' . $key, $postvalue);
                     update_post_meta($original_order->id, '_' . $key, $postvalue);
                 }
                 // User
                 if ($postvalue && $customer_id) {
                     update_user_meta($customer_id, $key, $postvalue);
                 }
             }
         }
         if ($checkout_object->posted['payment_method']) {
             $available_gateways = $woocommerce->payment_gateways->get_available_payment_gateways();
             if (isset($available_gateways[$checkout_object->posted['payment_method']])) {
                 $payment_method = $available_gateways[$checkout_object->posted['payment_method']];
                 $payment_method->validate_fields();
                 update_post_meta($renewal_order_id, '_payment_method', $payment_method->id);
                 update_post_meta($renewal_order_id, '_payment_method_title', $payment_method->get_title());
             }
         }
         // Set the shipping method for WC < 2.1
         if ($checkout_object->posted['shipping_method'] && method_exists($woocommerce->shipping, 'get_available_shipping_methods')) {
             $available_shipping_methods = $woocommerce->shipping->get_available_shipping_methods();
             if (isset($available_shipping_methods[$checkout_object->posted['shipping_method']])) {
                 $shipping_method = $available_shipping_methods[$checkout_object->posted['shipping_method']];
                 update_post_meta($renewal_order_id, '_shipping_method', $shipping_method->id);
                 update_post_meta($renewal_order_id, '_shipping_method_title', $shipping_method->label);
             }
         }
         if (isset($failed_order_id)) {
             $failed_order = new WC_Order($failed_order_id);
             if ($failed_order->status == 'failed') {
                 update_post_meta($failed_order_id, '_failed_order_replaced_by', $renewal_order_id);
             }
         }
         // Store fees, any new fees on this order should be applied now
         foreach ($woocommerce->cart->get_fees() as $fee) {
             $item_id = woocommerce_add_order_item($renewal_order_id, array('order_item_name' => $fee->name, 'order_item_type' => 'fee'));
             if ($fee->taxable) {
                 woocommerce_add_order_item_meta($item_id, '_tax_class', $fee->tax_class);
             } else {
                 woocommerce_add_order_item_meta($item_id, '_tax_class', '0');
             }
             woocommerce_add_order_item_meta($item_id, '_line_total', woocommerce_format_decimal($fee->amount));
             woocommerce_add_order_item_meta($item_id, '_line_tax', woocommerce_format_decimal($fee->tax));
         }
         // Store tax rows
         foreach (array_keys($woocommerce->cart->taxes + $woocommerce->cart->shipping_taxes) as $key) {
             $item_id = woocommerce_add_order_item($renewal_order_id, array('order_item_name' => WC_Tax::get_rate_code($key), 'order_item_type' => 'tax'));
             // Add line item meta
             if ($item_id) {
                 woocommerce_add_order_item_meta($item_id, 'rate_id', $key);
                 woocommerce_add_order_item_meta($item_id, 'label', WC_Tax::get_rate_label($key));
                 woocommerce_add_order_item_meta($item_id, 'compound', absint(WC_Tax::is_compound($key) ? 1 : 0));
                 woocommerce_add_order_item_meta($item_id, 'tax_amount', woocommerce_format_decimal(isset($woocommerce->cart->taxes[$key]) ? $woocommerce->cart->taxes[$key] : 0));
                 woocommerce_add_order_item_meta($item_id, 'shipping_tax_amount', woocommerce_format_decimal(isset($woocommerce->cart->shipping_taxes[$key]) ? $woocommerce->cart->shipping_taxes[$key] : 0));
             }
         }
         // Store shipping for all packages on this order (as this can differ between each order), WC 2.1
         if (method_exists($woocommerce->shipping, 'get_packages')) {
             $packages = $woocommerce->shipping->get_packages();
             foreach ($packages as $i => $package) {
                 if (isset($package['rates'][$checkout_object->shipping_methods[$i]])) {
                     $method = $package['rates'][$checkout_object->shipping_methods[$i]];
                     $item_id = woocommerce_add_order_item($renewal_order_id, array('order_item_name' => $method->label, 'order_item_type' => 'shipping'));
                     if ($item_id) {
                         woocommerce_add_order_item_meta($item_id, 'method_id', $method->id);
                         woocommerce_add_order_item_meta($item_id, 'cost', woocommerce_format_decimal($method->cost));
                         do_action('woocommerce_add_shipping_order_item', $renewal_order_id, $item_id, $i);
                     }
                 }
             }
         }
         update_post_meta($renewal_order_id, '_order_shipping', WC_Subscriptions::format_total($woocommerce->cart->shipping_total));
         update_post_meta($renewal_order_id, '_cart_discount', WC_Subscriptions::format_total($woocommerce->cart->get_cart_discount_total()));
         update_post_meta($renewal_order_id, '_order_tax', WC_Subscriptions::format_total($woocommerce->cart->tax_total));
         update_post_meta($renewal_order_id, '_order_shipping_tax', WC_Subscriptions::format_total($woocommerce->cart->shipping_tax_total));
         update_post_meta($renewal_order_id, '_order_total', WC_Subscriptions::format_total($woocommerce->cart->total));
         // WC < 2.3, set deprecated after tax discount total
         if (WC_Subscriptions::is_woocommerce_pre('2.3')) {
             update_post_meta($renewal_order_id, '_order_discount', WC_Subscriptions::format_total($woocommerce->cart->get_total_discount()));
         }
         update_post_meta($renewal_order_id, '_order_currency', get_woocommerce_currency());
         update_post_meta($renewal_order_id, '_prices_include_tax', get_option('woocommerce_prices_include_tax'));
         update_post_meta($renewal_order_id, '_customer_ip_address', isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']);
         update_post_meta($renewal_order_id, '_customer_user_agent', isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
         update_post_meta($renewal_order_id, '_checkout_renewal', 'yes');
         // Return the new order's ID to prevent WC creating an order
         $order_id = $renewal_order_id;
     }
     return $order_id;
 }
 /**
  * Creates a new order for renewing a subscription product based on the details of a previous order.
  *
  * @param $order WC_Order | int The WC_Order object or ID of the order for which the a new order should be created.
  * @param $product_id string The ID of the subscription product in the order which needs to be added to the new order.
  * @param $new_order_role string A flag to indicate whether the new order should become the master order for the subscription. Accepts either 'parent' or 'child'. Defaults to 'parent' - replace the existing order.
  * @deprecated 1.2
  * @since 1.0
  */
 public static function generate_renewal_order($original_order, $product_id, $new_order_role = 'parent')
 {
     _deprecated_function(__CLASS__ . '::' . __FUNCTION__, '1.2', 'WC_Subscriptions_Renewal_Order::generate_renewal_order( $original_order, $product_id, $new_order_role )');
     return WC_Subscriptions_Renewal_Order::generate_renewal_order($original_order, $product_id, $new_order_role);
 }
 /**
  * Version 1.2 introduced child renewal orders to keep a record of each completed subscription
  * payment. Before 1.2, these orders did not exist, so this function creates them.
  *
  * @since 1.2
  */
 private static function generate_renewal_orders()
 {
     global $woocommerce, $wpdb;
     $subscriptions_grouped_by_user = WC_Subscriptions_Manager::get_all_users_subscriptions();
     // Don't send any order emails
     $email_actions = array('woocommerce_low_stock', 'woocommerce_no_stock', 'woocommerce_product_on_backorder', 'woocommerce_order_status_pending_to_processing', 'woocommerce_order_status_pending_to_completed', 'woocommerce_order_status_pending_to_on-hold', 'woocommerce_order_status_failed_to_processing', 'woocommerce_order_status_failed_to_completed', 'woocommerce_order_status_pending_to_processing', 'woocommerce_order_status_pending_to_on-hold', 'woocommerce_order_status_completed', 'woocommerce_new_customer_note');
     foreach ($email_actions as $action) {
         remove_action($action, array(&$woocommerce, 'send_transactional_email'));
     }
     remove_action('woocommerce_payment_complete', 'WC_Subscriptions_Renewal_Order::maybe_record_renewal_order_payment', 10, 1);
     foreach ($subscriptions_grouped_by_user as $user_id => $users_subscriptions) {
         foreach ($users_subscriptions as $subscription_key => $subscription) {
             $order_post = get_post($subscription['order_id']);
             if (isset($subscription['completed_payments']) && count($subscription['completed_payments']) > 0 && $order_post != null) {
                 foreach ($subscription['completed_payments'] as $payment_date) {
                     $existing_renewal_order = $wpdb->get_var($wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE post_date_gmt = %s AND post_parent = %d AND post_type = 'shop_order'", $payment_date, $subscription['order_id']));
                     // If a renewal order exists on this date, don't generate another one
                     if (NULL !== $existing_renewal_order) {
                         continue;
                     }
                     $renewal_order_id = WC_Subscriptions_Renewal_Order::generate_renewal_order($subscription['order_id'], $subscription['product_id'], array('new_order_role' => 'child'));
                     if ($renewal_order_id) {
                         // Mark the order as paid
                         $renewal_order = new WC_Order($renewal_order_id);
                         $renewal_order->payment_complete();
                         // Avoid creating 100s "processing" orders
                         $renewal_order->update_status('completed');
                         // Set correct dates on the order
                         $renewal_order = array('ID' => $renewal_order_id, 'post_date' => $payment_date, 'post_date_gmt' => $payment_date);
                         wp_update_post($renewal_order);
                         update_post_meta($renewal_order_id, '_paid_date', $payment_date);
                         update_post_meta($renewal_order_id, '_completed_date', $payment_date);
                     }
                 }
             }
         }
     }
 }