Skip to content

feat(wallet): monthly plan credits, same rules as voice's call limit - #1460

Open
Dev-Bhumika03 wants to merge 1 commit into
juspay:assistfrom
Dev-Bhumika03:feat/wallet-plan-credits
Open

Dev-Bhumika03 wants to merge 1 commit into
juspay:assistfrom
Dev-Bhumika03:feat/wallet-plan-credits

Conversation

@Dev-Bhumika03

Copy link
Copy Markdown
Collaborator

⚠️ Deploy order: migration 086_wallet_plan_credits must run before this code goes live. Otherwise every wallet read fails, and chat (which fails open on billing errors) lets every merchant chat without limit until the migration runs.

Problem

Every new merchant gets a wallet with 0 credits, and Assist chat refuses every turn at 0 (insufficient_credits). So every onboarded widget is dead until someone recharges it by hand (e.g. kpspoint.com, 2 Nov).

What this does

Wallets can carry a monthly plan, with the same rules as Breeze Buddy voice's monthly call limit (nautilus checkMonthlyLimit / reset_monthly_order_counters):

Case Voice today Assist credits (this PR)
Monthly reset Used calls → 0 on the 1st (first order of the month) Balance → plan credits on the 1st, UTC (first credit check of the month)
Upgrade / downgrade Limit changes now, used count kept Balance moves by (new − old) now, used stays used
FROZEN Blocked Blocked
Trial Unlimited Unlimited
At the limit Overage if enabled, else blocked Blocked (no Assist overage)

The billing platform pushes the plan:

PUT /agent/voice/breeze-buddy/wallet/{merchant_id}/plan
{"plan_credits": 10000, "status": "ACTIVE" | "FROZEN" | "TRIAL"}
  • Admin only, same check as /recharge. nautilus already calls as nautilus-service (ADMIN).
  • Wallets without a plan (plan_status = 'NONE', all existing wallets) keep today's prepaid behaviour. They're never reset.
  • Every balance move writes a ledger row: plan_change, or plan_reset (keyed merchant+month).
  • Changes run under the wallet row lock, so 5 concurrent checks at a month change reset once.
  • plan_credits is 0 – 1,000,000,000.

Changes

  • 086_wallet_plan_credits.sql: wallets.plan_credits, plan_status, period_month (additive, with defaults).
  • services/breeze_buddy/wallet/plan.py: the rules as small pure functions, plus set_plan / reset_month.
  • accessor/.../wallets.py: apply_plan_update (lock → decide → ledger row → plan columns).
  • wallet/deduction.py: has_sufficient_credits applies FROZEN/TRIAL and the monthly reset. Chat and try-on callers are unchanged.
  • PUT /wallet/{merchant_id}/plan.

Not in this PR

  • nautilus wiring (pushing the plan on approve / upgrade / cancel / onboarding): separate PR.
  • Merchant delete still refuses a wallet with balance > 0. Only the dashboard admin button deletes, and that's left as is on purpose.

Testing

  • Unit: tests/breeze_buddy/test_wallet_plan.py (20 tests). Full suite: 4,888 passed.
  • End-to-end on a local server against a scratch DB with all 86 migrations, 23/23 checks:
    • FREE 5,000 → 3 chat turns → 4,997 → LITE 9,997 → same plan again 9,997 → FREE 4,997;
    • FROZEN blocks with credits left; TRIAL allows at 0;
    • new month resets to 5,000; 5 concurrent checks give exactly 1 reset ledger row;
    • a prepaid wallet with no plan is untouched;
    • non-admin 403, unknown merchant 404, bad status / negative credits 422.

🤖 Generated with Claude Code

New merchants get a 0-credit wallet and Assist chat refuses every turn at
zero, so every onboarded widget is dead until an admin recharges it.

Wallets can now carry a plan, pushed by the billing platform (nautilus for
Shopify) through PUT /wallet/{merchant_id}/plan {plan_credits, status}.
The rules mirror nautilus's voice limit (checkMonthlyLimit,
reset_monthly_order_counters):

- balance = plan_credits minus what was used this month
- back to plan_credits on the first credit check of a calendar month (UTC)
- a plan change moves the balance by (new - old) at once; used stays used
- FROZEN blocks, TRIAL is unlimited

Wallets without a plan (plan_status NONE) keep today's prepaid behaviour.
Every balance move writes a ledger row (plan_change / plan_reset); the
monthly reset is keyed merchant+month and runs under the wallet lock, so
concurrent checks reset once.

Migration 086 adds plan_credits, plan_status and period_month to wallets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: df8c1ed9-5557-485a-99b0-bae2d8ace112

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant