skip to Main Content

Currently, I’m working on a WooCommerce (5.2.2) project. My client wants to create a custom input field for Advance payment in the Backend (not for customers) so that when my client received an advance payment from the customer (delivery purpose) they can add manually and order total auto adjust from the backend. So I’ve wright a code and create a custom field in the post meta table and use that meta table value to calculate the total order, it works but I have to refresh twice to get Order’s total new value. here is my code and tell me how to fix it –

add_action( 'manage_shop_order_posts_custom_column' ,  array(&$this,'add_custom_column_content'), 11, 2 );

add_action( 'woocommerce_admin_order_totals_after_discount', array(&$this, 'vp_add_sub_total'), 10, 1);

add_action( 'woocommerce_process_shop_order_meta', array(&$this, 'save_order_custom_field_meta_data'), 12, 2 );


// Output a custom editable field in backend edit order pages under general section
         function editable_order_custom_field( $order ){            
        
            // Get "Delivery Type" from meta data (not item meta data)
            $updated_advance_payment = $order->get_meta('_advance_payment');
        
            // Replace "Delivery Type" value by the meta data if it exist
            $advancePayment = $updated_advance_payment ? $updated_advance_payment : ( isset($item_value) ? $item_value : '');
        
            // Display the custom editable field
            woocommerce_wp_text_input( 
                array(
                    'id'            => 'advance_payment',
                    'label'         => __("Advance Payment:", "woocommerce"),
                    'value'         => $advancePayment,
                    'wrapper_class' => 'form-field-wide',
                )
            );
        }

// Save the custom editable field value as order meta data and update order item meta data  
        function save_order_custom_field_meta_data( $post_id, $post ){
            if( isset( $_POST[ 'advance_payment' ] )){
                update_post_meta( $post_id, '_advance_payment', sanitize_text_field( $_POST[ 'advance_payment' ] ) );

                // Update the existing item meta data
                if( isset( $_POST[ 'item_id_ref' ] ) ){
                    wc_update_order_item_meta( $_POST[ 'item_id_ref' ], 'Advance Payment', $_POST[ 'advance_payment' ] );
                }
            }
        }

//Display Advance Payment and calculate
        function vp_add_sub_total( $the_order ) {
            global $post, $the_order;
            if ( empty( $the_order ) || $the_order->get_id() !== $post->ID ) {
                $the_order = wc_get_order( $post->ID );
            }
            ?>
            
            <tr>
            <td class="label">Advance Payment:</td>
            <td width="1%"></td>
            <td class="total"><?php echo wc_price(get_post_meta($post->ID, "_advance_payment", true));?></td>
            </tr>
            
            <?php

            $getTotal = $the_order->get_total();

            $updateTotal = $getTotal - get_post_meta($post->ID, "_advance_payment", true);

            $the_order->set_total($updateTotal);

            $the_order->save();

        }

Note : I create a small plugin for this advance payment.

Video link for reference : https://www.awesomescreenshot.com/video/3589010?key=b26b5951753bfdc8a969b53f526a36d1

2

