Add GoHighLevel CRM sync for tenant locations.
Warehouse leads/deals from GHL contacts and opportunities so Métricas and CRM can use the same scorecard as Clientify. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -118,6 +118,7 @@ export async function PATCH(req: NextRequest) {
|
||||
typeof body.errorMessage === 'string' ? body.errorMessage.trim() : undefined;
|
||||
const enabled =
|
||||
typeof body.enabled === 'boolean' ? body.enabled : undefined;
|
||||
const pit = typeof body.pit === 'string' ? body.pit.trim() : '';
|
||||
|
||||
if (!tenantId || !provider) {
|
||||
return NextResponse.json(
|
||||
@@ -193,7 +194,23 @@ export async function PATCH(req: NextRequest) {
|
||||
patch.error_message = null;
|
||||
}
|
||||
|
||||
if (!status && enabled === undefined && externalAccountId === undefined) {
|
||||
if (provider === 'gohighlevel' && (pit || externalAccountId !== undefined)) {
|
||||
const cur = await fetch(
|
||||
`${supabaseUrl()}/rest/v1/integrations?tenant_id=eq.${encodeURIComponent(tenantId)}&provider=eq.gohighlevel&select=meta`,
|
||||
{ headers, cache: 'no-store' }
|
||||
);
|
||||
let meta: Record<string, unknown> = {};
|
||||
if (cur.ok) {
|
||||
const rows = (await cur.json()) as { meta?: Record<string, unknown> }[];
|
||||
if (rows[0]?.meta && typeof rows[0].meta === 'object') meta = { ...rows[0].meta };
|
||||
}
|
||||
if (pit) meta.pit = pit;
|
||||
if (externalAccountId) meta.location_id = externalAccountId;
|
||||
patch.meta = meta;
|
||||
if (!label) patch.label = patch.label || 'GoHighLevel';
|
||||
}
|
||||
|
||||
if (!status && enabled === undefined && externalAccountId === undefined && !pit) {
|
||||
return NextResponse.json(
|
||||
{ error: 'status, enabled o externalAccountId requeridos' },
|
||||
{ status: 400 }
|
||||
|
||||
@@ -4,6 +4,7 @@ import { isAgencyRole, serviceHeaders, supabaseUrl, userRole } from '@/lib/agenc
|
||||
import { resolveActiveTenant } from '@/lib/tenant-context';
|
||||
import { syncAdsForTenants } from '@/lib/ads-sync';
|
||||
import { syncAllClientifyTenants } from '@/lib/clientify-sync';
|
||||
import { syncAllGhlTenants } from '@/lib/gohighlevel-sync';
|
||||
import { syncAllConnectedOrganic } from '@/lib/google-organic';
|
||||
import {
|
||||
getAgencyOAuthStatus,
|
||||
@@ -67,7 +68,15 @@ export async function POST(req: NextRequest) {
|
||||
|
||||
try {
|
||||
if (want('crm') || want('metrics')) {
|
||||
out.crm = await syncAllClientifyTenants({ tenantId });
|
||||
const [clientify, gohighlevel] = await Promise.all([
|
||||
syncAllClientifyTenants({ tenantId }),
|
||||
syncAllGhlTenants({ tenantId }),
|
||||
]);
|
||||
out.crm = {
|
||||
results: [...clientify.results, ...gohighlevel.results],
|
||||
clientify,
|
||||
gohighlevel,
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
out.crm = {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
superhumanConfigured,
|
||||
} from '@/lib/superhuman-docs';
|
||||
import { syncAllClientifyTenants } from '@/lib/clientify-sync';
|
||||
import { syncAllGhlTenants } from '@/lib/gohighlevel-sync';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
export const maxDuration = 300;
|
||||
@@ -92,12 +93,16 @@ export async function GET(req: NextRequest) {
|
||||
|
||||
// 4) Clientify CRM → leads/deals
|
||||
try {
|
||||
const crm = await syncAllClientifyTenants();
|
||||
const [clientify, gohighlevel] = await Promise.all([
|
||||
syncAllClientifyTenants(),
|
||||
syncAllGhlTenants(),
|
||||
]);
|
||||
const results = [...clientify.results, ...gohighlevel.results];
|
||||
out.crm = {
|
||||
ok: true,
|
||||
synced: crm.results.filter((r) => !r.error).length,
|
||||
withErrors: crm.results.filter((r) => r.error).length,
|
||||
results: crm.results,
|
||||
synced: results.filter((r) => !r.error).length,
|
||||
withErrors: results.filter((r) => r.error).length,
|
||||
results,
|
||||
};
|
||||
} catch (e) {
|
||||
out.crm = {
|
||||
|
||||
@@ -33,7 +33,7 @@ async function fetchCrmLeads(
|
||||
let useSelect = select;
|
||||
for (let offset = 0; offset < 80000; offset += pageSize) {
|
||||
const r = await fetch(
|
||||
`${base}/rest/v1/leads?select=${useSelect}${tidFilter}&crm=eq.clientify&order=created_at.desc&limit=${pageSize}&offset=${offset}`,
|
||||
`${base}/rest/v1/leads?select=${useSelect}${tidFilter}&crm=in.(clientify,gohighlevel)&order=created_at.desc&limit=${pageSize}&offset=${offset}`,
|
||||
{ headers, cache: 'no-store' }
|
||||
);
|
||||
if (!r.ok) {
|
||||
@@ -56,7 +56,7 @@ async function fetchCrmLeads(
|
||||
let q = supabase
|
||||
.from('leads')
|
||||
.select(select)
|
||||
.eq('crm', 'clientify')
|
||||
.in('crm', ['clientify', 'gohighlevel'])
|
||||
.order('created_at', { ascending: false })
|
||||
.range(offset, offset + pageSize - 1);
|
||||
let { data, error } = await q;
|
||||
@@ -64,7 +64,7 @@ async function fetchCrmLeads(
|
||||
const retry = await supabase
|
||||
.from('leads')
|
||||
.select(selectFallback)
|
||||
.eq('crm', 'clientify')
|
||||
.in('crm', ['clientify', 'gohighlevel'])
|
||||
.order('created_at', { ascending: false })
|
||||
.range(offset, offset + pageSize - 1);
|
||||
data = retry.data as typeof data;
|
||||
|
||||
@@ -91,7 +91,7 @@ async function fetchCrmLeads(
|
||||
let useSelect = select;
|
||||
for (let offset = 0; offset < 50000; offset += pageSize) {
|
||||
const r = await fetch(
|
||||
`${base}/rest/v1/leads?select=${useSelect}${tidFilter}&crm=eq.clientify&order=created_at.desc&limit=${pageSize}&offset=${offset}`,
|
||||
`${base}/rest/v1/leads?select=${useSelect}${tidFilter}&crm=in.(clientify,gohighlevel)&order=created_at.desc&limit=${pageSize}&offset=${offset}`,
|
||||
{ headers, cache: 'no-store' }
|
||||
);
|
||||
if (!r.ok) {
|
||||
@@ -114,14 +114,14 @@ async function fetchCrmLeads(
|
||||
let { data, error } = await supabase
|
||||
.from('leads')
|
||||
.select(select)
|
||||
.eq('crm', 'clientify')
|
||||
.in('crm', ['clientify', 'gohighlevel'])
|
||||
.order('created_at', { ascending: false })
|
||||
.range(offset, offset + pageSize - 1);
|
||||
if (error && offset === 0) {
|
||||
const retry = await supabase
|
||||
.from('leads')
|
||||
.select(selectFallback)
|
||||
.eq('crm', 'clientify')
|
||||
.in('crm', ['clientify', 'gohighlevel'])
|
||||
.order('created_at', { ascending: false })
|
||||
.range(offset, offset + pageSize - 1);
|
||||
data = retry.data as typeof data;
|
||||
|
||||
Reference in New Issue
Block a user