简体   繁体   中英

Reduce stock only for specific order statuses and payment method in Woocommerce

I'm working on a bit of custom Woocommerce functionality for a client. They use the BACS payment gateway to handle manual payments.

However, the gateway currently reduces the stock too early for our needs, ie, when the order is "On Hold". I would like to ONLY reduce the stock when the order is marked "Processing" or "Complete" (avoiding duplicate reductions).

I have manged to prevent the stock from reducing itself while "on hold" with the following snippet:

function wcs_do_not_reduce_onhold_stock( $reduce_stock, $order ) {
if ( $order->has_status( 'on-hold' ) ) {
$reduce_stock = false;
}
return $reduce_stock;
}
add_filter( 'woocommerce_can_reduce_order_stock', 'wcs_do_not_reduce_onhold_stock', 10, 2 );

I'm not too sure how to proceed though. While the above code works, adding the following condition does not:

else if ( $order->has_status( 'processing' ) || $order->has_status( 'completed' ) ) {
$reduce_stock = true;
}

In short, I'd ideally like the stock to change depending on the following stock statuses:

  • On Hold - Does nothing
  • Completed or Processing - Reduce Stock (Only once)
  • Cancelled - Increase Stock (Only if initially reduced)

Any help is much appreciated!

Using a custom function hooked in woocommerce_order_status_changed you will be able to target 'processing' and 'completed' order statuses change reducing order items stock.

I have added in your function a condition to target only "BACS" payment gateway on orders.

add_filter( 'woocommerce_can_reduce_order_stock', 'wcs_do_not_reduce_onhold_stock', 10, 2 );
function wcs_do_not_reduce_onhold_stock( $reduce_stock, $order ) {
    if ( $order->has_status( 'on-hold' ) && $order->get_payment_method() == 'bacs' ) {
        $reduce_stock = false;
    }
    return $reduce_stock;
}

add_action( 'woocommerce_order_status_changed', 'order_stock_reduction_based_on_status', 20, 4 );
function order_stock_reduction_based_on_status( $order_id, $old_status, $new_status, $order ){
    // Only for 'processing' and 'completed' order statuses change
    if ( $new_status == 'processing' || $new_status == 'completed' ){
    $stock_reduced = get_post_meta( $order_id, '_order_stock_reduced', true );
        if( empty($stock_reduced) && $order->get_payment_method() == 'bacs' ){
            wc_reduce_stock_levels($order_id);
        }
    }
}

Code goes in function.php file of the active child theme (or active theme).

Tested and works

The accepted answer did not work for me. The first part did but not the second, this is how I modified it:

// This is the same as the accepted answer
add_filter( 'woocommerce_can_reduce_order_stock', 'wcs_do_not_reduce_onhold_stock', 10, 2 );
function wcs_do_not_reduce_onhold_stock( $reduce_stock, $order ) {
    if ( $order->has_status( 'on-hold' ) && $order->get_payment_method() == 'bacs' ) {
        $reduce_stock = false;
    }
    return $reduce_stock;
}

// This is what I changed
add_action( 'woocommerce_order_status_processing', 'reduce_stock_on_bacs_order_status_change', 10, 1 );
add_action( 'woocommerce_order_status_completed', 'reduce_stock_on_bacs_order_status_change', 10, 1 );
function reduce_stock_on_bacs_order_status_change( $order_id ) {
  // Get the order object
  $order = wc_get_order( $order_id );
  
  // Check if the order was paid using BACS
  if ( 'bacs' == $order->get_payment_method() ) {
    // Check if the stock reduction has already been done for this order
    $stock_reduction_done = get_post_meta( $order_id, '_stock_reduction_done', true );
    if ( ! $stock_reduction_done ) {
      // Iterate over the order items
      foreach( $order->get_items() as $item_id => $item ) {
        // Reduce stock for each item
        $product = $item->get_product();
        $qty = $item->get_quantity();
        $product->reduce_stock( $qty );
      }
      
      // Mark the stock reduction as done for this order
      update_post_meta( $order_id, '_stock_reduction_done', true );
    }
  }
}

This will not reduce the stock for BACS payments until the order is marked as processing or completed .

can someone support please i have custom status wich named "wc-packed" and "wc-shipped" i need the stock level reduce when i choose one of them and not effective by any other status

and even i change from those status to another the stock level restored

and i have another custom status called "WC-RTRN"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM