✨ server: show friendly decline reasons#1141
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughDecline handling now normalizes mapped reasons, stores canonical text, conditionally sends localized push notifications, adds Spanish and Portuguese translations, expands coverage in server tests, and declares patch releases for the server and mobile packages. ChangesDecline reason mapping and notifications
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant reject
participant TransactionStore
participant sendPushNotification
reject->>reject: Normalize and resolve declineReason
reject->>TransactionStore: Upsert declined transaction
TransactionStore-->>reject: Return isNew
reject->>sendPushNotification: Send localized mapped reason when eligible
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
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. Comment |
There was a problem hiding this comment.
Code Review
This pull request expands the transaction decline reasons in the Panda webhook hook, normalizing the reasons to lowercase and introducing a pushReason property for customized push notifications. It also adds corresponding translations in Spanish and Portuguese, along with comprehensive test coverage. The review feedback suggests sorting the newly added translation keys alphabetically across all modified translation files to maintain consistency and avoid future merge conflicts.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6291fb3f-2f5c-4a79-a30a-64e1f0121a1c
📒 Files selected for processing (7)
.changeset/tall-geese-share.mdserver/hooks/panda.tsserver/i18n/es.jsonserver/i18n/pt.jsonserver/test/hooks/panda.test.tssrc/i18n/es.jsonsrc/i18n/pt.json
🦋 Changeset detectedLatest commit: 9021d2e The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 749b81ae-a65e-4523-9d53-6b64758891c4
📒 Files selected for processing (9)
.changeset/calm-wolves-translate.md.changeset/tall-geese-share.mdcspell.jsonserver/hooks/panda.tsserver/i18n/es.jsonserver/i18n/pt.jsonserver/test/hooks/panda.test.tssrc/i18n/es.jsonsrc/i18n/pt.json
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5e2e44a14e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1141 +/- ##
==========================================
- Coverage 73.27% 72.70% -0.58%
==========================================
Files 254 254
Lines 10839 11279 +440
Branches 3598 3791 +193
==========================================
+ Hits 7942 8200 +258
- Misses 2613 2788 +175
- Partials 284 291 +7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
♻️ Duplicate comments (1)
server/test/hooks/panda.test.ts (1)
3086-3092: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winTest expectation should match implementation's
.trim()onmerchantName.The implementation at
server/hooks/panda.tsusesspend.merchantName.trim(), but the test expectation here passesauthorization.json.body.spend.merchantNamewithout.trim(). If the test fixture's merchant name has leading or trailing whitespace, the notificationcontentswon't match and the test will fail.💚 Proposed fix
- merchantName: authorization.json.body.spend.merchantName, + merchantName: authorization.json.body.spend.merchantName.trim(),
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9cb9ce8a-2122-47bd-9d17-b616e557fa34
📒 Files selected for processing (8)
.changeset/calm-wolves-translate.md.changeset/tall-geese-share.mdserver/hooks/panda.tsserver/i18n/es.jsonserver/i18n/pt.jsonserver/test/hooks/panda.test.tssrc/i18n/es.jsonsrc/i18n/pt.json
98fc94a to
e872dc9
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e872dc9e11
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
d0403ef to
e9aaf57
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e9aaf5730c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
ab83b45 to
42af7ac
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 42af7ac6a5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 163eac8daf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
d99b701 to
a610a7e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1e7067bd41
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
7e8f6da to
8f4cd30
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8f4cd309da
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9021d2eb02
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| COALESCE(${transactions.payload}::jsonb->'bodies', '[]'::jsonb) || ${JSON.stringify([declinedBody])}::jsonb | ||
| )`, | ||
| }, | ||
| ...(payload.action === "created" && { |
There was a problem hiding this comment.
Deduplicate declined updated webhooks
When Panda retries a declined updated webhook, the case "updated" path falls through into this same declined reject call, but this guard is only installed for created events. Each retry with the same webhook id therefore appends another body, returns true from .returning(), and the caller sends another declined push notification; apply the event-id setWhere guard to declined updated events as well.
Useful? React with 👍 / 👎.
| await reject(account, payload, jsonBody, payload.body.spend.declinedReason ?? "transaction declined"); | ||
| const requestedReason = | ||
| payload.body.spend.declinedReason?.toLowerCase() === "webhook declined" | ||
| ? await getRequestedDeclineReason(payload.body.id, payload.body.spend.cardId) |
There was a problem hiding this comment.
Keep local reasons when requested id is absent
When a locally rejected requested authorization omits body.id (still accepted by the requested schema), reject stores that declined row under the webhook payload.id, but a later created webhook with declinedReason: "webhook declined" looks up the saved reason by the created transaction id here. Fresh evidence after the earlier local-decline thread: the schema still makes requested body.id optional, so this lookup misses those rows and falls back to a generic transaction declined notification/activity instead of the saved frozenCard or InsufficientAccountLiquidity reason.
Useful? React with 👍 / 👎.
Summary by CodeRabbit