From 254125ddb72e74da6212206503d1782e29d269ee Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 20 Apr 2026 12:21:00 +0000 Subject: [PATCH] adding batch push up when removal requests are made --- .../[portfolioId]/removal-requests/route.ts | 36 +++++++++++++++-- .../0181_removal_request_original_batch.sql | 1 + src/app/db/schema/removal_requests.ts | 1 + src/app/lib/hubspot/dealSync.ts | 39 +++++++++++++++---- 4 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 src/app/db/migrations/0181_removal_request_original_batch.sql diff --git a/src/app/api/portfolio/[portfolioId]/removal-requests/route.ts b/src/app/api/portfolio/[portfolioId]/removal-requests/route.ts index dea87550..67d9ecce 100644 --- a/src/app/api/portfolio/[portfolioId]/removal-requests/route.ts +++ b/src/app/api/portfolio/[portfolioId]/removal-requests/route.ts @@ -7,7 +7,7 @@ import { and, eq, desc } from "drizzle-orm"; import { z } from "zod"; import { getServerSession } from "next-auth"; import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions"; -import { syncRemovalRequestToHubSpot } from "@/app/lib/hubspot/dealSync"; +import { syncRemovalRequestToHubSpot, getDealBatch } from "@/app/lib/hubspot/dealSync"; const WRITE_ROLES = ["creator", "admin", "write"] as const; @@ -317,22 +317,52 @@ export async function PATCH( ); } + const requestType = (target[0].type ?? "removal") as "removal" | "re_addition"; + const dealId = target[0].hubspotDealId; + + // When approving a removal: fetch the current batch value and store it + // When approving a re-addition: find the stored batch from the original removal + let originalBatch: string | null = null; + let batchValue: string | null | undefined = undefined; + + if (action === "approved") { + if (requestType === "removal") { + originalBatch = await getDealBatch(dealId); + } else if (requestType === "re_addition") { + const [originalRemoval] = await db + .select({ originalBatch: propertyRemovalRequests.originalBatch }) + .from(propertyRemovalRequests) + .where( + and( + eq(propertyRemovalRequests.hubspotDealId, dealId), + eq(propertyRemovalRequests.type, "removal"), + eq(propertyRemovalRequests.status, "approved"), + ), + ) + .orderBy(desc(propertyRemovalRequests.reviewedAt)) + .limit(1); + batchValue = originalRemoval?.originalBatch ?? null; + } + } + await db .update(propertyRemovalRequests) .set({ status: action, reviewedBy: requestingUser.id, reviewedAt: new Date(), + ...(requestType === "removal" && action === "approved" ? { originalBatch } : {}), }) .where(eq(propertyRemovalRequests.id, BigInt(requestId))); void syncRemovalRequestToHubSpot({ - hubspotDealId: target[0].hubspotDealId, - type: (target[0].type ?? "removal") as "removal" | "re_addition", + hubspotDealId: dealId, + type: requestType, status: action, reason: target[0].reason, requestedByEmail: target[0].requestedByEmail, reviewedByEmail: requestingUser.email, + batchValue, }); return NextResponse.json({ success: true }); diff --git a/src/app/db/migrations/0181_removal_request_original_batch.sql b/src/app/db/migrations/0181_removal_request_original_batch.sql new file mode 100644 index 00000000..e9d3d853 --- /dev/null +++ b/src/app/db/migrations/0181_removal_request_original_batch.sql @@ -0,0 +1 @@ +ALTER TABLE "property_removal_requests" ADD COLUMN IF NOT EXISTS "original_batch" text; diff --git a/src/app/db/schema/removal_requests.ts b/src/app/db/schema/removal_requests.ts index ff03de24..a535536e 100644 --- a/src/app/db/schema/removal_requests.ts +++ b/src/app/db/schema/removal_requests.ts @@ -35,6 +35,7 @@ export const propertyRemovalRequests = pgTable( () => user.id, ), reviewedAt: timestamp("reviewed_at", { withTimezone: true }), + originalBatch: text("original_batch"), }, (table) => [ index("idx_removal_requests_deal_id").on(table.hubspotDealId), diff --git a/src/app/lib/hubspot/dealSync.ts b/src/app/lib/hubspot/dealSync.ts index 06a6b78d..8a5120d4 100644 --- a/src/app/lib/hubspot/dealSync.ts +++ b/src/app/lib/hubspot/dealSync.ts @@ -1,5 +1,16 @@ import { getHubSpotClient } from "./client"; +export async function getDealBatch(hubspotDealId: string): Promise { + try { + const client = getHubSpotClient(); + const deal = await client.crm.deals.basicApi.getById(hubspotDealId, ["batch"]); + return (deal.properties["batch"] as string | null | undefined) ?? null; + } catch (err) { + console.error("[HubSpot] getDealBatch failed", { dealId: hubspotDealId, error: err }); + return null; + } +} + export async function syncRemovalRequestToHubSpot(params: { hubspotDealId: string; type: "removal" | "re_addition"; @@ -7,6 +18,7 @@ export async function syncRemovalRequestToHubSpot(params: { reason: string; requestedByEmail: string; reviewedByEmail?: string | null; + batchValue?: string | null; }): Promise { try { const client = getHubSpotClient(); @@ -30,16 +42,27 @@ export async function syncRemovalRequestToHubSpot(params: { let log = `Requested by: ${params.requestedByEmail}\nReason: ${params.reason}`; if (params.reviewedByEmail) { - const action = params.status === "approved" ? "Approved" : "Declined"; - log += `\n${action} by: ${params.reviewedByEmail}`; + if (params.type === "re_addition" && params.status === "approved") { + log += `\nRe-added to project by: ${params.reviewedByEmail}`; + } else { + const action = params.status === "approved" ? "Approved" : "Declined"; + log += `\n${action} by: ${params.reviewedByEmail}`; + } } - await client.crm.deals.basicApi.update(params.hubspotDealId, { - properties: { - project_removal_status: statusLabel, - project_removal_request_log: log, - }, - }); + const properties: Record = { + project_removal_status: statusLabel, + project_removal_request_log: log, + }; + + // Set batch when approving removal; restore it when approving re-addition (if we have a value) + if (params.type === "removal" && params.status === "approved") { + properties["batch"] = "Removed from Program"; + } else if (params.type === "re_addition" && params.status === "approved" && params.batchValue != null) { + properties["batch"] = params.batchValue; + } + + await client.crm.deals.basicApi.update(params.hubspotDealId, { properties }); } catch (err) { console.error("[HubSpot] syncRemovalRequestToHubSpot failed", { dealId: params.hubspotDealId,