Internal use only.
public static _insert_tax_rate ( array $tax_rate ) : integer | ||
$tax_rate | array | |
return | integer | tax rate id |
/** * Create a tax rate. * * ## OPTIONS * * [--<field>=<value>] * : Associative args for the new tax rate. * * [--porcelain] * : Outputs just the new tax rate id. * * ## AVAILABLE FIELDS * * These fields are available for create command: * * * country * * state * * postcode * * city * * rate * * name * * priority * * compound * * shipping * * class * * order * * ## EXAMPLES * * wp wc tax create --country=US --rate=5 --class=standard --type=percent * * @since 2.5.0 */ public function create($__, $assoc_args) { $porcelain = isset($assoc_args['porcelain']); unset($assoc_args['porcelain']); $assoc_args = apply_filters('woocommerce_cli_create_tax_rate_data', $assoc_args); $tax_data = array('tax_rate_country' => '', 'tax_rate_state' => '', 'tax_rate' => '', 'tax_rate_name' => '', 'tax_rate_priority' => 1, 'tax_rate_compound' => 0, 'tax_rate_shipping' => 1, 'tax_rate_order' => 0, 'tax_rate_class' => ''); foreach ($tax_data as $key => $value) { $new_key = str_replace('tax_rate_', '', $key); $new_key = 'tax_rate' === $new_key ? 'rate' : $new_key; if (isset($assoc_args[$new_key])) { if (in_array($new_key, array('compound', 'shipping'))) { $tax_data[$key] = $assoc_args[$new_key] ? 1 : 0; } else { $tax_data[$key] = $assoc_args[$new_key]; } } } // Create tax rate. $id = WC_Tax::_insert_tax_rate($tax_data); // Add locales. if (!empty($assoc_args['postcode'])) { WC_Tax::_update_tax_rate_postcodes($id, wc_clean($assoc_args['postcode'])); } if (!empty($assoc_args['city'])) { WC_Tax::_update_tax_rate_cities($id, wc_clean($assoc_args['city'])); } do_action('woocommerce_cli_create_tax_rate', $id, $tax_data); if ($porcelain) { WP_CLI::line($id); } else { WP_CLI::success("Created tax rate {$id}."); } }
/** * Save shipping and tax options. */ public function wc_setup_shipping_taxes_save() { check_admin_referer('wc-setup'); $enable_shipping = isset($_POST['woocommerce_calc_shipping']); $enable_taxes = isset($_POST['woocommerce_calc_taxes']); if ($enable_shipping) { update_option('woocommerce_ship_to_countries', ''); } else { update_option('woocommerce_ship_to_countries', 'disabled'); } update_option('woocommerce_calc_taxes', $enable_taxes ? 'yes' : 'no'); update_option('woocommerce_prices_include_tax', sanitize_text_field($_POST['woocommerce_prices_include_tax'])); if ($enable_shipping && !empty($_POST['shipping_cost_domestic'])) { // Create a domestic shipping zone $zone = new WC_Shipping_Zone($zone_data['zone_id']); $zone->set_zone_name(__('Domestic', 'woocommerce')); $zone->set_zone_order(1); $zone->add_location(WC()->countries->get_base_country(), 'country'); $zone->save(); // Add a flat rate shipping method to this domestic zone $instance_id = $zone->add_shipping_method('flat_rate'); $shipping_method = new WC_Shipping_Flat_Rate($instance_id); $option_key = $shipping_method->get_instance_option_key(); // Update rate settings $costs = array(); $costs[] = wc_format_decimal(sanitize_text_field($_POST['shipping_cost_domestic'])); if ($item_cost = sanitize_text_field($_POST['shipping_cost_domestic_item'])) { $costs[] = $item_cost . ' * [qty]'; } $shipping_method->instance_settings['cost'] = implode(' + ', array_filter($costs)); $shipping_method->instance_settings['enabled'] = 'yes'; $shipping_method->instance_settings['type'] = 'order'; update_option($option_key, $shipping_method->instance_settings); } if ($enable_shipping && !empty($_POST['shipping_cost_worldwide'])) { // Add a flat rate shipping method to the worldwide zone $zone = WC_Shipping_Zones::get_zone(0); $instance_id = $zone->add_shipping_method('flat_rate'); $shipping_method = new WC_Shipping_Flat_Rate($instance_id); $option_key = $shipping_method->get_instance_option_key(); // Update rate settings $costs = array(); $costs[] = wc_format_decimal(sanitize_text_field($_POST['shipping_cost_worldwide'])); if ($item_cost = sanitize_text_field($_POST['shipping_cost_worldwide_item'])) { $costs[] = $item_cost . ' * [qty]'; } $shipping_method->instance_settings['cost'] = implode(' + ', array_filter($costs)); $shipping_method->instance_settings['enabled'] = 'yes'; $shipping_method->instance_settings['type'] = 'order'; update_option($option_key, $shipping_method->instance_settings); } if ($enable_taxes && !empty($_POST['woocommerce_import_tax_rates'])) { $locale_info = (include WC()->plugin_path() . '/i18n/locale-info.php'); $tax_rates = array(); $country = WC()->countries->get_base_country(); $state = WC()->countries->get_base_state(); if (isset($locale_info[$country])) { if (isset($locale_info[$country]['tax_rates'][$state])) { $tax_rates = $locale_info[$country]['tax_rates'][$state]; } elseif (isset($locale_info[$country]['tax_rates'][''])) { $tax_rates = $locale_info[$country]['tax_rates']['']; } if (isset($locale_info[$country]['tax_rates']['*'])) { $tax_rates = array_merge($locale_info[$country]['tax_rates']['*'], $tax_rates); } } if ($tax_rates) { $loop = 0; foreach ($tax_rates as $rate) { $tax_rate = array('tax_rate_country' => $rate['country'], 'tax_rate_state' => $rate['state'], 'tax_rate' => $rate['rate'], 'tax_rate_name' => $rate['name'], 'tax_rate_priority' => isset($rate['priority']) ? absint($rate['priority']) : 1, 'tax_rate_compound' => 0, 'tax_rate_shipping' => $rate['shipping'] ? 1 : 0, 'tax_rate_order' => $loop++, 'tax_rate_class' => ''); WC_Tax::_insert_tax_rate($tax_rate); } } } wp_redirect(esc_url_raw($this->get_next_step_link())); exit; }
/** * Test some discount logic which has caused issues in the past. * Tickets: * https://github.com/woothemes/woocommerce/issues/10573 * https://github.com/woothemes/woocommerce/issues/10963 * * Due to discounts being split amongst products in cart. */ public function test_cart_get_discounted_price() { global $wpdb; // We need this to have the calculate_totals() method calculate totals if (!defined('WOOCOMMERCE_CHECKOUT')) { define('WOOCOMMERCE_CHECKOUT', true); } # Test case 1 #10963 // Create dummy coupon - fixed cart, 1 value $coupon = WC_Helper_Coupon::create_coupon(); // Add coupon WC()->cart->add_discount($coupon->code); // Create dummy product - price will be 10 $product = WC_Helper_Product::create_simple_product(); // Add product to cart x1, calc and test WC()->cart->add_to_cart($product->id, 1); WC()->cart->calculate_totals(); $this->assertEquals('9.00', number_format(WC()->cart->total, 2, '.', '')); $this->assertEquals('1.00', number_format(WC()->cart->discount_cart, 2, '.', '')); // Add product to cart x2, calc and test WC()->cart->add_to_cart($product->id, 1); WC()->cart->calculate_totals(); $this->assertEquals('19.00', number_format(WC()->cart->total, 2, '.', '')); $this->assertEquals('1.00', number_format(WC()->cart->discount_cart, 2, '.', '')); // Add product to cart x3, calc and test WC()->cart->add_to_cart($product->id, 1); WC()->cart->calculate_totals(); $this->assertEquals('29.00', number_format(WC()->cart->total, 2, '.', '')); $this->assertEquals('1.00', number_format(WC()->cart->discount_cart, 2, '.', '')); // Clean up the cart WC()->cart->empty_cart(); WC()->cart->remove_coupons(); # Test case 2 #10573 update_post_meta($product->id, '_regular_price', '29.95'); update_post_meta($product->id, '_price', '29.95'); update_post_meta($coupon->id, 'discount_type', 'percent'); update_post_meta($coupon->id, 'coupon_amount', '10'); update_option('woocommerce_prices_include_tax', 'yes'); update_option('woocommerce_calc_taxes', 'yes'); $tax_rate = array('tax_rate_country' => '', 'tax_rate_state' => '', 'tax_rate' => '10.0000', 'tax_rate_name' => 'TAX', 'tax_rate_priority' => '1', 'tax_rate_compound' => '0', 'tax_rate_shipping' => '1', 'tax_rate_order' => '1', 'tax_rate_class' => ''); WC_Tax::_insert_tax_rate($tax_rate); $product = wc_get_product($product->id); WC()->cart->add_to_cart($product->id, 1); WC()->cart->add_discount($coupon->code); WC()->cart->calculate_totals(); $cart_item = current(WC()->cart->get_cart()); $this->assertEquals('24.51', number_format($cart_item['line_total'], 2, '.', '')); // Cleanup $wpdb->query("DELETE FROM {$wpdb->prefix}woocommerce_tax_rates"); $wpdb->query("DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations"); WC()->cart->empty_cart(); WC()->cart->remove_coupons(); update_option('woocommerce_prices_include_tax', 'no'); update_option('woocommerce_calc_taxes', 'no'); // Delete coupon WC_Helper_Coupon::delete_coupon($coupon->id); // Clean up product WC_Helper_Product::delete_product($product->id); }
/** * add_eu_countries_vat_rates. * * @version 2.3.10 * @since 2.3.10 */ function add_eu_countries_vat_rates() { if (!isset($_POST['add_eu_countries_vat_rates'])) { return; } if (!is_super_admin() && !is_shop_manager()) { return; } $loop = 0; foreach (wcj_get_european_union_countries_with_vat() as $country => $rate) { $tax_rate = array('tax_rate_country' => $country, 'tax_rate' => $rate, 'tax_rate_name' => isset($_POST['wcj_tax_name']) ? $_POST['wcj_tax_name'] : __('VAT', 'woocommerce'), 'tax_rate_priority' => 1, 'tax_rate_compound' => 0, 'tax_rate_shipping' => 1, 'tax_rate_order' => $loop++, 'tax_rate_class' => ''); $tax_rate_id = WC_Tax::_insert_tax_rate($tax_rate); WC_Tax::_update_tax_rate_postcodes($tax_rate_id, ''); WC_Tax::_update_tax_rate_cities($tax_rate_id, ''); } }
public function install_standard_rates() { // delete previous inserted standard rates $tax_rates = $this->get_tax_rates(); foreach ($tax_rates as $tax_rate) { $tax_rate_name = sprintf("EU VAT (%s)", $tax_rate->tax_rate_country); if (0 == strpos($tax_rate->tax_rate_name, $tax_rate_name)) { WC_Tax::_delete_tax_rate($tax_rate->tax_rate_id); } } foreach ($this->tax_rates_data as $key => $value) { $tax_rate = array('tax_rate_country' => $key, 'tax_rate_state' => '*', 'tax_rate' => $value["standard_rate"], 'tax_rate_name' => sprintf("EU VAT (%s) %s%%", $key, $value["standard_rate"]), 'tax_rate_priority' => 1, 'tax_rate_compound' => 1, 'tax_rate_shipping' => 1, 'tax_rate_class' => ''); $tax_rate_id = WC_Tax::_insert_tax_rate($tax_rate); WC_Tax::_update_tax_rate_postcodes($tax_rate_id, wc_clean('*')); WC_Tax::_update_tax_rate_cities($tax_rate_id, wc_clean('*')); } }
/** * copy of import function: WC_Tax_Rate_Importer->import() * https://github.com/woothemes/woocommerce/blob/master/includes/admin/importers/class-wc-tax-rate-importer.php */ private function import_dummy_tax() { // clear tax rate tables global $wpdb; $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rates"); $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations"); $file = WC_POS_PLUGIN_PATH . 'tests/data/sample_tax_rates.csv'; $delimiter = ','; $loop = 0; if (($handle = fopen($file, "r")) !== false) { $header = fgetcsv($handle, 0, $delimiter); if (10 === sizeof($header)) { while (($row = fgetcsv($handle, 0, $delimiter)) !== false) { list($country, $state, $postcode, $city, $rate, $name, $priority, $compound, $shipping, $class) = $row; $tax_rate = array('tax_rate_country' => $country, 'tax_rate_state' => $state, 'tax_rate' => $rate, 'tax_rate_name' => $name, 'tax_rate_priority' => $priority, 'tax_rate_compound' => $compound ? 1 : 0, 'tax_rate_shipping' => $shipping ? 1 : 0, 'tax_rate_order' => $loop++, 'tax_rate_class' => $class); $tax_rate_id = WC_Tax::_insert_tax_rate($tax_rate); WC_Tax::_update_tax_rate_postcodes($tax_rate_id, wc_clean($postcode)); WC_Tax::_update_tax_rate_cities($tax_rate_id, wc_clean($city)); } } fclose($handle); } }
/** * Save shipping and tax options. */ public function wc_setup_shipping_taxes_save() { check_admin_referer('wc-setup'); $enable_shipping = isset($_POST['woocommerce_calc_shipping']); $enable_taxes = isset($_POST['woocommerce_calc_taxes']); if ($enable_shipping) { update_option('woocommerce_ship_to_countries', ''); WC_Admin_Notices::add_notice('no_shipping_methods'); } else { update_option('woocommerce_ship_to_countries', 'disabled'); } update_option('woocommerce_calc_taxes', $enable_taxes ? 'yes' : 'no'); update_option('woocommerce_prices_include_tax', sanitize_text_field($_POST['woocommerce_prices_include_tax'])); if ($enable_taxes) { $locale_info = (include WC()->plugin_path() . '/i18n/locale-info.php'); $tax_rates = array(); $country = WC()->countries->get_base_country(); $state = WC()->countries->get_base_state(); if (isset($locale_info[$country])) { if (isset($locale_info[$country]['tax_rates'][$state])) { $tax_rates = $locale_info[$country]['tax_rates'][$state]; } elseif (isset($locale_info[$country]['tax_rates'][''])) { $tax_rates = $locale_info[$country]['tax_rates']['']; } if (isset($locale_info[$country]['tax_rates']['*'])) { $tax_rates = array_merge($locale_info[$country]['tax_rates']['*'], $tax_rates); } } if ($tax_rates) { $loop = 0; foreach ($tax_rates as $rate) { $tax_rate = array('tax_rate_country' => $rate['country'], 'tax_rate_state' => $rate['state'], 'tax_rate' => $rate['rate'], 'tax_rate_name' => $rate['name'], 'tax_rate_priority' => isset($rate['priority']) ? absint($rate['priority']) : 1, 'tax_rate_compound' => 0, 'tax_rate_shipping' => $rate['shipping'] ? 1 : 0, 'tax_rate_order' => $loop++, 'tax_rate_class' => ''); WC_Tax::_insert_tax_rate($tax_rate); } } } wp_redirect(esc_url_raw($this->get_next_step_link())); exit; }
/** * Take tax data from the request and return the updated or newly created rate. * * @todo Replace with CRUD in 2.7.0 * @param WP_REST_Request $request Full details about the request. * @param stdClass|null $current Existing tax object. * @return stdClass */ protected function create_or_update_tax($request, $current = null) { $id = absint(isset($request['id']) ? $request['id'] : 0); $data = array(); $fields = array('tax_rate_country', 'tax_rate_state', 'tax_rate', 'tax_rate_name', 'tax_rate_priority', 'tax_rate_compound', 'tax_rate_shipping', 'tax_rate_order', 'tax_rate_class'); foreach ($fields as $field) { // Keys via API differ from the stored names returned by _get_tax_rate. $key = 'tax_rate' === $field ? 'rate' : str_replace('tax_rate_', '', $field); // Remove data that was not posted. if (!isset($request[$key])) { continue; } // Test new data against current data. if ($current && $current->{$field} === $request[$key]) { continue; } // Add to data array. switch ($key) { case 'tax_rate_priority': case 'tax_rate_compound': case 'tax_rate_shipping': case 'tax_rate_order': $data[$field] = absint($request[$key]); break; case 'tax_rate_class': $data[$field] = 'standard' !== $request['tax_rate_class'] ? $request['tax_rate_class'] : ''; break; default: $data[$field] = wc_clean($request[$key]); break; } } if ($id) { WC_Tax::_update_tax_rate($id, $data); } else { $id = WC_Tax::_insert_tax_rate($data); } // Add locales. if (!empty($request['postcode'])) { WC_Tax::_update_tax_rate_postcodes($id, wc_clean($request['postcode'])); } if (!empty($request['city'])) { WC_Tax::_update_tax_rate_cities($id, wc_clean($request['city'])); } return WC_Tax::_get_tax_rate($id, OBJECT); }
/** * Test: calculate_totals */ function test_calculate_totals() { global $wpdb; update_option('woocommerce_calc_taxes', 'yes'); $tax_rate = array('tax_rate_country' => '', 'tax_rate_state' => '', 'tax_rate' => '10.0000', 'tax_rate_name' => 'TAX', 'tax_rate_priority' => '1', 'tax_rate_compound' => '0', 'tax_rate_shipping' => '1', 'tax_rate_order' => '1', 'tax_rate_class' => ''); WC_Tax::_insert_tax_rate($tax_rate); $object = new WC_Order(); $object->add_product(WC_Helper_Product::create_simple_product(), 4); $rate = new WC_Shipping_Rate('flat_rate_shipping', 'Flat rate shipping', '10', array(), 'flat_rate'); $item = new WC_Order_Item_Shipping(); $item->set_props(array('method_title' => $rate->label, 'method_id' => $rate->id, 'total' => wc_format_decimal($rate->cost), 'taxes' => $rate->taxes, 'meta_data' => $rate->get_meta_data())); $object->add_item($item); $object->calculate_totals(); $this->assertEquals(55, $object->get_total()); // Cleanup $wpdb->query("DELETE FROM {$wpdb->prefix}woocommerce_tax_rates"); $wpdb->query("DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations"); update_option('woocommerce_calc_taxes', 'no'); }
/** * City saving. */ public function test__update_tax_rate_cities() { global $wpdb; $to_save = 'SOMEWHERE;SOMEWHERE_ELSE'; $tax_rate = array('tax_rate_country' => 'GB', 'tax_rate_state' => '', 'tax_rate' => '20.0000', 'tax_rate_name' => 'VAT', 'tax_rate_priority' => '1', 'tax_rate_compound' => '0', 'tax_rate_shipping' => '1', 'tax_rate_order' => '1', 'tax_rate_class' => ''); // Run function $tax_rate_id = WC_Tax::_insert_tax_rate($tax_rate); WC_Tax::_update_tax_rate_cities($tax_rate_id, $to_save); $results = $wpdb->get_col($wpdb->prepare("SELECT location_code FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d ORDER BY location_code ASC", $tax_rate_id)); $this->assertEquals(array('SOMEWHERE', 'SOMEWHERE_ELSE'), $results); WC_Tax::_delete_tax_rate($tax_rate_id); }
/** * Handle submissions from assets/js/settings-views-html-settings-tax.js Backbone model. */ public static function tax_rates_save_changes() { if (!isset($_POST['current_class'], $_POST['wc_tax_nonce'], $_POST['changes'])) { wp_send_json_error('missing_fields'); exit; } $current_class = $_POST['current_class']; // This is sanitized seven lines later. if (!wp_verify_nonce($_POST['wc_tax_nonce'], 'wc_tax_nonce-class:' . $current_class)) { wp_send_json_error('bad_nonce'); exit; } $current_class = WC_Tax::format_tax_rate_class($current_class); // Check User Caps if (!current_user_can('manage_woocommerce')) { wp_send_json_error('missing_capabilities'); exit; } $changes = $_POST['changes']; foreach ($changes as $tax_rate_id => $data) { if (isset($data['deleted'])) { if (isset($data['newRow'])) { // So the user added and deleted a new row. // That's fine, it's not in the database anyways. NEXT! continue; } WC_Tax::_delete_tax_rate($tax_rate_id); } $tax_rate = array_intersect_key($data, array('tax_rate_country' => 1, 'tax_rate_state' => 1, 'tax_rate' => 1, 'tax_rate_name' => 1, 'tax_rate_priority' => 1, 'tax_rate_compound' => 1, 'tax_rate_shipping' => 1, 'tax_rate_order' => 1)); if (isset($data['newRow'])) { // Hurrah, shiny and new! $tax_rate['tax_rate_class'] = $current_class; $tax_rate_id = WC_Tax::_insert_tax_rate($tax_rate); } else { // Updating an existing rate ... if (!empty($tax_rate)) { WC_Tax::_update_tax_rate($tax_rate_id, $tax_rate); } } if (isset($data['postcode'])) { WC_Tax::_update_tax_rate_postcodes($tax_rate_id, array_map('wc_clean', $data['postcode'])); } if (isset($data['city'])) { WC_Tax::_update_tax_rate_cities($tax_rate_id, array_map('wc_clean', $data['city'])); } } wp_send_json_success(array('rates' => WC_Tax::get_rates_for_tax_class($current_class))); }
/** * Save tax rates. */ public function save_tax_rates() { global $wpdb; $current_class = sanitize_title($this->get_current_tax_class()); // get the tax rate id of the first submited row $first_tax_rate_id = key($_POST['tax_rate_country']); // get the order position of the first tax rate id $tax_rate_order = absint($wpdb->get_var($wpdb->prepare("SELECT tax_rate_order FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $first_tax_rate_id))); $index = isset($tax_rate_order) ? $tax_rate_order : 0; // Loop posted fields foreach ($_POST['tax_rate_country'] as $key => $value) { $mode = 0 === strpos($key, 'new-') ? 'insert' : 'update'; $tax_rate = $this->get_posted_tax_rate($key, $index++, $current_class); if ('insert' === $mode) { $tax_rate_id = WC_Tax::_insert_tax_rate($tax_rate); } elseif (1 == $_POST['remove_tax_rate'][$key]) { $tax_rate_id = absint($key); WC_Tax::_delete_tax_rate($tax_rate_id); continue; } else { $tax_rate_id = absint($key); WC_Tax::_update_tax_rate($tax_rate_id, $tax_rate); } if (isset($_POST['tax_rate_postcode'][$key])) { WC_Tax::_update_tax_rate_postcodes($tax_rate_id, wc_clean($_POST['tax_rate_postcode'][$key])); } if (isset($_POST['tax_rate_city'][$key])) { WC_Tax::_update_tax_rate_cities($tax_rate_id, wc_clean($_POST['tax_rate_city'][$key])); } } }
/** * TaxJar API call * * @return void */ public function taxjar_api_call($options = array()) { global $woocommerce; $this->_log(':::: TaxJar Plugin requested ::::'); // Process $options array and turn them into varibables $options = is_array($options) ? $options : array(); extract(array_replace_recursive(array('to_country' => null, 'to_state' => null, 'to_zip' => null, 'to_city' => null, 'amount' => null, 'shipping_amount' => null), $options)); // Initalize some variables & properties $store_settings = $this->get_store_settings(); $customer = $woocommerce->customer; $this->tax_rate = 0; $this->amount_to_collect = 0; $this->item_collectable = 0; $this->shipping_collectable = 0; $this->freight_taxable = 1; $this->has_nexus = 0; $this->tax_source = 'origin'; $this->rate_id = null; // Strict conditions to be met before API call can be conducted if (empty($to_state) || empty($to_country) || empty($to_zip) || $customer->is_vat_exempt()) { return false; } // Setup Vars for API call $to_zip = explode(',', $to_zip); $to_zip = array_shift($to_zip); $from_country = $store_settings['store_country_setting']; $from_state = $store_settings['store_state_setting']; $from_zip = $store_settings['taxjar_zip_code_setting']; $from_city = $store_settings['taxjar_city_setting']; $this->_log(':::: TaxJar API called ::::'); $url = $this->uri . 'taxes'; $body_string = sprintf('plugin=woo&to_state=%s&from_state=%s&amount=%s&shipping=%s&from_city=%s&from_zip=%s&to_city=%s&to_zip=%s&from_country=%s&to_country=%s&line_items[][quantity]=1&line_items[][unit_price]=%s', $to_state, $from_state, $amount, $shipping_amount, $from_city, $from_zip, $to_city, $to_zip, $from_country, $to_country, $amount); // Build the URL and Transient key $url = str_replace(' ', '%20', $url); $cache_key = hash('md5', $url . '/' . $body_string); // To check to see if we hit the API or not $taxjar_response = false; // Make sure we don't have a cached rate if (false === ($cache_value = wp_cache_get($cache_key, 'taxjar'))) { // Log this request $this->_log("Requesting: " . $url); // Make API call with API token in header $response = wp_remote_post($url, array('headers' => array('Authorization' => 'Token token="' . $this->settings['api_token'] . '"', 'Content-Type' => 'application/x-www-form-urlencoded'), 'user-agent' => $this->ua, 'body' => $body_string)); // Fail loudly if we get an error from wp_remote_post if (is_wp_error($response)) { new WP_Error('request', __("There was an error retrieving the tax rates. Please check your server configuration.")); } else { if (200 == $response['response']['code']) { // Log the response $this->_log("Received: " . $response['body']); // Decode Response $taxjar_response = json_decode($response['body']); $taxjar_response = $taxjar_response->tax; // Update Properties based on Response $this->has_nexus = (int) $taxjar_response->has_nexus; $this->tax_source = empty($taxjar_response->tax_source) ? 'origin' : $taxjar_response->tax_source; $this->amount_to_collect = $taxjar_response->amount_to_collect; if (!empty($taxjar_response->breakdown)) { if (!empty($taxjar_response->breakdown->shipping)) { $this->shipping_collectable = $taxjar_response->breakdown->shipping->tax_collectable; } $this->item_collectable = $this->amount_to_collect - $this->shipping_collectable; } $this->tax_rate = $taxjar_response->rate; $this->freight_taxable = (int) $taxjar_response->freight_taxable; // Create cache value $cache_value = $this->amount_to_collect . '::' . $this->tax_rate . '::' . $this->freight_taxable . '::' . $this->has_nexus . '::' . $this->tax_source . '::' . $this->item_collectable . '::' . $this->shipping_collectable; // Log the new cached value $this->_log("Cache Value: " . $cache_value); // Set Cache wp_cache_set($cache_key, $cache_value, 'taxjar', $this->cache_time); } else { // Log Response Error $this->_log("Received (" . $response['response']['code'] . "): " . $response['body']); } } } else { // Read the cached value based on our delimiter $cache_value = explode('::', $cache_value); // Set properties to the cached values $this->amount_to_collect = $cache_value[0]; $this->tax_rate = $cache_value[1]; $this->freight_taxable = $cache_value[2]; $this->has_nexus = $cache_value[3]; $this->tax_source = $cache_value[4]; $this->item_collectable = $cache_value[5]; $this->shipping_collectable = $cache_value[6]; // Log Cached Response $this->_log("Cached Amount: " . $this->amount_to_collect); $this->_log("Cached Nexus: " . $this->has_nexus); $this->_log("Cached Source: " . $this->tax_source); $this->_log("Cached Rate: " . $this->tax_rate); $this->_log("Shipping Taxable? " . $this->freight_taxable); $this->_log("Item Tax to Collect: " . $this->item_collectable); $this->_log("Shipping Tax to Collect: " . $this->shipping_collectable); } // Remove taxes if they are set somehow and customer is exempt if ($customer->is_vat_exempt()) { $wc_cart_object->remove_taxes(); } elseif ($this->has_nexus) { //} else { // Use Woo core to find matching rates for taxable address $source_zip = $this->tax_source == 'destination' ? $to_zip : $from_zip; $source_city = $this->tax_source == 'destination' ? $to_city : $from_city; if (strtoupper($to_city) == strtoupper($from_city)) { $source_city = $to_city; } // Setup Tax Rates $tax_rates = array("tax_rate_country" => $to_country, "tax_rate_state" => $to_state, "tax_rate_name" => sprintf("%s Tax", $to_state), "tax_rate_priority" => 1, "tax_rate_compound" => false, "tax_rate_shipping" => $this->freight_taxable, "tax_rate" => $this->tax_rate * 100, "tax_rate_class" => ''); // Clear the cached rates $this->clear_wc_tax_cache($to_country, $to_state, $source_city, $source_zip); $this->_log($source_city); $wc_rates = WC_Tax::find_rates(array('country' => $to_country, 'state' => $to_state, 'postcode' => $source_zip, 'city' => $source_city, 'tax_class' => '')); // If we have rates, use those, but if no rates returned create one to link with, or use the first rate returned. if (!empty($wc_rates)) { $this->_log('::: TAX RATES FOUND :::'); $this->_log($wc_rates); // Get the existing ID $rate_id = key($wc_rates); // Update Tax Rates with TaxJar rates ( rates might be coming from a cached taxjar rate ) $this->_log(':: UPDATING TAX RATES TO ::'); $this->_log($tax_rates); WC_TAX::_update_tax_rate($rate_id, $tax_rates); } else { // Insert a rate if we did not find one $this->_log(':: Adding New Tax Rate ::'); $rate_id = WC_Tax::_insert_tax_rate($tax_rates); WC_Tax::_update_tax_rate_postcodes($rate_id, wc_clean($source_zip)); WC_Tax::_update_tax_rate_cities($rate_id, wc_clean($source_city)); } $this->_log('Tax Rate ID Set: ' . $rate_id); $this->rate_id = $rate_id; } }
/** * Create a single tax. * * @param WP_REST_Request $request Full details about the request. * @return WP_Error|WP_REST_Response */ public function create_item($request) { if (!empty($request['id'])) { return new WP_Error('woocommerce_rest_tax_exists', __('Cannot create existing resource.', 'woocommerce'), array('status' => 400)); } $data = array('tax_rate_country' => $request['country'], 'tax_rate_state' => $request['state'], 'tax_rate' => $request['rate'], 'tax_rate_name' => $request['name'], 'tax_rate_priority' => (int) $request['priority'], 'tax_rate_compound' => (int) $request['compound'], 'tax_rate_shipping' => (int) $request['shipping'], 'tax_rate_order' => (int) $request['order'], 'tax_rate_class' => 'standard' !== $request['class'] ? $request['class'] : ''); // Create tax rate. $id = WC_Tax::_insert_tax_rate($data); // Add locales. if (!empty($request['postcode'])) { WC_Tax::_update_tax_rate_postcodes($id, wc_clean($request['postcode'])); } if (!empty($request['city'])) { WC_Tax::_update_tax_rate_cities($id, wc_clean($request['city'])); } $tax = WC_Tax::_get_tax_rate($id, OBJECT); $this->update_additional_fields_for_object($tax, $request); /** * Fires after a tax is created or updated via the REST API. * * @param stdClass $tax Data used to create the tax. * @param WP_REST_Request $request Request object. * @param boolean $creating True when creating tax, false when updating tax. */ do_action('woocommerce_rest_insert_tax', $tax, $request, true); $request->set_param('context', 'edit'); $response = $this->prepare_item_for_response($tax, $request); $response = rest_ensure_response($response); $response->set_status(201); $response->header('Location', rest_url(sprintf('/%s/%s/%d', $this->namespace, $this->rest_base, $id))); return $response; }
/** * import function. * * @param mixed $file */ public function import($file) { if (!is_file($file)) { $this->import_error(__('The file does not exist, please try again.', 'woocommerce')); } $this->import_start(); $loop = 0; if (($handle = fopen($file, "r")) !== false) { $header = fgetcsv($handle, 0, $this->delimiter); if (10 === sizeof($header)) { while (($row = fgetcsv($handle, 0, $this->delimiter)) !== false) { list($country, $state, $postcode, $city, $rate, $name, $priority, $compound, $shipping, $class) = $row; $tax_rate = array('tax_rate_country' => $country, 'tax_rate_state' => $state, 'tax_rate' => $rate, 'tax_rate_name' => $name, 'tax_rate_priority' => $priority, 'tax_rate_compound' => $compound ? 1 : 0, 'tax_rate_shipping' => $shipping ? 1 : 0, 'tax_rate_order' => $loop++, 'tax_rate_class' => $class); $tax_rate_id = WC_Tax::_insert_tax_rate($tax_rate); WC_Tax::_update_tax_rate_postcodes($tax_rate_id, wc_clean($postcode)); WC_Tax::_update_tax_rate_cities($tax_rate_id, wc_clean($city)); } } else { $this->import_error(__('The CSV is invalid.', 'woocommerce')); } fclose($handle); } // Show Result echo '<div class="updated settings-error below-h2"><p> ' . sprintf(__('Import complete - imported <strong>%s</strong> tax rates.', 'woocommerce'), $loop) . ' </p></div>'; $this->import_end(); }
/** * Create a tax * * @since 2.5.0 * * @param array $data * * @return array */ public function create_tax($data) { try { if (!isset($data['tax'])) { throw new WC_API_Exception('woocommerce_api_missing_tax_data', sprintf(__('No %1$s data specified to create %1$s', 'woocommerce'), 'tax'), 400); } // Check permissions if (!current_user_can('manage_woocommerce')) { throw new WC_API_Exception('woocommerce_api_user_cannot_create_tax', __('You do not have permission to create tax rates', 'woocommerce'), 401); } $data = apply_filters('woocommerce_api_create_tax_data', $data['tax'], $this); $tax_data = array('tax_rate_country' => '', 'tax_rate_state' => '', 'tax_rate' => '', 'tax_rate_name' => '', 'tax_rate_priority' => 1, 'tax_rate_compound' => 0, 'tax_rate_shipping' => 1, 'tax_rate_order' => 0, 'tax_rate_class' => ''); foreach ($tax_data as $key => $value) { $new_key = str_replace('tax_rate_', '', $key); $new_key = 'tax_rate' === $new_key ? 'rate' : $new_key; if (isset($data[$new_key])) { if (in_array($new_key, array('compound', 'shipping'))) { $tax_data[$key] = $data[$new_key] ? 1 : 0; } else { $tax_data[$key] = $data[$new_key]; } } } // Create tax rate $id = WC_Tax::_insert_tax_rate($tax_data); // Add locales if (!empty($data['postcode'])) { WC_Tax::_update_tax_rate_postcodes($id, wc_clean($data['postcode'])); } if (!empty($data['city'])) { WC_Tax::_update_tax_rate_cities($id, wc_clean($data['city'])); } do_action('woocommerce_api_create_tax', $id, $data); $this->server->send_status(201); return $this->get_tax($id); } catch (WC_API_Exception $e) { return new WP_Error($e->getErrorCode(), $e->getMessage(), array('status' => $e->getCode())); } }
/** * Save tax rates */ public function save_tax_rates() { $current_class = sanitize_title($this->get_current_tax_class()); $index = 0; // Loop posted fields foreach ($_POST['tax_rate_country'] as $key => $value) { $mode = 0 === strpos($key, 'new-') ? 'insert' : 'update'; $tax_rate = $this->get_posted_tax_rate($key, $index++, $current_class); if ('insert' === $mode) { $tax_rate_id = WC_Tax::_insert_tax_rate($tax_rate); } elseif (1 == $_POST['remove_tax_rate'][$key]) { WC_Tax::_delete_tax_rate($key); continue; } else { $tax_rate_id = $key; WC_Tax::_update_tax_rate($tax_rate_id, $tax_rate); } if (isset($_POST['tax_rate_postcode'][$key])) { WC_Tax::_update_tax_rate_postcodes($tax_rate_id, wc_clean($_POST['tax_rate_postcode'][$key])); } if (isset($_POST['tax_rate_city'][$key])) { WC_Tax::_update_tax_rate_cities($tax_rate_id, wc_clean($_POST['tax_rate_city'][$key])); } } }
/** * Save shipping and tax options */ public function wc_setup_shipping_taxes_save() { check_admin_referer('wc-setup'); $woocommerce_calc_shipping = isset($_POST['woocommerce_calc_shipping']) ? 'yes' : 'no'; $woocommerce_calc_taxes = isset($_POST['woocommerce_calc_taxes']) ? 'yes' : 'no'; update_option('woocommerce_calc_shipping', $woocommerce_calc_shipping); update_option('woocommerce_calc_taxes', $woocommerce_calc_taxes); update_option('woocommerce_prices_include_tax', sanitize_text_field($_POST['woocommerce_prices_include_tax'])); if ('yes' === $woocommerce_calc_shipping && !empty($_POST['shipping_cost_domestic'])) { // Delete existing settings if they exist delete_option('woocommerce_flat_rate_settings'); // Init rate and settings $shipping_method = new WC_Shipping_Flat_Rate(); $costs = array(); $costs[] = wc_format_decimal(sanitize_text_field($_POST['shipping_cost_domestic'])); if ($item_cost = sanitize_text_field($_POST['shipping_cost_domestic_item'])) { $costs[] = $item_cost . ' * [qty]'; } $shipping_method->settings['cost'] = implode(' + ', array_filter($costs)); $shipping_method->settings['enabled'] = 'yes'; $shipping_method->settings['type'] = 'order'; $shipping_method->settings['availability'] = 'specific'; $shipping_method->settings['countries'] = array(WC()->countries->get_base_country()); update_option($shipping_method->plugin_id . $shipping_method->id . '_settings', $shipping_method->settings); } if ('yes' === $woocommerce_calc_shipping && !empty($_POST['shipping_cost_international'])) { // Delete existing settings if they exist delete_option('woocommerce_international_delivery_settings'); // Init rate and settings $shipping_method = new WC_Shipping_International_Delivery(); $costs = array(); $costs[] = wc_format_decimal(sanitize_text_field($_POST['shipping_cost_international'])); if ($item_cost = sanitize_text_field($_POST['shipping_cost_international_item'])) { $costs[] = $item_cost . ' * [qty]'; } $shipping_method->settings['cost'] = implode(' + ', array_filter($costs)); $shipping_method->settings['enabled'] = 'yes'; $shipping_method->settings['type'] = 'order'; if (!empty($_POST['shipping_cost_domestic'])) { $shipping_method->settings['availability'] = 'excluding'; $shipping_method->settings['countries'] = array(WC()->countries->get_base_country()); } update_option($shipping_method->plugin_id . $shipping_method->id . '_settings', $shipping_method->settings); } if ('yes' === $woocommerce_calc_taxes && !empty($_POST['woocommerce_import_tax_rates'])) { $locale_info = (include WC()->plugin_path() . '/i18n/locale-info.php'); $tax_rates = array(); $country = WC()->countries->get_base_country(); $state = WC()->countries->get_base_state(); if (isset($locale_info[$country])) { if (isset($locale_info[$country]['tax_rates'][$state])) { $tax_rates = $locale_info[$country]['tax_rates'][$state]; } elseif (isset($locale_info[$country]['tax_rates'][''])) { $tax_rates = $locale_info[$country]['tax_rates']['']; } if (isset($locale_info[$country]['tax_rates']['*'])) { $tax_rates = array_merge($locale_info[$country]['tax_rates']['*'], $tax_rates); } } if ($tax_rates) { $loop = 0; foreach ($tax_rates as $rate) { $tax_rate = array('tax_rate_country' => $rate['country'], 'tax_rate_state' => $rate['state'], 'tax_rate' => $rate['rate'], 'tax_rate_name' => $rate['name'], 'tax_rate_priority' => isset($rate['priority']) ? absint($rate['priority']) : 1, 'tax_rate_compound' => 0, 'tax_rate_shipping' => $rate['shipping'] ? 1 : 0, 'tax_rate_order' => $loop++, 'tax_rate_class' => ''); WC_Tax::_insert_tax_rate($tax_rate); } } } wp_redirect(esc_url_raw($this->get_next_step_link())); exit; }
/** * @used-by callback_init_combined_tax_classes */ private static function init_tax_classes() { $standard_class_pos = array_search('Standard', static::$predefined_tax_classes); if ($standard_class_pos !== FALSE) { $tax_classes = array_merge(array_slice(static::$predefined_tax_classes, 0, $standard_class_pos), array_slice(static::$predefined_tax_classes, $standard_class_pos + 1)); } else { $tax_classes =& static::$predefined_tax_classes; } $redefined = array_map('trim', array_merge($tax_classes, array_diff(WC_Tax::get_tax_classes(), $tax_classes))); update_option('woocommerce_tax_classes', implode("\n", $redefined)); /////////////////////////////////////////////// // check and add '과세 상품' class $taxed_class = sanitize_title(static::$predefined_tax_classes[0]); /** @var array $taxed following keys are present: * - rate * - label * - shipping * - compound */ $taxed = WC_Tax::find_rates(array('country' => 'KR', 'state' => '', 'city' => '', 'postcode' => '', 'tax_class' => $taxed_class)); $taxed_rate_label = static::$predefined_tax_rates[0]; //과세율 $taxed_rate_found = static::find_tax_rate_label($taxed, $taxed_rate_label); if (!$taxed_rate_found) { WC_Tax::_insert_tax_rate(array('tax_rate_country' => 'KR', 'tax_rate_state' => '', 'tax_rate' => '10.00', 'tax_rate_name' => $taxed_rate_label, 'tax_rate_priority' => 1, 'tax_rate_shipping' => 1, 'tax_rate_compound' => 0, 'tax_rate_order' => 0, 'tax_rate_class' => $taxed_class)); } /////////////////////////////////////////////// // check and add '비과세 상품' class $untaxed_class = sanitize_title(static::$predefined_tax_classes[1]); /** @var array $untaxed */ $untaxed = WC_Tax::find_rates(array('country' => 'KR', 'state' => '', 'city' => '', 'postcode' => '', 'tax_class' => $untaxed_class)); $untaxed_rate_label = static::$predefined_tax_rates[1]; // 비과세율 $untaxed_rate_found = static::find_tax_rate_label($untaxed, $untaxed_rate_label); if (!$untaxed_rate_found) { WC_Tax::_insert_tax_rate(array('tax_rate_country' => 'KR', 'tax_rate_state' => '', 'tax_rate' => '0.00', 'tax_rate_name' => $untaxed_rate_label, 'tax_rate_priority' => 1, 'tax_rate_shipping' => 0, 'tax_rate_compound' => 0, 'tax_rate_order' => 0, 'tax_rate_class' => $untaxed_class)); } }