Commit 827c92967b6 for woocommerce

commit 827c92967b6d3071d9a21f6a531ab01ea21dcc08
Author: SH Sajal Chowdhury <72102985+shsajalchowdhury@users.noreply.github.com>
Date:   Thu Aug 27 15:38:28 2026 +0600

    Fix: Non-taxable cart fees stored as taxable in order items due to missing tax_status (#66302)

    * Fix: Non-taxable cart fees stored as taxable in order items (#53766)

    When a non-taxable fee is added via WC_Cart::add_fee() with
     = false, the order item created during checkout incorrectly
    retained tax_status = 'taxable' (the default) with tax_class = '0'
    (standard). Third-party tax plugins (e.g., TaxJar, Avatax) read
    tax_status and calculated tax on these fees.

    Root cause: create_order_fee_lines() in WC_Checkout omitted
    tax_status from set_props(), so it defaulted to TAXABLE. Also,
    tax_class was set to 0 (falsy but not empty) instead of the
    standard-class value (empty string).

    Fix: Set tax_status to 'none' and tax_class to '' when the fee is
    not taxable.

    * Align array assignment operators and add unit test for fee tax_status

    - Align => operators in create_order_fee_lines per WordPress coding standards
    - Add test_create_order_fee_lines_sets_correct_tax_status covering both
      taxable and non-taxable cart fees

    * Update plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php

    Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

    ---------

    Co-authored-by: Tom Cafferkey <tjcafferkey@gmail.com>
    Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

diff --git a/plugins/woocommerce/changelog/fix-53766-fee-tax_status-non-taxable b/plugins/woocommerce/changelog/fix-53766-fee-tax_status-non-taxable
new file mode 100644
index 00000000000..feb7d07ec78
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-53766-fee-tax_status-non-taxable
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Set tax_status to 'none' when creating fee order items from non-taxable cart fees.
diff --git a/plugins/woocommerce/includes/class-wc-checkout.php b/plugins/woocommerce/includes/class-wc-checkout.php
index 1483ef4dc01..b24e632e3a9 100644
--- a/plugins/woocommerce/includes/class-wc-checkout.php
+++ b/plugins/woocommerce/includes/class-wc-checkout.php
@@ -9,6 +9,7 @@
  */

 use Automattic\WooCommerce\Enums\OrderStatus;
+use Automattic\WooCommerce\Enums\ProductTaxStatus;
 use Automattic\WooCommerce\Enums\ProductType;
 use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
 use Automattic\WooCommerce\Internal\Tax\TaxRateDataStore;
@@ -615,12 +616,13 @@ class WC_Checkout {
 			$item->legacy_fee_key = $fee_key; // @deprecated 4.4.0 For legacy actions.
 			$item->set_props(
 				array(
-					'name'      => $fee->name,
-					'tax_class' => $fee->taxable ? $fee->tax_class : 0,
-					'amount'    => $fee->amount,
-					'total'     => $fee->total,
-					'total_tax' => $fee->tax,
-					'taxes'     => array(
+					'name'       => $fee->name,
+					'tax_class'  => $fee->taxable ? $fee->tax_class : '',
+					'tax_status' => $fee->taxable ? ProductTaxStatus::TAXABLE : ProductTaxStatus::NONE,
+					'amount'     => $fee->amount,
+					'total'      => $fee->total,
+					'total_tax'  => $fee->tax,
+					'taxes'      => array(
 						'total' => $fee->tax_data,
 					),
 				)
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php b/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php
index 9517be8f4cd..07db9678c6e 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-checkout-test.php
@@ -689,6 +689,42 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case {
 		$this->assertSame( 19.0, $tax_item->get_rate_percent() );
 	}

+	/**
+	 * @testdox create_order_fee_lines sets tax status to 'none' for non-taxable cart fees and 'taxable' for taxable ones.
+	 *
+	 * @testWith [true, "taxable", ""]
+	 *           [false, "none", ""]
+	 *
+	 * @param bool   $taxable Whether the cart fee is taxable.
+	 * @param string $expected_tax_status The expected tax status for the created fee order item.
+	 * @param string $expected_tax_class The expected tax class for the created fee order item.
+	 */
+	public function test_create_order_fee_lines_sets_correct_tax_status( $taxable, $expected_tax_status, $expected_tax_class ): void {
+		$product = WC_Helper_Product::create_simple_product();
+		WC()->cart->add_to_cart( $product->get_id(), 1 );
+
+		$add_fee = static function ( $cart ) use ( $taxable ) {
+			$cart->add_fee( 'Test fee', 10, $taxable );
+		};
+		add_action( 'woocommerce_cart_calculate_fees', $add_fee );
+
+		try {
+			WC()->cart->calculate_totals();
+			$order = wc_get_order( $this->sut->create_order( array( 'payment_method' => WC_Gateway_BACS::ID ) ) );
+		} finally {
+			remove_action( 'woocommerce_cart_calculate_fees', $add_fee );
+		}
+
+		$fee_items = $order->get_fees();
+
+		$this->assertCount( 1, $fee_items );
+
+		/** @var WC_Order_Item_Fee $fee_item */
+		$fee_item = array_values( $fee_items )[0];
+		$this->assertSame( $expected_tax_status, $fee_item->get_tax_status() );
+		$this->assertSame( $expected_tax_class, $fee_item->get_tax_class() );
+	}
+
 	/**
 	 * @testdox Checkout page contains login form for guests.
 	 */