/**
  * Pluggable function to render the checkout page payment fields form
  *
  * @since 3.0
  * @param WC_Gateway_Authorize_Net_AIM_Credit_Card $gateway gateway object
  */
 function woocommerce_authorize_net_aim_echeck_payment_fields($gateway)
 {
     // safely display the description, if there is one
     if ($gateway->get_description()) {
         echo '<p>' . wp_kses_post($gateway->get_description()) . '</p>';
     }
     $payment_method_defaults = array('account-number' => '', 'routing-number' => '');
     // for the test environment, display a notice and supply a default test payment method
     if ($gateway->is_environment('test')) {
         echo '<p>' . __('TEST MODE ENABLED', WC_Authorize_Net_AIM::TEXT_DOMAIN) . '</p>';
         $payment_method_defaults = array('account-number' => '8675309', 'routing-number' => '031202084');
     }
     // load the payment fields template file
     woocommerce_get_template('checkout/authorize-net-aim-echeck-payment-fields.php', array('payment_method_defaults' => $payment_method_defaults, 'sample_check_image_url' => SV_WC_Plugin_Compatibility::force_https_url($gateway->get_plugin()->get_plugin_url()) . '/' . $gateway->get_plugin()->get_framework_image_path() . 'example-check.png', 'states' => SV_WC_Plugin_Compatibility::WC()->countries->get_states('US')), '', $gateway->get_plugin()->get_plugin_path() . '/templates/');
 }
 /**
  * Include admin scripts
  */
 public function admin_scripts()
 {
     wp_enqueue_style('woocommerce_admin_styles', SV_WC_Plugin_Compatibility::WC()->plugin_url() . '/assets/css/admin.css');
     wp_register_style('woocommerce-csv_importer', $this->get_plugin_url() . '/assets/css/admin/wc-customer-order-csv-import.css', '', '1.0.0', 'screen');
     wp_enqueue_style('woocommerce-csv_importer');
 }
 /**
  * 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);
 }
        /**
         * Generates the POST pay form.  Some inline javascript will attempt to
         * auto-submit this pay form, so as to make the checkout process as
         * seamless as possile
         *
         * @since 2.1
         * @param int $order_id the order identifier
         * @return string payment page POST form
         */
        public function generate_pay_form($order_id)
        {
            // setup the order object
            $order = $this->get_order($order_id);
            $request_params = $this->get_hosted_pay_page_params($order);
            // standardized request data, for logging purposes
            $request = array('method' => 'POST', 'uri' => $this->get_hosted_pay_page_url($order), 'body' => json_encode($request_params));
            // log the request
            $this->log_hosted_pay_page_request($request);
            // attempt to automatically submit the form and bring them to the payza paymen site
            SV_WC_Plugin_Compatibility::wc_enqueue_js('
			$( "body" ).block( {
					message: "<img src=\\"' . esc_url(SV_WC_Plugin_Compatibility::WC()->plugin_url()) . '/assets/images/ajax-loader.gif\\" alt=\\"Redirecting&hellip;\\" style=\\"float:left; margin-right: 10px;\\" />' . __('Thank you for your order. We are now redirecting you to complete payment.', $this->text_domain) . '",
					overlayCSS: {
						background: "#fff",
						opacity: 0.6
					},
					css: {
						padding:         20,
						textAlign:       "center",
						color:           "#555",
						border:          "3px solid #aaa",
						backgroundColor: "#fff",
						cursor:          "wait",
						lineHeight:      "32px"
					}
				} );

			$( "#submit_' . $this->get_id() . '_payment_form" ).click();
		');
            $request_arg_fields = array();
            foreach ($request_params as $key => $value) {
                $request_arg_fields[] = '<input type="hidden" name="' . esc_attr($key) . '" value="' . esc_attr($value) . '" />';
            }
            return '<form action="' . esc_url($this->get_hosted_pay_page_url($order)) . '" method="post">' . implode('', $request_arg_fields) . '<input type="submit" class="button-alt" id="submit_' . $this->get_id() . '_payment_form" value="' . __('Pay Now', $this->text_domain) . '" />' . '<a class="button cancel" href="' . esc_url($order->get_cancel_order_url()) . '">' . __('Cancel Order', $this->text_domain) . '</a>' . '</form>';
        }
 /**
  * Process initial payment for a pre-order
  *
  * @since 2.0
  * @param \WC_Order $order the order object
  * @throws WC_Gateway_Braintree_Exception
  * @return array
  */
 private function process_pre_order_payment($order)
 {
     // do pre-authorization
     if (WC_Pre_Orders_Order::order_requires_payment_tokenization($order->id)) {
         // for an existing customer using a saved credit card, there's no way in braintree to simply
         // perform a $1 auth/void, so assume the saved card is valid already. If there is an issue
         // with the saved card, the pre-order payment will fail upon release anyway
         // exceptions are thrown if either the create_customer() or create_credit_card() method fails
         // add the braintree customer ID to the order, or create a new braintree customer and add/verify the new card added if needed
         if (!empty($order->braintree_order['customerId'])) {
             update_post_meta($order->id, '_wc_braintree_customer_id', $order->braintree_order['customerId']);
         } else {
             $order = $this->create_customer($order);
         }
         // add the braintree credit card token to the order, or create a new credit card for the customer and verify it if needed
         if (!empty($order->braintree_order['paymentMethodToken'])) {
             update_post_meta($order->id, '_wc_braintree_cc_token', $order->braintree_order['paymentMethodToken']);
         } else {
             $order = $this->create_credit_card($order);
         }
         // mark order as pre-ordered / reduce order stock
         WC_Pre_Orders_Order::mark_order_as_pre_ordered($order);
         // empty cart
         SV_WC_Plugin_Compatibility::WC()->cart->empty_cart();
         // redirect to thank you page
         return array('result' => 'success', 'redirect' => $this->get_return_url($order));
     } else {
         // charged upfront (or paying for a newly-released pre-order with the gateway), process just like regular product
         return parent::process_payment($order->id);
     }
 }
?>
/assets/images/help.png" width="16" height="16" /></label>
			<input id="wc-authorize-net-aim-echeck-routing-number" name="wc-authorize-net-aim-echeck-routing-number" type="text" class="input-text js-wc-payment-gateway-routing-number" autocomplete="off" value="<?php 
echo esc_attr($payment_method_defaults['routing-number']);
?>
" />
		</p>
		<p class="form-row form-row-last">
			<label for="wc-authorize-net-aim-echeck-account-number"><?php 
_e('Account Number (3-17 digits)', WC_Authorize_Net_AIM::TEXT_DOMAIN);
?>
 <img title="<?php 
esc_attr_e('Where do I find this?', WC_Authorize_Net_AIM::TEXT_DOMAIN);
?>
" class="js-wc-authorize-net-aim-echeck-account-help" style="margin-bottom:3px;cursor:pointer;box-shadow:none;" class="help_tip" src="<?php 
echo SV_WC_Plugin_Compatibility::WC()->plugin_url();
?>
/assets/images/help.png" width="16" height="16" /></label>
			<input id="wc-authorize-net-aim-echeck-account-number" name="wc-authorize-net-aim-echeck-account-number" type="text" class="input-text js-wc-payment-gateway-account-number" autocomplete="off" value="<?php 
echo esc_attr($payment_method_defaults['account-number']);
?>
" />
		</p>
		<div class="clear"></div>

		<p class="form-row">
			<label for="wc-authorize-net-aim-echeck-account-type"><?php 
_e('Account Type', WC_Authorize_Net_AIM::TEXT_DOMAIN);
?>
 <span class="required">*</span></label>
			<select id="wc-authorize-net-aim-echeck-account-type" name="wc-authorize-net-aim-echeck-account-type" class=" js-wc-payment-gateway-account-type" style="width:auto;">
 /**
  * Checks for proper gateway configuration including:
  *
  * + gateway enabled
  * + correct configuration (gateway specific)
  * + any dependencies met
  * + required currency
  * + required country
  *
  * @since 1.0
  * @see WC_Payment_Gateway::is_available()
  * @return true if this gateway is available for checkout, false otherwise
  */
 public function is_available()
 {
     // is enabled check
     $is_available = parent::is_available();
     // proper configuration
     if (!$this->is_configured()) {
         $is_available = false;
     }
     // all plugin dependencies met
     if (count($this->get_plugin()->get_missing_dependencies()) > 0) {
         $is_available = false;
     }
     // any required currencies?
     if (!$this->currency_is_accepted()) {
         $is_available = false;
     }
     // any required countries?
     if ($this->countries && SV_WC_Plugin_Compatibility::WC()->customer && SV_WC_Plugin_Compatibility::WC()->customer->get_country() && !in_array(SV_WC_Plugin_Compatibility::WC()->customer->get_country(), $this->countries)) {
         $is_available = false;
     }
     return apply_filters('wc_gateway_' . $this->get_id() + '_is_available', $is_available);
 }
 /**
  * Handles payment for guest / registered user checkout, using this logic:
  *
  * + If customer is logged in or creating an account, add them as a customer and save their card to the vault (if
  * they don't already exist and they're using a new card), and process the transaction
  *
  * + If customer is a guest, create a single transaction and don't create a customer or save the card to the vault
  *
  * @since 2.0
  * @param int $order_id the ID of the order
  * @return array|void
  */
 public function process_payment($order_id)
 {
     // get WC_Order object and add braintree-specific info
     $order = $this->get_order($order_id);
     try {
         /* registered customer checkout (already logged in or creating account at checkout) */
         if (is_user_logged_in() || 0 != $order->user_id) {
             // create new braintree customer if needed
             if (empty($order->braintree_order['customerId'])) {
                 $order = $this->create_customer($order);
             }
             // save card in vault if customer is using new card
             if (empty($order->braintree_order['paymentMethodToken'])) {
                 $order = $this->create_credit_card($order);
             }
             // payment failures are handled internally by do_transaction()
             if ($this->do_transaction($order)) {
                 // mark order as having received payment
                 $order->payment_complete();
                 SV_WC_Plugin_Compatibility::WC()->cart->empty_cart();
                 return array('result' => 'success', 'redirect' => $this->get_return_url($order));
             }
             /* guest checkout */
         } else {
             // payment failures are handled internally by do_guest_transaction()
             if ($this->do_guest_transaction($order)) {
                 // mark order as having received payment
                 $order->payment_complete();
                 SV_WC_Plugin_Compatibility::WC()->cart->empty_cart();
                 return array('result' => 'success', 'redirect' => $this->get_return_url($order));
             }
         }
     } catch (WC_Gateway_Braintree_Exception $e) {
         // mark order as failed, which adds an order note for the admin and displays a generic "payment error" to the customer
         $this->mark_order_as_failed($order, $e->getMessage());
         // add detailed debugging information
         $this->add_debug_message($e->getErrors());
     } catch (Braintree_Exception_Authorization $e) {
         $this->mark_order_as_failed($order, __('Authorization failed, ensure that your API key is correct and has permissions to create transactions.', WC_Braintree::TEXT_DOMAIN));
     } catch (Exception $e) {
         $this->mark_order_as_failed($order, sprintf(__('Error Type %s', WC_Braintree::TEXT_DOMAIN), get_class($e)));
     }
 }
 /**
  * Process payment & return result
  *
  * @since 2.0
  */
 public function process_payment($order_id)
 {
     $order = new WC_Order($order_id);
     $testmode = 'yes' == $this->testmode ? 'TRUE' : 'FALSE';
     try {
         $authnet_request = array("x_tran_key" => $this->transkey, "x_login" => $this->apilogin, "x_amount" => number_format($order->get_total(), 2, '.', ''), "x_card_num" => $_POST['ccnum'], "x_card_code" => isset($_POST['cvv']) ? $_POST['cvv'] : '', "x_exp_date" => $_POST['expmonth'] . "-" . $_POST['expyear'], "x_type" => $this->salemethod, "x_version" => "3.1", "x_delim_data" => "TRUE", "x_relay_response" => "FALSE", "x_method" => "CC", "x_first_name" => $order->billing_first_name, "x_last_name" => $order->billing_last_name, "x_address" => $order->billing_address_1, "x_city" => $order->billing_city, "x_state" => $order->billing_state, "x_zip" => $order->billing_postcode, "x_country" => $order->billing_country, "x_phone" => $order->billing_phone, "x_email" => $order->billing_email, "x_ship_to_first_name" => $order->shipping_first_name, "x_ship_to_last_name" => $order->shipping_last_name, "x_ship_to_company" => $order->shipping_company, "x_ship_to_address" => $order->shipping_address_1, "x_ship_to_city" => $order->shipping_city, "x_ship_to_country" => $order->shipping_country, "x_ship_to_state" => $order->shipping_state, "x_ship_to_zip" => $order->shipping_postcode, "x_cust_id" => $order->user_id, "x_customer_ip" => $_SERVER['REMOTE_ADDR'], "x_tax" => "Order Tax<|>Order Tax<|>" . SV_WC_Plugin_Compatibility::wc_format_decimal($order->order_tax, 2), "x_invoice_num" => ltrim($order->get_order_number(), '#'), "x_test_request" => $testmode, "x_delim_char" => '|', "x_encap_char" => '');
         // Don't send card details in the debug email
         $authnet_debug_request = $authnet_request;
         $authnet_debug_request['x_card_num'] = "XXXX";
         $authnet_debug_request['x_card_code'] = "XXXX";
         $authnet_debug_request['x_exp_date'] = "XXXX";
         $this->send_debugging_email("URL: " . $this->gatewayurl . "\n\nSENDING REQUEST:" . print_r($authnet_debug_request, true));
         // Send request
         $post = '';
         foreach ($authnet_request as $key => $val) {
             $post .= urlencode($key) . "=" . urlencode($val) . "&";
         }
         $post = substr($post, 0, -1);
         $response = wp_remote_post($this->gatewayurl, array('method' => 'POST', 'body' => $post, 'redirection' => 0, 'timeout' => 70, 'sslverify' => false));
         if (is_wp_error($response)) {
             throw new Exception(__('There was a problem connecting to the payment gateway.', WC_Authorize_Net_AIM::TEXT_DOMAIN));
         }
         if (empty($response['body'])) {
             throw new Exception(__('Empty Authorize.net response.', WC_Authorize_Net_AIM::TEXT_DOMAIN));
         }
         $content = $response['body'];
         // prep response
         foreach (preg_split("/\r?\n/", $content) as $line) {
             if (preg_match("/^1|2|3\\|/", $line)) {
                 $data = explode("|", $line);
             }
         }
         // store response
         $response['response_code'] = $data[0];
         $response['response_sub_code'] = $data[1];
         $response['response_reason_code'] = $data[2];
         $response['response_reason_text'] = $data[3];
         $response['approval_code'] = $data[4];
         $response['avs_code'] = $data[5];
         $response['transaction_id'] = $data[6];
         $response['invoice_number_echo'] = $data[7];
         $response['description_echo'] = $data[8];
         $response['amount_echo'] = $data[9];
         $response['method_echo'] = $data[10];
         $response['transaction_type_echo'] = $data[11];
         $response['customer_id_echo'] = $data[12];
         $response['first_name_echo'] = $data[13];
         $response['last_name_echo'] = $data[14];
         $response['company_echo'] = $data[15];
         $response['billing_address_echo'] = $data[16];
         $response['city_echo'] = $data[17];
         $response['state_echo'] = $data[18];
         $response['zip_echo'] = $data[19];
         $response['country_echo'] = $data[20];
         $response['phone_echo'] = $data[21];
         $response['fax_echo'] = $data[22];
         $response['email_echo'] = $data[23];
         $response['ship_first_name_echo'] = $data[24];
         $response['ship_last_name_echo'] = $data[25];
         $response['ship_company_echo'] = $data[26];
         $response['ship_billing_address_echo'] = $data[27];
         $response['ship_city_echo'] = $data[28];
         $response['ship_state_echo'] = $data[29];
         $response['ship_zip_echo'] = $data[30];
         $response['ship_country_echo'] = $data[31];
         $response['tax_echo'] = $data[32];
         $response['duty_echo'] = $data[33];
         $response['freight_echo'] = $data[34];
         $response['tax_exempt_echo'] = $data[35];
         $response['po_number_echo'] = $data[36];
         $response['md5_hash'] = $data[37];
         $response['cvv_response_code'] = $data[38];
         $response['cavv_response_code'] = $data[39];
         $this->send_debugging_email("RESPONSE RAW: " . $content . "\n\nRESPONSE:" . print_r($response, true));
         // Retreive response
         if (1 == $response['response_code'] || 4 == $response['response_code']) {
             // Successful payment
             $order->add_order_note(__('Authorize.net payment completed', WC_Authorize_Net_AIM::TEXT_DOMAIN) . ' (Response Code: ' . $response['response_code'] . ')');
             $order->payment_complete();
             SV_WC_Plugin_Compatibility::WC()->cart->empty_cart();
             // Return thank you redirect
             return array('result' => 'success', 'redirect' => $this->get_return_url($order));
         } else {
             $this->send_debugging_email("AUTHORIZE.NET ERROR:\nresponse_code:" . $response['response_code'] . "\nresponse_reasib_text:" . $response['response_reason_text']);
             $cancelNote = __('Authorize.net payment failed', WC_Authorize_Net_AIM::TEXT_DOMAIN) . ' (Response Code: ' . $response['response_code'] . '). ' . __('Payment was rejected due to an error', WC_Authorize_Net_AIM::TEXT_DOMAIN) . ': "' . $response['response_reason_text'] . '". ';
             $this->mark_order_as_failed($order, $cancelNote);
         }
     } catch (Exception $e) {
         $this->mark_order_as_failed($order, sprintf(__('Connection error: %s', WC_Authorize_Net_AIM::TEXT_DOMAIN), $e->getMessage()));
     }
 }
 /**
  * Handle the pre-order initial payment/tokenization, or defer back to the normal payment
  * processing flow
  *
  * @since 1.0
  * @see SV_WC_Payment_Gateway::process_payment()
  * @param boolean $result the result of this pre-order payment process
  * @param int $order_id the order identifier
  * @return true|array true to process this payment as a regular transaction, otherwise
  *         return an array containing keys 'result' and 'redirect'
  * @throws SV_WC_Payment_Gateway_Feature_Unsupported_Exception if pre-orders are not supported by this gateway or its current configuration
  */
 public function process_pre_order_payment($result, $order_id)
 {
     if (!$this->supports_pre_orders()) {
         throw new SV_WC_Payment_Gateway_Feature_Unsupported_Exception('Pre-Orders not supported by gateway');
     }
     if (WC_Pre_Orders_Order::order_contains_pre_order($order_id) && WC_Pre_Orders_Order::order_requires_payment_tokenization($order_id)) {
         $order = $this->get_order($order_id);
         try {
             // using an existing tokenized payment method
             if (isset($order->payment->token) && $order->payment->token) {
                 // save the tokenized card info for completing the pre-order in the future
                 $this->add_transaction_data($order);
             } else {
                 // otherwise tokenize the payment method
                 $order = $this->create_payment_token($order);
             }
             // mark order as pre-ordered / reduce order stock
             WC_Pre_Orders_Order::mark_order_as_pre_ordered($order);
             // empty cart
             SV_WC_Plugin_Compatibility::WC()->cart->empty_cart();
             // redirect to thank you page
             return array('result' => 'success', 'redirect' => $this->get_return_url($order));
         } catch (Exception $e) {
             $this->mark_order_as_failed($order, sprintf(_x('Pre-Order Tokenization attempt failed (%s)', 'Supports direct payment method pre-orders', $this->text_domain), $this->get_method_title(), $e->getMessage()));
         }
     }
     // processing regular product
     return $result;
 }