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.
Domain Model
Section titled “Domain Model”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
Domain Types
Section titled “Domain Types”Coupon — value object
Section titled “Coupon — value object”A coupon code a customer can apply. A first-class value object so a coupon is never a bare string, validated by shape.
| Field | Type | Description |
|---|---|---|
| code | String | |
| normalized | String | derived |
Business rules
- a coupon code cannot be blank
- a coupon must look like PIZZA10
Discount — value object
Section titled “Discount — value object”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.
| Field | Type | Description |
|---|---|---|
| kind | DealKind | |
| orderTotal | Decimal | The order total before the discount is applied. Never negative. |
| amountOff | Decimal | How much money the discount takes off. Never negative. |
| discountedTotal | Decimal | derived |
Business rules
- the order total cannot be negative
- a discount cannot be negative
- a discount cannot drive the order total negative
DealKind — enum
Section titled “DealKind — enum”The kind of deal a coupon represents. A plain enum used for reporting.
Values: Percentage, FixedAmount, FreeDelivery
Specifications
Section titled “Specifications”IsFreeOrder on Discount
Section titled “IsFreeOrder on Discount”Condition: discountedTotal == 0
Services
Section titled “Services”DiscountService
Section titled “DiscountService”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.
Operations
Section titled “Operations”-
cap(orderTotal: Decimal, requested: Decimal): Decimal -
rate(kind: DealKind): Decimal
Coverage
Section titled “Coverage”| Kind | Covered | Total |
|---|---|---|
| enum | 1 | 1 |
| value | 2 | 2 |
All declared constructs are documented. ✅