WooCommerce : emplacement d'inventaire de stock supplémentaire

Publié: 2022-12-07

Le plugin WooCommerce vous permet de gérer le stock pour chaque produit, mais vous n'avez qu'un seul champ de quantité de stock !

Que faire si vous avez deux entrepôts et que, en tant qu'administrateur de magasin, vous devez gérer l'inventaire de chaque emplacement ? De plus, que se passe-t-il si un article est en rupture de stock à l'emplacement 1, mais qu'il est en stock à l'emplacement 2, et que le client doit donc pouvoir l'acheter ?

Cette solution de contournement étonnante ajoutera un deuxième numéro d'entrée dans les paramètres du produit, redéfinira la quantité et l'état du stock sur le frontend en additionnant le stock 1 + le stock 2, et enfin diminuera le stock 1 jusqu'à ce qu'il atteigne 0, après quoi il diminuera le stock 2.

Ce comportement par défaut peut bien sûr être modifié, par exemple, il est possible de définir d'où le stock est réduit (par la distance ?) via un code supplémentaire. De plus, un code supplémentaire peut être écrit pour le rendre compatible avec des produits variables ou des types de produits personnalisés, ainsi que pour le faire fonctionner avec des remboursements. Quoi qu'il en soit, profitez-en!

Voici le deuxième champ de stock. Dans ce cas, la quantité de stock est de 0 dans l'entrepôt par défaut, donc techniquement le produit est en rupture de stock. Avec l'extrait ci-dessous et le fait qu'il y a 1 article en stock à l'emplacement 2, le produit est en fait "en stock" avec une quantité de "1". Lors de la commande, c'est la quantité qui est diminuée.

Extrait PHP : Gestion de l'emplacement du second stock

/**
 * @snippet       Second Stock Location @ WooCommerce Edit Product
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 7
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */

add_action( 'woocommerce_product_options_stock', 'bbloomer_additional_stock_location' );

function bbloomer_additional_stock_location() {
	global $product_object;
	echo '<div class="show_if_simple show_if_variable">';
	woocommerce_wp_text_input(
		array(
			'id' => '_stock2',
			'value' => get_post_meta( $product_object->get_id(), '_stock2', true ),
			'label' => '2nd Stock Location',
			'data_type' => 'stock',
		)
	);
	echo '</div>';
}

add_action( 'save_post_product', 'bbloomer_save_additional_stock' );
  
function bbloomer_save_additional_stock( $product_id ) {
    global $typenow;
    if ( 'product' === $typenow ) {
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
		if ( isset( $_POST['_stock2'] ) ) {
			update_post_meta( $product_id, '_stock2', $_POST['_stock2'] );
		}
	}
}

add_filter( 'woocommerce_product_get_stock_quantity' , 'bbloomer_get_overall_stock_quantity', 9999, 2 );

function bbloomer_get_overall_stock_quantity( $value, $product ) {
	$value = (int) $value + (int) get_post_meta( $product->get_id(), '_stock2', true );
    return $value;
}

add_filter( 'woocommerce_product_get_stock_status' , 'bbloomer_get_overall_stock_status', 9999, 2 );

function bbloomer_get_overall_stock_status( $status, $product ) {
	if ( ! $product->managing_stock() ) return $status;
	$stock = (int) $product->get_stock_quantity() + (int) get_post_meta( $product->get_id(), '_stock2', true );
	$status = $stock && ( $stock > 0 ) ? 'instock' : 'outofstock';
    return $status;
}

add_filter( 'woocommerce_payment_complete_reduce_order_stock', 'bbloomer_maybe_reduce_second_stock', 9999, 2 );

function bbloomer_maybe_reduce_second_stock( $reduce, $order_id ) {
	$order = wc_get_order( $order_id );
	$atleastastock2change = false;
	foreach ( $order->get_items() as $item ) {	
		if ( ! $item->is_type( 'line_item' ) ) {
			continue;
		}
		$product = $item->get_product();
		$item_stock_reduced = $item->get_meta( '_reduced_stock', true );
		if ( $item_stock_reduced || ! $product || ! $product->managing_stock() ) {
			continue;
		}
		$qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $order, $item );
		$stock1 = (int) get_post_meta( $product->get_id(), '_stock', true );
		if ( $qty <= $stock1 ) continue;
		$atleastastock2change = true;
	}
	if ( ! $atleastastock2change ) return $reduce;	
	foreach ( $order->get_items() as $item ) {	
		if ( ! $item->is_type( 'line_item' ) ) {
			continue;
		}
		$product = $item->get_product();
		$item_stock_reduced = $item->get_meta( '_reduced_stock', true );
		if ( $item_stock_reduced || ! $product || ! $product->managing_stock() ) {
			continue;
		}	
		$item_name = $product->get_formatted_name();
		$qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $order, $item );
		$stock1 = (int) get_post_meta( $product->get_id(), '_stock', true );
		$stock2 = (int) get_post_meta( $product->get_id(), '_stock2', true );
		if ( $qty <= $stock1 ) {
			wc_update_product_stock( $product, $qty, 'decrease' );
			$order->add_order_note( sprintf( 'Reduced stock for item "%s"; Stock 1: "%s" to "%s".', $item_name, $stock1, $stock1 - $qty ) );
		} else {		
			$newstock2 = $stock2 - ( $qty - $stock1 );
			wc_update_product_stock( $product, $stock1, 'decrease' );
			update_post_meta( $product->get_id(), '_stock2', $newstock2 );
			$item->add_meta_data( '_reduced_stock', $qty, true );
			$item->save();				
			$order->add_order_note( sprintf( 'Reduced stock for item "%s"; Stock 1: "%s" to "0" and Stock 2: "%s" to "%s".', $item_name, $stock1, $stock2, $newstock2 ) );
		}
	}
	$order->get_data_store()->set_stock_reduced( $order_id, true );
	return false;
}

En anglais simple :

  • bbloomer_additional_stock_location affiche le deuxième champ de quantité de stock
  • bbloomer_save_additional_stock enregistre le montant du stock personnalisé
  • bbloomer_get_overall_stock_quantity définit l'inventaire du produit sur stock 1 + stock 2
  • bbloomer_get_overall_stock_status définit l'état du stock du produit en fonction du stock 1 + stock 2
  • bbloomer_maybe_reduce_second_stock diminue le stock du stock 1 puis du stock 2 dans le cas où la quantité commandée est supérieure au stock 1, sinon il laisse WooCommerce faire la diminution de stock par défaut