如何根据自定义结帐字段设置要应用于订单的 WooCommerce 税级?

问题描述 投票:0回答:1

在 WooCommerce 中,我需要在结账页面添加一个“billing_legal_person”自定义字段,该字段可以在“个人”和“公司”之间进行选择,以反映客户是否应作为公司或个人纳税。那么,适用的增值税百分比应该根据该 billing_legal_person 选择的内容而不同。

我已成功创建 2 个税级:针对个人的默认(标准)税级和针对公司的新“公司”级。

我还可以使用以下代码成功地以编程方式申请一种税级或另一种税级:

add_filter( 'woocommerce_product_get_tax_class', 'my_set_taxrate_for_billing_legal_person', 10, 2 );
add_filter( 'woocommerce_product_variation_get_tax_class', 'my_set_taxrate_for_billing_legal_person', 10, 2 );

function my_set_taxrate_for_billing_legal_person( $tax_class, $product ) {
    // Commenting the line below, standard tax class is applied
    $tax_class = 'companies';

    return $tax_class;
}

我使用 Checkout Field Editor 插件轻松创建

billing_legal_person
选择字段(值“人员”或“公司”)。

在更改我的

billing_legal_person
自定义字段的内容时,我还设法强制重新计算税收:

add_filter( 'woocommerce_checkout_fields', 'my_checkout_fields_trigger_refresh', 9999 );

function my_checkout_fields_trigger_refresh( $fields ) {
   $fields['billing']['billing_legal_person']['class'][] = 'update_totals_on_change';

   return $fields;
}

我的问题是在

my_set_taxrate_for_billing_legal_person()
内部,我无法访问用户选择的
billing_legal_person
自定义字段的内容。

如果我检查

WC()->checkout->get_checkout_fields['billing_legal_person']
,我总是得到一个空值。

如果我检查

WC()->checkout->checkout->get_value('billing_first_name')
,我会得到预期的值(客户的名字)。但是,如果我随后检查
WC()->checkout->checkout->get_value('billing_legal_person')
,我会得到一个
NULL
值。我想我可以访问
billing_first_name
,因为它是标准字段,但我无法访问
billing_legal_person
,因为它是自定义字段,但我找不到任何有关如何访问自定义字段的线索。

所有基于检查的方法

$_POST['billing_legal_person']
都失败了,因为我需要在用户提交退房表格之前显示要支付的税款金额。

关于如何从

billing_legal_person
访问
my_set_taxrate_for_billing_legal_person()
自定义字段的内容,以便我可以检查它并返回一种或另一种税级,有什么帮助吗?

php wordpress woocommerce hook-woocommerce checkout
1个回答
0
投票

首先,不要使用结帐字段编辑器插件添加“billing_legal_person”自定义结帐字段,而是我们将使用手动编码的函数。

另外,删除您的

my_set_taxrate_for_billing_legal_person()
功能。

下面的代码将:

  • 在结帐和“我的帐户”>“编辑帐单地址”页面中为“法人”添加自定义必填选择字段。
  • “法人”将根据所选值显示/隐藏 WooCommerce 计费公司字段。
  • 当选择“公司”时,购物车物品税率将更改为“公司”,如果选择“个人”,购物车物品税率将重置为默认…
add_filter('woocommerce_billing_fields', 'add_legal_person_billing_field');
function add_legal_person_billing_field( $fields ) {
    $fields['billing_company']['class'][] = 'hidden'; 

    $fields['billing_legal_person'] = array(
        'label'       => __( 'Legal person', 'woocommerce' ),
        'type'        => 'select',
        'options'     => [
            ''        => __("Choose an option",  "woocommerce"),
            'Person'  => __("Person",  "woocommerce"),
            'Company' => __("Company", "woocommerce"),
        ],
        'required'    => true,
        'priority'    => 25,
    );
    return $fields;
}

// Validate Billing company field
add_action( 'woocommerce_checkout_process', 'validate_custom_checkout_fields' );
function validate_custom_checkout_fields() {
    if ( isset($_POST['billing_legal_person']) && $_POST['billing_legal_person'] === 'Company' 
    && isset($_POST['billing_company']) && empty($_POST['billing_company']) ) {
        wc_add_notice('Billing company is a required field.', 'error');
    }
}

// PHP: Replace "(optional)" with required for Billing company
add_filter( 'woocommerce_form_field' , 'remove_checkout_optional_fields_label', 10, 4 );
function remove_checkout_optional_fields_label( $field, $key, $args, $value ) {
    // Only on checkout page
    if( ( ( is_checkout() && ! is_wc_endpoint_url() ) 
    || is_wc_endpoint_url('edit-address') ) && $key === 'billing_company' ) {
        $optional = '&nbsp;<span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
        $required = '&nbsp;<abbr class="required" title="required">*</abbr>';
        $field = str_replace( $optional, $required, $field );
    }
    return $field;
}

