Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds
DataUtils::compute_quantity_refund_total
Compute the tax-inclusive refund total for a quantity-form line item, capped to the line's remaining refundable amount.
{@see compute_line_item_refund_total()} rounds each request independently, so a sequence of partial quantity refunds can drift from the stored line gross by up to a cent per request — round(unit × 2) + round(unit × 4) may exceed the line total that round(unit × 6) would produce. The quantity form is "server, compute the amount for me", so rather than rejecting its own arithmetic the server caps the result:
- The unit-derived amount is always clamped down to the remaining amount, so rounding drift can never push it over the remaining-amount cap the validators enforce. Shipping and fee lines carry a single unit whose derived amount is the full line total, so partially-refunded ones always resolve to their remainder through this clamp.
- A product quantity that consumes the line's remaining refundable units is topped up to the exact remaining amount — closing the line at currency precision with no stranded cents — but only when every prior refund on the line matches its own quantity-derived amount, i.e. the shortfall is provably accumulated rounding drift. An off-schedule prior refund (an explicit partial amount, or a dollar-only refund with no units) means the residue was deliberately withheld, and the quantity form must never silently pay it back out; the residue stays refundable through an explicit refund_total.
When no refundable amount remains, the unclamped amount is returned as-is: clamping to zero would trip the zero-refund guard with a misleading error, while the validators reject the line with line_item_already_refunded. Explicit client-supplied refund_total values are never capped — those stay strictly validated.
Method of the class: DataUtils{}
No Hooks.
Returns
float. The tax-inclusive refund total, carrying the line's sign.
Usage
// private - for code of main (parent) class only $result = $this->compute_quantity_refund_total( $item, $quantity, $refund_data ): float;
- $item(WC_Order_Item_Product|WC_Order_Item_Shipping|WC_Order_Item_Fee) (required)
- The order item.
- $quantity(int) (required)
- The quantity to refund (>= 1).
- $refund_data(array) (required)
- Refund-history snapshot from {@see compute_refunded_quantities_and_totals()} (see its return shape).
Changelog
| Since 11.1.0 | Introduced. |
DataUtils::compute_quantity_refund_total() DataUtils::compute quantity refund total code WC 11.1.2
private function compute_quantity_refund_total( $item, int $quantity, array $refund_data ): float {
$computed = $this->compute_line_item_refund_total( $item, $quantity );
$price_decimals = wc_get_price_decimals();
$signed_line_total = (float) $item->get_total() + (float) $item->get_total_tax();
$refunded_total = abs( (float) ( $refund_data['totals'][ $item->get_id() ] ?? 0.0 ) );
$remaining_total = NumberUtil::round( abs( $signed_line_total ) - $refunded_total, $price_decimals );
if ( $remaining_total <= 0 ) {
return $computed;
}
$sign = $signed_line_total < 0 ? -1.0 : 1.0;
$abs_computed = abs( $computed );
if ( $abs_computed > $remaining_total ) {
return $sign * $remaining_total;
}
if ( $item instanceof WC_Order_Item_Product && $abs_computed < $remaining_total ) {
$remaining_qty = $item->get_quantity() + ( $refund_data['qtys'][ $item->get_id() ] ?? 0 );
if (
$quantity >= $remaining_qty &&
$this->line_refund_history_matches_quantities( $item, $refund_data['line_refunds'][ $item->get_id() ] ?? array() )
) {
return $sign * $remaining_total;
}
}
return $computed;
}