#482 · Add coupon stacking logic for VIP tier

jinta/feature/vip-coupon-stack → main · 3 commits · 2 files changed
src/billing/discount.py +4 −2
12class DiscountEngine:
13 """Apply percentage discounts to an order total."""
14
15 def apply_discount(self, total: float, discount_pct: float) -> float:
16 return total * (1 - discount_pct / 100)
15 def apply_discount(self, total: float, discount_pct: float, is_vip: bool) -> float:
16 """Stack a 15% VIP bonus on top of any active coupon."""
17 combined_pct = discount_pct + (15 if is_vip else 0)
18 return total * (1 - combined_pct / 100)
AI review · needs acknowledgment
combined_pct has no upper bound. If a customer stacks an expired coupon (discount_pct=90) with the VIP tier (+15), the result is total * -0.05 — a negative charge. Suggested fix: combined_pct = min(discount_pct + (15 if is_vip else 0), 100).
19
20 def apply_coupon(self, total: float, coupon: Coupon) -> float:
21 return self.apply_discount(total, coupon.percent_off, False)

Type check — 3 errors, level 1 (blocking)

mypy --strict · ran in 4.2s
Blocking
src/checkout/cart.py:44: error: Missing positional argument "is_vip" in call to "apply_discount" [call-arg]
src/checkout/cart.py:102: error: Missing positional argument "is_vip" in call to "apply_discount" [call-arg]
src/checkout/cart.py:188: error: Missing positional argument "is_vip" in call to "apply_discount" [call-arg]
Found 3 errors in 1 file (checked 1 source file)
cart.py:44 — checkout_guest() View call site
cart.py:102 — checkout_member() View call site
cart.py:188 — recalculate_on_refund() View call site

Quality gate

Level 1 — blocks merge, no exceptions
SAST critical / high0
Secrets detected0
Tests passing14/14
Type check / build3 errors
Dependency critical CVE0
Level 2 — needs reviewer acknowledgment
Coverage on new code92%
AI review — logic issue1 open
Cyclomatic complexityok
Level 3 — informational only
PR size41 lines
Duplicate codenone found
SAST 0
AI review 2
Tests
No findings in this diff
Semgrep · p/owasp-top-ten, p/secrets, custom rules
Rule sets scanned3
Lines analyzed41
Scan time6.8s
Logic · discount.py:17
Unbounded combined_pct can exceed 100, producing a negative total when an expired coupon stacks with the VIP bonus.
Breaking change · discount.py:15
New required parameter is_vip is not backward compatible — surfaced as 3 type errors in cart.py.

System prompt scope: production bugs, security, unhandled edge cases only — style is left to the linter.

Coverage on new code92%
Unit tests14 passed / 14
Integration tests3 passed / 3
Mutation score81%
Flaky retries0

Reviewers

WP
worapoj requested changes
AI
ZuCodeView AI 2 comments