As you are using the order gran total to calculate your fee and as the hook you are using is located inside calculate_totals()
method, once order get updated, you will always need to press "recalculate" button to get the correct fee total and the correct order gran total with the correct amounts.
Since WooCommerce 3 your code is outdated and a bit obsolete with some mistakes… For example add_fee()
and update_fee()
methods are deprecated and replaced by some other ways.
Use instead the following:
add_action( 'woocommerce_order_after_calculate_totals', "custom_order_after_calculate_totals", 10, 2 );
function custom_order_after_calculate_totals( $and_taxes, $order ) {
if ( did_action( 'woocommerce_order_after_calculate_totals' ) >= 2 )
return;
$percentage = 0.03; // Fee percentage
$fee_data = array(
'name' => __('3% CC Fee'),
'amount' => wc_format_decimal( $order->get_total() * $percentage ),
'tax_status' => 'none',
'tax_class' => ''
);
$fee_items = $order->get_fees(); // Get fees
// Add fee
if( empty($fee_items) ){
$item = new WC_Order_Item_Fee(); // Get an empty instance object
$item->set_name( $fee_data['name'] );
$item->set_amount( $fee_data['amount'] );
$item->set_tax_class($fee_data['tax_class']);
$item->set_tax_status($fee_data['tax_status']);
$item->set_total($fee_data['amount']);
$order->add_item( $item );
$item->save(); // (optional) to be sure
}
// Update fee
else {
foreach ( $fee_items as $item_id => $item ) {
if( $item->get_name() === $fee_data['name'] ) {
$item->set_amount($fee_data['amount']);
$item->set_tax_class($fee_data['tax_class']);
$item->set_tax_status($fee_data['tax_status']);
$item->set_total($fee_data['amount']);
$item->save();
}
}
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Once order get updated and after press on recalculate button (to get the correct orders totals) both auto added and updated fee will work nicely.
Related: Add a fee to an order programmatically in Woocommerce 3
Update
Now if it doesn't work for any reason, you should remove the related item to update and add a new one as follows:
add_action( 'woocommerce_order_after_calculate_totals', "custom_order_after_calculate_totals", 10, 2 );
function custom_order_after_calculate_totals( $and_taxes, $order ) {
if ( did_action( 'woocommerce_order_after_calculate_totals' ) >= 2 )
return;
$percentage = 0.03; // Fee percentage
$fee_data = array(
'name' => __('3% CC Fee'),
'amount' => wc_format_decimal( $order->get_total() * $percentage ),
'tax_status' => 'none',
'tax_class' => ''
);
$fee_items = $order->get_fees(); // Get fees
// Add fee
if( empty($fee_items) ){
$item = new WC_Order_Item_Fee(); // Get an empty instance object
$item->set_name( $fee_data['name'] );
$item->set_amount( $fee_data['amount'] );
$item->set_tax_class($fee_data['tax_class']);
$item->set_tax_status($fee_data['tax_status']);
$item->set_total($fee_data['amount']);
$order->add_item( $item );
$item->save(); // (optional) to be sure
}
// Update fee
else {
foreach ( $fee_items as $item_id => $item ) {
if( $item->get_name() === $fee_data['name'] ) {
$item->remove_item( $item_id ); // Remove the item
$item = new WC_Order_Item_Fee(); // Get an empty instance object
$item->set_name( $fee_data['name'] );
$item->set_amount( $fee_data['amount'] );
$item->set_tax_class($fee_data['tax_class']);
$item->set_tax_status($fee_data['tax_status']);
$item->set_total($fee_data['amount']);
$order->add_item( $item );
$item->save(); // (optional) to be sure
}
}
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…