Orders: Calculate and Apply Tax Rates to REST API Orders
WooCommerce Tax Rates calculate and apply without any need to extend the code, but if you use a Tax plugin to modify WooCommerce Tax Rates and it does not yet support WooCommerce Orders created via the REST API, you may need a solution similar to these. Below we provide two examples (one for TaxJar and one for Avalara AvaTax) to help solve for this issue.
Important: Always test customizations to your site on a staging environment before making changes to your live / production site. If you are not experienced with testing changes on a staging site, here is a good article to review.
TaxJar
/**
* Hook into the Order Save and Taxjar to calculate totals.
* @param bool $and_taxes True if Taxes should be calculated.
* @param WC_Abstract_Order $order The current order.
*/
function xx_taxjar_extension( $and_taxes, $order ){
if ( !( $order instanceof WC_Order ) || ( 'rest-api' != $order->get_created_via() ) )
return;
if ( !class_exists('WC_Taxjar_Integration') )
return;
$taxjar = new WC_Taxjar_Integration;
$address = $taxjar->get_address_from_order( $order );
$line_items = array();
$taxjar->backend_tax_classes = array();
$order_items = $order->get_items();
foreach ( $order_items as $item_key => $item ) {
if ( is_object( $item ) ) { // Woo 3.0+
$id = $item->get_product_id();
$quantity = $item->get_quantity();
$unit_price = wc_format_decimal( $item->get_subtotal() / $quantity );
$discount = wc_format_decimal( $item->get_subtotal() - $item->get_total() );
$tax_class_name = $item->get_tax_class();
$tax_status = $item->get_tax_status();
} else { // Woo 2.6
$id = $item['product_id'];
$quantity = $item['qty'];
$unit_price = wc_format_decimal( $item['line_subtotal'] / $quantity );
$discount = wc_format_decimal( $item['line_subtotal'] - $item['line_total'] );
$tax_class_name = $item['tax_class'];
$product = $order->get_product_from_item( $item );
$tax_status = $product ? $product->get_tax_status() : 'taxable';
}
$taxjar->backend_tax_classes[$id] = $tax_class_name;
$tax_class = explode( '-', $tax_class_name );
$tax_code = '';
if ( isset( $tax_class ) && is_numeric( end( $tax_class ) ) ) {
$tax_code = end( $tax_class );
}
if ( 'taxable' !== $tax_status ) {
$tax_code = '99999';
}
if ( $unit_price ) {
array_push($line_items, array(
'id' => $id . '-' . $item_key,
'quantity' => $quantity,
'product_tax_code' => $tax_code,
'unit_price' => $unit_price,
'discount' => $discount,
));
}
}
if ( method_exists( $order, 'get_shipping_total' ) ) {
$shipping = $order->get_shipping_total(); // Woo 3.0+
} else {
$shipping = $order->get_total_shipping(); // Woo 2.6
}
$taxes = $taxjar->calculate_tax( array(
'to_country' => $address[ 'to_country' ],
'to_state' => $address[ 'to_state' ],
'to_zip' => $address[ 'to_zip' ],
'to_city' => $address[ 'to_city' ],
'to_street' => $address[ 'to_street' ],
'shipping_amount' => $shipping,
'line_items' => $line_items,
) );
foreach ( $order_items as $item_key => $item ) {
$product_id = $item->get_product_id();
$line_item_key = $product_id . '-' . $item_key;
$item_taxes = $item->get_taxes();
$taxes_charged = 0;
if( sizeof($item_taxes) > 0 ){
if( sizeof($item_taxes["total"]) > 0 ){
foreach( $item_taxes["total"] AS $tax_total ){
$taxes_charged = (float)$tax_total;
}
}
}
if( $taxes_charged == 0 ){
if ( isset( $taxes['rate_ids'][ $line_item_key ] ) ) {
$rate_id = $taxes['rate_ids'][ $line_item_key ];
$item_tax = new WC_Order_Item_Tax();
$item_tax->set_rate( $rate_id );
$item_tax->set_order_id( $order->get_id() );
$item_tax->save();
}
}
}
}
add_action( 'woocommerce_order_before_calculate_totals', 'xx_taxjar_extension', 10, 2 );
Avalara AvaTax
/**
* Hook into the Order Save and calculate Avatax totals.
* @param bool $and_taxes True if Taxes should be calculated.
* @param WC_Abstract_Order $order The current order.
*/
function xx_avatax_calc_tax( $and_taxes, $wc_order ){
if ( !( $wc_order instanceof WC_Order ) || ( 'rest-api' !== $wc_order->get_created_via() ) )
return;
if ( !function_exists( 'wc_avatax' ) )
return;
if( !$and_taxes )
return;
wc_avatax()->get_order_handler()->calculate_order_tax( $wc_order );
}
add_action( 'woocommerce_order_before_calculate_totals', 'xx_avatax_calc_tax', 10, 2 );