Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@devkiran
Copy link
Collaborator

@devkiran devkiran commented Oct 17, 2025

…m failure fee

Summary by CodeRabbit

  • Bug Fixes
    • Blocked direct-debit payout failures no longer trigger failure fees or record card details. The system now skips fee charging and avoids storing payment method info for blocked charges, while preserving existing fee-charging behavior for non-blocked direct-debit failures. Log messages now reflect when a blocked charge was skipped and when a fee was successfully charged.

@linear
Copy link

linear bot commented Oct 17, 2025

@devkiran devkiran requested a review from steven-tey October 17, 2025 11:55
@vercel
Copy link
Contributor

vercel bot commented Oct 17, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Oct 17, 2025 0:32am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 17, 2025

Walkthrough

Modifies payout invoice failure processing to skip charging failure fees and recording card details when a direct_debit charge outcome type is "blocked"; retains existing fee charging flow for non-blocked direct_debit charges.

Changes

Cohort / File(s) Summary
Direct debit blocked charge handling
apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts
Add isBlocked = charge?.outcome?.type === "blocked" check; if blocked, skip creating payment intent, charging failure fee, and recording card last4 (log skip). If not blocked, create PaymentIntent, set chargedFailureFee = true on success, and record cardLast4 when available.

Sequence Diagram(s)

sequenceDiagram
  participant Webhook as Stripe Webhook
  participant Processor as processPayoutInvoiceFailure
  participant Stripe as Stripe API
  participant DB as Database/Logger

  Webhook->>Processor: payload (payout invoice failure)
  Processor->>Processor: extract charge, paymentMethod
  alt charge.outcome.type == "blocked"
    Processor->>DB: log "skipped fee for blocked charge"
  else not blocked
    Processor->>Stripe: create PaymentIntent (failure fee)
    Stripe-->>Processor: PaymentIntent result
    alt success
      Processor->>DB: set chargedFailureFee = true
      Processor->>DB: record cardLast4 (if present)
      Processor->>DB: log "charged failure fee"
    else failure
      Processor->>DB: log "failure charging fee"
    end
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • steven-tey

Poem

🐰 A blocked charge hops past the fee,
I nibble logs and let it be.
For honest payments I still pursue,
A gentle thump — the fee goes through. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Skip the invoice failure fee for failed ACH payments that are blocked" directly and clearly summarizes the main change in the changeset. The code modification specifically introduces logic to skip charging the payout failure fee for direct_debit (ACH) payment failures when the charge outcome type is "blocked", which aligns precisely with what the title communicates. The title is concise, specific, and avoids vague terminology—a reviewer scanning the commit history would immediately understand the primary change without ambiguity.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch eng-1531

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts (1)

88-106: LGTM! Logic correctly skips failure fee for blocked charges.

The conditional block correctly implements the PR objective by preventing failure fee charges for blocked direct debit payments. The placement of cardLast4 and chargedFailureFee assignments maintains consistency with the email data structure.

Consider adding a log statement when skipping the fee for better observability:

   if (!isBlocked) {
     const { paymentIntent, paymentMethod } = await createPaymentIntent({
       stripeId: workspace.stripeId,
       amount: PAYOUT_FAILURE_FEE_CENTS,
       description: `Dub Partners payout failure fee for invoice ${invoice.id}`,
       statementDescriptor: "Dub Partners",
     });

     if (paymentIntent) {
       chargedFailureFee = true;
       console.log(
         `Charged a failure fee of $${PAYOUT_FAILURE_FEE_CENTS / 100} to ${workspace.slug}.`,
       );
     }

     if (paymentMethod?.card) {
       cardLast4 = paymentMethod.card.last4;
     }
+  } else {
+    console.log(
+      `Skipped charging failure fee for blocked direct debit charge on invoice ${invoice.id}.`,
+    );
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46a8b5a and 4dbe5d9.

📒 Files selected for processing (1)
  • apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts (2)
apps/web/lib/stripe/create-payment-intent.ts (1)
  • createPaymentIntent (4-76)
apps/web/lib/partners/constants.ts (1)
  • PAYOUT_FAILURE_FEE_CENTS (9-9)
⏰ 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). (1)
  • GitHub Check: build
🔇 Additional comments (1)
apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts (1)

84-86: LGTM! Safe handling of blocked charges.

The optional chaining correctly handles cases where charge or outcome might be undefined, and "blocked" is a valid Stripe charge outcome type.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts (1)

106-110: Consider using the log() utility for consistency.

The console.log here is informational and appropriate, but for consistency with line 21 and better observability across the system, consider using the log() utility:

-    } else {
-      console.log(
-        `Skipped charging failure fee for blocked direct debit charge on invoice ${invoice.id}.`,
-      );
-    }
+    } else {
+      await log({
+        message: `Skipped charging failure fee for blocked direct debit charge on invoice ${invoice.id}.`,
+        type: "info",
+      });
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4dbe5d9 and e5807e4.

📒 Files selected for processing (1)
  • apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts (2)
apps/web/lib/stripe/create-payment-intent.ts (1)
  • createPaymentIntent (4-76)
apps/web/lib/partners/constants.ts (1)
  • PAYOUT_FAILURE_FEE_CENTS (9-9)
⏰ 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). (1)
  • GitHub Check: build
🔇 Additional comments (2)
apps/web/app/(ee)/api/stripe/webhook/utils/process-payout-invoice-failure.ts (2)

88-105: LGTM! Fee charging logic is correct.

The conditional charging of the failure fee when !isBlocked is appropriate, and the error handling correctly leaves chargedFailureFee as false if the payment intent creation fails. The cardLast4 assignment captures the backup payment method used for the fee, not the original direct debit method.


84-86: Verify that charging fees when charge.outcome is undefined is intentional.

Stripe's charge.outcome field is not guaranteed to be present — it's nullable or omitted for non-card payments, older charges, or when risk evaluation doesn't apply. When charge.outcome is undefined, the line const isBlocked = charge?.outcome?.type === "blocked" evaluates to false, and the failure fee is charged. Confirm this is the intended behavior or add explicit handling (e.g., skip fee or log warning) for missing outcome data.

@steven-tey steven-tey merged commit e201c45 into main Oct 17, 2025
7 of 8 checks passed
@steven-tey steven-tey deleted the eng-1531 branch October 17, 2025 17:14
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.

3 participants