From 74de1525357f70b8999c559052a5cbda452210f0 Mon Sep 17 00:00:00 2001 From: vedanshujain Date: Thu, 9 Jul 2020 01:42:12 +0530 Subject: [PATCH] Use tax location from order while computing tax in discount. We were not passing tax location while computing discount in orders, hence it was defaulting to shop's base address resulting in incorrect tax calculation. This commit refactors `get_rates` method into another method that allows getting rates from location directly. --- includes/abstracts/abstract-wc-order.php | 13 +++++++++++-- includes/class-wc-tax.php | 18 ++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/includes/abstracts/abstract-wc-order.php b/includes/abstracts/abstract-wc-order.php index a694d1aa151..4c794c8c1b2 100644 --- a/includes/abstracts/abstract-wc-order.php +++ b/includes/abstracts/abstract-wc-order.php @@ -1270,6 +1270,8 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order { */ protected function set_item_discount_amounts( $discounts ) { $item_discounts = $discounts->get_discounts_by_item(); + $tax_location = $this->get_tax_location(); + $tax_location = array( $tax_location['country'], $tax_location['state'], $tax_location['postcode'], $tax_location['city'] ); if ( $item_discounts ) { foreach ( $item_discounts as $item_id => $amount ) { @@ -1277,7 +1279,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order { // If the prices include tax, discounts should be taken off the tax inclusive prices like in the cart. if ( $this->get_prices_include_tax() && wc_tax_enabled() && 'taxable' === $item->get_tax_status() ) { - $taxes = WC_Tax::calc_tax( $amount, WC_Tax::get_rates( $item->get_tax_class() ), true ); + $taxes = WC_Tax::calc_tax( $amount, WC_Tax::get_rates_from_location( $item->get_tax_class(), $tax_location ), true ); // Use unrounded taxes so totals will be re-calculated accurately, like in cart. $amount = $amount - array_sum( $taxes ); @@ -1299,6 +1301,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order { $coupon_code_to_id = wc_list_pluck( $coupons, 'get_id', 'get_code' ); $all_discounts = $discounts->get_discounts(); $coupon_discounts = $discounts->get_discounts_by_coupon(); + $tax_location = $this->get_tax_location(); + $tax_location = array( + $tax_location['country'], + $tax_location['state'], + $tax_location['postcode'], + $tax_location['city'], + ); if ( $coupon_discounts ) { foreach ( $coupon_discounts as $coupon_code => $amount ) { @@ -1321,7 +1330,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order { continue; } - $taxes = array_sum( WC_Tax::calc_tax( $item_discount_amount, WC_Tax::get_rates( $item->get_tax_class() ), $this->get_prices_include_tax() ) ); + $taxes = array_sum( WC_Tax::calc_tax( $item_discount_amount, WC_Tax::get_rates_from_location( $item->get_tax_class(), $tax_location ), $this->get_prices_include_tax() ) ); if ( 'yes' !== get_option( 'woocommerce_tax_round_at_subtotal' ) ) { $taxes = wc_round_tax_total( $taxes ); } diff --git a/includes/class-wc-tax.php b/includes/class-wc-tax.php index f80a7d8422d..cb72d9bbe1d 100644 --- a/includes/class-wc-tax.php +++ b/includes/class-wc-tax.php @@ -405,7 +405,7 @@ class WC_Tax { $criteria_string = implode( ' AND ', $criteria ); - // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $found_rates = $wpdb->get_results( " SELECT tax_rates.*, COUNT( locations.location_id ) as postcode_count, COUNT( locations2.location_id ) as city_count @@ -479,8 +479,22 @@ class WC_Tax { * @return array */ public static function get_rates( $tax_class = '', $customer = null ) { + $tax_class = sanitize_title( $tax_class ); + $location = self::get_tax_location( $tax_class, $customer ); + return self::get_rates_from_location( $tax_class, $location, $customer ); + } + + /** + * Get's an arrau of matching rates from location and tax class. $customer parameter is used to preserve backward compatibility for filter. + * + * @param string $tax_class Tax class to get rates for. + * @param array $location Location to compute rates for. Should be in form: array( country, state, postcode, city). + * @param object $customer Only used to maintain backward compatibility for filter `woocommerce-matched_rates`. + * + * @return mixed|void + */ + public static function get_rates_from_location( $tax_class, $location, $customer = null ) { $tax_class = sanitize_title( $tax_class ); - $location = self::get_tax_location( $tax_class, $customer ); $matched_tax_rates = array(); if ( count( $location ) === 4 ) {