WC_REST_Order_Refunds_Controller::create_refund_with_computed_totalsprivateWC 11.1.0

Create a refund with server-computed per-line totals (compute_totals mode).

Mirrors the wc/v4 refund creation pipeline: line items may omit refund_total (computed from quantity at the order's stored unit price, tax-inclusive, clamped to the remaining refundable amount), input is validated against the order's refund history, and the refund amount is derived from the line items unless an explicit amount override is supplied. Validation follows the same rules as the wc/v4 creation endpoint; error codes are prefixed with woocommerce_rest_ at this v3 boundary like the rest of the v3 surface.

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

Возвращает

WP_Error|WC_Data. The created refund, or WP_Error object on failure.

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

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

Список изменений

С версии 11.1.0 Введена.

Код WC_REST_Order_Refunds_Controller::create_refund_with_computed_totals() WC 11.1.1

private function create_refund_with_computed_totals( $request ) {
	$order = wc_get_order( (int) $request['order_id'] );

	// wc_get_order can return a WC_Order_Refund for refund IDs — reject those
	// here since refunds are not refundable themselves.
	if ( ! $order instanceof WC_Order ) {
		return new WP_Error( 'woocommerce_rest_invalid_order_id', __( 'Invalid order ID.', 'woocommerce' ), array( 'status' => 404 ) );
	}

	// Normalize each line to the engine's schema shape and validate value
	// types here: the REST layer cannot, because the line_items schema
	// property is readonly for backward compatibility, so its args are not
	// registered.
	$line_items = array();
	foreach ( (array) ( $request['line_items'] ?? array() ) as $line_item ) {
		if ( ! is_array( $line_item ) ) {
			return new WP_Error( 'woocommerce_rest_invalid_line_item', __( 'Each line item must be an object.', 'woocommerce' ), array( 'status' => 400 ) );
		}

		$line_item = $this->normalize_line_item( $line_item );
		if ( is_wp_error( $line_item ) ) {
			return $line_item;
		}

		$line_items[] = $line_item;
	}

	// The shared engine runs the whole creation preparation: fill missing
	// refund totals, validate against the order's refund history, convert to
	// the internal wc_create_refund() format, resolve the amount, and apply
	// the aggregate guards. Its WP_Errors carry their HTTP status in the
	// error data and use unprefixed codes; they are prefixed here at the v3
	// boundary like every other error the endpoint returns.
	$prepared = $this->get_data_utils()->prepare_refund_creation_or_error(
		$order,
		$line_items,
		$request->has_param( 'amount' ),
		$request['amount'],
		'wc-rest-refunds'
	);

	if ( is_wp_error( $prepared ) ) {
		return $this->prefix_error_code( $prepared );
	}

	$line_item_data = $prepared['line_items'];
	$refund_amount  = $prepared['amount'];

	// Mirror the resolved values back onto the request so the pre_insert filter
	// below and any other downstream readers see the same internal-format
	// line_items and amount the legacy path exposes after
	// RestApiParameterUtil::adjust_create_refund_request_parameters().
	$request->set_param( 'line_items', $line_item_data );
	$request->set_param( 'amount', strval( $refund_amount ) );

	$refund = wc_create_refund(
		array(
			'order_id'       => $order->get_id(),
			'amount'         => $refund_amount,
			'reason'         => empty( $request['reason'] ) ? null : $request['reason'],
			'line_items'     => $line_item_data,
			'refund_payment' => is_bool( $request['api_refund'] ) ? $request['api_refund'] : true,
			'restock_items'  => is_bool( $request['api_restock'] ) ? $request['api_restock'] : true,
		)
	);

	// Same code and status as the legacy path above so a wc_create_refund
	// failure looks identical to clients regardless of the compute_totals flag.
	if ( is_wp_error( $refund ) ) {
		return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', $refund->get_error_message(), array( 'status' => 500 ) );
	}

	if ( ! $refund ) {
		return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', __( 'Cannot create order refund, please try again.', 'woocommerce' ), array( 'status' => 500 ) );
	}

	if ( ! empty( $request['meta_data'] ) ) {
		MetaDataUtil::update( $request['meta_data'], $refund );
		$refund->save_meta_data();
	}

	/**
	 * Filters an object before it is inserted via the REST API.
	 *
	 * The dynamic portion of the hook name, `$this->post_type`,
	 * refers to the object type slug.
	 *
	 * @param WC_Data         $refund   Object object.
	 * @param WP_REST_Request $request  Request object.
	 * @param bool            $creating If is creating a new object.
	 *
	 * @since 3.0.0
	 */
	return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $refund, $request, true );
}