2

Based on Add a checkout checkbox field that enable a percentage fee in Woocommerce answer code I created a checkbox on the checkout page.

When it is checked, it applies a 15% freight forwarding fee.

// Add a custom checkbox fields before order notes
add_action( 'woocommerce_before_order_notes', 'add_custom_checkout_checkbox', 20 );
function add_custom_checkout_checkbox(){

    // Add a custom checkbox field
    woocommerce_form_field( 'forwarding_fee', array(
        'type'  => 'checkbox',
        'label' => __('15% forwarding fee'),
        'class' => array( 'form-row-wide' ),
    ), '' );
}


// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_fee_script' );
function checkout_fee_script() {
    // Only on Checkout
    if( is_checkout() && ! is_wc_endpoint_url() ) :

    if( WC()->session->__isset('enable_fee') )
        WC()->session->__unset('enable_fee')
    ?>
    <script type="text/javascript">
    jQuery( function($){
        if (typeof wc_checkout_params === 'undefined') 
            return false;

        $('form.checkout').on('change', 'input[name=forwarding_fee]', function(e){
            var fee = $(this).prop('checked') === true ? '1' : '';

            $.ajax({
                type: 'POST',
                url: wc_checkout_params.ajax_url,
                data: {
                    'action': 'enable_fee',
                    'enable_fee': fee,
                },
                success: function (result) {
                    $('body').trigger('update_checkout');
                },
            });
        });
    });
    </script>
    <?php
    endif;
}

// Get Ajax request and saving to WC session
add_action( 'wp_ajax_enable_fee', 'get_enable_fee' );
add_action( 'wp_ajax_nopriv_enable_fee', 'get_enable_fee' );
function get_enable_fee() {
    if ( isset($_POST['enable_fee']) ) {
        WC()->session->set('enable_fee', ($_POST['enable_fee'] ? true : false) );
    }
    die();
}

// Add a custom dynamic 15% fee
add_action( 'woocommerce_cart_calculate_fees', 'custom_percetage_fee', 20, 1 );
function custom_percetage_fee( $cart ) {
    // Only on checkout
    if ( ( is_admin() && ! defined( 'DOING_AJAX' ) ) || ! is_checkout() )
        return;

    $percent = 15;

    if( WC()->session->get('enable_fee') )
        $cart->add_fee( __( 'Forwarding fee', 'woocommerce')." ($percent%)", ($cart->get_subtotal() * $percent / 100) );
}

Currently, this fee is calculated from the subtotal and added up to the order total value.

I need a solution where this fee is calculated from a sum of subtotal + shipping AND IS NOT added to the order total value.

I will rename "fee" to "deposit".


Please see a screenshot:

enter image description here

7uc1f3r
  • 28,449
  • 17
  • 32
  • 50
Rudolfs
  • 137
  • 3
  • 18

1 Answers1

2

Since you don't want to add it to the total, you can add a custom table row to the woocommerce-checkout-review-order-table instead of a cart fee. So my answer is not based on the WooCommerce fee and is completely separate from it.

The custom table row will then show/hide the percentage, based on if the checkbox is checked.

Explanation via one-line comments, added to my answer.

So you get:

// Add checkbox field
function action_woocommerce_before_order_notes( $checkout ) {
    // Add field
    woocommerce_form_field( 'my_id', array(
        'type'          => 'checkbox',
        'class'         => array( 'form-row-wide' ),
        'label'         => __( '15% and some other text', 'woocommerce' ),
        'required'      => false,  
    ), $checkout->get_value( 'my_id' ));
}
add_action( 'woocommerce_before_order_notes', 'action_woocommerce_before_order_notes', 10, 1 );

// Save checkbox value
function action_woocommerce_checkout_create_order( $order, $data ) {
    // Set the correct value
    $checkbox_value = isset( $_POST['my_id'] ) ? 'yes' : 'no';
    
    // Update meta data
    $order->update_meta_data( '_my_checkbox_value', $checkbox_value );
}
add_action( 'woocommerce_checkout_create_order', 'action_woocommerce_checkout_create_order', 10, 2 );

