- Project name: Cashier
- Type: Elixir library/service
- Purpose: Manage shopping carts, apply pricing rules, compute totals
- Target users: Supermarket checkout systems
| Code | Name | Price |
|---|---|---|
| GR1 | Green tea | £3.11 |
| SR1 | Strawberries | £5.00 |
| CF1 | Coffee | £11.23 |
- BOGO (Buy One Get One Free): Every 2nd Green Tea free
- Bulk Fixed: 3+ strawberries at £4.50 each
- Bulk Fraction: 3+ coffees at 2/3 price
| Basket | Expected Total |
|---|---|
| GR1,SR1,GR1,GR1,CF1 | £22.45 |
| GR1,GR1 | £3.11 |
| SR1,SR1,GR1,SR1 | £16.61 |
| GR1,CF1,SR1,CF1,CF1 | £30.57 |
- Hexagonal (Ports & Adapters)
- Domain: Cart, CartItem, Product
- Ports: ProductCatalogue, PricingRule
- Adapters: InMemoryCatalogue, PricingRules
- Session: GenServer per checkout
new_checkout()→ Sessionscan(Session, code)→ :oktotal(Session)→ Decimalformatted_total(Session)→ "£XX.XX"clear(Session)→ :okstop(Session)→ :ok
- Product codes: 1-32 bytes
- Prices: non-negative, max £999,999.99
- Rules validated at startup
- Quantity: non-negative
- Unit tests for domain
- Unit tests for rules
- Property-based tests (StreamData)
- Integration via Cashier module
- All expected basket totals pass
- Empty cart returns £0.00
- Zero quantity handled gracefully
- Duplicate rules rejected at startup
- Session auto-expires after idle