woocommerce / woocommerce

A customizable, open-source ecommerce platform built on WordPress. Build any commerce solution you can imagine.
https://woocommerce.com
9.39k stars 10.76k forks source link

Orders from backend overwrite tax data added via 'woocommerce_ajax_calc_line_taxes' #9313

Closed Biont closed 9 years ago

Biont commented 9 years ago

I am implementing support for one of the more fancy German tax regulations concerning fees/shipping and need to make it work for orders created from the back-end as well.

I hooked into woocommerce_ajax_calc_line_taxes, did my calculations and added the resulting tax data to $items[ 'shipping_taxes' ]

However, the data shown on the resulting table is not what I returned in the filter. This is because in WC_AJAX::calc_line_taxes - L1627-L1658, the taxes get recalculated for all matched tax classes.

The result is that my _regular tax_ tax gets overwritten while the _reduced rate_ data shows up in the result.

Is this intentional behaviour? What would be the intended way of setting custom tax data for back-end orders?

The only way I'm seeing is hooking into woocommerce_find_rates and ensuring no rates are returned for this specific call to WC_Tax::find_rates(), but that seems pretty messy.

Am I on the wrong track or is this a mistake in how WC_AJAX handles order data?

mikejolley commented 9 years ago

This method recalcs all taxes. Why does it need to be done programmatically and not through regular tax rates in this case? Rates can apply to shipping only.

Biont commented 9 years ago

@mikejolley: We need to tax shipping/fees based on the (cart) items' tax rates. See here for more information: split-tax

mikejolley commented 9 years ago

Won't be possible with current implementation. Find where you need a hook during calculation and submit a PR.

Biont commented 9 years ago

@mikejolley I will happily provide a pull request. Could you perhaps nudge me towards the implementation that is most likely to be accepted?

There would be several ways to do this:

1. Move the filter down.

That means running $items through 'woocommerce_ajax_calc_line_taxes' after the taxes are calculated and before the order is re-saved and sent to the template. There might be undesired side-effects from this which I am unaware of. However, since you generally did not consider settings taxes a use-case of this filter and that's the only thing that happens after it runs, it might be the most simple change that works without extending the API. It would also enable developers to only change those taxes that need adjustment

2. Add another filter

Don't move 'woocommerce_ajax_calc_line_taxes', but instead add another 'woocommerce_ajax_after_calc_line_taxes' or something like that. More secure (in terms of side-effects), but it's "yet another filter" to keep track of (and deprecate should the need arise)

3. Add a kill-switch for tax calculations

Either pass something like 'calc_taxes'=> TRUE into $items and check for it after the filter was applied. That would enable users to bypass tax calculations if they set the value to FALSE

Alternatively, use an additional if ( apply_filters( 'woocommerce_ajax_bypass_tax_calculations', TRUE ) ) to determine if taxes need to be calculated. The downside is that if you return FALSE here, you need to calculate ALL taxes manually, not just those that need attention. (Unless of course we add separate switches for item and shipping taxes, but it's still not ideal then).

glueckpress commented 9 years ago

This method recalcs all taxes. Why does it need to be done programmatically and not through regular tax rates in this case? Rates can apply to shipping only.

@mikejolley When there are multiple tax rates present in one cart, German law ( :sob: you may as well stop reading here) requires taxes for shipping costs and other fees to be recalculated depending on each line item in relation to cart subtotal.

The logic behind this is actually pretty… logical. To a degree that even commercial German software providers rarely bother thinking about it.

In the example @Biont posted above the audio book (assumed to come as a CD) and the DVD are each taxed at 19% while the book is taxed at only 7%. In order to have customer pay a “fair” (!!!) amount of taxes on their shippings costs only, the tax on shipping costs must respect these differences. Therefore, the part of shipping costs that’s caused by the book should be taxed at only 7% while the other parts caused by the DVD and the CD should be taxed at 19% each. Voilá, meet German split tax. (We’ve actually invented the term ourselves.)

That’s why we have to recalculate programmatically which tax rate needs to be applied to what portion of taxes for shipping costs, and then, of course, apply those calculations through the filter mentioned above.

TL;DR: One does not simply apply a single standardized tax rate to shipping costs when multiple tax rates are present in a cart. :stuck_out_tongue_winking_eye:

mikejolley commented 9 years ago

@glueckpress @Biont not that I can fight the law, but this sounds pretty retarded - how can the price of the product be a fair determination of the proportion of shipping cost?

What if I'm shipping a $10 feather and a $1 anvil for example :)

In the UK it's based on the highest rated tax class. So if you have a reduced rate item and a standard rate item, you pay standard rate on the shipping.

For your situation I guess you could either add multiple shipping rows and tax each separately, or the woocommerce_ajax_after_calc_line_taxes suggestion so you have a chance to adjust things after WC has done it's tax logic.

glueckpress commented 9 years ago

but this sounds pretty retarded

Whole-heartedly agreed.