skip to Main Content

I’m working on a WooCommerce store where we offer free shipping for orders over €100. However, when a partial refund is processed from an order with multiple products and for example 1 product is returned and the total order value drops below €100, the shipping method is not recalculated. The "Free Shipping" option remains, but it should revert to a flat rate of €9 for orders under €100.

EXAMPLE:

Product 1 costs 33€

Product 2 costs 44€

Product 3 costs 55€

Total order price: 132€ = Freeshipping

Client requests to return product 2 so the total value changes under the 100€ on the order.

Total order price: 88€ + 9€ standard shippingcosts.

But now it keeps saying freeshipping when I return 1 product what is incorrect.

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();
    }
}

Here’s what I’ve tried so far:

  1. Hooked into the woocommerce_order_refunded action to recalculate shipping costs.
  2. Removed the free shipping method when the total is less than €100.
  3. Added a new shipping method with a flat rate of €9.

What am I missing or doing wrong? How can I force WooCommerce to properly update the shipping method dynamically after a refund?

2

Answers


  1. The issue is that WooCommerce isn’t automatically recalculating the shipping after a partial refund, leading to Free Shipping being incorrectly applied when the total falls below €100. The solution involves adjusting the total and shipping methods dynamically after a refund.

    Here’s the updated code:

    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();
        }
    }
    
    Login or Signup to reply.
  2. There are some mistakes, complications, unnecessary and missing things in your code.

    Try the following instead:

    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 );
    
        // Check that order items subtotal is under a specific amount
        if ( $order->get_subtotal() < 100 ) {
            $free_shipping_removed = false; // Initialize
    
            // Loop through shipping items
            foreach ( $order->get_shipping_methods() as $item_id => $item ) {
                // Check for free shpping method
                if ( $item->get_method_id() === 'free_shipping') {
                    $order->remove_item($item_id); // Remove free shpping
                    $free_shipping_removed = true; // Flag it as removed
                }
            }
    
            // When free shipping method has been removed
            if ( $free_shipping_removed ) {
                // Get an empty instance of WC_Order_Item_Shipping object
                $shipping_item = new WC_Order_Item_Shipping(); 
    
                // Define desired properties via available methods
                $shipping_item->set_method_title( esc_html__("Verzendkosten") );
                $shipping_item->set_method_id( "flat_rate" ); 
                $shipping_item->set_total( 9 ); 
    
                // Calculate taxes
                $shipping_item->calculate_taxes( array(
                    'country'   => $order->get_shipping_country(),
                    'state'     => $order->get_shipping_state(),
                    'postcode'  => $order->get_shipping_postcode(),
                    'city'      => $order->get_shipping_city(),
                ) );
    
                // Add the flat rate shipping method
                $order->add_item($shipping_item);
    
                // Recalculate totals and save changes (save method is already included)
                $order->calculate_totals();
            }
        }
    }
    

    It should work.

    Related: Add update or remove WooCommerce shipping order items

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search