nopSolutions/nopCommerce · error · NopException

Cannot do partial refund for order.

Error message

Cannot do partial refund for order.

What it means

Thrown by OrderProcessingService.PartiallyRefundAsync when CanPartiallyRefundAsync(order, amountToRefund) returns false. A partial online refund is allowed only when OrderTotal > 0, there is a refundable remainder (OrderTotal - RefundedAmount > 0), amountToRefund does not exceed that remainder, PaymentStatus is Paid or PartiallyRefunded, and the payment method supports partial refund. It guards against over-refunding and against refunding via a gateway that cannot do partials.

Source

Thrown at src/Libraries/Nop.Services/Orders/OrderProcessingService.cs:2832

        return false;
    }

    /// <summary>
    /// Partially refunds an order (from admin panel)
    /// </summary>
    /// <param name="order">Order</param>
    /// <param name="amountToRefund">Amount to refund</param>
    /// <returns>
    /// A task that represents the asynchronous operation
    /// The task result contains a list of errors; empty list if no errors
    /// </returns>
    public virtual async Task<IList<string>> PartiallyRefundAsync(Order order, decimal amountToRefund)
    {
        ArgumentNullException.ThrowIfNull(order);

        if (!await CanPartiallyRefundAsync(order, amountToRefund))
            throw new NopException("Cannot do partial refund for order.");

        var request = new RefundPaymentRequest();
        RefundPaymentResult result = null;
        try
        {
            request.Order = order;
            request.AmountToRefund = amountToRefund;
            request.IsPartialRefund = true;

            result = await _paymentService.RefundAsync(request);

            if (result.Success)
            {
                //total amount refunded
                var totalAmountRefunded = order.RefundedAmount + amountToRefund;

                //update order info
                order.RefundedAmount = totalAmountRefunded;

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Guard with: if (!await _orderProcessingService.CanPartiallyRefundAsync(order, amountToRefund)) return; and clamp/validate the amount first.
  2. Compute the remainder and clamp amountToRefund = Math.Min(amountToRefund, order.OrderTotal - order.RefundedAmount).
  3. Verify _paymentService.SupportPartiallyRefundAsync(order.PaymentMethodSystemName); use PartiallyRefundOfflineAsync if the gateway cannot do it.
  4. Confirm PaymentStatus is Paid or PartiallyRefunded before offering the action.

Example fix

// before
var errors = await _orderProcessingService.PartiallyRefundAsync(order, amount);

// after
var remaining = order.OrderTotal - order.RefundedAmount;
amount = Math.Min(amount, remaining);
if (!await _orderProcessingService.CanPartiallyRefundAsync(order, amount))
    return new[] { "Partial refund not available." };

var errors = await _orderProcessingService.PartiallyRefundAsync(order, amount);
Defensive patterns

Strategy: validation

Validate before calling

var remaining = order.OrderTotal - order.RefundedAmount;
amountToRefund = Math.Min(amountToRefund, remaining);
if (!await _orderProcessingService.CanPartiallyRefundAsync(order, amountToRefund))
    return Array.Empty<string>();

return await _orderProcessingService.PartiallyRefundAsync(order, amountToRefund);

Prevention

When it happens

Trigger: Calling PartiallyRefundAsync when: amountToRefund > OrderTotal - RefundedAmount; OrderTotal == 0; remainder <= 0 (fully refunded); PaymentStatus not Paid/PartiallyRefunded; or the payment method does not support partial refund.

Common situations: Passing an amount that exceeds the remaining refundable total; refunding more than once such that nothing is left; payment gateway plugin lacking partial-refund support; order not Paid; rounding/currency mismatches making amountToRefund marginally exceed the remainder.

Related errors


AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13). Data as JSON: /api/errors/d0a476c636333719. Report an issue: GitHub.