Skip to content

Promotions — version 1

Promotions bounded context — the deals and discounts the pizzeria runs. It owns the rule that anchors this context: a discount can lower an order’s total, but it can never drive that total below zero. The rule is enforced as an invariant on a Discount value object, exposed as a reusable spec, and computed by a pure domain operation.

classDiagram
    class DealKind {
        <<enumeration>>
        Percentage
        FixedAmount
        FreeDelivery
    }
    class Coupon {
        <<value object>>
        +String code
        +String /normalized
    }
    class Discount {
        <<value object>>
        +DealKind kind
        +Decimal orderTotal
        +Decimal amountOff
        +Decimal /discountedTotal
    }
    Discount *-- DealKind

A coupon code a customer can apply. A first-class value object so a coupon is never a bare string, validated by shape.

FieldTypeDescription
codeString
normalizedStringderived

Business rules

  • a coupon code cannot be blank
  • a coupon must look like PIZZA10

A discount applied to an order total. THE rule of this context: the discounted total can never be negative — a deal can take the total to exactly zero (a free pizza) but no further. Both the gross total and the discount are non-negative, and the invariant proves the result stays non-negative too.

FieldTypeDescription
kindDealKind
orderTotalDecimalThe order total before the discount is applied. Never negative.
amountOffDecimalHow much money the discount takes off. Never negative.
discountedTotalDecimalderived

Business rules

  • the order total cannot be negative
  • a discount cannot be negative
  • a discount cannot drive the order total negative

The kind of deal a coupon represents. A plain enum used for reporting.

Values: Percentage, FixedAmount, FreeDelivery

Condition: discountedTotal == 0

A domain service with pure operations (expression bodies). cap clamps a requested discount so it can never exceed the order total (the safe way to build a Discount); rate gives the percentage rate for a deal kind.

  • cap(orderTotal: Decimal, requested: Decimal): Decimal

  • rate(kind: DealKind): Decimal

KindCoveredTotal
enum11
value22

All declared constructs are documented.