fix(billing): cleanup discount payments#1969
Conversation
WalkthroughRemoved discount/coupon support across backend and web: deleted discount schemas and types, removed controller endpoint and route, stripped discount logic from services and webhook, eliminated related tests, hooks, query keys, and UI coupon elements — payment flows now use direct amount handling without discount metadata. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
rect #eef8ff
participant U as User
participant W as Web App
participant A as API (StripeService)
participant S as Stripe
end
U->>W: Enter amount & payment method
W->>A: POST /payment-intent (amount in cents)
A->>S: Create PaymentIntent (no discount metadata)
S-->>A: PaymentIntent client_secret
A-->>W: PaymentIntentResult
W->>S: Confirm PaymentIntent
S-->>W: Confirmation result
W-->>U: Show success/failure
sequenceDiagram
autonumber
rect #fff7ec
participant S as Stripe
participant A as API Webhook
participant W as Wallet Service
end
S->>A: payment_intent.succeeded webhook
A->>A: Read paymentIntent.amount / amount_received (ignore discount metadata)
A->>W: Top up wallet with amount
W-->>A: Success/Failure
A-->>S: 2xx/5xx response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
Comment |
Codecov Report❌ Patch coverage is ❌ Your patch status has failed because the patch coverage (0.00%) is below the target coverage (50.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #1969 +/- ##
==========================================
+ Coverage 45.44% 45.71% +0.26%
==========================================
Files 1005 1009 +4
Lines 28496 28498 +2
Branches 7470 7461 -9
==========================================
+ Hits 12951 13027 +76
- Misses 14324 15177 +853
+ Partials 1221 294 -927
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/api/src/billing/services/stripe/stripe.service.ts (1)
113-140: Guard against zero- or sub-cent payment intentsWe now compute
amountCents = Math.round(params.amount * 100)and always call Stripe. If the caller passes0(or something that rounds to0), Stripe will throwinvalid_request_error: Amount must be at least 1. Before the cleanup we short-circuited zero-amount flows viahandleZeroAmountPayment, but that branch is gone even though the helper is still present.Please either:
- bail out early and call
handleZeroAmountPaymentwhenamountCents <= 0, or- throw a validation error before touching Stripe (so the controller can surface a clean 4xx response).
Without that, a malicious/buggy client can still force Stripe rejects (and we log + surface them as generic failures).
const amountCents = Math.round(params.amount * 100); + if (amountCents <= 0) { + return await this.handleZeroAmountPayment(params.customer, amountCents); + } + const paymentIntent = await this.paymentIntents.create({
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
apps/api/test/functional/__snapshots__/docs.spec.ts.snapis excluded by!**/*.snap
📒 Files selected for processing (11)
apps/api/src/billing/controllers/stripe/stripe.controller.ts(1 hunks)apps/api/src/billing/http-schemas/stripe.schema.ts(0 hunks)apps/api/src/billing/routes/stripe-coupons/stripe-coupons.router.ts(1 hunks)apps/api/src/billing/services/stripe-webhook/stripe-webhook.service.ts(1 hunks)apps/api/src/billing/services/stripe/stripe.service.spec.ts(0 hunks)apps/api/src/billing/services/stripe/stripe.service.ts(3 hunks)apps/deploy-web/src/components/user/payment/PaymentForm.tsx(2 hunks)apps/deploy-web/src/pages/payment.tsx(3 hunks)apps/deploy-web/src/queries/queryKeys.ts(0 hunks)apps/deploy-web/src/queries/usePaymentQueries.spec.tsx(1 hunks)apps/deploy-web/src/queries/usePaymentQueries.ts(1 hunks)
💤 Files with no reviewable changes (3)
- apps/api/src/billing/services/stripe/stripe.service.spec.ts
- apps/deploy-web/src/queries/queryKeys.ts
- apps/api/src/billing/http-schemas/stripe.schema.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Never use type any or cast to type any. Always define the proper TypeScript types.
Files:
apps/api/src/billing/controllers/stripe/stripe.controller.tsapps/deploy-web/src/queries/usePaymentQueries.tsapps/deploy-web/src/queries/usePaymentQueries.spec.tsxapps/api/src/billing/services/stripe-webhook/stripe-webhook.service.tsapps/api/src/billing/routes/stripe-coupons/stripe-coupons.router.tsapps/api/src/billing/services/stripe/stripe.service.tsapps/deploy-web/src/pages/payment.tsxapps/deploy-web/src/components/user/payment/PaymentForm.tsx
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code
Files:
apps/api/src/billing/controllers/stripe/stripe.controller.tsapps/deploy-web/src/queries/usePaymentQueries.tsapps/deploy-web/src/queries/usePaymentQueries.spec.tsxapps/api/src/billing/services/stripe-webhook/stripe-webhook.service.tsapps/api/src/billing/routes/stripe-coupons/stripe-coupons.router.tsapps/api/src/billing/services/stripe/stripe.service.tsapps/deploy-web/src/pages/payment.tsxapps/deploy-web/src/components/user/payment/PaymentForm.tsx
**/*.spec.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)
Don't use
jest.mock()to mock dependencies in test files. Instead, usejest-mock-extendedto create mocks and pass mocks as dependencies to the service under test.
**/*.spec.{ts,tsx}: Usesetupfunction instead ofbeforeEachin test files
setupfunction must be at the bottom of the rootdescribeblock in test files
setupfunction creates an object under test and returns it
setupfunction should accept a single parameter with inline type definition
Don't use shared state insetupfunction
Don't specify return type ofsetupfunction
Files:
apps/deploy-web/src/queries/usePaymentQueries.spec.tsx
apps/{deploy-web,provider-console}/**/*.spec.tsx
📄 CodeRabbit inference engine (.cursor/rules/query-by-in-tests.mdc)
Use
queryBymethods instead ofgetBymethods in test expectations in.spec.tsxfiles
Files:
apps/deploy-web/src/queries/usePaymentQueries.spec.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: baktun14
PR: akash-network/console#1933
File: apps/deploy-web/src/pages/payment.tsx:92-116
Timestamp: 2025-09-18T07:44:29.079Z
Learning: In the payment system, discount calculation is not applied during payment processing. Instead, when users claim coupons/discounts, the discount amount is applied directly to their account balance. Therefore, the payment flow should charge parseFloat(amount) as entered, not a discounted amount.
📚 Learning: 2025-07-21T08:24:27.953Z
Learnt from: CR
PR: akash-network/console#0
File: .cursor/rules/query-by-in-tests.mdc:0-0
Timestamp: 2025-07-21T08:24:27.953Z
Learning: Applies to apps/{deploy-web,provider-console}/**/*.spec.tsx : Use `queryBy` methods instead of `getBy` methods in test expectations in `.spec.tsx` files
Applied to files:
apps/deploy-web/src/queries/usePaymentQueries.spec.tsx
📚 Learning: 2025-09-18T07:44:29.079Z
Learnt from: baktun14
PR: akash-network/console#1933
File: apps/deploy-web/src/pages/payment.tsx:92-116
Timestamp: 2025-09-18T07:44:29.079Z
Learning: In the payment system, discount calculation is not applied during payment processing. Instead, when users claim coupons/discounts, the discount amount is applied directly to their account balance. Therefore, the payment flow should charge parseFloat(amount) as entered, not a discounted amount.
Applied to files:
apps/api/src/billing/services/stripe/stripe.service.tsapps/deploy-web/src/pages/payment.tsxapps/deploy-web/src/components/user/payment/PaymentForm.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: validate / validate-app
- GitHub Check: test-build
- GitHub Check: validate / validate-app
- GitHub Check: test-build
🔇 Additional comments (5)
apps/api/src/billing/routes/stripe-coupons/stripe-coupons.router.ts (1)
5-40: Removal aligns with API surface simplificationThanks for pruning the unused customer-discounts route and keeping only the apply flow—nothing else in the router (or OpenAPI registration) references the removed schemas anymore.
apps/api/src/billing/controllers/stripe/stripe.controller.ts (1)
9-120: Controller changes look consistentImports and method surface now match the slimmer discount-free Stripe service; confirmPayment/applyCoupon paths remain intact.
apps/deploy-web/src/queries/usePaymentQueries.ts (1)
88-95: Front-end mutation updates LGTMThe apply-coupon mutation now matches the new “credit wallet directly” behavior—no stray discount invalidations left behind.
apps/deploy-web/src/queries/usePaymentQueries.spec.tsx (1)
4-127: Tests track the updated exports correctlyNo dangling expectations for discounts—test coverage still exercises the remaining hooks.
apps/deploy-web/src/components/user/payment/PaymentForm.tsx (1)
3-83: UI cleanup matches the new flowProps and display logic now focus on raw amounts, which is exactly what we want after removing discount math.
apps/api/src/billing/services/stripe-webhook/stripe-webhook.service.ts
Outdated
Show resolved
Hide resolved
|
@baktun14 could you please add "Why" section to explain the motivation behind this change |
Sure, done. |
9424a5d to
c42145d
Compare
* fix(billing): remove discounts calculations from ui * fix(billing): remove discount calculations from api * fix(billing): disable coupon button when loading * fix(billing): pr fixes * fix: remove unused function
* fix(billing): remove discounts calculations from ui * fix(billing): remove discount calculations from api * fix(billing): disable coupon button when loading * fix(billing): pr fixes * fix: remove unused function
* fix(billing): remove discounts calculations from ui * fix(billing): remove discount calculations from api * fix(billing): disable coupon button when loading * fix(billing): pr fixes * fix: remove unused function
Why
Previously the coupon were claimed, then shown as a receipt with sub total in the payment page, and then users were expected to either do a 0$ amount payment or greater to claim the coupon amount. That logic was removed in favor of just adding to the balance directly when claiming the coupon.
In this pr, I cleaned up the remnents of the old coupon logic.
Summary by CodeRabbit
Refactor
API
Tests