// Hide Billing company field on checkout page load 
add_action('wp_head', 'checkout_legal_person_css');
function checkout_legal_person_css() {
    if ( ( is_checkout() && ! is_wc_endpoint_url() ) || is_wc_endpoint_url('edit-address') ) : ?>
    <style>
        #billing_company_field.hidden {display:none !important;}
    </style>
    <?php endif;
}

// JavaScript / Ajax: Show/hide billing company and set the tax rate via Ajax
add_action( 'template_redirect' , 'checkout_legal_person_js' );
function checkout_legal_person_js() {
    if ( ( is_checkout() && ! is_wc_endpoint_url() ) || is_wc_endpoint_url('edit-address') ) :

    $legal_person = WC()->customer->get_meta('billing_legal_person');
    if ( is_checkout() && $legal_person ) {
        WC()->session->set('legal_person', $legal_person);
    }
    
    wc_enqueue_js("
        const company         = '#billing_company',       
              companyField    = company+'_field', 
              legalPers       = '#billing_legal_person',
              isCheckout      = ".( is_checkout() ? 'true' : 'false' ).";

        function showHideCompanyField( legalPers, companyField ) {
            if ( $(legalPers).val() === 'Company' ) {
                $(companyField).show();
            } else {
                $(companyField).hide();
            }
        }

        // On start:
        $(legalPers).selectWoo();
        $(companyField).addClass('validate-required woocommerce-invalid woocommerce-invalid-required-field');
        showHideCompanyField( legalPers, companyField );
        $(companyField).removeClass('hidden');

        // On Legal Person change: Show/Hide company field
        $('form.woocommerce-checkout,.woocommerce-edit-address form').on('change', legalPers, function() {
            showHideCompanyField( legalPers, companyField );
            
            if ( isCheckout ) {
                $.ajax({
                    type: 'POST',
                    url: '".admin_url('admin-ajax.php')."',
                    data: {
                        'action': 'legal_person_tax',
                        'legal_person' : $(legalPers).val(), 
                    },
                    success: function (response) {
                        $(document.body).trigger('update_checkout');
                        console.log(response);
                    }
                });
            }
        });
    ");
    endif;
}

// PHP AJAX receiver: Set "legal_person" session variable
add_action('wp_ajax_legal_person_tax', 'set_legal_person_tax' );
add_action('wp_ajax_nopriv_legal_person_tax', 'set_legal_person_tax' );
function set_legal_person_tax() {
    if ( isset($_POST['legal_person']) && ! empty($_POST['legal_person']) ) {
        WC()->session->set('legal_person', esc_attr($_POST['legal_person']));
    }
    wp_die(esc_attr($_POST['legal_person']));
}

// Dynamically change tax rate based on chosen "legal_person"
add_action('woocommerce_before_calculate_totals', 'define_cart_item_tax_class_for_companies');
function define_cart_item_tax_class_for_companies( $cart )
{
    if ((is_admin() && !defined('DOING_AJAX')))
        return;

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

    $legal_person = WC()->session->get('legal_person');
    $legal_person = $legal_person ? $legal_person : WC()->customer->get_meta('billing_legal_person');

    if ( $legal_person === 'Company' ) {
        // Loop through cart items and set the updated price
        foreach ($cart->get_cart() as $item) {
            $item['data']->set_tax_class('companies'); // Set tax class
        }
    }
}

// Remove session variable when order is placed
add_action('woocommerce_checkout_order_created', 'unset_legal_person_session_variable');
function unset_legal_person_session_variable() {
    WC()->session->__unset('legal_person');
}

// Change tax rate if customer is a a company
add_filter( 'woocommerce_product_get_tax_class', 'tax_rate_based_on_chosen_legal_person', 10, 2 );
add_filter( 'woocommerce_product_variation_get_tax_class', 'tax_rate_based_on_chosen_legal_person', 10, 2 );
function tax_rate_based_on_chosen_legal_person( $tax_class, $product ) {
    $legal_person = WC()->customer->get_meta('billing_legal_person');

    if ( $legal_person === 'Company' ) {
        $tax_class = 'companies';
    }
    return $tax_class;
}

代码位于子主题的functions.php 文件中(或插件中)。已测试并有效。

© www.soinside.com 2019 - 2024. All rights reserved.