Disable VAT conditionally for specific product categories on Woocommerce checkout

安稳与你 提交于 2020-03-20 12:41:48

问题


In woocommerce I am using Timologia for WooCommerce plugin, which checks if user wants invoice or plain receipt (this is required in Greece). So this plugin add a select field in checkout page with "No" (default) or "Yes" as options.

If customer select "Yes" then "zero vat" is applied for products in specific categories and everything works fine in the checkout page.

But when customer place the order, on the order received page and on backend (order edit page) the specific item prices are not anymore without VAT.

Here is my code:

add_action( 'woocommerce_checkout_update_order_review', 'tfwc_taxexempt_checkout_based_invoice_choice' ); 

function tfwc_taxexempt_checkout_based_invoice_choice( $post_data ) {
    global $woocommerce;
    $woocommerce->customer->set_is_vat_exempt( false );
    parse_str($post_data);
    if ( $billing_timologio == 'Y' ) 

    add_filter( 'woocommerce_product_get_tax_class', 'wc_diff_rate_for_user', 1, 2 );

    function wc_diff_rate_for_user( $tax_class, $product ) {

    // let's get all the product category for this product...

    $terms = get_the_terms( $product->id, 'product_cat' );
    foreach ( $terms as $term ) { // checking each category 

    // if it's one of the category we'er looking for
    if(in_array($term->term_id, array(228,231,222))) {
        $tax_class = 'Zero Rate';
        // found it... no need to check other $term
        break;
    }
}

    return $tax_class;
  }
}

This code was working fine on WC version 2.X, and stopped working fine in version 3+

Any help is appreciated.


回答1:


Update 3

The plugin and your code are outdated, with some mistakes and errors. In the code bellow I am using another way with ajax and WC_Session.

The "Tax rate" behavior on products entered including taxes.

To make any code that manipulate tax rates effective, the products prices need to be entered excluding taxes. If not, additional code is required to grab the product price excluding taxes as custom cart item data, to make the "Zero rate" tax effective.

I have added a custom function partially copied from the plugin code, that adds a checkout select field billing_timologio, to make the code testable.

Also the add to cart ajax button is replaced by a button linked to single product pages for the defined product categories, as we add the product price excluding taxes as custom cart item data.

The code (only for Woocommerce version 3.3+):

// Your product categories settings
function get_my_terms(){
    return array( 'clothing' );
    return array( 222, 228, 231 );
}

// Change add to cart ajax button to a button linked to single product pages for specific product categories
add_filter( 'woocommerce_loop_add_to_cart_link', 'conditionally_replace_add_to_cart', 10, 2 );
function conditionally_replace_add_to_cart( $html, $product ) {
    if ( has_term( get_my_terms(), 'product_cat', $product_id )  && $product->is_type('simple') ) {
        // Set HERE your button link
        $link = get_permalink($product_id);
        $text = __("Read More", "woocommerce");
        $html = '<a href="' . $link . '" class="button alt add_to_cart_button">' . $text . '</a>';
    }
    return $html;
}

// Adding a custom checkout select field
add_filter( 'woocommerce_billing_fields', 'custom_billing_fields', 20, 1 );
function custom_billing_fields($billing_fields) {

    $billing_fields['billing_timologio'] = array(
        'type'        => 'select',
        'label'       => __('INVOICE'),
        'placeholder' => _x('INVOICE', 'placeholder'),
        'required'    => false,
        'class'       => array('form-row-wide'),
        'clear'       => true,
        'options'     => array(
            'N' => __('No'),
            'Y' => __('Yes'),
        ),
        'value' => '',
    );
    return $billing_fields;
}

