/** * 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…\\" 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; }