Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partner level commission amount and coupon #1834

Merged
merged 9 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
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
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
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,12 +129,13 @@ export async function checkoutSessionCompleted(event: Stripe.Event) {

// for program links
if (link.programId) {
const { program, partner } =
const { program, partner, commissionAmount } =
await prisma.programEnrollment.findUniqueOrThrow({
where: {
linkId: link.id,
},
select: {
commissionAmount: true,
program: true,
partner: {
select: {
Expand All @@ -145,16 +146,23 @@ export async function checkoutSessionCompleted(event: Stripe.Event) {
});

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: partner.id,
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 Down
30 changes: 19 additions & 11 deletions apps/web/app/api/stripe/integration/webhook/invoice-paid.ts
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 @@ -111,12 +111,13 @@ export async function invoicePaid(event: Stripe.Event) {

// for program links
if (link.programId) {
const { program, partner } =
const { program, partner, commissionAmount } =
await prisma.programEnrollment.findUniqueOrThrow({
where: {
linkId: link.id,
},
select: {
commissionAmount: true,
program: true,
partner: {
select: {
Expand All @@ -127,16 +128,23 @@ export async function invoicePaid(event: Stripe.Event) {
});

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: partner.id,
commissionAmount,
},
customer: {
id: saleData.customer_id,
linkId: saleData.link_id,
clickId: saleData.click_id,
},
sale: {
invoiceId: saleData.invoice_id,
eventId: saleData.event_id,
paymentProcessor: saleData.payment_processor,
amount: saleData.amount,
currency: saleData.currency,
},
metadata: {
...leadEvent.data[0],
stripeMetadata: invoice,
Expand Down
30 changes: 19 additions & 11 deletions apps/web/app/api/track/sale/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DubApiError } from "@/lib/api/errors";
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 { parseRequestBody } from "@/lib/api/utils";
import { withWorkspaceEdge } from "@/lib/auth/workspace-edge";
import { getLeadEvent, recordSale } from "@/lib/tinybird";
Expand Down Expand Up @@ -121,12 +121,13 @@ export const POST = withWorkspaceEdge(

// for program links
if (link.programId) {
const { program, partner } =
const { program, partner, commissionAmount } =
await prismaEdge.programEnrollment.findUniqueOrThrow({
where: {
linkId: link.id,
},
select: {
commissionAmount: true,
program: true,
partner: {
select: {
Expand All @@ -137,16 +138,23 @@ export const POST = withWorkspaceEdge(
});

const saleRecord = createSaleData({
customerId: customer.id,
linkId: link.id,
clickId: clickData.click_id,
invoiceId,
eventId,
paymentProcessor,
amount,
currency,
partnerId: partner.id,
program,
partner: {
id: partner.id,
commissionAmount,
},
customer: {
id: customer.id,
linkId: link.id,
clickId: clickData.click_id,
},
sale: {
amount,
currency,
invoiceId,
eventId,
paymentProcessor,
},
metadata: clickData,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
DICEBEAR_AVATAR_URL,
fetcher,
formatDate,
formatDateTime,
} from "@dub/utils";
import { useParams } from "next/navigation";
import { memo } from "react";
Expand Down Expand Up @@ -73,7 +74,11 @@ const SaleTableBusinessInner = memo(
{
id: "createdAt",
header: "Date",
accessorFn: (d) => formatDate(d.createdAt, { month: "short" }),
cell: ({ row }) => (
<p title={formatDateTime(row.original.createdAt)}>
{formatDate(row.original.createdAt, { month: "short" })}
</p>
),
},
{
header: "Customer",
Expand Down
15 changes: 11 additions & 4 deletions apps/web/app/app.dub.co/embed/sales.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { SALES_PAGE_SIZE } from "@/lib/partners/constants";
import { PartnerSaleResponse } from "@/lib/types";
import { Gift, Table, usePagination, useTable } from "@dub/ui";
import { currencyFormatter, fetcher, formatDate } from "@dub/utils";
import {
currencyFormatter,
fetcher,
formatDate,
formatDateTime,
} from "@dub/utils";
import useSWR from "swr";

export function EmbedSales({ salesCount }: { salesCount: number }) {
Expand All @@ -28,9 +33,11 @@ export function EmbedSales({ salesCount }: { salesCount: number }) {
{
id: "createdAt",
header: "Date",
cell: ({ row }) => {
return formatDate(row.original.createdAt, { month: "short" });
},
cell: ({ row }) => (
<p title={formatDateTime(row.original.createdAt)}>
{formatDate(row.original.createdAt, { month: "short" })}
</p>
),
},
{
id: "saleAmount",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import {
useTable,
} from "@dub/ui";
import { CircleDollar } from "@dub/ui/icons";
import { currencyFormatter, fetcher, formatDate } from "@dub/utils";
import {
currencyFormatter,
fetcher,
formatDate,
formatDateTime,
} from "@dub/utils";
import useSWR from "swr";

export function SaleTablePartner({ limit }: { limit?: number }) {
Expand Down Expand Up @@ -52,9 +57,11 @@ export function SaleTablePartner({ limit }: { limit?: number }) {
id: "createdAt",
header: "Date",
accessorKey: "timestamp",
cell: ({ row }) => {
return formatDate(row.original.createdAt, { month: "short" });
},
cell: ({ row }) => (
<p title={formatDateTime(row.original.createdAt)}>
{formatDate(row.original.createdAt, { month: "short" })}
</p>
),
},
{
id: "customer",
Expand Down
33 changes: 21 additions & 12 deletions apps/web/lib/actions/partners/backfill-link-data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getEvents } from "@/lib/analytics/get-events";
import { createSaleData } from "@/lib/api/sales/sale";
import { createSaleData } from "@/lib/api/sales/create-sale-data";
import { SaleEvent } from "@/lib/types";
import { prisma } from "@dub/prisma";

Expand All @@ -8,18 +8,20 @@ export const backfillLinkData = async (programEnrollmentId: string) => {
where: {
id: programEnrollmentId,
},
include: {
select: {
program: {
include: {
workspace: true,
},
},
link: true,
partner: true,
id: true,
commissionAmount: true,
},
});

const { program, link, partner } = programEnrollment;
const { program, link, partner, commissionAmount } = programEnrollment;
const workspace = program.workspace;

if (!link) {
Expand Down Expand Up @@ -52,16 +54,23 @@ export const backfillLinkData = async (programEnrollmentId: string) => {

const data = saleEvents.map((e: SaleEvent) => ({
...createSaleData({
customerId: e.customer.id,
linkId: e.link.id,
clickId: e.click.id,
invoiceId: e.invoice_id,
eventId: e.eventId,
paymentProcessor: e.payment_processor,
amount: e.sale.amount,
currency: "usd",
partnerId: partner.id,
program,
partner: {
id: partner.id,
commissionAmount,
},
customer: {
id: e.customer.id,
clickId: e.click.id,
linkId: e.link.id,
},
sale: {
invoiceId: e.invoice_id,
eventId: e.eventId,
paymentProcessor: e.payment_processor,
amount: e.sale.amount,
currency: "usd",
},
metadata: e.click,
}),
createdAt: new Date(e.timestamp),
Expand Down
33 changes: 33 additions & 0 deletions apps/web/lib/api/sales/calculate-earnings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Program, ProgramEnrollment } from "@dub/prisma/client";

/*
Calculate the commission earned for a sale
*/
export const calculateEarnings = ({
program,
partner,
sales,
saleAmount,
}: {
program: Pick<Program, "commissionAmount" | "commissionType">;
partner?: Pick<ProgramEnrollment, "commissionAmount">;
sales: number;
saleAmount: number;
}) => {
const commissionAmount =
partner?.commissionAmount ?? program.commissionAmount;

if (!commissionAmount) {
return 0;
}

if (program.commissionType === "percentage") {
return saleAmount * (commissionAmount / 100);
}

if (program.commissionType === "flat") {
return sales * commissionAmount;
}

throw new Error("Invalid commissionType");
};
Loading
Loading