/**
  * Perform a lookup for the order and update tax totals
  *
  * @since 4.2
  * @param (array) $items an array of CartItems
  * @param (array) $type_array an array mapping item IDs to item types (cart/shipping)
  * @param (boolean) is this lookup for a subscription renewal order?
  */
 public function do_lookup($items, $type_array, $subscription = false)
 {
     // Fire request if we are ready to do so
     if ($this->ready_for_lookup()) {
         $taxcloud_ids = $lookup_data = array();
         if (!$subscription) {
             // Remove currently applied taxes (delete order item instead?)
             $this->remove_tax();
             // Generate lookup data
             $lookup_data = $this->generate_lookup_data($items);
             WT_Orders::update_meta($this->order_id, 'lookup_data', $lookup_data);
             // Generate TaxCloud Cart/Order IDs
             $taxcloud_ids = $this->generate_order_ids();
             WT_Orders::update_meta($this->order_id, 'taxcloud_ids', $taxcloud_ids);
         } else {
             // Only generate lookup data
             $lookup_data = $this->generate_lookup_data($items);
         }
         $mapping_array = WT_Orders::get_meta($this->order_id, 'mapping_array');
         // Retrieve validated destination addresses
         $destination_address = maybe_validate_address($this->destination_address, $this->order_id);
         // Used in every tax lookup
         $all_cart_items = array();
         $tax_total = $shipping_tax_total = 0;
         // Fetch some information about the order
         $exempt_cert = $this->get_exemption_certificate();
         $customer_id = $this->get_customer_id();
         $delivered_by_seller = wt_is_local_delivery($this->get_shipping_method());
         // Loop through locations in lookup_data array and send a Lookup request for each
         foreach ($lookup_data as $location_key => $items) {
             // Fetch cart_id
             $cart_id = isset($taxcloud_ids[$location_key]['cart_id']) ? $taxcloud_ids[$location_key]['cart_id'] : '';
             // Get the origin address
             $origin_address = wootax_get_address($location_key);
             // Build request array
             $req = array('customerID' => $customer_id, 'cartID' => $cart_id, 'cartItems' => $items, 'origin' => $origin_address, 'destination' => $destination_address, 'deliveredBySeller' => $delivered_by_seller);
             if (!empty($exempt_cert)) {
                 $req['exemptCert'] = $exempt_cert;
             }
             // Send Lookup request
             $res = TaxCloud()->send_request('Lookup', $req);
             if ($res !== false) {
                 // Initialize some vars
                 $cart_items = $res->CartItemsResponse->CartItemResponse;
                 // Store the returned CartID for later use
                 $taxcloud_ids[$location_key]['cart_id'] = $res->CartID;
                 // If cart_items only contains one item, it will not be an array.
                 // In that case, convert to an array
                 if (!is_array($cart_items)) {
                     $cart_items = array($cart_items);
                 }
                 // Loop through items and update tax amounts
                 foreach ($cart_items as &$cart_item) {
                     // Fetch item info
                     $index = $cart_item->CartItemIndex;
                     $item_id = $mapping_array[$location_key][$index];
                     $type = isset($type_array[$item_id]) ? $type_array[$item_id] : 'cart';
                     $tax = $cart_item->TaxAmount;
                     // Update item tax
                     if (!$subscription) {
                         $this->apply_item_tax($item_id, $tax);
                     }
                     // Keep track of cart tax/shipping tax totals
                     if ($type == 'cart') {
                         $tax_total += $tax;
                     } else {
                         $shipping_tax_total += $tax;
                     }
                     // Add ItemID property so @see $this->ajax_update_order_tax() can work as expected
                     $cart_item->ItemID = $item_id;
                 }
             } else {
                 // Return error
                 return TaxCloud()->get_error_message();
             }
             // Add cart_items to all_cart_items array
             $all_cart_items[] = $cart_items;
         }
         if (!$subscription) {
             // Save updated tax totals
             $this->update_tax_totals($tax_total, $shipping_tax_total);
             // Update TaxCloud IDs array
             WT_Orders::update_meta($this->order_id, 'taxcloud_ids', $taxcloud_ids);
             // Reset identifiers array (only useful before first lookup from "edit order" screen)
             WT_Orders::update_meta($this->order_id, 'identifiers', array());
             // Store mapping array in reverse order (map item ids to item indexes)
             $new_mapping_array = array();
             foreach ($mapping_array as $location => $mappings) {
                 foreach ($mappings as $item_index => $item_id) {
                     if (!isset($new_mapping_array[$location])) {
                         $new_mapping_array[$location] = array();
                     }
                     $new_mapping_array[$location][$item_id] = $item_index;
                 }
             }
             WT_Orders::update_meta($this->order_id, 'mapping_array', $new_mapping_array);
             // Update index/location mappings
             foreach ($lookup_data as $address_key => $items) {
                 foreach ($items as $item) {
                     $item_id = $item['ItemID'];
                     if ($item_id == WT_SHIPPING_ITEM) {
                         // WC 2.1 shipping
                         WT_Orders::update_meta($this->order_id, 'shipping_index', $item['Index']);
                     } else {
                         wc_update_order_item_meta($item_id, '_wootax_location_id', $address_key);
                         wc_update_order_item_meta($item_id, '_wootax_index', $item['Index']);
                     }
                 }
             }
         }
         // Return CartItems
         $return_arr = array();
         foreach ($all_cart_items as $cart_items) {
             $return_arr = array_merge($return_arr, $cart_items);
         }
         return $return_arr;
     } else {
         return 'An error occurred while calculating order taxes. It is possible that the order has already been "completed" or that no customer shipping address is available. Please try again.';
     }
 }
 /**
  * Perform a tax lookup for the user's cart
  *
  * @since 4.2
  */
 public function do_lookup()
 {
     // Remove currently applied taxes
     $this->remove_tax();
     // Retrieve validated destination addresses
     $destination_address = maybe_validate_address($this->destination_address);
     // Define some variable used in every tax lookup
     $tax_array = array();
     $lookup_data = array();
     $tax_total = 0;
     $shipping_tax_total = 0;
     // Fetch some information about this order
     $exempt_cert = $this->get_exemption_certificate();
     $customer_id = $this->get_customer_id();
     $delivered_by_seller = wt_is_local_delivery($this->get_shipping_method());
     // Loop through locations in lookup_data array and send a Lookup request for each
     foreach ($this->lookup_data as $location_key => $items) {
         $lookup_data[$location_key] = $items;
         // Fetch cart_id
         $cart_id = isset($this->taxcloud_ids[$location_key]) ? $this->taxcloud_ids[$location_key]['cart_id'] : '';
         // Get the origin address
         $origin_address = wootax_get_address($location_key);
         // Build Lookup request (cartID empty for first request)
         $req = array('customerID' => $customer_id, 'cartID' => $cart_id, 'cartItems' => $items, 'origin' => $origin_address, 'destination' => $destination_address, 'deliveredBySeller' => $delivered_by_seller);
         if (!empty($exempt_cert)) {
             $req['exemptCert'] = $exempt_cert;
         }
         // Send Lookup request
         $res = $this->taxcloud->send_request('Lookup', $req);
         if ($res !== false) {
             // Initialize some vars
             $cart_items = $res->CartItemsResponse->CartItemResponse;
             // Store cartID to improve efficiency of subsequent lookup requests
             $this->taxcloud_ids[$location_key]['cart_id'] = $res->CartID;
             // If cart_items only contains one item, it will not be an array.
             // In that case, convert to an array to avoid the need for extra code
             if (!is_array($cart_items)) {
                 $cart_items = array($cart_items);
             }
             // Loop through items and update tax amounts
             foreach ($cart_items as &$cart_item) {
                 // Fetch item info
                 $index = $cart_item->CartItemIndex;
                 $tax = $cart_item->TaxAmount;
                 $type = $this->mapping_array[$location_key][$index]['type'];
                 // Update item tax
                 switch ($type) {
                     case 'cart':
                         $item_id = $this->mapping_array[$location_key][$index]['key'];
                         // Identifier is cart item key
                         $this->apply_item_tax($item_id, $tax);
                         $tax_total += $tax;
                         break;
                     case 'shipping':
                         $item_id = WT_SHIPPING_ITEM;
                         // Identifier is SHIPPING
                         $shipping_tax_total += $tax;
                         break;
                     case 'fee':
                         $item_id = $this->mapping_array[$location_key][$index]['index'];
                         // Identifier is cart fee index
                         $this->apply_fee_tax($item_id, $tax);
                         $tax_total += $tax;
                         break;
                 }
                 // Add item tax to cart_taxes array
                 $this->cart_taxes[$item_id] = $tax;
                 // Map item id to location
                 $this->location_mapping_array[$item_id] = $location_key;
             }
         } else {
             // We will not display ZIP mismatch errors or SoapFaults. These messages tend to be disruptive and there is not much the customer can do to resolve them.
             $error = $this->taxcloud->get_error_message();
             if (strpos($error, 'zip') === false && strpos($error, 'SoapFault') === false) {
                 wc_add_notice('An error occurred while calculating the tax for this order. ' . $error, 'error');
             }
             return;
         }
     }
     // Update item identifiers
     $this->update_item_identifiers();
     // Save updated tax totals
     $this->update_tax_totals($tax_total, $shipping_tax_total);
     // Set value of lookup_sent to prevent duplicate lookups
     $this->lookup_sent = $this->get_order_hash();
     // Save checkout data in session
     $this->save_session_data();
 }