Automattic\WooCommerce\StoreApi\Routes\V1

Checkout::get_route_post_responseprotectedWC 1.0

Process an order.

  1. Obtain Draft Order
  2. Process Request
  3. Process Customer
  4. Validate Order
  5. Process Payment

Метод класса: Checkout{}

Возвращает

\WP_REST_Response|\WP_Error.

Использование

// protected - в коде основоного (родительского) или дочернего класса
$result = $this->get_route_post_response( $request );
$request(WP_REST_Request) (обязательный)
Request object.

Код Checkout::get_route_post_response() WC 9.9.3

protected function get_route_post_response( \WP_REST_Request $request ) {
	wc_log_order_step( '[Store API #1] Place Order flow initiated', null, false, true );

	$validation_callback = $this->validate_callback( $request );

	if ( is_wp_error( $validation_callback ) ) {
		return $validation_callback;
	}

	/**
	 * Ensure required permissions based on store settings are valid to place the order.
	 */
	$this->validate_user_can_place_order();

	/**
	 * Before triggering validation, ensure totals are current and in turn, things such as shipping costs are present.
	 * This is so plugins that validate other cart data (e.g. conditional shipping and payments) can access this data.
	 */
	$this->cart_controller->calculate_totals();

	/**
	 * Validate that the cart is not empty.
	 */
	$this->cart_controller->validate_cart_not_empty();
	wc_log_order_step( '[Store API #2] Cart validated' );

	/**
	 * Validate items and fix violations before the order is processed.
	 */
	$this->cart_controller->validate_cart();

	/**
	 * Persist customer session data from the request first so that OrderController::update_addresses_from_cart
	 * uses the up-to-date customer address.
	 */
	$this->update_customer_from_request( $request );
	wc_log_order_step( '[Store API #3] Updated customer data from request' );

	/**
	 * Create (or update) Draft Order and process request data.
	 */
	$this->create_or_update_draft_order( $request );
	wc_log_order_step( '[Store API #4] Created/Updated draft order', array( 'order_object' => $this->order ) );
	$this->update_order_from_request( $request );
	wc_log_order_step( '[Store API #5] Updated order with posted data', array( 'order_object' => $this->order ) );
	$this->process_customer( $request );
	wc_log_order_step( '[Store API #6] Created and/or persisted customer data from order', array( 'order_object' => $this->order ) );

	/**
	 * Validate updated order before payment is attempted.
	 */
	$this->order_controller->validate_order_before_payment( $this->order );
	wc_log_order_step( '[Store API #7] Validated order data', array( 'order_object' => $this->order ) );

	/**
	 * Hold coupons for the order as soon as the draft order is created.
	 */
	try {
		// $this->order->get_billing_email() is already validated by validate_order_before_payment()
		$this->order->hold_applied_coupons( $this->order->get_billing_email() );
	} catch ( \Exception $e ) {
		// Turn the Exception into a RouteException for the API.
		throw new RouteException(
			'woocommerce_rest_coupon_reserve_failed',
			esc_html( $e->getMessage() ),
			400
		);
	}

	/**
	 * Reserve stock for the order.
	 *
	 * In the shortcode based checkout, when POSTing the checkout form the order would be created and fire the
	 * `woocommerce_checkout_order_created` action. This in turn would trigger the `wc_reserve_stock_for_order`
	 * function so that stock would be held pending payment.
	 *
	 * Via the block based checkout and Store API we already have a draft order, but when POSTing to the /checkout
	 * endpoint we do the same; reserve stock for the order to allow time to process payment.
	 *
	 * Note, stock is only "held" while the order has the status wc-checkout-draft or pending. Stock is freed when
	 * the order changes status, or there is an exception.
	 *
	 * @see ReserveStock::get_query_for_reserved_stock()
	 *
	 * @since 9.2 Stock is no longer held for all draft orders, nor on non-POST requests. See https://github.com/woocommerce/woocommerce/issues/44231
	 * @since 9.2 Uses wc_reserve_stock_for_order() instead of using the ReserveStock class directly.
	 */
	try {
		wc_reserve_stock_for_order( $this->order );
	} catch ( ReserveStockException $e ) {
		throw new RouteException(
			esc_html( $e->getErrorCode() ),
			esc_html( $e->getMessage() ),
			esc_html( $e->getCode() )
		);
	}
	wc_log_order_step( '[Store API #8] Reserved stock for order', array( 'order_object' => $this->order ) );

	wc_do_deprecated_action(
		'__experimental_woocommerce_blocks_checkout_order_processed',
		array(
			$this->order,
		),
		'6.3.0',
		'woocommerce_store_api_checkout_order_processed',
		'This action was deprecated in WooCommerce Blocks version 6.3.0. Please use woocommerce_store_api_checkout_order_processed instead.'
	);

	wc_do_deprecated_action(
		'woocommerce_blocks_checkout_order_processed',
		array(
			$this->order,
		),
		'7.2.0',
		'woocommerce_store_api_checkout_order_processed',
		'This action was deprecated in WooCommerce Blocks version 7.2.0. Please use woocommerce_store_api_checkout_order_processed instead.'
	);

	// Set the order status to 'pending' as an initial step.
	// This allows the order to proceed towards completion. The hook
	// 'woocommerce_store_api_checkout_order_processed' (fired below) can be used
	// to set a custom status *after* this point.
	// If payment isn't needed, the custom status is kept. If payment is needed,
	// the payment gateway's statuses take precedence.
	$this->order->update_status( 'pending' );

	/**
	 * Fires before an order is processed by the Checkout Block/Store API.
	 *
	 * This hook informs extensions that $order has completed processing and is ready for payment.
	 *
	 * This is similar to existing core hook woocommerce_checkout_order_processed. We're using a new action:
	 * - To keep the interface focused (only pass $order, not passing request data).
	 * - This also explicitly indicates these orders are from checkout block/StoreAPI.
	 *
	 * @since 7.2.0
	 *
	 * @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/3238
	 * @example See docs/examples/checkout-order-processed.md

	 * @param \WC_Order $order Order object.
	 */
	do_action( 'woocommerce_store_api_checkout_order_processed', $this->order );

	/**
	 * Process the payment and return the results.
	 */
	$payment_result = new PaymentResult();

	if ( $this->order->needs_payment() ) {
		$this->process_payment( $request, $payment_result );
	} else {
		$this->process_without_payment( $request, $payment_result );
	}

	wc_log_order_step(
		'[Store API #9] Order processed',
		array(
			'order_object'           => $this->order,
			'processed_with_payment' => $this->order->needs_payment() ? 'yes' : 'no',
			'payment_status'         => $payment_result->status,
		),
		true
	);

	return $this->prepare_item_for_response(
		(object) [
			'order'          => wc_get_order( $this->order ),
			'payment_result' => $payment_result,
		],
		$request
	);
}