I wonder how they would handle a cart-level coupon rule in code like this - like a general 10% off coupon. I think the cart should be responsible for applying the coupon to discount the total of the order - even if the discounting rules apply at the item level.
That being said, I guess the goal of this blog post is to keep map methods clean and simple?
The eligibility logic of a coupon should be written inside the coupon itself.
Example in pseudocode.
// returns an AppliableCoupon, which knows what are the eligible items.
appliable_coupon = coupon.for_eligible(items)
// item.total_cost will call appliable_coupon.check(item) to see if the coupon is valid for that specific item.
items.map(|item| item.total_cost(appliable_coupon))
This has the following benefits:
if you introduce a new coupon type, neither the Cart nor the Item need to be changed.
it’s hard to misuse. You can’t apply a coupon directly. You need to get an AppliableCoupon, which you can only get through coupon.for_eligible(items).
It’s all functional and immutable, if you like that kind of things.
I wonder how they would handle a cart-level coupon rule in code like this - like a general
10% off
coupon. I think the cart should be responsible for applying the coupon to discount the total of the order - even if the discounting rules apply at the item level.That being said, I guess the goal of this blog post is to keep
map
methods clean and simple?Even more tricky would be “2 for 1” / multibuy / combo offers since an
Item
won’t know what else is in aCart
.The eligibility logic of a coupon should be written inside the coupon itself.
Example in pseudocode.
This has the following benefits:
Cart
nor theItem
need to be changed.AppliableCoupon
, which you can only get throughcoupon.for_eligible(items)
.