1
votes

I'm making an effort to improve my inventory management and do it straight from WooCommerce (So that it's not necessary to to use external CSV file calculations)

I need to know how much much of each product I need to order (Missing stock). To determine this I calculate using _stock native value and 2 custom fields:

_missing_stock : Amount of missing stock / how much stock I need to order

_ref_stock : Reference stock number (set manually, desired amount of stock in the warehouse)

so: Missing Stock = Reference stock - Stock value


The intention is to automatically calculate and update the Missing Stock value based on the Reference Stock that has been set and the Current Stock of the product. As a product stock lowers with purchases, with this I am quickly able to view how much stock of each product needs to be ordered.

Based on Product regular price calculation based on 2 custom fields in Woocommerce 3 answer code which has some similarities I have managed to create the custom fields and come so far.

However I am not able to figure out how to finally automatically update the _missing_stock value automatically.

This is the code I have managed to come up to, naturally (and probably) not entirely correct.

// Adding and displaying additional Stock custom fields
add_action( 'woocommerce_product_options_stock_status', 'additional_product_stock_option_fields', 50 );
function additional_product_stock_option_fields() {
    $domain = "woocommerce";
    global $post;

    echo '</div><div class="options_group stock show_if_simple show_if_external show_if_composite">';

    woocommerce_wp_text_input( array(
        'id'            => '_ref_stock',
        'label'         => __("Reference Stock", $domain ),
        'placeholder'   => '',
        'description'   => __("Amount of desired target stock in warehouse )", $domain ),
        'desc_tip'      => true,
    ) );


    woocommerce_wp_text_input( array(
        'id'            => '_missing_stock',
        'label'         => __("Missing Stock", $domain ) . ' ('. get_woocommerce_currency_symbol() . ')',
        'placeholder'   => '',
        'description'   => __("Amount of stock that needs to be ordered", $domain ),
        'desc_tip'      => true,
    ) );

    echo '<input type="hidden" name="_custom_stock_nonce" value="' . wp_create_nonce() . '">';

}

// Utility function that save "Reference Stock" and "missing_stock" custom fields values
function saving_ref_stock_and_missing_stock( $product ) {
    // Security check
    if ( isset($_POST['_custom_stock_nonce']) && ! wp_verify_nonce($_POST['_custom_stock_nonce']) ) {
        return;
    }

    // Save "Reference Stock" and "missing_stock" custom fields values
    if( isset($_POST['_ref_stock']) && isset($_POST['_missing_stock']) ) {
        $product->update_meta_data('_ref_stock', sanitize_text_field( (float) $_POST['_ref_stock'] ) );
        $product->update_meta_data('_missing_stock', sanitize_text_field( (float) $_POST['_missing_stock'] ) );
    }
}

// Utility function: Calculate and save product "missing stock" custom field from the "Reference Stock" custom field and the "Stock" field
function calculate_and_save_new_product_stock( $product ) {

// Check if product stock management is enabled
 if ( !$product->managing_stock() ) {
    // Calculate and save the missing stock
    if( isset($_POST['_ref_stock']) && isset($_POST['_missing_stock'])
    && $_POST['_ref_stock'] > 0 && $_POST['_missing_stock'] > 0 ) {

        // Catch the stock data
        $ref_stock    = (float) $_POST['_ref_stock'];
        $missing_stock = (float) $_POST['_missing_stock'];
        $current_stock   = (float) $product->get_stock_quantity();

        // Calculating missing stock
        $missing_stock  = $ref_stock - $current_stock;

     
        }
    }
}

// Saving and calculating Stock values
add_action( 'woocommerce_admin_process_product_object', 'update_product_meta_data', 100, 1 );
function update_product_meta_data( $product ) {

    // Saving "Reference Stock" and "missing_stock" custom fields values
    saving_ref_stock_and_missing_stock( $product ); // <== To be removed if not used with the first function

    // Calculate and save Missing Stock from the "Reference Stock" and the "Stock" custom fields
    calculate_and_save_new_product_missing_stock( $product );
}

Thank you in advance for the attention and advice.

1

1 Answers

1
votes

The code you are already using and have adapted is slightly more extensive than your question, so below is a simplified version.

You can indeed use woocommerce_admin_process_product_object when you are going to save the adjustment in the backend to determine the value of the custom field.

However, after an order when an adjustment of the stock takes place, the value of your custom field will not automatically adjust.

For that you can use the woocommerce_product_set_stock action hook.

This code is written for 'simple' products but can easily be extended to other types of products if desired.

Explanation via comment tags added via in the code

// Adding and displaying additional custom fields
function action_woocommerce_product_options_stock_status() {
    $domain = 'woocommerce';
    
    echo '</div><div class="options_group">';
    
    woocommerce_wp_text_input( array(
        'id'                 => '_ref_stock',
        'label'              => __( 'Reference Stock', $domain ),
        'placeholder'        => '',
        'description'        => __( 'Amount of desired target stock in warehouse', $domain ),
        'desc_tip'           => true,
    ));

    woocommerce_wp_text_input( array(
        'id'                 => '_missing_stock',
        'label'              => __( 'Missing Stock', $domain ),
        'placeholder'        => '',
        'description'        => __( 'Amount of stock that needs to be ordered', $domain ),
        'desc_tip'           => true,
        'custom_attributes'  => array( 'readonly' => 'readonly' ),
    ));
}
add_action( 'woocommerce_product_options_stock_status', 'action_woocommerce_product_options_stock_status', 10, 1 );

// Save custom field
function action_woocommerce_admin_process_product_object( $product ) {
    // Isset
    if ( isset( $_POST['_ref_stock'] ) ) {
        // ID & value
        $ref_stock_id = '_ref_stock';
        $ref_stock_val = sanitize_text_field( $_POST['_ref_stock'] );
        
        // Update ref stock
        $product->update_meta_data( $ref_stock_id, $ref_stock_val );
        
        // Get stock quantity
        $current_stock = (float) $product->get_stock_quantity();

        // NOT empty
        if ( ! empty ( $current_stock ) ) {
            // ID
            $missing_stock_id = '_missing_stock';
            
            // Calculating missing stock
            $missing_stock_val = $ref_stock_val - $current_stock;
            
            // Update missing stock
            $product->update_meta_data( $missing_stock_id, $missing_stock_val );
        }
    }
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );

// When the stock changed
function action_woocommerce_product_set_stock ( $product_with_stock ) {
    global $pagenow;

    // Exit
    if ( is_admin() && $pagenow === 'post.php' )
        return;
    
    // Get meta
    $ref_stock_val = $product_with_stock->get_meta( '_ref_stock' );
    
    // NOT empty
    if ( ! empty ( $ref_stock_val ) ) {
        // Get stock quantity
        $current_stock = (float) $product_with_stock->get_stock_quantity();

        // NOT empty
        if ( ! empty ( $current_stock ) ) {
            // ID
            $missing_stock_id = '_missing_stock';
            
            // Calculating missing stock
            $missing_stock_val = $ref_stock_val - $current_stock;
            
            // Update missing stock
            $product_with_stock->update_meta_data( $missing_stock_id, $missing_stock_val );
            
            // Save
            $product_with_stock->save();
        }       
    }
}
add_action( 'woocommerce_product_set_stock', 'action_woocommerce_product_set_stock', 10, 1 );