Search code examples
phpjquerywoocommercedokanfee

Cash On Delivery fee based on Dokan vendors count in WooCommerce


In WooCommerce Dokan multivendor shop I have Cash On Delivery (COD) payment for customers.

I created a code that counts the vendors in the cart and multiply them with the fee that i want per vendor. on my example is 2 € per vendor. so lets say that we have 1 product of each vendors(for now we have 2 vendors) on the cart. That should be 2 * 2 = 4€ total cost of COD.

That is working perfectly but when I received the order I see the fee only in main order and not in the suborders. it should be 2€ in one suborder and the other 2€ in the other suborder.

That has been working the whole time but since 11.02.2021 it suddenly stopped. Any ideas that could help me ?

Here is the code that I am using:

// 2 € Fee COD - Add a custom fee based on cart subtotal: 
add_action( 'woocommerce_cart_calculate_fees', 'custom_fee_for_dokan', 999, 1 );
function custom_fee_for_dokan ( $cart ) {
    $car_items  = WC()->cart->get_cart(); // Cart items

    $items_sort = array(); // Initializing

    // Loop through cart items
    foreach ( $car_items as $cart_item_key => $cart_item ) {
        // Get the vendor_id
        $vendor_id   = get_post_field( 'post_author', $cart_item['product_id'] );
    
        $store_info  = dokan_get_store_info( $vendor_id ); // Get the store data
        $store_name  = $store_info['store_name'];          // Get the store name
    
        // Set in multidimentional array the vendor and then the cart item key
        $items_sort[$store_name][$cart_item_key] = $vendor_id;
    }

    if ( count($car_items) > 1 ) {
        ksort( $items_sort ); // Sorting by vendor name
    }

    $vendors = 0;

    // Loop by vendor name
    foreach ( $items_sort as $store_name => $values ) {
        $vendor_id  = reset($values); // The vendor id
        $store_url = dokan_get_store_url( $vendor_id );  // Get the store URL (if needed)
        $vendors++;
    } 

    // End of Loop

    $flatrate = $vendors * 2;

    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( ! ( is_checkout() && ! is_wc_endpoint_url() ) )
        return; // Only checkout page

    $payment_method = WC()->session->get( 'chosen_payment_method' );

    if ( 'cod' == $payment_method ) {
       // $surcharge == $vendors;
        $cart->add_fee( 'Pay on delivery', $flatrate , true );
    }
}

// jQuery - Update checkout on methode payment change
add_action( 'wp_footer', 'nik_checkout' );
function nik_checkout() {
    if ( ! ( is_checkout() && ! is_wc_endpoint_url() ) )
        return; // Only checkout page
    ?>
    <script type="text/javascript">
    jQuery( function($){
        $('form.checkout').on('change', 'input[name="payment_method"]', function(){
            $(document.body).trigger('update_checkout');
        });
    });
    </script>
    <?php
}

Solution

  • The issue is related to Dokan plugin that does not split the fee by suborders anymore in the plugin recent versions. So you should ask Dokan support, to check if it's not a bug introduced on last updates or if it's not a new available setting.

    Now your code is outdated and complicated for nothing. It can really be simplified and optimized.

    The following code will set a COD fee based on dokan vendors count:

    // COD Fee based on vendors count 
    add_action( 'woocommerce_cart_calculate_fees', 'dokan_cod_fee_vendors_based' );
    function dokan_cod_fee_vendors_based ( $cart ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) )
            return;
        
        // Only checkout page
        if ( ! ( is_checkout() && ! is_wc_endpoint_url() ) )
            return;
            
        $fee_by_vendor = 2; // HERE set the fee by vendor
        $vendors_array = array(); // Initializing
    
        // Loop through cart items
        foreach ( $cart->get_cart() as $item ) {
            $vendor_id = get_post_field('post_author', $item['product_id']); // Get the vendor_id
        
            // Set in an indexed array to get how many vendors
            $vendors_array[$vendor_id] = $vendor_id;
        }
    
        $fee_total = count($vendors_array) * $fee_by_vendor; // Get fee total by vendor
    
        if ( 'cod' === WC()->session->get( 'chosen_payment_method' ) ) {
            $cart->add_fee( 'Cash On Delivery Fee', $fee_total, true ); // Apply the fee
        }
    }
    
    // jQuery - Update checkout on methode payment change
    add_action( 'wp_footer', 'payment_refresh_checkout_js' );
    function payment_refresh_checkout_js() {
        // Only checkout page
        if ( ! ( is_checkout() && ! is_wc_endpoint_url() ) )
            return; // Exit
        ?>
        <script type="text/javascript">
        jQuery( function($){
            $('form.checkout').on('change', 'input[name="payment_method"]', function(){
                $(document.body).trigger('update_checkout');
            });
        });
        </script>
        <?php
    }
    

    Code goes in functions.php file of the active child theme (or active theme). It should works.