/**
  * Create a new subscription from a cart item on checkout.
  *
  * The function doesn't validate whether the cart item is a subscription product, meaning it can be used for any cart item,
  * but the item will need a `subscription_period` and `subscription_period_interval` value set on it, at a minimum.
  *
  * @param WC_Order $order
  * @param WC_Cart $cart
  * @since 2.0
  */
 public static function create_subscription($order, $cart)
 {
     global $wpdb;
     try {
         // Start transaction if available
         $wpdb->query('START TRANSACTION');
         // Set the recurring line totals on the subscription
         $variation_id = wcs_cart_pluck($cart, 'variation_id');
         $product_id = empty($variation_id) ? wcs_cart_pluck($cart, 'product_id') : $variation_id;
         // We need to use the $order->order_date value because the post_date_gmt isn't always set
         $order_date_gmt = get_gmt_from_date($order->order_date);
         $subscription = wcs_create_subscription(array('start_date' => $cart->start_date, 'order_id' => $order->id, 'customer_id' => $order->get_user_id(), 'billing_period' => wcs_cart_pluck($cart, 'subscription_period'), 'billing_interval' => wcs_cart_pluck($cart, 'subscription_period_interval'), 'customer_note' => $order->customer_note));
         if (is_wp_error($subscription)) {
             throw new Exception($subscription->get_error_message());
         }
         // Set the subscription's billing and shipping address
         $subscription = wcs_copy_order_address($order, $subscription);
         $subscription->update_dates(array('trial_end' => $cart->trial_end_date, 'next_payment' => $cart->next_payment_date, 'end' => $cart->end_date));
         // Store trial period for PayPal
         if (wcs_cart_pluck($cart, 'subscription_trial_length') > 0) {
             update_post_meta($subscription->id, '_trial_period', wcs_cart_pluck($cart, 'subscription_trial_period'));
         }
         // Set the payment method on the subscription
         $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
         if ($cart->needs_payment() && isset($available_gateways[$order->payment_method])) {
             $subscription->set_payment_method($available_gateways[$order->payment_method]);
         }
         if (!$cart->needs_payment() || 'yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) {
             $subscription->update_manual('true');
         } elseif (!isset($available_gateways[$order->payment_method]) || !$available_gateways[$order->payment_method]->supports('subscriptions')) {
             $subscription->update_manual('true');
         }
         wcs_copy_order_meta($order, $subscription, 'subscription');
         // Store the line items
         foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
             $item_id = self::add_cart_item($subscription, $cart_item, $cart_item_key);
         }
         // Store fees (although no fees recur by default, extensions may add them)
         foreach ($cart->get_fees() as $fee_key => $fee) {
             $item_id = $subscription->add_fee($fee);
             if (!$item_id) {
                 // translators: placeholder is an internal error number
                 throw new Exception(sprintf(__('Error %d: Unable to create subscription. Please try again.', 'woocommerce-subscriptions'), 403));
             }
             // Allow plugins to add order item meta to fees
             do_action('woocommerce_add_order_fee_meta', $order->id, $item_id, $fee, $fee_key);
         }
         self::add_shipping($subscription, $cart);
         // Store tax rows
         foreach (array_keys($cart->taxes + $cart->shipping_taxes) as $tax_rate_id) {
             if ($tax_rate_id && !$subscription->add_tax($tax_rate_id, $cart->get_tax_amount($tax_rate_id), $cart->get_shipping_tax_amount($tax_rate_id)) && apply_filters('woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated') !== $tax_rate_id) {
                 // translators: placeholder is an internal error number
                 throw new Exception(sprintf(__('Error %d: Unable to add tax to subscription. Please try again.', 'woocommerce-subscriptions'), 405));
             }
         }
         // Store coupons
         foreach ($cart->get_coupons() as $code => $coupon) {
             if (!$subscription->add_coupon($code, $cart->get_coupon_discount_amount($code), $cart->get_coupon_discount_tax_amount($code))) {
                 // translators: placeholder is an internal error number
                 throw new Exception(sprintf(__('Error %d: Unable to create order. Please try again.', 'woocommerce-subscriptions'), 406));
             }
         }
         // Set the recurring totals on the subscription
         $subscription->set_total($cart->shipping_total, 'shipping');
         $subscription->set_total($cart->get_cart_discount_total(), 'cart_discount');
         $subscription->set_total($cart->get_cart_discount_tax_total(), 'cart_discount_tax');
         $subscription->set_total($cart->tax_total, 'tax');
         $subscription->set_total($cart->shipping_tax_total, 'shipping_tax');
         $subscription->set_total($cart->total);
         // If we got here, the subscription was created without problems
         $wpdb->query('COMMIT');
     } catch (Exception $e) {
         // There was an error adding the subscription
         $wpdb->query('ROLLBACK');
         return new WP_Error('checkout-error', $e->getMessage());
     }
     return $subscription;
 }
/**
 * Function to create an order from a subscription. It can be used for a renewal or for a resubscribe
 * order creation. It is the common in both of those instances.
 *
 * @param  WC_Subscription|int $subscription Subscription we're basing the order off of
 * @param  string $type        Type of new order. Default values are 'renewal_order'|'resubscribe_order'
 * @return WC_Order            New order
 */
function wcs_create_order_from_subscription($subscription, $type)
{
    $type = wcs_validate_new_order_type($type);
    if (is_wp_error($type)) {
        return $type;
    }
    global $wpdb;
    try {
        $wpdb->query('START TRANSACTION');
        if (!is_object($subscription)) {
            $subscription = wcs_get_subscription($subscription);
        }
        $new_order = wc_create_order(array('customer_id' => $subscription->get_user_id(), 'customer_note' => $subscription->customer_note));
        $new_order->post->post_title = wcs_get_new_order_title($type);
        wcs_copy_order_meta($subscription, $new_order, $type);
        // Copy over line items and allow extensions to add/remove items or item meta
        $items = apply_filters('wcs_new_order_items', $subscription->get_items(array('line_item', 'fee', 'shipping', 'tax')), $new_order, $subscription);
        $items = apply_filters('wcs_' . $type . '_items', $items, $new_order, $subscription);
        foreach ($items as $item_index => $item) {
            $item_name = apply_filters('wcs_new_order_item_name', $item['name'], $item, $subscription);
            $item_name = apply_filters('wcs_' . $type . '_item_name', $item_name, $item, $subscription);
            // Create order line item on the renewal order
            $recurring_item_id = wc_add_order_item($new_order->id, array('order_item_name' => $item_name, 'order_item_type' => $item['type']));
            // Remove recurring line items and set item totals based on recurring line totals
            foreach ($item['item_meta'] as $meta_key => $meta_values) {
                foreach ($meta_values as $meta_value) {
                    wc_add_order_item_meta($recurring_item_id, $meta_key, maybe_unserialize($meta_value));
                }
            }
        }
        // If we got here, the subscription was created without problems
        $wpdb->query('COMMIT');
        return apply_filters('wcs_new_order_created', $new_order, $subscription);
    } catch (Exception $e) {
        // There was an error adding the subscription
        $wpdb->query('ROLLBACK');
        return new WP_Error('new-order-error', $e->getMessage());
    }
}