@@ -5,13 +5,14 @@ import { includeProgramEnrollment } from "@/lib/api/links/include-program-enroll
55import { includeTags } from "@/lib/api/links/include-tags" ;
66import { syncTotalCommissions } from "@/lib/api/partners/sync-total-commissions" ;
77import { verifyQstashSignature } from "@/lib/cron/verify-qstash" ;
8+ import { conn } from "@/lib/planetscale" ;
89import { storage } from "@/lib/storage" ;
910import { recordLink } from "@/lib/tinybird" ;
1011import { redis } from "@/lib/upstash" ;
1112import { sendBatchEmail } from "@dub/email" ;
1213import PartnerAccountMerged from "@dub/email/templates/partner-account-merged" ;
1314import { prisma } from "@dub/prisma" ;
14- import { log , prettyPrint , R2_URL , toCentsNumber } from "@dub/utils" ;
15+ import { log , prettyPrint , R2_URL } from "@dub/utils" ;
1516import * as z from "zod/v4" ;
1617
1718export const dynamic = "force-dynamic" ;
@@ -60,10 +61,12 @@ export async function POST(req: Request) {
6061 select : {
6162 id : true ,
6263 email : true ,
64+ image : true ,
6365 payoutMethodHash : true ,
6466 programs : {
6567 select : {
6668 programId : true ,
69+ tenantId : true ,
6770 } ,
6871 } ,
6972 users : {
@@ -99,6 +102,12 @@ export async function POST(req: Request) {
99102 ) ;
100103 }
101104
105+ if ( sourceAccount . id === targetAccount . id ) {
106+ return new Response (
107+ `Source and target partner accounts must be different. Source account: ${ sourceAccount . email } (${ sourceAccount . id } ), Target account: ${ targetAccount . email } (${ targetAccount . id } )` ,
108+ ) ;
109+ }
110+
102111 const {
103112 id : sourcePartnerId ,
104113 users : sourcePartnerUsers ,
@@ -164,18 +173,20 @@ export async function POST(req: Request) {
164173 `Updated ${ updatedLinksRes . count } links, ${ updatedCustomersRes . count } customers, ${ updatedCommissionsRes . count } commissions, and ${ updatedPayoutsRes . count } payouts` ,
165174 ) ;
166175
167- // update notification emails, messages, and partner comments
176+ // update discount codes, notification emails, messages, and partner comments
168177 const [
178+ updatedDiscountCodesRes ,
169179 updatedNotificationEmailsRes ,
170180 updatedMessagesRes ,
171181 updatedPartnerCommentsRes ,
172182 ] = await Promise . all ( [
183+ prisma . discountCode . updateMany ( updateManyPayload ) ,
173184 prisma . notificationEmail . updateMany ( updateManyPayload ) ,
174185 prisma . message . updateMany ( updateManyPayload ) ,
175186 prisma . partnerComment . updateMany ( updateManyPayload ) ,
176187 ] ) ;
177188 console . log (
178- `Updated ${ updatedNotificationEmailsRes . count } notification emails, ${ updatedMessagesRes . count } messages, and ${ updatedPartnerCommentsRes . count } partner comments` ,
189+ `Updated ${ updatedDiscountCodesRes . count } discount codes, ${ updatedNotificationEmailsRes . count } notification emails, ${ updatedMessagesRes . count } messages, and ${ updatedPartnerCommentsRes . count } partner comments` ,
179190 ) ;
180191
181192 const updatedLinks = await prisma . link . findMany ( {
@@ -240,6 +251,50 @@ export async function POST(req: Request) {
240251 console . log ( prettyPrint ( res ) ) ;
241252 }
242253
254+ const existingEnrollments = sourcePartnerEnrollments . filter (
255+ ( { programId } ) =>
256+ targetPartnerEnrollments . some (
257+ ( { programId : targetProgramId } ) => programId === targetProgramId ,
258+ ) ,
259+ ) ;
260+
261+ if ( existingEnrollments . length > 0 ) {
262+ for ( const sourceEnrollment of existingEnrollments ) {
263+ const targetEnrollment = targetPartnerEnrollments . find (
264+ ( { programId } ) => programId === sourceEnrollment . programId ,
265+ ) ;
266+ await prisma . $transaction ( async ( tx ) => {
267+ // delete old source enrollment
268+ await tx . programEnrollment . delete ( {
269+ where : {
270+ partnerId_programId : {
271+ partnerId : sourcePartnerId ,
272+ programId : sourceEnrollment . programId ,
273+ } ,
274+ } ,
275+ } ) ;
276+
277+ // update target enrollment with source enrollment's tenantId if target enrollment does not have a tenantId
278+ if ( sourceEnrollment . tenantId && ! targetEnrollment ?. tenantId ) {
279+ await tx . programEnrollment . update ( {
280+ where : {
281+ partnerId_programId : {
282+ partnerId : targetPartnerId ,
283+ programId : sourceEnrollment . programId ,
284+ } ,
285+ } ,
286+ data : {
287+ tenantId : sourceEnrollment . tenantId ,
288+ } ,
289+ } ) ;
290+ }
291+ } ) ;
292+ console . log (
293+ `Deleted old source enrollment for program ${ sourceEnrollment . programId } .${ sourceEnrollment . tenantId ? ` Since there was a tenantId, we updated the target enrollment with the same tenantId: ${ sourceEnrollment . tenantId } ` : "" } ` ,
294+ ) ;
295+ }
296+ }
297+
243298 // If source account has rewind, need to delete and recalculate for the target account
244299 if ( sourceAccount . partnerRewinds . length > 0 ) {
245300 const deletedRewinds = await prisma . partnerRewind . deleteMany ( {
@@ -248,43 +303,6 @@ export async function POST(req: Request) {
248303 } ,
249304 } ) ;
250305 console . log ( `Deleted ${ deletedRewinds . count } partner rewinds` ) ;
251-
252- const rewindStats = await prisma . programEnrollment
253- . aggregate ( {
254- where : {
255- partnerId : targetPartnerId ,
256- } ,
257- _sum : {
258- totalClicks : true ,
259- totalLeads : true ,
260- totalSaleAmount : true ,
261- totalCommissions : true ,
262- } ,
263- } )
264- . then ( ( res ) => ( {
265- totalClicks : res . _sum . totalClicks ?? 0 ,
266- totalLeads : res . _sum . totalLeads ?? 0 ,
267- totalRevenue : toCentsNumber ( res . _sum . totalSaleAmount ?? 0 ) ,
268- totalEarnings : toCentsNumber ( res . _sum . totalCommissions ?? 0 ) ,
269- } ) ) ;
270-
271- await prisma . partnerRewind . upsert ( {
272- where : {
273- partnerId_year : {
274- partnerId : targetPartnerId ,
275- year : 2025 ,
276- } ,
277- } ,
278- update : rewindStats ,
279- create : {
280- partnerId : targetPartnerId ,
281- year : 2025 ,
282- ...rewindStats ,
283- } ,
284- } ) ;
285- console . log (
286- `Upserted partner rewind for ${ targetPartnerId } in 2025: ${ prettyPrint ( rewindStats ) } ` ,
287- ) ;
288306 }
289307
290308 // Remove the user if there are no workspaces left
@@ -327,18 +345,14 @@ export async function POST(req: Request) {
327345
328346 try {
329347 // Finally, delete the partner account
330- const deletedPartner = await prisma . partner . delete ( {
331- where : {
332- id : sourcePartnerId ,
333- } ,
334- } ) ;
348+ await conn . execute ( `DELETE FROM Partner WHERE id = ?` , [ sourcePartnerId ] ) ;
335349 console . log (
336- `Deleted partner ${ deletedPartner . email } (${ deletedPartner . id } )` ,
350+ `Deleted partner ${ sourceAccount . email } (${ sourceAccount . id } )` ,
337351 ) ;
338352
339- if ( deletedPartner . image ) {
353+ if ( sourceAccount . image ) {
340354 await storage . delete ( {
341- key : deletedPartner . image . replace ( `${ R2_URL } /` , "" ) ,
355+ key : sourceAccount . image . replace ( `${ R2_URL } /` , "" ) ,
342356 } ) ;
343357 }
344358 } catch ( error ) {
0 commit comments