Disable VAT conditionally for specific product categories on Woocommerce checkout

后端 未结 1 1798
梦谈多话
梦谈多话 2021-01-16 21:09

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 fie

相关标签:
1条回答
  • 2021-01-16 21:43

    Update 3

    The plugin and your code are outdated, with some mistakes and errors. In the code below 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.

    0 讨论(0)
提交回复
热议问题