{"record":{"id":"dfa83d592c476ad1","repo":"nopSolutions/nopCommerce","slug":"you-can-t-partially-refund-offline-this-order","errorCode":null,"errorMessage":"You can't partially refund (offline) this order","messagePattern":"You can't partially refund \\(offline\\) this order","errorType":"exception","errorClass":"NopException","httpStatus":null,"severity":"error","filePath":"src/Libraries/Nop.Services/Orders/OrderProcessingService.cs","lineNumber":2943,"sourceCode":"        if (order.PaymentStatus == PaymentStatus.Paid ||\r\n            order.PaymentStatus == PaymentStatus.PartiallyRefunded)\r\n            return true;\r\n\r\n        return false;\r\n    }\r\n\r\n    /// <summary>\r\n    /// Partially refunds an order (offline)\r\n    /// </summary>\r\n    /// <param name=\"order\">Order</param>\r\n    /// <param name=\"amountToRefund\">Amount to refund</param>\r\n    /// <returns>A task that represents the asynchronous operation</returns>\r\n    public virtual async Task PartiallyRefundOfflineAsync(Order order, decimal amountToRefund)\r\n    {\r\n        ArgumentNullException.ThrowIfNull(order);\r\n\r\n        if (!CanPartiallyRefundOffline(order, amountToRefund))\r\n            throw new NopException(\"You can't partially refund (offline) this order\");\r\n\r\n        //total amount refunded\r\n        var totalAmountRefunded = order.RefundedAmount + amountToRefund;\r\n\r\n        //update order info\r\n        order.RefundedAmount = totalAmountRefunded;\r\n        //mark payment status as 'Refunded' if the order total amount is fully refunded\r\n        order.PaymentStatus = order.OrderTotal == totalAmountRefunded ? PaymentStatus.Refunded : PaymentStatus.PartiallyRefunded;\r\n        await _orderService.UpdateOrderAsync(order);\r\n\r\n        //add a note\r\n        await AddOrderNoteAsync(order, $\"Order has been marked as partially refunded. Amount = {amountToRefund}\");\r\n\r\n        //raise event       \r\n        await _eventPublisher.PublishAsync(new OrderRefundedEvent(order, amountToRefund));\r\n\r\n        //check order status\r\n        await CheckOrderStatusAsync(order);\r","sourceCodeStart":2925,"sourceCodeEnd":2961,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Libraries/Nop.Services/Orders/OrderProcessingService.cs#L2925-L2961","documentation":"Thrown by OrderProcessingService.PartiallyRefundOfflineAsync when CanPartiallyRefundOffline(order, amountToRefund) returns false. An offline partial refund is allowed only when OrderTotal > 0, a refundable remainder exists (OrderTotal - RefundedAmount > 0), amountToRefund does not exceed the remainder, and PaymentStatus is Paid or PartiallyRefunded. Unlike the online version, no payment-method capability check is performed because the gateway is bypassed.","triggerScenarios":"Calling PartiallyRefundOfflineAsync when: amountToRefund > OrderTotal - RefundedAmount; OrderTotal == 0; remainder <= 0; or PaymentStatus not Paid/PartiallyRefunded.","commonSituations":"Amount exceeds remaining refundable total; order already fully refunded; order not Paid (Pending/Authorized); staff using offline partial refund on an order with no refundable remainder.","solutions":["Guard with: if (!_orderProcessingService.CanPartiallyRefundOffline(order, amountToRefund)) return; and report the reason.","Clamp amountToRefund = Math.Min(amountToRefund, order.OrderTotal - order.RefundedAmount).","Confirm PaymentStatus is Paid or PartiallyRefunded before enabling the action.","For zero-total or fully-refunded orders, no partial refund is possible."],"exampleFix":"// before\nawait _orderProcessingService.PartiallyRefundOfflineAsync(order, amount);\n\n// after\nvar remaining = order.OrderTotal - order.RefundedAmount;\namount = Math.Min(amount, remaining);\nif (!_orderProcessingService.CanPartiallyRefundOffline(order, amount))\n    return;\n\nawait _orderProcessingService.PartiallyRefundOfflineAsync(order, amount);","handlingStrategy":"validation","validationCode":"var remaining = order.OrderTotal - order.RefundedAmount;\namountToRefund = Math.Min(amountToRefund, remaining);\nif (!_orderProcessingService.CanPartiallyRefundOffline(order, amountToRefund))\n    return;\n\nawait _orderProcessingService.PartiallyRefundOfflineAsync(order, amountToRefund);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Clamp amountToRefund to OrderTotal - RefundedAmount.","Confirm PaymentStatus is Paid or PartiallyRefunded.","Skip for zero-total or fully-refunded orders."],"tags":["refund","partial","offline","payment"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}