// The jQuery Ajax script
add_action( 'wp_footer', 'custom_checkout_script' );
function custom_checkout_script() {
    // Only checkout page
    if( is_checkout() && ! is_wc_endpoint_url() ):

    // Removing WC_Session "
    if( WC()->session->__isset('billing_timologio') ){
        WC()->session->__unset('billing_timologio');
    }
    ?>
    <script type="text/javascript">
    jQuery( function($){
        if (typeof wc_checkout_params === 'undefined')
            return false;

        // On load reset value to 'N'
        $('#billing_timologio_field select').val('N');

        // On change (Ajax)
        $('#billing_timologio_field select').change( function () {
            $.ajax({
                type: 'POST',
                url: wc_checkout_params.ajax_url,
                data: {
                    'action': 'get_ajax_billing_timologio',
                    'b_timologio': $(this).val() == 'Y' ? 1 : 0,
                },
                success: function (result) {
                    $('body').trigger('update_checkout');
                }
            });
        });
    });
    </script>
    <?php
    endif;
}

// The Wordpress Ajax receiver
add_action( 'wp_ajax_get_ajax_billing_timologio', 'get_ajax_billing_timologio' );
add_action( 'wp_ajax_nopriv_get_ajax_billing_timologio', 'get_ajax_billing_timologio' );
function get_ajax_billing_timologio() {
    if ( $_POST['b_timologio'] == '1' ){
        WC()->session->set('billing_timologio', '1');
    } else {
        WC()->session->set('billing_timologio', '0');
    }
    die();
}

// Save the product price excluding tax as custom cart item data
add_filter('woocommerce_add_cart_item_data', 'add_price_excl_vat_as_custom_cart_item_data', 20, 3);
function add_price_excl_vat_as_custom_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
    if ( ! wc_prices_include_tax() )
        return $cart_item_data;

    $_product_id = $variation_id > 0 ? $variation_id : $product_id;
    $product = wc_get_product($_product_id); // The WC_Product Object

    // Save the price excluding tax as custom cart item data
    if( has_term( get_my_terms(), 'product_cat', $product_id ) ) {
        $cart_item_data['price_excl_tax'] = wc_get_price_excluding_tax( $product, array( 'price' => $product->get_price() ) );
    }

    return $cart_item_data;
}

// Changing conditionally specific items tax rate
add_action( 'woocommerce_before_calculate_totals', 'zero_tax_items_based_on_invoice_choice', 30, 1 );
function zero_tax_items_based_on_invoice_choice( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    // Loop through cart items
    foreach ( $cart->get_cart() as $cart_item ) {
        // Check for product categories and enabled "billing_timologio" field
        if( has_term( get_my_terms(), 'product_cat', $cart_item['product_id'] ) && WC()->session->get('billing_timologio') ){
            // Set the item tax rate to "Zero rate"
            $cart_item['data']->set_tax_class('Zero Rate');

            // Set price excluding taxes
            if( isset($cart_item['price_excl_tax']) ){
                $cart_item['data']->set_price($cart_item['price_excl_tax']);
            }
        }
    }
}

Code goes in function.php file of your active child theme (or active theme). Tested and works.

On order received, order view and (admin) order edit pages, the tax will be set to "Zero Rate" for the specific items when customer has selected "Yes" for "BILLING INVOICE" (ΤΙΜΟΛΟΓΙΟ).

The related product price remaining to the defined product categories will have this time the correct price excluding taxes


Original answer.

I seems that there is 2 errors:

  • The first is $product->id to be replaced by $product->get_id()
  • The second, you need to put the internal function outside

Also the code can be simplified.

Without any guaranty as your code can't be tested for real, try this instead:

add_action( 'woocommerce_checkout_update_order_review', 'tfwc_taxexempt_checkout_based_invoice_choice' ); 
function tfwc_taxexempt_checkout_based_invoice_choice( $post_data ) {
    WC()->customer->set_is_vat_exempt( false );

    parse_str($post_data);

    if ( $billing_timologio == 'Y' ) 
        add_filter( 'woocommerce_product_get_tax_class', 'wc_diff_rate_for_user', 1, 2 );
    }
}

function wc_diff_rate_for_user( $tax_class, $product ) {
    // Checking for specific product categories
    if( has_term( array(228,231,222), 'product_cat', $product->get_id() ) ) {
        return 'Zero Rate';
    }
    return $tax_class;
}

I hope it will work.



来源:https://stackoverflow.com/questions/52208837/disable-vat-conditionally-for-specific-product-categories-on-woocommerce-checkou

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!