0

I am adding a WooCommerce cart fee like so :

  add_action('woocommerce_cart_calculate_fees', function($cart) { 
      $cart->add_fee(__('Popust za vjernost'), -10, 0);
  });

I thought adding a 0 as the third argument would set the tax to 0 but WooCommerce still adds tax to the fee.

How can I set the tax to 0?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
franka
  • 33
  • 6
  • @LoicTheAztec Ah, I see, and there is no way to override the taxes? Have you any suggestions for other options? – franka Sep 01 '23 at 07:15
  • @LoicTheAztec In the answer you reference as a duplicate, you do not solve the issue of adding a discount without tax. Do you not think other people might want a solution to this problem? – franka Sep 01 '23 at 07:34
  • @LoicTheAztec OK, would I do that by accessing the fee object directly, or subtracting the tax from the cart total? – franka Sep 01 '23 at 07:36
  • @LoicTheAztec I think it's worth posting the solution as an answer, I can see other people finding it useful. – franka Sep 01 '23 at 07:37
  • I've posted a feature request to add a `add_discount` method to the cart. – franka Sep 01 '23 at 08:36
  • Well I fixed it by editing WooCommerce's core changing `class-wc-cart-totals.php` lines `330` `$fee->object->tax_data = wc_remove_number_precision_deep(0);` and ``331` `$fee->object->tax = wc_remove_number_precision_deep(0);` not ideal but it works! – franka Sep 01 '23 at 21:47

2 Answers2

1

Overwriting cores files is not a solution, as it can affect other processes and you will lose your changes each time you will update WooCommerce.

Using WC_Cart add_fee() method with a negative amount, is a tweak to add a discount. In that case, the "taxable" optional 3rd argument doesn't work, and taxes are always applied. This has been reported to WooCommerce many times and the response was that WC_Cart add_fee() method was not made for discounts.

1) Reminder about WC_Cart add_fee() method 4 available arguments:

/**
 * Add additional fee to the cart.
 *
 * This method should be called on a callback attached to the
 * woocommerce_cart_calculate_fees action during cart/checkout. Fees do not
 * persist.
 *
 * @uses WC_Cart_Fees::add_fee
 * @param string $name      Unique name for the fee. Multiple fees of the same name cannot be added.
 * @param float  $amount    Fee amount (do not enter negative amounts).
 * @param bool   $taxable   Is the fee taxable? (default: false).
 * @param string $tax_class The tax class for the fee if taxable. A blank string is standard tax class. (default: '').
 */
WC()->cart->add_fee( $name, $amount, $taxable, $tax_class );

2) Make the "taxable" 3rd argument working with negative amounts:

The following code will enable "taxable" when using a negative amount, allowing to add a discount without taxes when the "taxable" argument is set to false:

// Adjust cart total amount
add_filter( 'woocommerce_cart_get_total', 'filter_cart_get_total', 10, 1 );
function filter_cart_get_total( $total ) {
    $tax_amount = 0;

    foreach( WC()->cart->get_fees() as $fee ) {
        if( ! $fee->taxable && $fee->tax < 0 ) {
            $tax_amount -= $fee->tax;
        }
    }

    if( $tax_amount != 0 ) {
        $total += $tax_amount;
    }
    return $total;
}

// Adjust Fee taxes (array of tax totals)
add_filter( 'woocommerce_cart_get_fee_taxes', 'filter_cart_get_fee_taxes', 10, 1 );
function filter_cart_get_fee_taxes( $fee_taxes ) {
    $fee_taxes = array();
    
    foreach( WC()->cart->get_fees() as $fee ) {
        if( $fee->taxable ) {
            foreach( $fee->tax_data as $tax_key => $tax_amount ) {
                if( isset($fee_taxes[$tax_key]) ) {
                    $fee_taxes[$tax_key] += $tax_amount;
                } else {
                    $fee_taxes[$tax_key] = $tax_amount;
                }
            }
        }
    }
    return $fee_taxes;
}

// Displayed fees: Remove taxes from non taxable fees with negative amount
add_filter( 'woocommerce_cart_totals_fee_html', 'filter_cart_totals_fee_html', 10, 2 );
function filter_cart_totals_fee_html( $fee_html, $fee ) {
    if( ! $fee->taxable && $fee->tax < 0 ) {
        return wc_price( $fee->total );
    }
    return $fee_html;
}

// Adjust Order fee item(s) for negative non taxable fees
add_action( 'woocommerce_checkout_create_order_fee_item', 'alter_checkout_create_order_fee_item', 10, 4 );
function alter_checkout_create_order_fee_item( $item, $fee_key, $fee, $order ) {
    if ( ! $fee->taxable && $fee->tax < 0 ) {
        $item->set_taxes(['total' => []]);
        $item->set_total_tax(0);
    }
}

Code goes in functions.php file of your child theme (or in a plugin).


3) Testing using Add_fee():

Below, we add a discount without taxes using a negative amount:

add_action( 'woocommerce_cart_calculate_fees', 'add_discount_without_tax' );
function add_discount_without_tax( $cart ) { 
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;
    
    // Add a NON taxable DISCOUNT (negative amount, "taxable" argument set to "false")
    $cart->add_fee(__('Discount (no tax)'), -10, false); 
};

This time it works, taxes are not applied and when order is submitted, same thing.

Code goes in functions.php file of your child theme (or in a plugin).

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thanks Loic, I did think of this method but the tax still appears in the order fee in the order. My client did not want this so I had to edit the core files. I did try returning 0 in this filter `woocommerce_cart_totals_get_fees_from_cart_taxes` but it did not work, any ideas why? – franka Sep 02 '23 at 07:47
  • Hold on, I didn't see the `filter_cart_get_fee_taxes` function, I though you were just adding the taxes back to the cart totals. I will test it now. – franka Sep 02 '23 at 08:14
  • 1
    I've tested and the taxes do not appear in order. Cheers Loic you are the master! – franka Sep 02 '23 at 08:21
0

To set the tax to 0 for a WooCommerce cart fee, you can use the fourth argument of the add_fee method to specify that tax should not be applied. Here's how you can modify your code:

add_action('woocommerce_cart_calculate_fees', function($cart) { 
    $cart->add_fee(__('Popust za vjernost'), -10, false, '');
});

By passing false as the third argument and an empty string '' as the fourth argument, you are indicating that no tax should be applied to the fee. This should prevent WooCommerce from adding tax to the fee.