// Add table row on the checkout page
function action_woocommerce_before_order_total() {
    // Initialize
    $percent = 15;
    
    // Get subtotal & shipping total
    $subtotal       = WC()->cart->subtotal;
    $shipping_total = WC()->cart->get_shipping_total();
    
    // Total
    $total = $subtotal + $shipping_total;
    
    // Result
    $result = ( $total / 100 ) * $percent;
    
    // The Output
    echo '<tr class="my-class">
        <th>' . __( 'My text', 'woocommerce' ) . '</th>
        <td data-title="My text">' . wc_price( $result ) . '</td>
    </tr>';
}
add_action( 'woocommerce_review_order_before_order_total', 'action_woocommerce_before_order_total', 10, 0 );
    
// Show/hide table row on the checkout page with jQuery
function action_wp_footer() {
    // Only on checkout
    if ( is_checkout() && ! is_wc_endpoint_url() ) :
    ?>
    <script type="text/javascript">
    jQuery( function($){
        // Selector
        var my_input = 'input[name=my_id]';
        var my_class = '.my-class';
        
        // Show or hide
        function show_or_hide() {
            if ( $( my_input ).is(':checked') ) {
                return $( my_class ).show();
            } else {
                return $( my_class ).hide();               
            }           
        }
        
        // Default
        $( document ).ajaxComplete(function() {
            show_or_hide();
        });
        
        // On change
        $( 'form.checkout' ).change(function() {
            show_or_hide();
        });
    });
    </script>
    <?php
    endif;
}
add_action( 'wp_footer', 'action_wp_footer', 10, 0 );

// If desired, add new table row to emails, order received (thank you page) & my account -> view order
function filter_woocommerce_get_order_item_totals( $total_rows, $order, $tax_display ) {    
    // Get checkbox value
    $checkbox_value = $order->get_meta( '_my_checkbox_value' );
    
    // NOT equal to yes, return
    if ( $checkbox_value != 'yes' ) return $total_rows;
    
    // Initialize
    $percent = 15;
    
    // Get subtotal & shipping total
    $subtotal       = $order->get_subtotal();
    $shipping_total = $order->get_shipping_total();
    
    // Total
    $total = $subtotal + $shipping_total;
    
    // Result
    $result = ( $total / 100 ) * $percent;
    
    // Save the value to be reordered
    $order_total = $total_rows['order_total'];
    
    // Remove item to be reordered
    unset( $total_rows['order_total'] );
    
    // Add new row
    $total_rows['my_text'] = array(
        'label' =>  __( 'My text:', 'woocommerce' ),
        'value' => wc_price( $result ),
    );
    
    // Reinsert removed in the right order
    $total_rows['order_total'] = $order_total;

    return $total_rows;
}
add_filter( 'woocommerce_get_order_item_totals', 'filter_woocommerce_get_order_item_totals', 10, 3 );
7uc1f3r
  • 28,449
  • 17
  • 32
  • 50
  • Awesome! Is it possible to also display this fee/deposit in the backend: Woocommerce>Orders>Edit order page in the same place the woocommerce fee would be? – Rudolfs Sep 16 '21 at 11:21
  • 1
    @Rudolfs yes, that is possible, namely via the [`woocommerce_admin_order_items_after_fees`](https://github.com/woocommerce/woocommerce/blob/1d725d8dc83f5c5d95a5acb6672d36f4fc1bd33a/includes/admin/meta-boxes/views/html-order-items.php#L74) action hook – 7uc1f3r Sep 16 '21 at 11:35
  • Cool! Also, is there a meta key for this fee/deposit value so I can display it in the invoice? – Rudolfs Sep 16 '21 at 11:40
  • 1
    @Rudolfs no, the calculation is currently being performed again. If you want to save the value as meta data from the checkout page you can extend the 2nd part of my answer. (`woocommerce_checkout_create_order`) – 7uc1f3r Sep 16 '21 at 11:43