Boss: a returns desk
Returning all three mugs from a discounted order refunds £5.01 on a £5.00 order. Not much, until it's every discounted order for a year. Finance wants the penny back. The returns page has already been redesigned around better types. The returns desk behind it hasn't.
ReturnsDesk::quote() works out refunds in float pounds, finds orders by asking a global container, decides whether the 30 days are up with whatever new DateTime() says today is, and ignores a SKU it doesn't recognise. None of it is new. This is World 5 in one method.
Your checklist
| Level | Ask of ReturnsDesk |
|---|---|
| 5.1 Value objects | Does it take an OrderReference, so normalising and checking happen once, before it's called? |
| 5.2 Money | Is every amount Money in integer pence, with the discount allocated so the shares add up? |
| 5.3 Immutable all the way down | Are dates DateTimeImmutable, and is every modify() result used? |
| 5.4 Dependency injection | Does it ask for orders and the time in its constructor, rather than fetching them? |
| 5.5 Small interfaces | Does it depend on the smallest interface it needs, so a test's fake has one method? |
The tests use a one-method fake for the orders and a stopped clock, so the desk has to accept both. ShopServices passes the real DatabaseOrderRepository, which implements the big OrderRepository. Both fit, if you pick the right interface.