/**
  * Create new orders based on the parsed data
  */
 private function process_orders()
 {
     global $wpdb;
     $this->imported = $this->merged = 0;
     // peforming a dry run?
     $dry_run = isset($_POST['dry_run']) && $_POST['dry_run'] ? true : false;
     $this->log->add('---');
     $this->log->add(__('Processing orders.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN));
     foreach ($this->posts as $post) {
         // orders with custom order order numbers can be checked for existance, otherwise there's not much we can do
         if (!empty($post['order_number_formatted']) && isset($this->processed_posts[$post['order_number_formatted']])) {
             $this->skipped++;
             $this->log->add(sprintf(__('> Order %s already processed. Skipping.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $post['order_number_formatted']), true);
             continue;
         }
         // see class-wc-checkout.php for reference
         $order_data = array('post_date' => date('Y-m-d H:i:s', $post['date']), 'post_type' => 'shop_order', 'post_title' => 'Order – ' . date('F j, Y @ h:i A', $post['date']), 'post_status' => 'publish', 'ping_status' => 'closed', 'post_excerpt' => $post['order_comments'], 'post_author' => 1, 'post_password' => uniqid('order_'));
         if (!$dry_run) {
             // track whether download permissions need to be granted
             $add_download_permissions = false;
             $order_id = wp_insert_post($order_data);
             if (is_wp_error($order_id)) {
                 $this->errored++;
                 $this->log->add(sprintf(__('> Error inserting %s: %s', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $post['order_number_formatted'], $order_id->get_error_message()), true);
             }
             // empty update to bump up the post_modified date to today's date (otherwise it would match the post_date, which isn't quite right)
             wp_update_post(array('ID' => $order_id));
             // set order status
             wp_set_object_terms($order_id, $post['status'], 'shop_order_status');
             // handle special meta fields
             update_post_meta($order_id, '_order_key', apply_filters('woocommerce_generate_order_key', uniqid('order_')));
             update_post_meta($order_id, '_order_currency', get_woocommerce_currency());
             // TODO: fine to use store default?
             if (!SV_WC_Plugin_Compatibility::is_wc_version_gte_2_1()) {
                 update_post_meta($order_id, '_order_taxes', array());
                 // pre-2.1
             }
             update_post_meta($order_id, '_prices_include_tax', get_option('woocommerce_prices_include_tax'));
             // add order postmeta
             foreach ($post['postmeta'] as $meta) {
                 $meta_processed = false;
                 // we don't set the "download permissions granted" meta, we call the woocommerce function to take care of this for us
                 if (('Download Permissions Granted' == $meta['key'] || '_download_permissions_granted' == $meta['key']) && $meta['value']) {
                     $add_download_permissions = true;
                     $meta_processed = true;
                 }
                 if (!$meta_processed) {
                     update_post_meta($order_id, $meta['key'], $meta['value']);
                 }
                 // set the paying customer flag on the user meta if applicable
                 if ('_customer_user' == $meta['key'] && $meta['value'] && in_array($post['status'], array('processing', 'completed', 'refunded'))) {
                     update_user_meta($meta['value'], "paying_customer", 1);
                 }
             }
             // handle order items
             $order_items = array();
             $order_item_meta = null;
             foreach ($post['order_items'] as $item) {
                 $product = null;
                 $variation_item_meta = array();
                 // if there's a product_id then we've already determined during parsing that this product exists
                 if ($item['product_id']) {
                     $product = get_product($item['product_id']);
                     // handle variations
                     if (($product->is_type('variable') || $product->is_type('variation') || $product->is_type('subscription_variation')) && method_exists($product, 'get_variation_id')) {
                         foreach ($product->get_variation_attributes() as $key => $value) {
                             $variation_item_meta[] = array('meta_name' => esc_attr(substr($key, 10)), 'meta_value' => $value);
                             // remove the leading 'attribute_' from the name to get 'pa_color' for instance
                         }
                     }
                 }
                 // order item
                 $order_items[] = array('order_item_name' => $product ? $product->get_title() : __('Unknown Product', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), 'order_item_type' => 'line_item');
                 // standard order item meta
                 $_order_item_meta = array('_qty' => (int) $item['qty'], '_tax_class' => '', '_product_id' => $item['product_id'], '_variation_id' => $product && method_exists($product, 'get_variation_id') ? $product->get_variation_id() : 0, '_line_subtotal' => number_format((double) $item['total'], 2, '.', ''), '_line_subtotal_tax' => 0, '_line_total' => number_format((double) $item['total'], 2, '.', ''), '_line_tax' => 0);
                 // add any product variation meta
                 foreach ($variation_item_meta as $meta) {
                     $_order_item_meta[$meta['meta_name']] = $meta['meta_value'];
                 }
                 // include any arbitrary order item meta
                 $_order_item_meta = array_merge($_order_item_meta, $item['meta']);
                 $order_item_meta[] = $_order_item_meta;
             }
             foreach ($order_items as $key => $order_item) {
                 $order_item_id = woocommerce_add_order_item($order_id, $order_item);
                 if ($order_item_id) {
                     foreach ($order_item_meta[$key] as $meta_key => $meta_value) {
                         if (strpos($meta_value, ':{i')) {
                             $meta_value = unserialize(stripslashes($meta_value));
                             //'a:1:{i:0;s:19:"2014-05-01 08:00:00";}';
                         }
                         woocommerce_add_order_item_meta($order_item_id, $meta_key, $meta_value);
                     }
                 }
             }
             // create the shipping order items (WC 2.1+)
             foreach ($post['order_shipping'] as $order_shipping) {
                 $shipping_order_item = array('order_item_name' => $order_shipping['title'], 'order_item_type' => 'shipping');
                 $shipping_order_item_id = woocommerce_add_order_item($order_id, $shipping_order_item);
                 if ($shipping_order_item_id) {
                     woocommerce_add_order_item_meta($shipping_order_item_id, 'method_id', $order_shipping['method_id']);
                     woocommerce_add_order_item_meta($shipping_order_item_id, 'cost', $order_shipping['cost']);
                 }
             }
             // create the tax order items (WC 2.1+)
             foreach ($post['tax_items'] as $tax_item) {
                 $tax_order_item = array('order_item_name' => $tax_item['title'], 'order_item_type' => 'tax');
                 $tax_order_item_id = woocommerce_add_order_item($order_id, $tax_order_item);
                 if ($tax_order_item_id) {
                     woocommerce_add_order_item_meta($tax_order_item_id, 'rate_id', $tax_item['rate_id']);
                     woocommerce_add_order_item_meta($tax_order_item_id, 'label', $tax_item['label']);
                     woocommerce_add_order_item_meta($tax_order_item_id, 'compound', $tax_item['compound']);
                     woocommerce_add_order_item_meta($tax_order_item_id, 'tax_amount', $tax_item['tax_amount']);
                     woocommerce_add_order_item_meta($tax_order_item_id, 'shipping_tax_amount', $tax_item['shipping_tax_amount']);
                 }
             }
             // Grant downloadalbe product permissions
             if ($add_download_permissions) {
                 woocommerce_downloadable_product_permissions($order_id);
             }
             // add order notes
             $order = new WC_Order($order_id);
             foreach ($post['notes'] as $order_note) {
                 $order->add_order_note($order_note);
             }
             // record the product sales
             $order->record_product_sales();
         }
         // ! dry run
         // was an original order number provided?
         if (!empty($post['order_number_formatted'])) {
             if (!$dry_run) {
                 // do our best to provide some custom order number functionality while also allowing 3rd party plugins to provide their own custom order number facilities
                 do_action('woocommerce_set_order_number', $order, $post['order_number'], $post['order_number_formatted']);
                 $order->add_order_note(sprintf(__("Original order #%s", WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $post['order_number_formatted']));
                 // get the order so we can display the correct order number
                 $order = new WC_Order($order_id);
             }
             $this->processed_posts[$post['order_number_formatted']] = $post['order_number_formatted'];
         }
         $this->imported++;
         $this->log->add(sprintf(__('> Finished importing order %s', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $dry_run ? "" : $order->get_order_number()));
     }
     $this->log->add(__('Finished processing orders.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN));
     unset($this->posts);
 }
 /**
  * Add any settings error
  *
  * @since 1.6
  */
 public function add_settings_errors()
 {
     global $wpdb;
     // nothing doing
     if (!isset($_POST['woocommerce_order_number_start'])) {
         return;
     }
     $newvalue = $_POST['woocommerce_order_number_start'];
     $oldvalue = get_option('woocommerce_order_number_start');
     // no change to starting order number
     if ((int) $newvalue === (int) $oldvalue) {
         return;
     }
     if ($this->is_order_number_start_invalid($newvalue)) {
         // bad value
         if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_1()) {
             WC_Admin_Settings::add_error(__('Order Number Start must be a number greater than or equal to 0.', self::TEXT_DOMAIN));
         } else {
             $this->errors = __('Order Number Start must be a number greater than or equal to 0.', self::TEXT_DOMAIN);
         }
         return;
     }
     if ($this->is_order_number_start_in_use($newvalue)) {
         // existing order number with a greater incrementing value
         $post_id = (int) $wpdb->get_var($wpdb->prepare("SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_order_number' AND meta_value = %d", $this->get_max_order_number()));
         if (class_exists('WC_Order')) {
             $order = new WC_Order($post_id);
             $highest_order_number = $order->get_order_number();
         } else {
             $highest_order_number = $post_id;
         }
         if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_1()) {
             WC_Admin_Settings::add_error(sprintf(__('There is an existing order (%s) with a number greater than or equal to %s.  To set a new order number start please choose a higher number or permanently delete the relevant order(s).', self::TEXT_DOMAIN), $highest_order_number, (int) $newvalue));
         } else {
             $this->errors = sprintf(__('There is an existing order (%s) with a number greater than or equal to %s.  To set a new order number start please choose a higher number or permanently delete the relevant order(s).', self::TEXT_DOMAIN), $highest_order_number, (int) $newvalue);
         }
         return;
     }
 }
 /**
  * Parse the order input file, building and returning an array of order data
  * to import into the database.
  *
  * The order data is broken into two portions:  the couple of defined fields
  * that make up the wp_posts table, and then the name-value meta data that is
  * inserted into the wp_postmeta table.  Within the meta data category, there
  * are known meta fields, such as 'billing_first_name' for instance, and then
  * arbitrary meta fields are allowed and identified by a CSV column title with
  * the prefix 'meta:'.
  *
  * @param array $parsed_data the raw data parsed from the CSV file
  * @param array $raw_headers the headers parsed from the CSV file
  * @param boolean $merging whether this is a straight import, or merge.  For
  *        the order import this will always be false.
  * @param int $record_offset number of records to skip before processing
  *
  * @return array associative array containing the key 'order' mapped to the parsed
  *         data, and key 'skipped' with a count of the skipped rows
  */
 private function parse_orders($parsed_data, $raw_headers, $merging, $record_offset)
 {
     global $WC_CSV_Import, $wpdb;
     $allow_unknown_products = isset($_POST['allow_unknown_products']) && $_POST['allow_unknown_products'] ? true : false;
     $results = array();
     // Count row
     $row = 0;
     // Track skipped records
     $skipped = 0;
     // detect whether this is an import from the Customer/Order CSV Export plugin by checking for the required header names
     $csv_export_file = false;
     if (in_array('Item SKU', $raw_headers) && in_array('Item Name', $raw_headers) && in_array('Item Variation', $raw_headers) && in_array('Item Amount', $raw_headers) && in_array('Row Price', $raw_headers) && in_array('Order ID', $raw_headers)) {
         $csv_export_file = true;
         // Note: Although I would have liked to have first transformed the
         //   Customer/Order CSV Export format into our standard format, then
         //   all error reporting line numbers would be thrown off, so we'll
         //   just deal with that other format in here
     }
     // get the known shipping methods and payment gateways once
     $available_methods = SV_WC_Plugin_Compatibility::WC()->shipping()->load_shipping_methods();
     $available_gateways = SV_WC_Plugin_Compatibility::WC()->payment_gateways->payment_gateways();
     $shop_order_status = (array) get_terms('shop_order_status', array('hide_empty' => 0, 'orderby' => 'id'));
     // get all defined taxes, keyed off of id
     $tax_rates = array();
     foreach ($wpdb->get_results("SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates") as $_row) {
         $tax_rates[$_row->tax_rate_id] = $_row;
     }
     // Format order data
     foreach ($parsed_data as $item) {
         $row++;
         // skip record?
         if ($row <= $record_offset) {
             $WC_CSV_Import->log->add(sprintf(__('> Row %s - skipped due to record offset.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $row));
             continue;
         }
         $postmeta = $order = array();
         if (!$csv_export_file) {
             // standard format:  optional integer order number and formatted order number
             $order_number = !empty($item['order_number']) ? $item['order_number'] : null;
             $order_number_formatted = !empty($item['order_number_formatted']) ? $item['order_number_formatted'] : $order_number;
             $WC_CSV_Import->log->add(sprintf(__('> Row %s - preparing for import.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $row));
             // validate the supplied formatted order number/order number
             if (is_numeric($order_number_formatted) && !$order_number) {
                 $order_number = $order_number_formatted;
             }
             // use formatted for underlying order number if possible
             if ($order_number && !is_numeric($order_number)) {
                 $WC_CSV_Import->log->add(sprintf(__('> > Skipped. Order number field must be an integer: %s.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $order_number));
                 $skipped++;
                 continue;
             }
             if ($order_number_formatted && !$order_number) {
                 $WC_CSV_Import->log->add(__('> > Skipped. Formatted order number provided but no numerical order number, see the documentation for further details.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN));
                 $skipped++;
                 continue;
             }
         } else {
             // Customer/Order CSV Export plugin format.  If the Sequential
             //  Order Numbers Pro plugin is installed, order_number will be
             //  available, if the Order ID is numeric use that, but otherwise
             //  we have no idea what the underlying sequential order number might be
             $order_number_formatted = $item['order_id'];
             $order_number = !empty($item['order_number']) ? $item['order_number'] : (is_numeric($order_number_formatted) ? $order_number_formatted : 0);
         }
         // obviously we can't set the order's post_id, so to have the ability to set order numbers
         //  we do the best that we can and make sure things work even better when a compatible
         //  plugin like the Sequential Order Number plugin is installed
         if ($order_number_formatted) {
             // verify that this order number isn't already in use
             // we'll give 3rd party plugins two chances to hook in their custom order number facilities:
             // first by performing a simple search using the order meta field name used by both this and the
             // Sequential Order Number Pro plugin, allowing other plugins to filter over it if needed,
             // while still providing this plugin with some base functionality
             $query_args = array('numberposts' => 1, 'meta_key' => apply_filters('woocommerce_order_number_formatted_meta_name', '_order_number_formatted'), 'meta_value' => $order_number_formatted, 'post_type' => 'shop_order', 'post_status' => 'publish', 'fields' => 'ids');
             $order_id = 0;
             $orders = get_posts($query_args);
             if (!empty($orders)) {
                 list($order_id) = get_posts($query_args);
             }
             // and secondly allowing other plugins to return an entirely different order number if the simple search above doesn't do it for them
             $order_id = apply_filters('woocommerce_find_order_by_order_number', $order_id, $order_number_formatted);
             if ($order_id) {
                 $WC_CSV_Import->log->add(sprintf(__('> > Skipped. Order %s already exists.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $order_number_formatted));
                 $skipped++;
                 continue;
             }
         }
         // handle the special (optional) customer_user field
         if (isset($item['customer_user']) && $item['customer_user']) {
             // attempt to find the customer user
             $found_customer = false;
             if (is_int($item['customer_user'])) {
                 $found_customer = get_user_by('ID', $item['customer_user']);
                 if (!$found_customer) {
                     $WC_CSV_Import->log->add(sprintf(__('> > Skipped. Cannot find customer with id %s.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $item['customer_user']));
                     $skipped++;
                     continue;
                 }
             } elseif (is_email($item['customer_user'])) {
                 // check by email
                 $found_customer = email_exists($item['customer_user']);
             }
             if (!$found_customer) {
                 // still haven't found the customer, check by username
                 $found_customer = username_exists($item['customer_user']);
             }
             if (!$found_customer) {
                 // no sign of this customer
                 $WC_CSV_Import->log->add(sprintf(__('> > Skipped. Cannot find customer with email/username %s.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $item['customer_user']));
                 $skipped++;
                 continue;
             } else {
                 $item['customer_user'] = $found_customer;
                 // user id
             }
         } elseif ($csv_export_file && isset($item['billing_email']) && $item['billing_email']) {
             // see if we can link the user by billing email
             $found_customer = email_exists($item['billing_email']);
             if ($found_customer) {
                 $item['customer_user'] = $found_customer;
             } else {
                 $item['customer_user'] = 0;
             }
             // guest checkout
         } else {
             // guest checkout
             $item['customer_user'] = 0;
         }
         if (!empty($item['status'])) {
             // check order status value
             $found_status = false;
             $available_statuses = array();
             foreach ($shop_order_status as $status) {
                 if (0 == strcasecmp($status->slug, $item['status'])) {
                     $found_status = true;
                 }
                 $available_statuses[] = $status->slug;
             }
             if (!$found_status) {
                 // unknown order status
                 $WC_CSV_Import->log->add(sprintf(__('> > Skipped. Unknown order status %s (%s).', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $item['status'], implode($available_statuses, ', ')));
                 $skipped++;
                 continue;
             }
         } else {
             $item['status'] = 'processing';
             // default
         }
         if (!empty($item['date'])) {
             if (false === ($item['date'] = strtotime($item['date']))) {
                 // invalid date format
                 $WC_CSV_Import->log->add(sprintf(__('> > Skipped. Invalid date format %s.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $item['date']));
                 $skipped++;
                 continue;
             }
         } else {
             $item['date'] = time();
         }
         $order_notes = array();
         if (!empty($item['order_notes'])) {
             $order_notes = explode("|", $item['order_notes']);
         }
         // build the order data object
         $order['status'] = $item['status'];
         $order['date'] = $item['date'];
         $order['order_comments'] = !empty($item['customer_note']) ? $item['customer_note'] : null;
         $order['notes'] = $order_notes;
         if (!is_null($order_number)) {
             $order['order_number'] = $order_number;
         }
         // optional order number, for convenience
         if ($order_number_formatted) {
             $order['order_number_formatted'] = $order_number_formatted;
         }
         // totals
         $order_tax = $order_shipping_tax = null;
         // Get any known order meta fields, and default any missing ones to 0/null
         // the provided shipping/payment method will be used as-is, and if found in the list of available ones, the respective titles will also be set
         foreach ($this->order_meta_fields as $column) {
             switch ($column) {
                 // this will be cased for pre WC 2.1 only
                 case 'shipping_method':
                     $value = isset($item[$column]) ? $item[$column] : '';
                     // look up shipping method by id or title
                     $shipping_method = isset($available_methods[$value]) ? $value : null;
                     if (!$shipping_method) {
                         // try by title
                         foreach ($available_methods as $method) {
                             if (0 === strcasecmp($method->title, $value)) {
                                 $shipping_method = $method->id;
                                 break;
                                 // go with the first one we find
                             }
                         }
                     }
                     if ($shipping_method) {
                         // known shipping method found
                         $postmeta[] = array('key' => '_shipping_method', 'value' => $shipping_method);
                         $postmeta[] = array('key' => '_shipping_method_title', 'value' => $available_methods[$shipping_method]->title);
                     } elseif ($csv_export_file && $value) {
                         // Customer/Order CSV Export format, shipping method title with no corresponding shipping method type found, so just use the title
                         $postmeta[] = array('key' => '_shipping_method', 'value' => '');
                         $postmeta[] = array('key' => '_shipping_method_title', 'value' => $value);
                     } elseif ($value) {
                         // Standard format, shipping method but no title
                         $postmeta[] = array('key' => '_shipping_method', 'value' => $value);
                         $postmeta[] = array('key' => '_shipping_method_title', 'value' => '');
                     } else {
                         // none
                         $postmeta[] = array('key' => '_shipping_method', 'value' => '');
                         $postmeta[] = array('key' => '_shipping_method_title', 'value' => '');
                     }
                     break;
                 case 'payment_method':
                     $value = isset($item[$column]) ? $item[$column] : '';
                     // look up shipping method by id or title
                     $payment_method = isset($available_gateways[$value]) ? $value : null;
                     if (!$payment_method) {
                         // try by title
                         foreach ($available_gateways as $method) {
                             if (0 === strcasecmp($method->title, $value)) {
                                 $payment_method = $method->id;
                                 break;
                                 // go with the first one we find
                             }
                         }
                     }
                     if ($payment_method) {
                         // known payment method found
                         $postmeta[] = array('key' => '_payment_method', 'value' => $payment_method);
                         $postmeta[] = array('key' => '_payment_method_title', 'value' => $available_gateways[$payment_method]->title);
                     } elseif ($csv_export_file && $value) {
                         // Customer/Order CSV Export format, payment method title with no corresponding payments method type found, so just use the title
                         $postmeta[] = array('key' => '_payment_method', 'value' => '');
                         $postmeta[] = array('key' => '_payment_method_title', 'value' => $value);
                     } elseif ($value) {
                         // Standard format, payment method but no title
                         $postmeta[] = array('key' => '_payment_method', 'value' => $value);
                         $postmeta[] = array('key' => '_payment_method_title', 'value' => '');
                     } else {
                         // none
                         $postmeta[] = array('key' => '_payment_method', 'value' => '');
                         $postmeta[] = array('key' => '_payment_method_title', 'value' => '');
                     }
                     break;
                     // handle numerics
                 // handle numerics
                 case 'order_shipping':
                     // legacy
                 // legacy
                 case 'shipping_total':
                     $order_shipping = isset($item[$column]) ? $item[$column] : 0;
                     // save the order shipping total for later use
                     $postmeta[] = array('key' => '_order_shipping', 'value' => number_format((double) $order_shipping, 2, '.', ''));
                     break;
                 case 'order_shipping_tax':
                     // legacy
                 // legacy
                 case 'shipping_tax_total':
                     // ignore blanks but allow zeroes
                     if (isset($item[$column]) && is_numeric($item[$column])) {
                         $order_shipping_tax = $item[$column];
                     }
                     break;
                 case 'order_tax':
                     // legacy
                 // legacy
                 case 'tax_total':
                     // ignore blanks but allow zeroes
                     if (isset($item[$column]) && is_numeric($item[$column])) {
                         $order_tax = $item[$column];
                     }
                     break;
                 case 'order_discount':
                 case 'cart_discount':
                 case 'order_total':
                     $value = isset($item[$column]) ? $item[$column] : 0;
                     $postmeta[] = array('key' => '_' . $column, 'value' => number_format((double) $value, 2, '.', ''));
                     break;
                 case 'billing_country':
                 case 'shipping_country':
                     $value = isset($item[$column]) ? $item[$column] : '';
                     // support country name or code by converting to code
                     $country_code = array_search($value, SV_WC_Plugin_Compatibility::WC()->countries->countries);
                     if ($country_code) {
                         $value = $country_code;
                     }
                     $postmeta[] = array('key' => '_' . $column, 'value' => $value);
                     break;
                 case 'Download Permissions Granted':
                 case 'download_permissions_granted':
                     if (isset($item['download_permissions_granted'])) {
                         if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_1()) {
                             $postmeta[] = array('key' => '_download_permissions_granted', 'value' => $item['download_permissions_granted']);
                         } else {
                             $postmeta[] = array('key' => 'Download Permissions Granted', 'value' => $item['download_permissions_granted']);
                         }
                     }
                     break;
                 default:
                     $postmeta[] = array('key' => '_' . $column, 'value' => isset($item[$column]) ? $item[$column] : "");
             }
         }
         // Get any custom meta fields
         foreach ($item as $key => $value) {
             if (!$value) {
                 continue;
             }
             // Handle meta: columns - import as custom fields
             if (strstr($key, 'meta:')) {
                 // Get meta key name
                 $meta_key = isset($raw_headers[$key]) ? $raw_headers[$key] : $key;
                 $meta_key = trim(str_replace('meta:', '', $meta_key));
                 // Add to postmeta array
                 $postmeta[] = array('key' => esc_attr($meta_key), 'value' => $value);
             }
         }
         $order_shipping_methods = array();
         $_shipping_methods = array();
         if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_1()) {
             // pre WC 2.1 format of a single shipping method
             if (isset($item['shipping_method']) && $item['shipping_method']) {
                 // collect the shipping method id/cost
                 $_shipping_methods[] = array($item['shipping_method'], isset($item['shipping_cost']) ? $item['shipping_cost'] : null);
             }
             // collect any additional shipping methods
             $i = null;
             if (isset($item['shipping_method_1'])) {
                 $i = 1;
             } elseif (isset($item['shipping_method_2'])) {
                 $i = 2;
             }
             if (!is_null($i)) {
                 while (!empty($item['shipping_method_' . $i])) {
                     $_shipping_methods[] = array($item['shipping_method_' . $i], isset($item['shipping_cost_' . $i]) ? $item['shipping_cost_' . $i] : null);
                     $i++;
                 }
             }
             // if the order shipping total wasn't set, calculate it
             if (!isset($order_shipping)) {
                 $order_shipping = 0;
                 foreach ($_shipping_methods as $_shipping_method) {
                     $order_shipping += $_shipping_method[1];
                 }
                 $postmeta[] = array('key' => '_order_shipping' . $column, 'value' => number_format((double) $order_shipping, 2, '.', ''));
             } elseif (isset($order_shipping) && 1 == count($_shipping_methods) && is_null($_shipping_methods[0][1])) {
                 // special case: if there was a total order shipping but no cost for the single shipping method, use the total shipping for the order shipping line item
                 $_shipping_methods[0][1] = $order_shipping;
             }
             foreach ($_shipping_methods as $_shipping_method) {
                 // look up shipping method by id or title
                 $shipping_method = isset($available_methods[$_shipping_method[0]]) ? $_shipping_method[0] : null;
                 if (!$shipping_method) {
                     // try by title
                     foreach ($available_methods as $method) {
                         if (0 === strcasecmp($method->title, $_shipping_method[0])) {
                             $shipping_method = $method->id;
                             break;
                             // go with the first one we find
                         }
                     }
                 }
                 if ($shipping_method) {
                     // known shipping method found
                     $order_shipping_methods[] = array('method_id' => $shipping_method, 'cost' => $_shipping_method[1], 'title' => $available_methods[$shipping_method]->title);
                 } elseif ($csv_export_file && $_shipping_method[0]) {
                     // Customer/Order CSV Export format, shipping method title with no corresponding shipping method type found, so just use the title
                     $order_shipping_methods[] = array('method_id' => '', 'cost' => $_shipping_method[1], 'title' => $_shipping_method[0]);
                 } elseif ($_shipping_method[0]) {
                     // Standard format, shipping method but no title
                     $order_shipping_methods[] = array('method_id' => $_shipping_method[0], 'cost' => $_shipping_method[1], 'title' => '');
                 }
             }
         }
         $order_items = array();
         if (!$csv_export_file) {
             // standard format
             if (!empty($item['order_item_1'])) {
                 // one or more order items
                 $i = 1;
                 while (!empty($item['order_item_' . $i])) {
                     // split on non-escaped pipes
                     // http://stackoverflow.com/questions/6243778/split-string-by-delimiter-but-not-if-it-is-escaped
                     $_item_meta = preg_split("~\\\\.(*SKIP)(*FAIL)|\\|~s", $item['order_item_' . $i]);
                     // fallback: try a simple explode, since the above apparently doesn't always work
                     if ($item['order_item_' . $i] && empty($_item_meta)) {
                         $_item_meta = explode('|', $item['order_item_' . $i]);
                     }
                     // pop off the special sku, qty and total values
                     $product_identifier = array_shift($_item_meta);
                     // sku or product_id:id
                     $qty = array_shift($_item_meta);
                     $total = array_shift($_item_meta);
                     if (!$product_identifier || !$qty || !$total) {
                         // invalid item
                         $WC_CSV_Import->log->add(sprintf(__('> > Skipped. Missing SKU, quantity or total for %s on row %s.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), 'order_item_' . $i, $row));
                         $skipped++;
                         continue 2;
                         // break outer loop
                     }
                     // product_id or sku
                     if (false !== strpos($product_identifier, 'product_id:')) {
                         // product by product_id
                         $product_id = substr($product_identifier, 11);
                         // not a product
                         if ('product' != get_post_type($product_id)) {
                             $product_id = '';
                         }
                     } else {
                         // find by sku
                         $product_id = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_sku' AND meta_value=%s LIMIT 1", $product_identifier));
                     }
                     if (!$allow_unknown_products && !$product_id) {
                         // unknown product
                         $WC_CSV_Import->log->add(sprintf(__('> > Skipped. Unknown order item: %s.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $product_identifier));
                         $skipped++;
                         continue 2;
                         // break outer loop
                     }
                     // get any additional item meta
                     $item_meta = array();
                     foreach ($_item_meta as $pair) {
                         // replace any escaped pipes
                         $pair = str_replace('\\|', '|', $pair);
                         // find the first ':' and split into name-value
                         $split = strpos($pair, ':');
                         $name = substr($pair, 0, $split);
                         $value = substr($pair, $split + 1);
                         $item_meta[$name] = $value;
                     }
                     $order_items[] = array('product_id' => $product_id, 'qty' => $qty, 'total' => $total, 'meta' => $item_meta);
                     $i++;
                 }
             }
         } else {
             // CSV Customer/Order Export format
             $sku = $item['item_sku'];
             $qty = $item['item_amount'];
             $total = $item['row_price'];
             if (!$sku || !$qty || !$total) {
                 // invalid item
                 $WC_CSV_Import->log->add(sprintf(__('> > Row %d - %s - skipped. Missing SKU, quantity or total', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $row, $item['order_id']));
                 $skipped++;
                 continue;
                 // break outer loop
             }
             // find by sku
             $product_id = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_sku' AND meta_value=%s LIMIT 1", $sku));
             if (!$product_id) {
                 // unknown product
                 $WC_CSV_Import->log->add(sprintf(__('> > Row %d - %s - skipped. Unknown order item: %s.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $row, $item['order_id'], $sku));
                 $skipped++;
                 continue;
                 // break outer loop
             }
             $order_items[] = array('product_id' => $product_id, 'qty' => $qty, 'total' => $total);
         }
         $tax_items = array();
         // standard tax item format which supports multiple tax items in numbered columns containing a pipe-delimated, colon-labeled format
         if (!empty($item['tax_item_1']) || !empty($item['tax_item'])) {
             // one or more order tax items
             // get the first tax item
             $tax_item = !empty($item['tax_item_1']) ? $item['tax_item_1'] : $item['tax_item'];
             $i = 1;
             $tax_amount_sum = $shipping_tax_amount_sum = 0;
             while ($tax_item) {
                 $tax_item_data = array();
                 // turn "label: Tax | tax_amount: 10" into an associative array
                 foreach (explode('|', $tax_item) as $piece) {
                     list($name, $value) = explode(':', $piece);
                     $tax_item_data[trim($name)] = trim($value);
                 }
                 // default rate id to 0 if not set
                 if (!isset($tax_item_data['rate_id'])) {
                     $tax_item_data['rate_id'] = 0;
                 }
                 // have a tax amount or shipping tax amount
                 if (isset($tax_item_data['tax_amount']) || isset($tax_item_data['shipping_tax_amount'])) {
                     // try and look up rate id by label if needed
                     if (isset($tax_item_data['label']) && $tax_item_data['label'] && !$tax_item_data['rate_id']) {
                         foreach ($tax_rates as $tax_rate) {
                             if (0 === strcasecmp($tax_rate->tax_rate_name, $tax_item_data['label'])) {
                                 // found the tax by label
                                 $tax_item_data['rate_id'] = $tax_rate->tax_rate_id;
                                 break;
                             }
                         }
                     }
                     // check for a rate being specified which does not exist, and clear it out (technically an error?)
                     if ($tax_item_data['rate_id'] && !isset($tax_rates[$tax_item_data['rate_id']])) {
                         $tax_item_data['rate_id'] = 0;
                     }
                     // default label of 'Tax' if not provided
                     if (!isset($tax_item_data['label']) || !$tax_item_data['label']) {
                         $tax_item_data['label'] = 'Tax';
                     }
                     // default tax amounts to 0 if not set
                     if (!isset($tax_item_data['tax_amount'])) {
                         $tax_item_data['tax_amount'] = 0;
                     }
                     if (!isset($tax_item_data['shipping_tax_amount'])) {
                         $tax_item_data['shipping_tax_amount'] = 0;
                     }
                     // handle compound flag by using the defined tax rate value (if any)
                     if (!isset($tax_item_data['tax_rate_compound'])) {
                         $tax_item_data['tax_rate_compound'] = '';
                         if ($tax_item_data['rate_id']) {
                             $tax_item_data['tax_rate_compound'] = $tax_rates[$tax_item_data['rate_id']]->tax_rate_compound;
                         }
                     }
                     $tax_items[] = array('title' => '', 'rate_id' => $tax_item_data['rate_id'], 'label' => $tax_item_data['label'], 'compound' => $tax_item_data['tax_rate_compound'], 'tax_amount' => $tax_item_data['tax_amount'], 'shipping_tax_amount' => $tax_item_data['shipping_tax_amount']);
                     // sum up the order totals, in case it wasn't part of the import
                     $tax_amount_sum += $tax_item_data['tax_amount'];
                     $shipping_tax_amount_sum += $tax_item_data['shipping_tax_amount'];
                 }
                 // get the next tax item (if any)
                 $i++;
                 $tax_item = isset($item['tax_item_' . $i]) ? $item['tax_item_' . $i] : null;
             }
             if (!is_numeric($order_tax)) {
                 $order_tax = $tax_amount_sum;
             }
             if (!is_numeric($order_shipping_tax)) {
                 $order_shipping_tax = $shipping_tax_amount_sum;
             }
         }
         // default to zero if not set
         if (!is_numeric($order_tax)) {
             $order_tax = 0;
         }
         if (!is_numeric($order_shipping_tax)) {
             $order_shipping_tax = 0;
         }
         // no tax items specified, so create a default one using the tax totals
         if (0 == count($tax_items)) {
             $tax_items[] = array('title' => '', 'rate_id' => 0, 'label' => 'Tax', 'compound' => '', 'tax_amount' => $order_tax, 'shipping_tax_amount' => $order_shipping_tax);
         }
         // add the order tax totals to the order meta
         $postmeta[] = array('key' => '_order_tax', 'value' => number_format((double) $order_tax, 2, '.', ''));
         $postmeta[] = array('key' => '_order_shipping_tax', 'value' => number_format((double) $order_shipping_tax, 2, '.', ''));
         // Customer/Order CSV Export format has orders broken up onto multiple lines, one per order item
         //  so detect whether we are continuing an existing order
         if ($csv_export_file) {
             $ix = count($results);
             if ($ix > 0 && $results[$ix - 1]['order_number_formatted'] == $order['order_number_formatted']) {
                 // continuing an existing order, add the current order item
                 $results[$ix - 1]['order_items'][] = $order_items[0];
                 $order = null;
             }
         }
         if ($order) {
             $order['postmeta'] = $postmeta;
             $order['order_items'] = $order_items;
             $order['order_shipping'] = $order_shipping_methods;
             // WC 2.1+
             $order['tax_items'] = $tax_items;
             // the order array will now contain the necessary name-value pairs for the wp_posts table, and also any meta data in the 'postmeta' array
             $results[] = $order;
         }
     }
     // Result
     return array($this->type => $results, 'skipped' => $skipped);
 }
 /**
  * Capture a credit card charge for a prior authorization if this payment
  * method was used for the given order, the charge hasn't already been
  * captured, and the gateway supports issuing a capture request
  *
  * @since 1.0
  * @param \WC_Order|int $order the order identifier or order object
  */
 public function maybe_capture_charge($order)
 {
     if (!is_object($order)) {
         $order = new WC_Order($order);
     }
     // bail if the order wasn't paid for with this gateway
     if (!$this->has_gateway($order->payment_method)) {
         return;
     }
     $gateway = $this->get_gateway($order->payment_method);
     // ensure that it supports captures
     if (!$this->can_capture_charge($gateway)) {
         return;
     }
     // ensure the authorization is still valid for capture
     if (!$gateway->authorization_valid_for_capture($order)) {
         return;
     }
     // remove order status change actions, otherwise we get a whole bunch of capture calls and errors
     remove_action('woocommerce_order_action_wc_' . $this->get_id() . '_capture_charge', array($this, 'maybe_capture_charge'));
     // since a capture results in an update to the post object (by updating
     // the paid date) we need to unhook the save_post action, otherwise we
     // can get boomeranged and change the status back to on-hold
     if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_1()) {
         // WC 2.1+
         remove_action('woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Data::save', 40, 2);
     } else {
         // WC 2.0
         remove_action('woocommerce_process_shop_order_meta', 'woocommerce_process_shop_order_meta', 10, 2);
     }
     // perform the capture
     $gateway->do_credit_card_capture($order);
 }