---
title: "Apply discounts on the server in one fixed · Agent Wranglers"
url: https://agentwranglers.se/playbook/ecommerce/promotions-and-claims/discount-order
id: ECM-36
level: Recommended
updated: 2026-10-27
build: a2a6bdfed830
tokens: 981
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Apply discounts on the server in one fixed order

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Promotions and claims](https://agentwranglers.se/playbook/ecommerce/promotions-and-claims.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: ECM-36
- Level: Recommended
- Chapter: [Promotions and claims](https://agentwranglers.se/playbook/ecommerce/promotions-and-claims.md)
- Rule: Apply promotions in one documented order, such as line discounts, then order discounts, then shipping discounts, then tax. Write which promotions combine as data, and never let a line go below zero.
- Check: A property test applies random sets of promotions to random carts. The total never falls below zero, no line is negative, and the same promotions in any input order give the same total.
- How: Two coupons applied in a different order give a different total, and the buyer, the invoice and the refund then disagree. Keep each promotion as a record with its type, amount or percentage, start and end, and the promotions it may combine with. Compute the cart on the server only, as [Work out every amount on the server](https://agentwranglers.se/playbook/application-security/limits-and-business-logic/server-side-business-rules.md) requires. Spread each order discount across the lines, as [Refund exactly what each returned line cost](https://agentwranglers.se/playbook/ecommerce/returns-and-refunds/refunds-by-line.md) needs. An announced price cut on goods to EU consumers shows the prior price, as [Show the lowest earlier price beside a discount](https://agentwranglers.se/playbook/payments/price-display-and-consumer-law/price-reduction-prior-price.md) says.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### TypeScript example

```ts
const STAGES = ['line', 'order', 'shipping'] as const;

export function applyPromotions(cart: PricedCart, promotions: Promotion[]): PricedCart {
  return STAGES.reduce(
    (current, stage) => promotions
      .filter(p => p.stage === stage)
      .sort((a, b) => a.priority - b.priority || a.id.localeCompare(b.id))
      .reduce((c, p) => p.apply(c), current),
    cart,
  );
}
```

### Python example

```python
STAGES = ("line", "order", "shipping")

def apply_promotions(cart, promotions):
    for stage in STAGES:
        for promotion in sorted((p for p in promotions if p.stage == stage), key=lambda p: (p.priority, p.id)):
            cart = promotion.apply(cart)
    return cart
```

## Related rules

- APS-52 [Work out every amount on the server](https://agentwranglers.se/playbook/application-security/limits-and-business-logic/server-side-business-rules.md) in Application security
- ECM-34 [Refund exactly what each returned line cost](https://agentwranglers.se/playbook/ecommerce/returns-and-refunds/refunds-by-line.md) in E-commerce and fulfilment
- PAY-9 [Show the lowest earlier price beside a discount](https://agentwranglers.se/playbook/payments/price-display-and-consumer-law/price-reduction-prior-price.md) in Payments and billing

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/ecommerce/promotions-and-claims/discount-order">Agent Wranglers e-commerce and fulfilment playbook</a>`. In code you write, add a comment next to it with the same link.

- Next: [Limit each coupon per customer instead of per account](https://agentwranglers.se/playbook/ecommerce/promotions-and-claims/coupon-limits.md)
- [Promotions and claims](https://agentwranglers.se/playbook/ecommerce/promotions-and-claims.md)
