我在一家 WooCommerce 商店工作,我们为超过 100 欧元的订单提供免费送货服务。但是,当对包含多个产品的订单进行部分退款时,例如退回 1 个产品,并且订单总价值低于 100 欧元,则不会重新计算送货方式。 “免费送货”选项仍然存在,但对于 100 欧元以下的订单,它应恢复为 9 欧元的统一费率。
示例:
产品 1 售价 33 欧元
产品 2 售价 44 欧元
产品 3 售价 55 欧元
订单总价:132€ = 免运费
客户请求退回产品 2,因此订单总价值低于 100 欧元。
订单总价:88 欧元 + 9 欧元标准运费。
但是现在当我退回 1 个产品时,它一直说免费送货,这是不正确的。
add_action('woocommerce_order_refunded', 'adjust_shipping_after_refund', 10, 2);
function adjust_shipping_after_refund($order_id, $refund_id) {
$order = wc_get_order($order_id);
$total_sale_price = 0;
// Calculate new total after refund
foreach ($order->get_items() as $item_id => $item) {
$product = $item->get_product();
$quantity = $item->get_quantity();
$sale_price = $product->get_sale_price();
if ($sale_price) {
$total_sale_price += $sale_price * $quantity;
} else {
$total_sale_price += $product->get_regular_price() * $quantity;
}
}
// If the total is under €100, apply flat rate shipping
if ($total_sale_price < 100) {
foreach ($order->get_shipping_methods() as $shipping_item_id => $shipping_item) {
if ($shipping_item->get_method_id() === 'free_shipping') {
$order->remove_item($shipping_item_id); // Remove free shipping
}
}
// Add flat rate shipping of €9
if (empty($order->get_shipping_methods())) {
$rate = new WC_Shipping_Rate('flat_rate', 'Verzendkosten', 9, array(), 'flat_rate');
$shipping_item = new WC_Order_Item_Shipping();
$shipping_item->set_props(array(
'method_title' => $rate->get_label(),
'method_id' => $rate->get_method_id(),
'total' => wc_format_decimal($rate->get_cost())
));
$order->add_item($shipping_item);
}
// Recalculate totals
$order->calculate_totals();
$order->save();
}
}
这是我迄今为止尝试过的:
我错过了什么或做错了什么?如何强制 WooCommerce 在退款后动态正确更新送货方式?
问题在于,WooCommerce 在部分退款后不会自动重新计算运费,导致当总额低于 100 欧元时,
Free Shipping
被错误应用。解决方案包括在退款后动态调整总额和运输方式。
这是更新后的代码:
add_action('woocommerce_order_refunded', 'adjust_shipping_after_refund', 10, 2);
function adjust_shipping_after_refund($order_id, $refund_id) {
$order = wc_get_order($order_id);
// Use WooCommerce's built-in method to get the total after refunds
$total_sale_price = $order->get_total(); // This includes refunds automatically
// If the total is under €100, switch to flat rate shipping
if ($total_sale_price < 100) {
// Remove free shipping if it's applied
foreach ($order->get_shipping_methods() as $shipping_item_id => $shipping_item) {
if ($shipping_item->get_method_id() === 'free_shipping') {
$order->remove_item($shipping_item_id);
}
}
// Add flat rate shipping of €9
if (empty($order->get_shipping_methods())) {
$rate = new WC_Shipping_Rate('flat_rate', 'Flat Rate Shipping', 9, array(), 'flat_rate');
$shipping_item = new WC_Order_Item_Shipping();
$shipping_item->set_props(array(
'method_title' => $rate->get_label(),
'method_id' => $rate->get_method_id(),
'total' => wc_format_decimal($rate->get_cost())
));
$order->add_item($shipping_item);
}
// Recalculate the totals after adding the new shipping cost
$order->calculate_totals();
$order->save();
}
}
我找到了问题的答案:
<?php
// Zorg ervoor dat de verzendkosten worden aangepast na een terugbetaling
add_action('woocommerce_order_refunded', 'adjust_shipping_after_refund', 10, 2);
function adjust_shipping_after_refund($order_id, $refund_id) {
$order = wc_get_order($order_id);
$refund = wc_get_order($refund_id);
if (!$order || !$refund) {
return;
}
$total_sale_price = 0;
$total_refunded_sale_price = 0;
$free_shipping_removed = false;
// Pad naar je eigen logbestand in de wp-content map
$log_file = WP_CONTENT_DIR . '/verzendkost_update.log';
// Log de initiële status van de bestelling en het totaal
error_log("Start processing refund for Order ID: {$order_id}. Refund ID: {$refund_id}" . PHP_EOL, 3, $log_file);
// Bereken het totaalbedrag van de bestelling op basis van line items
foreach ($order->get_items('line_item') as $item_id => $item) {
$product = $item->get_product();
if (!$product) {
error_log("Product niet gevonden voor item ID $item_id in order ID $order_id." . PHP_EOL, 3, $log_file);
continue;
}
$quantity = $item->get_quantity();
$line_total = $item->get_total(); // Haal het lijntotaal op
$total_sale_price += $line_total;
// Log details van elk product en de prijs
error_log("Product: {$product->get_name()}, Line Total: {$line_total}, Quantity: {$quantity}, Subtotal: {$line_total}" . PHP_EOL, 3, $log_file);
}
// Controleer welke itemtypes aanwezig zijn in de refund
foreach ($refund->get_items() as $item_id => $item) {
$item_type = $item->get_type();
error_log("Refund Item Type: {$item_type}" . PHP_EOL, 3, $log_file);
}
// Bereken het totaalbedrag van de terugbetalingen op basis van line items in de refund
foreach ($refund->get_items('line_item') as $refund_item_id => $refund_item) {
$refund_product = $refund_item->get_product();
if (!$refund_product) {
error_log("Product niet gevonden voor refund item ID $refund_item_id in order ID $order_id." . PHP_EOL, 3, $log_file);
continue;
}
$refunded_quantity = abs($refund_item->get_quantity());
$refund_total = $refund_item->get_total(); // Dit is een negatieve waarde
$refund_subtotal = abs($refund_total); // Absolute waarde voor berekening
$total_refunded_sale_price += $refund_subtotal;
// Log details van elk refund item en de prijs
error_log("Refund Product: {$refund_product->get_name()}, Refund Total: {$refund_total}, Refunded Quantity: {$refunded_quantity}, Refund Subtotal: {$refund_subtotal}" . PHP_EOL, 3, $log_file);
}
// Bereken het netto totaalbedrag na terugbetalingen
$net_sale_price = $total_sale_price - $total_refunded_sale_price;
// Log het netto totale bedrag
error_log("Net sale price after refund: {$net_sale_price}" . PHP_EOL, 3, $log_file);
// Controleer of gratis verzending moet worden verwijderd en de verzendkosten van €9 moeten worden toegevoegd
if ($net_sale_price < 100) {
error_log("Net sale price is below 100 EUR. Checking for free shipping..." . PHP_EOL, 3, $log_file);
// Log alle huidige verzendmethoden
foreach ($order->get_shipping_methods() as $shipping_item) {
$method_id = $shipping_item->get_method_id();
$instance_id = $shipping_item->get_instance_id();
$method_title = $shipping_item->get_method_title();
error_log("Shipping Method Found - ID: {$method_id}, Instance ID: {$instance_id}, Title: {$method_title}" . PHP_EOL, 3, $log_file);
}
// Verwijder gratis verzending door te controleren op method_title
foreach ($order->get_shipping_methods() as $item_id => $item) {
if ($item->get_method_title() === 'Gratis verzending') {
$order->remove_item($item_id); // Verwijder gratis verzending
$free_shipping_removed = true; // Zet de vlag voor het verwijderen
error_log("Free shipping removed." . PHP_EOL, 3, $log_file);
}
}
if ($free_shipping_removed) {
// Controleer of er al een flat rate shipping method bestaat
$flat_rate_exists = false;
foreach ($order->get_shipping_methods() as $item) {
if ($item->get_method_id() === 'flat_rate') {
$item->set_total(9);
$item->save();
$flat_rate_exists = true;
error_log("Existing flat rate shipping updated to €9." . PHP_EOL, 3, $log_file);
}
}
if (!$flat_rate_exists) {
// Voeg een nieuwe flat rate shipping method toe
$shipping_item = new WC_Order_Item_Shipping();
$shipping_item->set_method_title("Verzendkosten");
$shipping_item->set_method_id("flat_rate");
$shipping_item->set_total(9);
$order->add_item($shipping_item);
$order->save();
error_log("Flat rate shipping of €9 added." . PHP_EOL, 3, $log_file);
}
// Herbereken de bestelling en sla deze op
$order->calculate_totals();
$order->save();
// Log de nieuwe bestellingstotalen
error_log("New order totals after adding shipping: " . print_r($order->get_order_item_totals(), true) . PHP_EOL, 3, $log_file);
} else {
error_log("Free shipping was not removed." . PHP_EOL, 3, $log_file);
}
} else {
error_log("Net sale price is above 100 EUR. No shipping changes required." . PHP_EOL, 3, $log_file);
}
}
?>
我使用 _sale_price (我之前没有提到为什么使用它)。我使用这个是因为 _regular_price 不是我们的商店价格。
但更进一步,所有内容都与我的代码相同。如果您使用此功能,只需将其更改为 _regulare_price 即可。
上面的代码工作正确。