nopSolutions/nopCommerce · error · NopException

You can't refund this order

Error message

You can't refund this order

What it means

Thrown by OrderProcessingService.RefundOfflineAsync when CanRefundOffline(order) returns false. An offline (manual) full refund is allowed only when OrderTotal > 0, RefundedAmount == 0 (no prior partial refunds), and PaymentStatus == Paid. Offline refunds bypass the payment gateway, so the order must be Paid and not already partially refunded.

Source

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

        //     return false;

        if (order.PaymentStatus == PaymentStatus.Paid)
            return true;

        return false;
    }

    /// <summary>
    /// Refunds an order (offline)
    /// </summary>
    /// <param name="order">Order</param>
    /// <returns>A task that represents the asynchronous operation</returns>
    public virtual async Task RefundOfflineAsync(Order order)
    {
        ArgumentNullException.ThrowIfNull(order);

        if (!CanRefundOffline(order))
            throw new NopException("You can't refund this order");

        //amout to refund
        var amountToRefund = order.OrderTotal;

        //total amount refunded
        var totalAmountRefunded = order.RefundedAmount + amountToRefund;

        //update order info
        order.RefundedAmount = totalAmountRefunded;
        order.PaymentStatus = PaymentStatus.Refunded;
        await _orderService.UpdateOrderAsync(order);

        //add a note
        await AddOrderNoteAsync(order, $"Order has been marked as refunded. Amount = {amountToRefund}");

        //raise event       
        await _eventPublisher.PublishAsync(new OrderRefundedEvent(order, amountToRefund));

View on GitHub (pinned to 64bdf2ff08)

Solutions

  1. Guard with: if (!_orderProcessingService.CanRefundOffline(order)) return; and report the reason.
  2. If RefundedAmount > 0, use PartiallyRefundOfflineAsync(order, remaining) instead.
  3. Confirm PaymentStatus == Paid before showing the offline refund action.
  4. For free/zero-total orders, no refund is needed.

Example fix

// before
await _orderProcessingService.RefundOfflineAsync(order);

// after
if (!_orderProcessingService.CanRefundOffline(order))
    return;

await _orderProcessingService.RefundOfflineAsync(order);
Defensive patterns

Strategy: validation

Validate before calling

if (!_orderProcessingService.CanRefundOffline(order))
    return;

await _orderProcessingService.RefundOfflineAsync(order);

Prevention

When it happens

Trigger: Calling RefundOfflineAsync when: OrderTotal == 0; RefundedAmount > 0; or PaymentStatus != Paid. Common when an admin tries an offline refund on an order that is not Paid or that was already partially refunded.

Common situations: Order still Pending or Authorized (not Paid); a partial refund already applied (use PartiallyRefundOfflineAsync); zero-total order; staff using offline refund because the gateway refund failed but the order is not in Paid state.

Related errors


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