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

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
697a4d8
Update route.ts
devkiran May 22, 2025
1d2af5b
Update route.ts
devkiran May 22, 2025
aa5851e
wip
devkiran May 22, 2025
d9f3b16
Merge branch 'main' into bank-debits
steven-tey May 22, 2025
e844fd5
Update add-payout-method-modal.tsx
devkiran May 23, 2025
455177d
update payment methods
devkiran May 23, 2025
f5284ca
Update payout-invoice-sheet.tsx
devkiran May 23, 2025
91e77b7
Merge branch 'main' into bank-debits
devkiran May 23, 2025
e427b75
update partner payment methods
devkiran May 23, 2025
d0e1853
rename
devkiran May 23, 2025
a5b1e7f
add calculatePayoutFee
devkiran May 23, 2025
8f093a5
Update add-payment-method-modal.tsx
devkiran May 23, 2025
3cb89f4
improve the naming
devkiran May 23, 2025
66192ae
Update payment-methods.ts
devkiran May 23, 2025
65c4571
Update payout-invoice-sheet.tsx
devkiran May 23, 2025
1e8e331
Merge branch 'main' into bank-debits
devkiran May 25, 2025
e47a348
DirectDebitPaymentMethod
devkiran May 25, 2025
f6a5e08
fix the types
devkiran May 25, 2025
bdccb76
some improvements
devkiran May 25, 2025
050ad28
Update payout-invoice-sheet.tsx
devkiran May 25, 2025
35f5e96
Merge branch 'main' into bank-debits
steven-tey May 25, 2025
62763be
Merge branch 'main' into bank-debits
steven-tey May 25, 2025
a50132a
Merge branch 'main' into bank-debits
devkiran May 26, 2025
49b5889
Merge branch 'main' into bank-debits
steven-tey May 26, 2025
c3a6af3
update to use direct_debit
devkiran May 26, 2025
97d04d4
Merge branch 'main' into bank-debits
steven-tey May 26, 2025
640d2d8
Merge branch 'main' into bank-debits
steven-tey May 27, 2025
2a259b2
Merge branch 'main' into bank-debits
devkiran May 27, 2025
e3a2cf9
Merge branch 'main' into bank-debits
devkiran May 28, 2025
a620b52
Merge branch 'main' into bank-debits
steven-tey May 28, 2025
6d16bef
Merge branch 'main' into bank-debits
steven-tey May 29, 2025
db3d4b8
address feedback from coderabbit
devkiran May 29, 2025
2782ba7
Merge branch 'main' into bank-debits
steven-tey May 29, 2025
611557d
Merge branch 'main' into bank-debits
steven-tey May 29, 2025
e728067
Merge branch 'main' into bank-debits
steven-tey May 30, 2025
0ab93ae
Merge branch 'main' into bank-debits
steven-tey May 30, 2025
649ea5c
Merge branch 'main' into bank-debits
steven-tey May 30, 2025
6b890b1
Merge branch 'main' into bank-debits
steven-tey May 31, 2025
a6682b6
Merge branch 'main' into bank-debits
steven-tey May 31, 2025
2eaecf6
Merge branch 'main' into bank-debits
steven-tey Jun 1, 2025
06e827a
Merge branch 'main' into bank-debits
steven-tey Jun 1, 2025
b418011
Merge branch 'main' into bank-debits
steven-tey Jun 1, 2025
e314eb6
Merge branch 'main' into bank-debits
steven-tey Jun 2, 2025
7baa46d
Merge branch 'main' into bank-debits
steven-tey Jun 2, 2025
0042416
Merge branch 'main' into bank-debits
steven-tey Jun 2, 2025
f4e7916
Merge branch 'main' into bank-debits
steven-tey Jun 2, 2025
e7de543
Merge branch 'main' into bank-debits
steven-tey Jun 2, 2025
f51371d
Merge branch 'main' into bank-debits
steven-tey Jun 3, 2025
caa1078
Merge branch 'main' into bank-debits
steven-tey Jun 3, 2025
7b15a0f
Merge branch 'main' into bank-debits
steven-tey Jun 3, 2025
39e978c
Merge branch 'main' into bank-debits
steven-tey Jun 4, 2025
d49ca82
Merge branch 'main' into bank-debits
steven-tey Jun 4, 2025
01d3206
Merge branch 'main' into bank-debits
steven-tey Jun 4, 2025
7269da3
Merge branch 'main' into bank-debits
steven-tey Jun 5, 2025
745138d
Merge branch 'main' into bank-debits
steven-tey Jun 5, 2025
5e624a0
Merge branch 'main' into bank-debits
steven-tey Jun 5, 2025
25f38e6
Merge branch 'main' into bank-debits
steven-tey Jun 6, 2025
a9c005f
DIRECT_DEBIT_PAYMENT_METHOD_TYPES
steven-tey Jun 6, 2025
2689657
Merge branch 'main' into bank-debits
steven-tey Jun 7, 2025
1ed2530
Merge branch 'main' into bank-debits
steven-tey Jun 7, 2025
edac12c
Merge branch 'main' into bank-debits
steven-tey Jun 7, 2025
7cc1757
Merge branch 'main' into bank-debits
steven-tey Jun 8, 2025
078c306
Merge branch 'main' into bank-debits
steven-tey Jun 9, 2025
60578be
Merge branch 'main' into bank-debits
steven-tey Jun 9, 2025
a5e4d85
Merge branch 'main' into bank-debits
steven-tey Jun 12, 2025
e80b8c1
Merge branch 'main' into bank-debits
steven-tey Jun 12, 2025
7ca2953
Merge branch 'main' into bank-debits
steven-tey Jun 12, 2025
7edf569
Merge branch 'main' into bank-debits
steven-tey Jun 12, 2025
5b6e04a
Merge branch 'main' into bank-debits
steven-tey Jun 12, 2025
256557d
Merge branch 'main' into bank-debits
steven-tey Jun 13, 2025
8c1917e
Merge branch 'main' into bank-debits
steven-tey Jun 19, 2025
40a9784
Merge branch 'main' into bank-debits
steven-tey Jun 19, 2025
8fd292d
Merge branch 'main' into bank-debits
steven-tey Jun 19, 2025
cda9b84
Merge branch 'main' into bank-debits
steven-tey Jun 20, 2025
c3d0e9c
Merge branch 'main' into bank-debits
steven-tey Jun 20, 2025
001b37b
Merge branch 'main' into bank-debits
steven-tey Jun 20, 2025
97bfc5e
Merge branch 'main' into bank-debits
steven-tey Jun 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions apps/web/app/(ee)/api/cron/payouts/confirm/confirm-payouts.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { createId } from "@/lib/api/create-id";
import { PAYOUT_FEES } from "@/lib/partners/constants";
import {
DIRECT_DEBIT_PAYMENT_METHOD_TYPES,
PAYMENT_METHOD_TYPES,
} from "@/lib/partners/constants";
import {
CUTOFF_PERIOD,
CUTOFF_PERIOD_TYPES,
} from "@/lib/partners/cutoff-period";
import { calculatePayoutFee } from "@/lib/payment-methods";
import { stripe } from "@/lib/stripe";
import { resend } from "@dub/email/resend";
import { VARIANT_TO_FROM_MAP } from "@dub/email/resend/constants";
Expand All @@ -12,8 +16,6 @@ import { prisma } from "@dub/prisma";
import { chunk, log } from "@dub/utils";
import { Program, Project } from "@prisma/client";

