function test_returns_false_if_not_shipping_to_nexus_area()
 {
     update_option('woocommerce_default_country', 'US:CO');
     $tj = new WC_Taxjar_Integration();
     $tj_nexus = new WC_Taxjar_Nexus($tj);
     $this->assertFalse($tj_nexus->has_nexus_check('US', 'XO'));
 }
 public function init_form_fields()
 {
     if (!$this->on_settings_page()) {
         return;
     }
     $default_wc_settings = explode(':', get_option('woocommerce_default_country'));
     add_action('admin_enqueue_scripts', array($this, 'load_taxjar_admin_assets'));
     $tj_connection = new WC_TaxJar_Connection($this);
     if (empty($default_wc_settings[1])) {
         $default_wc_settings[1] = "N/A";
     }
     // Build the form array
     $this->form_fields = array('taxjar_title_step_1' => array('title' => __('<h3>Step 1:</h3>', 'wc-taxjar'), 'type' => 'hidden', 'description' => '<h3>Activate your TaxJar WooCommerce Plugin</h3>'), 'api_token' => array('title' => __('API Token', 'wc-taxjar'), 'type' => 'text', 'description' => __('<a href="' . $this->app_uri . 'account#api-access" target="_blank">Click here</a> to get your API token.', 'wc-taxjar'), 'desc_tip' => false, 'default' => ''));
     if (!$tj_connection->can_connect || !$tj_connection->api_token_valid) {
         $this->form_fields = array_merge($this->form_fields, array('taxjar_status' => $tj_connection->get_form_settings_field()));
     }
     if ($this->post_or_setting('api_token') && $tj_connection->api_token_valid) {
         $this->form_fields = array_merge($this->form_fields, array('taxjar_title_step_2' => array('title' => __('<h3>Step 2:</h3>', 'wc-taxjar'), 'type' => 'hidden', 'description' => '<h3>Configure your sales tax settings</h3>'), 'enabled' => array('title' => __('Sales Tax Calculation', 'wc-taxjar'), 'type' => 'checkbox', 'label' => __('Enable TaxJar Calculations', 'wc-taxjar'), 'default' => 'no', 'description' => __('If enabled, TaxJar will calculate all sales tax for your store.', 'wc-taxjar'))));
         if ($this->post_or_setting('enabled')) {
             $tj_nexus = new WC_Taxjar_Nexus($this);
             $this->form_fields = array_merge($this->form_fields, array('nexus' => $tj_nexus->get_form_settings_field()));
         }
         $this->form_fields = array_merge($this->form_fields, array('taxjar_download' => $this->download_orders->get_form_settings_field(), 'store_zip' => array('title' => __('Ship From Zip Code', 'wc-taxjar'), 'type' => 'text', 'description' => __('Enter the zip code from which your store ships products.', 'wc-taxjar'), 'desc_tip' => true, 'default' => ''), 'store_city' => array('title' => __('Ship From City', 'wc-taxjar'), 'type' => 'text', 'description' => __('Enter the city where your store ships from.', 'wc-taxjar'), 'desc_tip' => true, 'default' => ''), 'store_state' => array('title' => __('Ship From State', 'wc-taxjar'), 'type' => 'hidden', 'description' => __('We have automatically detected your ship from state as being ' . $default_wc_settings[1] . '.', 'wc-taxjar'), 'class' => 'input-text disabled regular-input', 'disabled' => 'disabled'), 'store_country' => array('title' => __('Ship From Country', 'wc-taxjar'), 'type' => 'hidden', 'description' => __('We have automatically detected your ship from country as being ' . $default_wc_settings[0] . '.', 'wc-taxjar'), 'class' => 'input-text disabled regular-input', 'disabled' => 'disabled'), 'debug' => array('title' => __('Debug Log', 'wc-taxjar'), 'type' => 'checkbox', 'label' => __('Enable logging', 'wc-taxjar'), 'default' => 'no', 'description' => __('Log events such as API requests.', 'wc-taxjar'))));
     }
 }
 public function wc_taxjar_update_nexus_cache()
 {
     $taxjar_nexus = new WC_Taxjar_Nexus(new WC_Taxjar_Integration());
     $taxjar_nexus->get_or_update_cached_nexus(true);
     die;
 }
 /**
  * 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_country) || empty($to_zip) || $customer->is_vat_exempt()) {
         return false;
     }
     $taxjar_nexus = new WC_Taxjar_Nexus($this);
     if (!$taxjar_nexus->has_nexus_check($to_country, $to_state)) {
         $this->_log(':::: Order not shipping to nexus area ::::');
         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'];
     $shipping_amount = is_null($shipping_amount) ? 0.0 : $shipping_amount;
     $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;
     }
 }