{"record":{"id":"98c83c3be450a9c0","repo":"dotnet/eShop","slug":"the-total-of-order-item-is-lower-than-applied-disc","errorCode":null,"errorMessage":"The total of order item is lower than applied discount","messagePattern":"The total of order item is lower than applied discount","errorType":"exception","errorClass":"OrderingDomainException","httpStatus":null,"severity":"error","filePath":"src/Ordering.Domain/AggregatesModel/OrderAggregate/OrderItem.cs","lineNumber":32,"sourceCode":"    \n    public decimal Discount { get; private set; }\n    \n    public int Units { get; private set; }\n\n    public int ProductId { get; private set; }\n\n    protected OrderItem() { }\n\n    public OrderItem(int productId, string productName, decimal unitPrice, decimal discount, string pictureUrl, int units = 1)\n    {\n        if (units <= 0)\n        {\n            throw new OrderingDomainException(\"Invalid number of units\");\n        }\n\n        if ((unitPrice * units) < discount)\n        {\n            throw new OrderingDomainException(\"The total of order item is lower than applied discount\");\n        }\n\n        ProductId = productId;\n\n        ProductName = productName;\n        UnitPrice = unitPrice;\n        Discount = discount;\n        Units = units;\n        PictureUrl = pictureUrl;\n    }\n    \n    public void SetNewDiscount(decimal discount)\n    {\n        if (discount < 0)\n        {\n            throw new OrderingDomainException(\"Discount is not valid\");\n        }\n","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/dotnet/eShop/blob/9b4f9434f46fdc5c1a6e9e936af2868340cdbc48/src/Ordering.Domain/AggregatesModel/OrderAggregate/OrderItem.cs#L14-L50","documentation":"Thrown by the OrderItem constructor when (unitPrice * units) < discount — i.e. the line discount exceeds the gross line total, which would produce a negative net price. The aggregate treats this as an invariant violation and refuses to construct the item. It is an OrderingDomainException.","triggerScenarios":"Creating an OrderItem (via constructor or Order.AddOrderItem) where the discount value passed is larger than unitPrice * units. Common when a percentage discount is mis-encoded as an absolute amount (e.g. 10 meaning 10% applied as $10), or when a fixed promo exceeds the item price for low-quantity lines.","commonSituations":"Promotion engine emitting a discount > line subtotal; client sending discount in cents vs dollars unit mismatch; a 100%-or-more coupon applied to a single low-price unit; tests hard-coding a discount without scaling to quantity.","solutions":["Clamp/validate the discount so it never exceeds unitPrice * units at the call site before constructing the OrderItem.","Normalize discount representation: if discounts are percentages, compute absolute = subtotal * pct/100 and cap at subtotal.","Reject the order line with a 400 when the supplied discount is greater than the line total rather than letting it reach the domain.","Add a unit test asserting OrderItem construction for discount == subtotal succeeds but discount > subtotal throws."],"exampleFix":"// before\norder.AddOrderItem(p.Id, p.Name, p.Price, discount, url, qty);\n\n// after\nvar lineTotal = p.Price * qty;\nvar safeDiscount = Math.Min(discount, lineTotal);\norder.AddOrderItem(p.Id, p.Name, p.Price, safeDiscount, url, qty);","handlingStrategy":"validation","validationCode":"var lineTotal = unitPrice * units;\nif (discount > lineTotal) discount = lineTotal; // or reject\norder.AddOrderItem(productId, name, unitPrice, discount, url, units);","typeGuard":"static bool IsDiscountWithinLine(decimal unitPrice, int units, decimal discount) => discount <= unitPrice * units;","tryCatchPattern":"try {\n    order.AddOrderItem(id, name, price, discount, url, units);\n} catch (OrderingDomainException ex) when (ex.Message.Contains(\"lower than applied discount\")) {\n    // promo exceeded subtotal — clamp and retry, or reject the line\n}","preventionTips":["Cap discount at the line subtotal before constructing OrderItem.","Keep discount representation consistent (absolute vs percentage).","Validate promo results against the line total in the promotion engine."],"tags":["domain","ordering","validation","pricing","ddd"],"backgroundTag":null,"analyzedSha":"9b4f9434f46fdc5c1a6e9e936af2868340cdbc48","analyzedAt":"2026-08-13T19:29:36.594Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}