/** * Output origin address select metabox * * @since 4.2 * @param (WP_Post) $post post/product being edited */ public static function output_shipping_metabox($post) { $addresses = fetch_business_addresses(); echo '<p>Use the box below to search for and add "Shipping Origin Addresses" for this product. These are the locations from which this item will be shipped.</p>'; echo '<p>When an item can be shipped from multiple locations, WooTax will assume that it is sent from the business location in the customer\'s state.</p>'; // Fetch addresses for this product $origin_addresses = fetch_product_origin_addresses($post->ID); // Output addresses echo '<select class="' . (version_compare(WOOCOMMERCE_VERSION, '2.3', '<') ? 'chosen_select' : 'wc-enhanced-select') . '" name="_wootax_origin_addresses[]" multiple>'; if (is_array($addresses) && count($addresses) > 0) { foreach ($addresses as $key => $address) { echo '<option value="' . $key . '"' . (in_array($key, $origin_addresses) ? " selected" : "") . '>' . get_formatted_address($address) . '</option>'; } } else { echo '<option value="">There are no addresses to select.</option>'; } echo '</select>'; }
/** * Stores an array of items in TaxCloud-friendly format and organized by location key in the lookup_data property * * @since 4.2 */ private function generate_lookup_data($items = NULL) { // Fetch order items $order_items = $items; // Exit if we do not have any items if (count($order_items) == 0) { WT_Orders::update_meta($this->order_id, 'lookup_data', array()); WT_Orders::update_meta($this->order_id, 'mapping_array', array()); return; } // Determine the state where the customer is located $customer_state = $this->destination_address['State']; // Initialize some vars that we need for the foreach loop below $data = $mapping_array = $counters_array = $fee_items = $shipping_items = array(); // This will hold the ID of the first found origin address/location for this order; Fees and shipping chars will be attached to it $first_found = false; // Loop through order items; group items by their shipping origin address and format data for tax lookup foreach ($order_items as $item_key => $item) { $item_id = $item['ItemID']; $type = $item['Type']; switch ($type) { case 'cart': // Fetch shipping origin addresses for this product_id $item_ids = array('product_id' => $this->order->get_item_meta($item_id, '_product_id', true), 'variation_id' => $this->order->get_item_meta($item_id, '_variation_id', true)); $product = $this->order->get_product_from_item($item_ids); $origin_addresses = fetch_product_origin_addresses($product->id); $address_found = WT_DEFAULT_ADDRESS; /** * Attempt to find proper origin address * If there is more than one address available, we will use the first address that occurs in the customer's state * If there no shipping location in the customer's state, we will use the default origin address * Developers can modify the selected shipping origin address using the wootax_origin_address filter */ if (count($origin_addresses) == 1) { // There is only one address ID to fetch, with index 0 $address_found = $origin_addresses[0]; } else { // Find an address in the customer's state if possible foreach ($origin_addresses as $key) { if (isset(WT_Orders::$addresses[$key]['state']) && WT_Orders::$addresses[$key]['state'] == $customer_state) { $address_found = $key; break; } } } // Allow developers to use their own logic to determine the appropriate shipment origin for a product $address_found = apply_filters('wootax_origin_address', $address_found, $customer_state, $this); // Store the id of the first shipping location we find for the order so we can attach shipping items and fees later on if ($first_found === false) { $first_found = $address_found; } // Initialize arrays to avoid PHP notices if (!isset($data[$address_found]) || !is_array($data[$address_found])) { $data[$address_found] = array(); } if (!isset($counters_array[$address_found])) { $counters_array[$address_found] = 0; } if (!isset($mapping_array[$address_found])) { $mapping_array[$address_found] = array(); } // Update mapping array $mapping_array[$address_found][] = $item_id; // Update item data before storing in $data array $item['Index'] = $counters_array[$address_found]; $item['Price'] = apply_filters('wootax_taxable_price', $item['Price'], false, $item_id); unset($item['Type']); // Add formatted item data to the $data array $data[$address_found][] = $item; // Increment counter $counters_array[$address_found]++; break; case 'shipping': // Push this item to the shipping array; the cost of shipping will be attached to the first daughter order later on $shipping_items[$item_id] = $item; break; case 'fee': // Push this item to the fee array; it will be attached to the first daughter order later on $fee_items[$item_id] = $item; break; } } // Attach shipping items and fees to the first daughter order if ($first_found !== false) { foreach ($shipping_items + $fee_items as $key => $item) { // Get new item index $index = $counters_array[$first_found]; // Add to items array (Type index not included here) $data[$first_found][] = array('Index' => $index, 'ItemID' => $item['ItemID'], 'TIC' => $item['TIC'], 'Price' => apply_filters('wootax_taxable_price', $item['Price'], false, $item['ItemID']), 'Qty' => $item['Qty']); // Update mapping array $mapping_array[$first_found][$index] = $key; // Increment counter $counters_array[$first_found]++; } } // Save mapping array/first found and return lookup data WT_Orders::update_meta($this->order_id, 'mapping_array', $mapping_array); WT_Orders::update_meta($this->order_id, 'first_found', $first_found); return $data; }