const allowedPaymentMethods = ["us_bank_account", "card", "link"];

export async function confirmPayouts({
workspace,
program,
Expand Down Expand Up @@ -83,9 +85,10 @@ export async function confirmPayouts({

const fee =
amount *
PAYOUT_FEES[workspace.plan?.split(" ")[0] ?? "business"][
paymentMethod.type === "us_bank_account" ? "ach" : "card"
];
calculatePayoutFee({
paymentMethod: paymentMethod.type,
plan: workspace.plan,
});

const total = amount + fee;

Expand Down Expand Up @@ -117,7 +120,7 @@ export async function confirmPayouts({
await stripe.paymentIntents.create({
amount: invoice.total,
customer: workspace.stripeId!,
payment_method_types: allowedPaymentMethods,
payment_method_types: PAYMENT_METHOD_TYPES,
payment_method: paymentMethod.id,
currency: "usd",
confirmation_method: "automatic",
Expand Down Expand Up @@ -154,9 +157,12 @@ export async function confirmPayouts({
return invoice;
});

// Send emails to all the partners involved in the payouts if the payout method is ACH
// This is because ACH takes 4 business days to process, so we want to give partners a heads up
if (newInvoice && paymentMethod.type === "us_bank_account") {
// Send emails to all the partners involved in the payouts if the payout method is Direct Debit
// This is because Direct Debit takes 4 business days to process, so we want to give partners a heads up
if (
newInvoice &&
DIRECT_DEBIT_PAYMENT_METHOD_TYPES.includes(paymentMethod.type)
) {
if (!resend) {
// this should never happen, but just in case
await log({
Expand Down
14 changes: 11 additions & 3 deletions apps/web/app/(ee)/api/stripe/webhook/charge-failed.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { PAYOUT_FAILURE_FEE_CENTS } from "@/lib/partners/constants";
import {
DIRECT_DEBIT_PAYMENT_METHOD_TYPES,
PAYOUT_FAILURE_FEE_CENTS,
} from "@/lib/partners/constants";
import { stripe } from "@/lib/stripe";
import { sendEmail } from "@dub/email";
import PartnerPayoutFailed from "@dub/email/templates/partner-payout-failed";
Expand Down Expand Up @@ -80,8 +83,13 @@ export async function chargeFailed(event: Stripe.Event) {
let cardLast4: string | undefined;
let chargedFailureFee = false;

// Charge failure fee for ACH payment failures
if (charge.payment_method_details?.type === "us_bank_account") {
// Charge failure fee for direct debit payment failures
if (
charge.payment_method_details &&
DIRECT_DEBIT_PAYMENT_METHOD_TYPES.includes(
charge.payment_method_details.type as Stripe.PaymentMethod.Type,
)
) {
const [cards, links] = await Promise.all([
stripe.paymentMethods.list({
customer: workspace.stripeId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import { DubApiError } from "@/lib/api/errors";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
import {
DIRECT_DEBIT_PAYMENT_METHOD_TYPES,
DIRECT_DEBIT_PAYMENT_TYPES_INFO,
PAYMENT_METHOD_TYPES,
} from "@/lib/partners/constants";
import { stripe } from "@/lib/stripe";
import { APP_DOMAIN } from "@dub/utils";
import { NextResponse } from "next/server";
import Stripe from "stripe";
import { z } from "zod";

const addPaymentMethodSchema = z.object({
method: z.enum(PAYMENT_METHOD_TYPES as [string, ...string[]]).optional(),
});

// GET /api/workspaces/[idOrSlug]/billing/payment-methods - get all payment methods
export const GET = withWorkspace(async ({ workspace }) => {
if (!workspace.stripeId) {
return NextResponse.json([]);
Expand All @@ -15,28 +27,28 @@ export const GET = withWorkspace(async ({ workspace }) => {
customer: workspace.stripeId,
});

// reorder to put ACH first
const ach = paymentMethods.data.find(
(method) => method.type === "us_bank_account",
// reorder to put direct debit first
const directDebit = paymentMethods.data.find((method) =>
DIRECT_DEBIT_PAYMENT_METHOD_TYPES.includes(method.type),
);

return NextResponse.json([
...(ach ? [ach] : []),
...paymentMethods.data.filter((method) => method.id !== ach?.id),
...(directDebit ? [directDebit] : []),
...paymentMethods.data.filter((method) => method.id !== directDebit?.id),
]);
} catch (error) {
console.error(error);
return NextResponse.json([]);
}
});

const addPaymentMethodSchema = z.object({
method: z.enum(["card", "us_bank_account"]).optional(),
});

// POST /api/workspaces/[idOrSlug]/billing/payment-methods - add a payment method for the workspace
export const POST = withWorkspace(async ({ workspace, req }) => {
if (!workspace.stripeId) {
return NextResponse.json({ error: "Workspace does not have a Stripe ID" });
throw new DubApiError({
code: "bad_request",
message: "Workspace does not have a Stripe ID.",
});
}

const { method } = addPaymentMethodSchema.parse(await parseRequestBody(req));
Expand All @@ -53,10 +65,20 @@ export const POST = withWorkspace(async ({ workspace, req }) => {
return NextResponse.json({ url });
}

const paymentMethodOption = DIRECT_DEBIT_PAYMENT_TYPES_INFO.find(
(type) => type.type === method,
)?.option;

const { url } = await stripe.checkout.sessions.create({
mode: "setup",
customer: workspace.stripeId,
payment_method_types: [method],
payment_method_types: [
method as Stripe.Checkout.SessionCreateParams.PaymentMethodType,
],
payment_method_options: {
[method]: paymentMethodOption,
},
currency: "usd",
success_url: `${APP_DOMAIN}/${workspace.slug}/settings/billing`,
cancel_url: `${APP_DOMAIN}/${workspace.slug}/settings/billing`,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ export const PaymentMethodTypesList = (paymentMethod?: Stripe.PaymentMethod) =>
? `Account ending in ****${paymentMethod.us_bank_account.last4}`
: "Not connected",
},
{
type: "acss_debit",
title: "ACSS Debit",
icon: GreekTemple,
description: paymentMethod?.acss_debit
? `Account ending in ****${paymentMethod.acss_debit.last4}`
: "Not connected",
},
{
type: "sepa_debit",
title: "SEPA Debit",
icon: GreekTemple,
description: paymentMethod?.sepa_debit
? `Account ending in ****${paymentMethod.sepa_debit.last4}`
: "Not connected",
},
{
type: "link",
title: "Link",
Expand Down
Loading