Promotion Manager
Problem
Design PromotionManager to manage reusable coupons and one-use vouchers. One sequential manager stores coupon rules and redemption counts, together with the voucher definitions supplied at construction.
Requirements
- Coupon administration. Creating a coupon stores its definition with zero uses and its supplied active status. Deleting a coupon removes it and its counts. Changing its active status controls whether it can be listed or redeemed without changing its counts.
- Coupon eligibility. A coupon is eligible only when it is active,
ageis strictly greater thanminimumAgeExclusive,cartValueis strictly greater thanminimumCartValueExclusive, andatis strictly less thanexpiresAt. - Coupon usage. A coupon becomes unavailable after
overallUseLimitsuccessful redemptions, or to one user after that user reachesperUserUseLimit. A successful redemption returnstrueand increases both counts by one; every rejected redemption returnsfalsewithout changing either count. - Voucher use. An unassigned voucher can be redeemed once by any user. A preassigned voucher can be redeemed once only by its assigned user; another user's rejected attempt does not consume it.
- Available promotions.
listAvailablereturns exactly the coupon IDs and voucher codes that the supplied user could redeem with the same age, cart value, and time. Neither returned list has a required order.
API
VoucherDefinition is an object with string field code and nullable string field assignedUserId. A null assignment makes the voucher available to any user.
CouponDefinition is an object with fields couponId: string, minimumAgeExclusive: integer, minimumCartValueExclusive: integer, overallUseLimit: integer, perUserUseLimit: integer, expiresAt: integer, and active: boolean.
Availability is an object with couponIds and voucherCodes, both lists of strings.
| Signature | Returns | Behavior |
|---|---|---|
PromotionManager(vouchers: list<VoucherDefinition>) | Not applicable | Creates a manager with the supplied distinct, unused vouchers and no coupons. |
createCoupon(definition: CouponDefinition) | void | Adds a coupon whose ID has never been used by this manager. |
deleteCoupon(couponId: string) | void | Permanently removes an existing coupon. |
setCouponActive(couponId: string, active: boolean) | void | Sets the active status of an existing coupon. |
listAvailable(userId: string, age: integer, cartValue: integer, at: integer) | Availability | Reports promotions that satisfy the requirements above. |
redeemCoupon(couponId: string, userId: string, age: integer, cartValue: integer, at: integer) | boolean | Attempts one coupon redemption. A missing or deleted coupon returns false. |
redeemVoucher(voucherCode: string, userId: string) | boolean | Attempts one voucher redemption. A missing voucher returns false. |
Examples
Start with an unassigned voucher OPEN and a voucher USER7 assigned to u7, then create active coupon SAVE with age threshold 18, cart threshold 1000, overall limit 2, per-user limit 1, and expiry time 200.
| Step | Operation | Result |
|---|---|---|
| 1 | listAvailable("u1", 18, 1500, 100) | Voucher codes contain OPEN; coupon IDs do not contain SAVE. |
| 2 | redeemCoupon("SAVE", "u1", 19, 1500, 100) | true. |
| 3 | redeemCoupon("SAVE", "u1", 19, 1500, 100) | false. |
| 4 | redeemVoucher("USER7", "u2") | false. |
| 5 | redeemVoucher("USER7", "u7") | true. |
Constraints
- The constructor receives from 0 through 1,000 voucher definitions with distinct codes.
- At most 1,000 coupons are created and at most 10,000 public method calls occur in one testcase.
- Every identifier contains from 1 through 64 visible ASCII characters.
0 <= age <= 150.0 <= cartValue, minimumAgeExclusive, minimumCartValueExclusive, at, expiresAt <= 1,000,000,000.1 <= perUserUseLimit <= overallUseLimit <= 1,000,000.- Coupon IDs are never reused after deletion. Coupon administration methods receive existing IDs.
Notes
Calls are sequential, use one manager, and are observed in call order. Methods do not wait. All numeric values and counts are integers; counts cannot become negative. Behavior outside the stated input constraints is not judged.