WooCommerce数字钱包折扣金额计算异常及税费显示问题求助
问题场景
- 订单商品金额22.05,运费9.66,订单总计31.71
- 数字钱包余额500,完全可覆盖订单金额
- 折扣费用始终显示为-31.70,而非预期的-31.71
- 订单总计正确显示为0,但仍展示"含0.01税费"的提示,逻辑不合理
代码问题排查
1. 折扣金额计算偏差原因
在hpb2b_handle_wallet_usage函数中,存在两个问题导致金额偏差:
- 依赖
WC()->cart->total作为抵扣基数,但该值在调用calculate_totals()前可能未完成精确计算,存在浮点精度误差 - 使用
ceil()向上取整的方式,会在部分场景下导致金额截断或偏差,不符合常规财务计算逻辑
2. 税费提示不合理原因
adjust_final_total_based_on_wallet仅强制将订单总计设为0,但未处理已计算的税费金额,前端仍会展示税费明细,造成逻辑矛盾。
修正后的代码
// Wallet value applied to cart including shipping cost function hpb2b_handle_wallet_usage() { if (isset($_POST['use_wallet'])) { $use_wallet = $_POST['use_wallet'] === 'yes'; if ($use_wallet) { $user_id = get_current_user_id(); $balance = get_user_meta($user_id, '_wallet_balance', true) ?: 0; WC()->session->set('use_wallet', true); // 改用明细求和获取精确订单总额(含商品、运费、税费) $cart = WC()->cart; $total_cart_and_shipping = $cart->cart_contents_total + $cart->shipping_total + $cart->get_cart_contents_tax() + $cart->get_shipping_tax(); $total_to_deduct = min($balance, $total_cart_and_shipping); // 四舍五入到分,符合常规财务计算逻辑 $total_to_deduct = round($total_to_deduct * 100) / 100; WC()->session->set('wallet_amount', $total_to_deduct); } else { WC()->session->set('use_wallet', false); WC()->session->set('wallet_amount', 0); } } WC()->cart->calculate_totals(); wp_die(); } add_action('wp_ajax_apply_wallet_discount', 'hpb2b_handle_wallet_usage'); add_action('wp_ajax_nopriv_apply_wallet_discount', 'hpb2b_handle_wallet_usage'); add_action('woocommerce_cart_calculate_fees', 'apply_wallet_discount_to_cart_and_shipping', 20); function apply_wallet_discount_to_cart_and_shipping($cart) { if (is_admin() && !defined('DOING_AJAX')) return; if (WC()->session->get('use_wallet')) { $discount_amount = WC()->session->get('wallet_amount'); if ($discount_amount > 0) { $cart->add_fee(__('Carteira Digital', 'hpb2b-custom'), -$discount_amount, false); } } } add_action('woocommerce_thankyou', 'update_wallet_balance_after_purchase', 10, 1); function update_wallet_balance_after_purchase($order_id) { $order = wc_get_order($order_id); $user_id = $order->get_user_id(); $balance = get_user_meta($user_id, '_wallet_balance', true) ?: 0; if (WC()->session->get('use_wallet')) { $discount_amount = WC()->session->get('wallet_amount'); update_user_meta($user_id, '_wallet_balance', max(0, $balance - $discount_amount)); WC()->session->set('use_wallet', false); WC()->session->set('wallet_amount', 0); } } add_filter('woocommerce_calculated_total', 'adjust_final_total_based_on_wallet', 10, 2); function adjust_final_total_based_on_wallet($total, $cart) { if (WC()->session->get('use_wallet')) { $wallet_amount = WC()->session->get('wallet_amount'); $cart_total = $cart->cart_contents_total + $cart->shipping_total + $cart->get_cart_contents_tax() + $cart->get_shipping_tax(); if ($wallet_amount >= $cart_total) { return 0; } else { return max(0, $cart_total - $wallet_amount); } } return $total; } // 钱包覆盖全额时,隐藏购物车税费显示 add_filter('woocommerce_cart_taxes_total', 'adjust_tax_display_when_wallet_covers', 10, 1); function adjust_tax_display_when_wallet_covers($tax_total) { if (WC()->session->get('use_wallet')) { $wallet_amount = WC()->session->get('wallet_amount'); $cart = WC()->cart; $cart_total = $cart->cart_contents_total + $cart->shipping_total + $cart->get_cart_contents_tax() + $cart->get_shipping_tax(); if ($wallet_amount >= $cart_total) { return 0; } } return $tax_total; } // 订单创建时记录钱包使用状态 add_action('woocommerce_checkout_create_order', 'save_wallet_usage_to_order', 10, 2); function save_wallet_usage_to_order($order, $data) { if (WC()->session->get('use_wallet')) { $order->update_meta_data('_use_wallet', true); $order->update_meta_data('_wallet_amount', WC()->session->get('wallet_amount')); } } // 订单页面隐藏不合理的税费明细 add_filter('woocommerce_order_taxes', 'adjust_order_tax_display_when_wallet_covers', 10, 2); function adjust_order_tax_display_when_wallet_covers($taxes, $order) { $use_wallet = get_post_meta($order->get_id(), '_use_wallet', true); $wallet_amount = get_post_meta($order->get_id(), '_wallet_amount', true); if ($use_wallet && $wallet_amount >= $order->get_total()) { return []; } return $taxes; }
关键修改说明
折扣金额精确计算:
- 替换
WC()->cart->total为明细求和方式,避免WC内部计算时机导致的精度误差 - 将
ceil()改为round(),确保金额四舍五入到分,符合常规财务逻辑
- 替换
税费提示修正:
- 新增购物车税费过滤逻辑,钱包覆盖全额时将税费总额设为0,前端不再显示税费提示
- 新增订单元数据记录,保存钱包使用状态,确保订单页面也能正确隐藏不合理的税费明细
内容的提问来源于stack exchange,提问作者Pedro
相关产品推荐
相关产品推荐

