Automattic\WooCommerce\Checkout\Helpers

ReserveStock::reserve_stock_for_order()publicWC 1.0

Put a temporary hold on stock for an order if enough is available.

Method of the class: ReserveStock{}

Return

null. Nothing (null).

Usage

$ReserveStock = new ReserveStock();
$ReserveStock->reserve_stock_for_order( $order, $minutes );
$order(\WC_Order) (required)
Order object.
$minutes(int)
How long to reserve stock in minutes.
Default: woocommerce_hold_stock_minutes

ReserveStock::reserve_stock_for_order() code WC 9.4.2

public function reserve_stock_for_order( $order, $minutes = 0 ) {
	$minutes = $minutes ? $minutes : (int) get_option( 'woocommerce_hold_stock_minutes', 60 );
	/**
	 * Filters the number of minutes an order should reserve stock for.
	 *
	 * This hook allows the number of minutes that stock in an order should be reserved for to be filtered, useful for third party developers to increase/reduce the number of minutes if the order meets certain criteria, or to exclude an order from stock reservation using a zero value.
	 *
	 * @since 8.8.0
	 *
	 * @param int       $minutes How long to reserve stock for the order in minutes. Defaults to woocommerce_hold_stock_minutes or 10 if block checkout entry.
	 * @param \WC_Order $order Order object.
	 */
	$minutes = (int) apply_filters( 'woocommerce_order_hold_stock_minutes', $minutes, $order );

	if ( ! $minutes || ! $this->is_enabled() ) {
		return;
	}

	$held_stock_notes = array();

	try {
		$items = array_filter(
			$order->get_items(),
			function ( $item ) {
				return $item->is_type( 'line_item' ) && $item->get_product() instanceof \WC_Product && $item->get_quantity() > 0;
			}
		);
		$rows  = array();

		foreach ( $items as $item ) {
			$product = $item->get_product();

			if ( ! $product->is_in_stock() ) {
				throw new ReserveStockException(
					'woocommerce_product_out_of_stock',
					sprintf(
						/* translators: %s: product name */
						__( '"%s" is out of stock and cannot be purchased.', 'woocommerce' ),
						$product->get_name()
					),
					403
				);
			}

			// If stock management is off, no need to reserve any stock here.
			if ( ! $product->managing_stock() || $product->backorders_allowed() ) {
				continue;
			}

			$managed_by_id = $product->get_stock_managed_by_id();

			/**
			 * Filter order item quantity.
			 *
			 * @param int|float             $quantity Quantity.
			 * @param WC_Order              $order    Order data.
			 * @param WC_Order_Item_Product $item Order item data.
			 */
			$item_quantity = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $order, $item );

			$rows[ $managed_by_id ] = isset( $rows[ $managed_by_id ] ) ? $rows[ $managed_by_id ] + $item_quantity : $item_quantity;

			if ( count( $held_stock_notes ) < 5 ) {
				// translators: %1$s is a product's formatted name, %2$d: is the quantity of said product to which the stock hold applied.
				$held_stock_notes[] = sprintf( _x( '- %1$s &times; %2$d', 'held stock note', 'woocommerce' ), $product->get_formatted_name(), $rows[ $managed_by_id ] );
			}
		}

		if ( ! empty( $rows ) ) {
			foreach ( $rows as $product_id => $quantity ) {
				$this->reserve_stock_for_product( $product_id, $quantity, $order, $minutes );
			}
		}
	} catch ( ReserveStockException $e ) {
		$this->release_stock_for_order( $order );
		throw $e;
	}

	// Add order note after successfully holding the stock.
	if ( ! empty( $held_stock_notes ) ) {
		$remaining_count = count( $rows ) - count( $held_stock_notes );
		if ( $remaining_count > 0 ) {
			$held_stock_notes[] = sprintf(
				// translators: %d is the remaining order items count.
				_nx( '- ...and %d more item.', '- ... and %d more items.', $remaining_count, 'held stock note', 'woocommerce' ),
				$remaining_count
			);
		}

		$order->add_order_note(
			sprintf(
				// translators: %1$s is a time in minutes, %2$s is a list of products and quantities.
				_x( 'Stock hold of %1$s minutes applied to: %2$s', 'held stock note', 'woocommerce' ),
				$minutes,
				'<br>' . implode( '<br>', $held_stock_notes )
			)
		);
	}
}