Skip to content

Commit

Permalink
Merge pull request #1829 from dubinc/dub-customer
Browse files Browse the repository at this point in the history
Set referral discount via Dub Customer object
  • Loading branch information
steven-tey authored Dec 29, 2024
2 parents 4f7414e + 99f0145 commit 33da169
Show file tree
Hide file tree
Showing 117 changed files with 2,444 additions and 1,803 deletions.
2 changes: 1 addition & 1 deletion apps/web/app/api/analytics/client/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getAnalytics } from "@/lib/analytics/get-analytics";
import { calculateEarnings } from "@/lib/api/sales/commission";
import { calculateEarnings } from "@/lib/api/sales/calculate-earnings";
import { withEmbedToken } from "@/lib/embed/auth";
import { analyticsQuerySchema } from "@/lib/zod/schemas/analytics";
import { NextResponse } from "next/server";
Expand Down
18 changes: 15 additions & 3 deletions apps/web/app/api/customers/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getCustomerOrThrow } from "@/lib/api/customers/get-customer-or-throw";
import { transformCustomer } from "@/lib/api/customers/transform-customer";
import { DubApiError } from "@/lib/api/errors";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
Expand All @@ -24,7 +25,7 @@ export const GET = withWorkspace(
},
);

return NextResponse.json(CustomerSchema.parse(customer));
return NextResponse.json(CustomerSchema.parse(transformCustomer(customer)));
},
{
requiredAddOn: "conversion",
Expand Down Expand Up @@ -52,11 +53,22 @@ export const PATCH = withWorkspace(
},
data: { name, email, avatar, externalId },
include: {
link: true,
link: {
include: {
programEnrollment: {
include: {
partner: true,
discount: true,
},
},
},
},
},
});

return NextResponse.json(CustomerSchema.parse(updatedCustomer));
return NextResponse.json(
CustomerSchema.parse(transformCustomer(updatedCustomer)),
);
} catch (error) {
if (error.code === "P2002") {
throw new DubApiError({
Expand Down
17 changes: 10 additions & 7 deletions apps/web/app/api/customers/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { transformCustomer } from "@/lib/api/customers/transform-customer";
import { DubApiError } from "@/lib/api/errors";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
Expand All @@ -22,7 +23,9 @@ export const GET = withWorkspace(
},
});

return NextResponse.json(CustomerSchema.array().parse(customers));
return NextResponse.json(
CustomerSchema.array().parse(customers.map(transformCustomer)),
);
},
{
requiredAddOn: "conversion",
Expand All @@ -48,14 +51,14 @@ export const POST = withWorkspace(
projectId: workspace.id,
projectConnectId: workspace.stripeConnectId,
},
include: {
link: true,
},
});

