1
votes

I need to calculate the extra shipping cost the backorder products will have. I first thought of duplicate the shipping cost per product, but this is not accurate. So I thought I should withing my function run another function (same as woocommerce uses) to calculate the shipping cost for each and all backorder product in the cart.

Here is where I am so far.

// Add a extra shipping fee to each backordered product
add_action('woocommerce_cart_calculate_fees', 'add_backorder_shipping_fee', 20, 1);
function add_backorder_shipping_fee($cart)
{
    if (is_admin() && !defined('DOING_AJAX'))
        return;

    $backorderNumber = 0;
    // Loop through the cart items (added products).
    foreach (WC()->cart->get_cart() as $cart_item) {
        // Product Info
        $product = $cart_item['data'];
        // Quantity of product in cart (being purchased).
        $buyingQuantity = $cart_item['quantity'];
        if (!empty($product && $product->backorders_allowed())) {
            // Calculate if product quantity in cart is more than stock, returns negative if so.
            $isBuyingMoreThanStock = $product->stock_quantity - $buyingQuantity;
            if ($isBuyingMoreThanStock < 0) {
                //!ITEMS: Calculate the number of items are being backordered.
                //  $backorderNumber = $backorderNumber + ($isBuyingMoreThanStock * -1);

                //!PRODUCTS: Calculate the number of products are being backordered.
                $backorderNumber = $backorderNumber + 1;
            }
        }
    }
    // Get the shipping cost.
    $totalShippingCost = WC()->cart->get_shipping_total() + WC()->cart->get_shipping_tax();
    // Calculate and apply the above shipping cost to each backordered item.
    $extraShippingFee = $backorderNumber * $totalShippingCost;
    // Create the fee.
    if ($backorderNumber > 0 && $totalShippingCost > 0) {
        $cart->add_fee(__('Backorder Extra Shipping Fee (' . $backorderNumber . ')', 'woocommerce'), $extraShippingFee);
    }
}


So instead of get the current shipping cost and multiple by the number of backordered product, I would like to calculate the extra fee just like woocommerce calculate the shipping cost. Another thing that comes to mind is if I could apply this to Fedex live rate API as well.

1
I do not really understand your meaning about accurate, is WooCommerce shipping fee calculate doesn't accurate?Rach Chen
Why doing a is_admin() check at the beginning? This way your function never works on the cart page since the cart page is not the admin dashboard page. Maybe you should re-think your code before asking a question to developers out here.Mr. Jo

1 Answers

0
votes

I suggest an alternative solution based on WooCommerce shipping fee calculate method.

// Calculate and sum all backorder product shipping fees
add_filter( 'woocommerce_shipping_packages', function ( $packages ) { 

foreach ( $packages as $package_key => &$package ){
    $backorders = array();
    foreach ( $package['contents'] as $cartkey => $values ){
        if ( $values['data']->is_on_backorder() ){
            if ( empty($i) ) $i = 1; else $i++;
            $backorders[ $i ][ $cartkey ] = $values; // Get backorders
        } else {
            $backorders[ 0 ][ $cartkey ] = $values; // Get NOT backorders
        }
    }

    if ( count( $backorders ) <= 1 ) continue; // Break if no backorder

    $tax_rates = WC_Tax::get_shipping_tax_rates();
    $new_packages = array();
    foreach ( $backorders as $i => $backorder ){
        $new_packages[ $i ] = $package;
        $new_packages[ $i ]['contents'] = $backorder;
        $new_packages[ $i ]['contents_cost'] = array_sum( wp_list_pluck( $backorder, 'line_total' ) ); // calculate products total
        $new_packages[ $i ] = WC()->shipping()->calculate_shipping_for_package( $new_packages[ $i ] ); // calculate shipping cost
    }

    foreach ( $package['rates'] as $ratekey => &$rate ){
        $rate->cost = 0;
        foreach ( $new_packages as $i => $new_package ){
            if ( empty( $new_package['rates'][$ratekey] ) ) continue;
            $rate->cost += $new_package['rates'][$ratekey]->cost; // sum shipping costs
        }
        $rate->taxes = WC_Tax::calc_tax( $rate->cost, $tax_rates, true ); // re-calculate taxes
        $rate->label = 'Shipped in order'; // change shipping label if you want
    }
}

return $packages;

});

The advantage of this method is that it also supports shipping calculation using shipping classes such as flat_rate and table_rate.