WooCommerce: VAT on grouped products

I’m new to WooCommerce and I have the problem that grouped products always show the default VAT because I can’t change the tax setting on the grouped products. The simple products combined by the grouped one have the reduced rate.

So I probably have to change the output in my (sub-)theme to the VAT of the first connected simple product, right?

Read More

How can I do that?

** Edit **

I have no problem with the shop calculating the VAT wrong. I have a problem with displaying the tax on grouped products. It shows the default rate with the grouped product even if all connected simple products have a reduced rate. And since I have to show the rate on the product page in germany I have to change that.

Related posts

2 comments

  1. code update:

    add_action( 'woocommerce_grouped_product_list_before_price', 
                'woocommerce_grouped_product_tax_on_single', 10, 1, $child_product, $mode );
    
    function woocommerce_grouped_product_tax_on_single( $child_product, $mode = null ) {
    //uncomment next line and choose one of the output options from »switch case "{OPTION}"«
    //$mode = 'tax-name-rate-amount';
        $_taxobj = new WC_Tax();
        $obj = $_taxobj->get_shop_base_rate($child_product->get_tax_class());
        $i_or_e = get_option('woocommerce_prices_include_tax') == 'no' ? 'excl.' : 'incl.'; 
    ?>
        <td class="grp_tax">
        <?php
            foreach ( $obj as $sobj ) {
    
               $stax = woocommerce_price( $sobj['rate'] / 100 * 
                       ( get_option('woocommerce_prices_include_tax') == 'no' ? 
                       $child_product->get_price_including_tax() : 
                       $child_product->get_price_excluding_tax() ) );
    
                switch ($mode) {
                    case null:
                        $format = " %s %s";
                        $variables = array($i_or_e, $sobj['label']);
                        break;
                    case "tax-name":
                        $format = " %s %s";
                        $variables = array($i_or_e, $sobj['label']);
                        break;
                    case "tax-name-rate":
                        $format = " %s %s %s%%";
                        $variables = array($i_or_e, 
                                            $sobj['label'], 
                                            number_format($sobj['rate']));
                        break;
                    case "tax-name-rate-amount":
                        $format = " %s %s (%s%% - %s)";
                        $variables = array($i_or_e, 
                                            $sobj['label'], 
                                            number_format($sobj['rate']), 
                                            $stax);
                        break;
                }
                $output = vsprintf($format, $variables);
            }
            echo $output;
            ?>
        </td>
        <?php
    }
    

    The updated code is pretty much the same, but with some new features. Like @noxoc pointed out, it would be nicer to use a hook. Above code uses the woocommerce_grouped_product_list_before_price action to hook in. This one is already defined inside grouped.php. Unfortunately this – in my mind – doesn’t read nice, because you get something like »tax information price«, personally I want it to read like »price tax information«. For that I added a action woocommerce_grouped_product_list_after_price inside grouped.php:

        //this is the existing action
        <?php do_action ( 'woocommerce_grouped_product_list_before_price', 
                          $child_product['product'] ); ?>
        //this is the table cell for the price
        <td class="price">
            {SOME CODE}
        </td>
        //this is the NEW action you have to add yourself
        <?php do_action ( 'woocommerce_grouped_product_list_after_price', 
                          $child_product['product'] ); ?>
    

    As you can see the new action pretty much replicates the existing one. If you added the action, you can change the add_action() line in above code to use it:

        add_action( 'woocommerce_grouped_product_list_after_price', 
        'woocommerce_grouped_product_tax_on_single', 10, 1, $child_product, $mode );
    

    Additionally I added some options to choose which information to show on output. You have to set the $mode variable for that. This should be pretty much self-explanatory – see the comment inside code. This could for example be used for setting the variable at a options page in the backend. Besides that it of course is possible to change the formatting of the output, just follow the use cases in the code do your own.


    code:

        $_taxobj = new WC_Tax();
        $obj = $_taxobj->get_shop_base_rate($child_product['product']->get_tax_class());
    
        $i_or_e = get_option('woocommerce_prices_include_tax') == 'no' ? 'excl.' : 'incl.';
        foreach ( $obj as $sobj ) { printf(" %s %s%% %s", $i_or_e, number_format($sobj['rate']), $sobj['label']); }
    

    That would be going into the grouped.php located at {THEME-FOLDER}/woocommerce/single-product/add-to-cart/ inside the <td class="price">{CONTENT INSIDE}</td> code. The code is able to distinguish between included/excluded tax and gets according the tax rate as well as the tax label for the simple products inside the group.

  2. You could add a custom field to the product group eg. tax_class and then overwrite it with a filter in you functions.php. Example:

    add_filter( 'woocommerce_de_print_including_tax', 'foo_woocommerce_de_print_including_tax', 10 , 1);
    function foo_woocommerce_de_print_including_tax($value) {
        global $product;
        $product->tax_class = get_post_meta($product->id, 'tax_class', true);
        return $value;
    }
    

    However I’m not sure which filter would suit best. This seems a bit dirty, but should do the trick.

Comments are closed.