return NextResponse.json(CustomerSchema.parse(customer), {
status: 201,
});
return NextResponse.json(
CustomerSchema.parse(transformCustomer(customer)),
{
status: 201,
},
);
} catch (error) {
if (error.code === "P2002") {
throw new DubApiError({
Expand Down
15 changes: 15 additions & 0 deletions apps/web/app/api/embed/analytics/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { getAnalytics } from "@/lib/analytics/get-analytics";
import { withEmbedToken } from "@/lib/embed/auth";
import { NextResponse } from "next/server";

// GET /api/embed/analytics – get timeseries analytics for a link from an embed token
export const GET = withEmbedToken(async ({ link }) => {
const analytics = await getAnalytics({
event: "composite",
groupBy: "timeseries",
linkId: link.id,
interval: "1y",
});

return NextResponse.json(analytics);
});
40 changes: 40 additions & 0 deletions apps/web/app/api/embed/leaderboard/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { withEmbedToken } from "@/lib/embed/auth";
import { LeaderboardPartnerSchema } from "@/lib/zod/schemas/partners";
import { prisma } from "@dub/prisma";
import { NextResponse } from "next/server";
import z from "node_modules/zod/lib";

// GET /api/embed/sales – get sales for a link from an embed token
export const GET = withEmbedToken(async ({ program, searchParams }) => {
const programEnrollments = await prisma.programEnrollment.findMany({
where: {
programId: program.id,
},
orderBy: [
{
link: {
saleAmount: "desc",
},
},
{
link: {
leads: "desc",
},
},
{
link: {
clicks: "desc",
},
},
],
select: {
partner: true,
link: true,
},
take: 20,
});

return NextResponse.json(
z.array(LeaderboardPartnerSchema).parse(programEnrollments),
);
});
10 changes: 8 additions & 2 deletions apps/web/app/api/embed/sales/route.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { withEmbedToken } from "@/lib/embed/auth";
import { SALES_PAGE_SIZE } from "@/lib/partners/constants";
import z from "@/lib/zod";
import { PartnerSaleResponseSchema } from "@/lib/zod/schemas/partners";
import { prisma } from "@dub/prisma";
import { NextResponse } from "next/server";

// GET /api/embed/sales – get sales for a link from an embed token
export const GET = withEmbedToken(async ({ link }) => {
export const GET = withEmbedToken(async ({ link, searchParams }) => {
const { page } = z
.object({ page: z.coerce.number().optional().default(1) })
.parse(searchParams);

const sales = await prisma.sale.findMany({
where: {
linkId: link.id,
Expand All @@ -25,7 +30,8 @@ export const GET = withEmbedToken(async ({ link }) => {
},
},
},
take: 3,
take: SALES_PAGE_SIZE,
skip: (page - 1) * SALES_PAGE_SIZE,
orderBy: {
createdAt: "desc",
},
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/events/client/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getEvents } from "@/lib/analytics/get-events";
import { calculateEarnings } from "@/lib/api/sales/commission";
import { calculateEarnings } from "@/lib/api/sales/calculate-earnings";
import { withEmbedToken } from "@/lib/embed/auth";
import { eventsQuerySchema } from "@/lib/zod/schemas/analytics";
import { NextResponse } from "next/server";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getAnalytics } from "@/lib/analytics/get-analytics";
import { getProgramEnrollmentOrThrow } from "@/lib/api/programs/get-program-enrollment-or-throw";
import { calculateEarnings } from "@/lib/api/sales/commission";
import { calculateEarnings } from "@/lib/api/sales/calculate-earnings";
import { withPartner } from "@/lib/auth/partner";
import { analyticsQuerySchema } from "@/lib/zod/schemas/analytics";
import { NextResponse } from "next/server";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/programs/[programId]/analytics/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getAnalytics } from "@/lib/analytics/get-analytics";
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { analyticsQuerySchema } from "@/lib/zod/schemas/analytics";
import { NextResponse } from "next/server";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { prisma } from "@dub/prisma";
import { NextResponse } from "next/server";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/programs/[programId]/customers/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import {
CustomerSchema,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { prisma } from "@dub/prisma";
import { NextResponse } from "next/server";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/programs/[programId]/invites/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { partnerInvitesQuerySchema } from "@/lib/zod/schemas/partners";
import { ProgramInviteSchema } from "@/lib/zod/schemas/programs";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/programs/[programId]/metrics/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { getProgramMetricsQuerySchema } from "@/lib/zod/schemas/programs";
import { prisma } from "@dub/prisma";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { PartnerSchema } from "@/lib/zod/schemas/partners";
import { prisma } from "@dub/prisma";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { partnersCountQuerySchema } from "@/lib/zod/schemas/partners";
import { prisma } from "@dub/prisma";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/programs/[programId]/partners/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import {
EnrolledPartnerSchema,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { MIN_PAYOUT_AMOUNT } from "@/lib/partners/constants";
import { payoutsCountQuerySchema } from "@/lib/zod/schemas/payouts";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/programs/[programId]/payouts/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import {
PayoutResponseSchema,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/programs/[programId]/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { NextResponse } from "next/server";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { getSalesAmountQuerySchema } from "@/lib/zod/schemas/partners";
import { prisma } from "@dub/prisma";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/programs/[programId]/sales/count/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import { getSalesCountQuerySchema } from "@/lib/zod/schemas/partners";
import { prisma } from "@dub/prisma";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/programs/[programId]/sales/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getStartEndDates } from "@/lib/analytics/utils/get-start-end-dates";
import { getProgramOrThrow } from "@/lib/api/programs/get-program";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { withWorkspace } from "@/lib/auth";
import {
getSalesQuerySchema,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { notifyPartnerSale } from "@/lib/api/partners/notify-partner-sale";
import { createSaleData } from "@/lib/api/sales/sale";
import { createSaleData } from "@/lib/api/sales/create-sale-data";
import { getLeadEvent, recordSale } from "@/lib/tinybird";
import { redis } from "@/lib/upstash";
import { sendWorkspaceWebhook } from "@/lib/webhook/publish";
Expand Down Expand Up @@ -129,32 +129,36 @@ export async function checkoutSessionCompleted(event: Stripe.Event) {

// for program links
if (link.programId) {
const { program, partner } =
const { program, partnerId, commissionAmount } =
await prisma.programEnrollment.findUniqueOrThrow({
where: {
linkId: link.id,
},
select: {
program: true,
partner: {
select: {
id: true,
},
},
partnerId: true,
commissionAmount: true,
},
});

const saleRecord = createSaleData({
customerId: saleData.customer_id,
linkId: saleData.link_id,
clickId: saleData.click_id,
invoiceId: saleData.invoice_id,
eventId: saleData.event_id,
paymentProcessor: saleData.payment_processor,
amount: saleData.amount,
currency: saleData.currency,
partnerId: partner.id,
program,
partner: {
id: partnerId,
commissionAmount,
},
customer: {
id: saleData.customer_id,
linkId: saleData.link_id,
clickId: saleData.click_id,
},
sale: {
amount: saleData.amount,
currency: saleData.currency,
invoiceId: saleData.invoice_id,
eventId: saleData.event_id,
paymentProcessor: saleData.payment_processor,
},
metadata: {
...leadEvent.data[0],
stripeMetadata: charge,
Expand All @@ -168,7 +172,7 @@ export async function checkoutSessionCompleted(event: Stripe.Event) {
waitUntil(
notifyPartnerSale({
partner: {
id: partner.id,
id: partnerId,
referralLink: link.shortLink,
},
program,
Expand Down
Loading

0 comments on commit 33da169

Please sign in to comment.