PluginUs.Net - Business Tools for WooCommerce and WordPress

[realize your idea - make your dreams come true]
Botoscope is currently in early access

Support Forum

You need to log-in to create request (topic) to the support

Price Rounding Issue with tax

The support doesn work on Saturdays and Sundays, so some Friday requests can be answered on Monday. If you have problems with registration ask help on contact us page please
If you not got email within 24~36 business hours, firstly check your spam box, and if no any email from the support there - back to the forum and read answer here. DO NOT ANSWER ON EMAILS [noreply@pluginus.net] FROM THE FORUM!! Emails are just for your info, all answers should be published only here.
The support doesn work on Saturdays and Sundays, so some Friday requests can be answered on Monday.
Support notice: Our support team will be on vacation from August 8 to September 3, so response times may be delayed and replies may be irregular.
Hello,
I need assistance to fix a problem.
I’m building a multilingual online shop. The base prices are inclusive of tax and are in euros (e.g. €61.50). As soon as I change the country (and the tax rate varies by country), the price isn’t rounded (€60.53).
I’m using the following code:
add_filter('woocs_raw_woocommerce_price', 'custom_woocs_round_to_five_cents', 99, 1);

function custom_woocs_round_to_five_cents($price) {

    if ( is_admin() && !defined( 'DOING_AJAX' ) ) return $price;
        if (!is_numeric($price) || $price <= 0) {
            return $price;
        }
    return round($price * 20, 2) / 20;
}
What could be the problem?
Thank you in advance for your help.

Hello

Two things: why your filter cannot work where it is, and what to use instead. I checked all of this against WooCommerce 11.0.0, released today, so the hook names below are current.

Why your code has no effect.

woocs_raw_woocommerce_price fires on the product price before WooCommerce does any tax work. Your prices are entered inclusive of tax, so after your callback returns, WooCommerce strips the tax rate of your base country to get the net figure and then applies the rate of the customer's country. Your 61.50 is a clean multiple of five cents, but it goes through a subtraction and an addition after that, and what comes out is 60.53. Rounding upstream of that arithmetic cannot survive it.

Also worth saying plainly: when the currency itself is not changing, FOX is not involved in this at all. You would see the same figures with the plugin deactivated. This is standard WooCommerce tax behaviour.

Option one, and I would try this first.

You may not want rounding at all. You want the same gross price in every country. WooCommerce has a filter for exactly that:

add_filter('woocommerce_adjust_non_base_location_prices', '__return_false');

With this, WooCommerce stops removing the base tax when the customer is outside your base country. A product priced at 61.50 including tax stays 61.50 for everyone, and only the tax portion inside that amount changes with the country. No rounding, no drift, and the cart total agrees with the line items automatically.

The trade-off is that your margin then varies by country, since a higher local rate eats into the net amount. That is a commercial decision, not a technical one. WooCommerce marks this filter as experimental, but it is present and working in 11.0.0.

Option two, if you really do need rounding after tax.

Round where the tax has already been applied:

woocommerce_get_price_including_tax woocommerce_get_price_excluding_tax

Both are still in WooCommerce 11.0.0 and both receive the final figure. Be aware that they affect displayed prices only. Cart and order totals are calculated separately, so you will also need woocommerce_calculated_total, otherwise the cart total will not match the sum of the rows above it. And once you round the gross amount, the tax line no longer matches the rate exactly, which is a question for your accountant rather than for code.

Option three, FOX hooks worth experimenting with.

If you do want behaviour that depends on the selected currency rather than on the country, these are the points to work from. In all of them you can read the state like this:

global $WOOCS; $current = $WOOCS->current_currency; $base = $WOOCS->default_currency; $all = $WOOCS->get_currencies();

woocs_raw_woocommerce_price — the price after currency conversion, before tax. This is the one you are already using. Useful for per-currency price shaping, not for anything tax related.

woocs_precision_on_calc, receives the precision and the currency. This is how you set a different number of decimals per currency, for example zero decimals for currencies where cents make no sense.

woocs_fixed_raw_woocommerce_price, fires when a per-product fixed price is applied, so you can adjust or override that specific value.

woocs_convert_price and woocs_back_convert_price, the conversion in both directions, if you need to intervene in the rate arithmetic itself.

woocs_price_html and woocs_price_html_tail, for the rendered price markup.

A practical pattern for your case would be to combine option one or two with a currency check inside the callback, so the rule only applies to the currencies where you want it:

global $WOOCS; if ($WOOCS->current_currency !== 'EUR') { return $price; }

My recommendation is to try woocommerce_adjust_non_base_location_prices first. If fixed gross prices per country are acceptable commercially, it solves the whole thing in one line and you can drop the rounding entirely.


Here is the example block to add at the end, before the vacation note.

Here is a complete example you can drop into your child theme's functions.php and experiment with. It is commented so you can switch the parts on and off independently.

add_filter('woocommerce_adjust_non_base_location_prices', '__return_false');

add_filter('woocommerce_get_price_including_tax', function ($price, $qty, $product) {

	global $WOOCS;

	if (is_admin() && !wp_doing_ajax()) {
		return $price;
	}

	if (!is_numeric($price) || $price <= 0) {
		return $price;
	}

	if (isset($WOOCS) && 'EUR' !== $WOOCS->current_currency) {
		return $price;
	}

	return round((float) $price * 20) / 20;
}, 99, 3);

add_filter('woocommerce_calculated_total', function ($total) {
	return round((float) $total * 20) / 20;
}, 99);

 

Approach A is active as written. To test approach B instead, comment out the woocommerce_adjust_non_base_location_prices line and uncomment the two add_filter lines under approach B.

 

One note on timing so you are not left waiting. Our support team is on vacation from August 8 to September 3, so replies in that period will be irregular.

Kind regards, Ross

Hello Ross

Thank you very much for the detailed answer!

Based on this I can now experiment.

Best regards

Hello

You are Welcome :)