Answers


  1. You need to calculate Advance Payment before display. you can use woocommerce_admin_order_item_headers action hook.

    add_action( 'woocommerce_admin_order_item_headers', 'calculate_advance_payment', 10, 1);
    add_action( 'woocommerce_admin_order_totals_after_discount', 'vp_add_sub_total', 10, 1);
    add_action( 'woocommerce_process_shop_order_meta', 'save_order_custom_field_meta_data', 12, 2 );
    add_action( 'woocommerce_admin_order_data_after_order_details', 'editable_order_custom_field' );
    
    // Output a custom editable field in backend edit order pages under general section
    function editable_order_custom_field( $order ){            
    
        // Get "Delivery Type" from meta data (not item meta data)
        $updated_advance_payment = $order->get_meta('_advance_payment');
    
        // Replace "Delivery Type" value by the meta data if it exist
        $advancePayment = $updated_advance_payment ? $updated_advance_payment : ( isset($item_value) ? $item_value : '');
    
        // Display the custom editable field
        woocommerce_wp_text_input( 
            array(
                'id'            => 'advance_payment',
                'label'         => __("Advance Payment:", "woocommerce"),
                'value'         => $advancePayment,
                'wrapper_class' => 'form-field-wide',
            )
        );
    }
    
    // Save the custom editable field value as order meta data and update order item meta data  
    function save_order_custom_field_meta_data( $post_id, $post ){
        if( isset( $_POST[ 'advance_payment' ] )){
            update_post_meta( $post_id, '_advance_payment', sanitize_text_field( $_POST[ 'advance_payment' ] ) );
    
            // Update the existing item meta data
            if( isset( $_POST[ 'item_id_ref' ] ) ){
                wc_update_order_item_meta( $_POST[ 'item_id_ref' ], 'Advance Payment', $_POST[ 'advance_payment' ] );
            }
        }
    }
    
    function calculate_advance_payment( $the_order ) {
        $getTotal = $the_order->get_total();
        $updateTotal = $getTotal - get_post_meta($the_order->get_id(), "_advance_payment", true);
        $the_order->set_total($updateTotal);
        $the_order->save();
    }
    
    function vp_add_sub_total( $the_order ) {
        global $post, $the_order; ?>
        <tr>
        <td class="label">Advance Payment:</td>
        <td width="1%"></td>
        <td class="total"><?php echo wc_price(get_post_meta($post->ID, "_advance_payment", true));?></td>
        </tr><?php
    }
    
    Login or Signup to reply.
  2. I was looking for this solution. Unfortunately the solution posted above gave this error "Unsupported operand types: string – string". I used var_dump($getTotal); var_dump( $advanced_payment); to analyze the data. Since it’s adding+ 2 numbers that are in a string add (int) or (float) before variable $variable. float is used when numbers contain a decimal. Use (int) for integers that are whole numbers. Example: (int)$variable , (float)$variable. Here’s an article which helped me. Here’s the modified solution which gave no errors and updated the order total.

    add_action( 'woocommerce_admin_order_item_headers', 'calculate_advance_payment', 10, 1);
    add_action( 'woocommerce_admin_order_totals_after_discount', 'vp_add_sub_total', 10, 1);
    add_action( 'woocommerce_process_shop_order_meta', 'save_order_custom_field_meta_data', 12, 2 );
    add_action( 'woocommerce_admin_order_data_after_order_details', 'editable_order_custom_field' );
    
    // Output a custom editable field in backend edit order pages under general section
    function editable_order_custom_field( $order ){            
        
        // Get "Delivery Type" from meta data (not item meta data)
        $updated_advance_payment = $order->get_meta('advance_payment');
    
        // Replace "Delivery Type" value by the meta data if it exist
        $advanced_payment = $updated_advance_payment ? $updated_advance_payment : ( isset($item_value) ? $item_value : '');
    
        // Display the custom editable field
        woocommerce_wp_text_input( 
            array(
                'id'            => 'advance_payment',
                'label'         => __("Advance Payment:", "woocommerce"),
                'value'         => $advanced_payment,
                'wrapper_class' => 'form-field-wide',
            )
        );
    }
    
    // Save the custom editable field value as order meta data and update order item meta data  
    function save_order_custom_field_meta_data( $post_id, $post ){
        //global $order;
        if( isset( $_POST[ 'advance_payment' ] )){
            update_post_meta( $post_id, 'advance_payment', sanitize_text_field( $_POST[ 'advance_payment' ] ) );
            
            // Update the existing item meta data
            if( isset( $_POST[ 'item_id_ref' ] ) ){
                wc_update_order_item_meta( $_POST[ 'item_id_ref' ], 'Advance Payment', $_POST[ 'advance_payment' ] );
            }
        }
    }
    
    function calculate_advance_payment( $order ) {
        $order_id = $order->get_id();
        $getTotal = $order->get_total();
        $advanced_payment = get_post_meta($order_id, 'advance_payment', true);
        $order_total = (float)$getTotal - (float)$advanced_payment;
        $order->set_total( $order_total );
        $order->save();
    }
    
    function vp_add_sub_total( $order ) {
        global $post, $order; 
    ?>
        <tr>
        <td class="label">Advance Payment:</td>
        <td width="1%"></td>
        <td class="total"><?php echo wc_price(get_post_meta($post->ID, "advance_payment", true));?></td>
        </tr><?php
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search