feat: KPIs con totales absolutos, backfill ads y ventas en cruce canal

Comparativas WoW/MoM/YoY muestran prev/Δ además del %; sync ads admite
histórico desde 2025; tabla ads↔CRM añade cierres, ventas y ROAS.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4Ventures
2026-09-28 10:23:36 +02:00
parent dd50251de2
commit cf27eba74d
30 changed files with 2367 additions and 514 deletions

View File

@@ -215,8 +215,9 @@ export async function applyOrganicMatches(
meta: {
property_id: m.ga4.propertyId,
measurement_id: m.ga4.measurementId,
matched_at: new Date().toISOString(),
},
last_sync_at: new Date().toISOString(),
// last_sync_at solo tras volcar organic_daily (no al emparejar)
error_message: null,
});
if (ok) ga4 += 1;
@@ -231,8 +232,10 @@ export async function applyOrganicMatches(
status: 'connected',
external_account_id: m.gsc.siteUrl,
label: m.gsc.siteUrl,
meta: { site_url: m.gsc.siteUrl },
last_sync_at: new Date().toISOString(),
meta: {
site_url: m.gsc.siteUrl,
matched_at: new Date().toISOString(),
},
error_message: null,
}
);
@@ -686,19 +689,21 @@ export async function syncAllConnectedOrganic(opts?: {
gscSiteUrl: cfg.gscSiteUrl,
days,
});
// bump last_sync on integrations
await fetch(
`${supabaseUrl()}/rest/v1/integrations?tenant_id=eq.${encodeURIComponent(tenantId)}&provider=in.(ga4,search_console)`,
{
method: 'PATCH',
headers: {
...headers,
'Content-Type': 'application/json',
Prefer: 'return=minimal',
},
body: JSON.stringify({ last_sync_at: new Date().toISOString() }),
}
);
// Solo marcar last_sync_at si hubo filas (no mentir tras match vacío)
if (r.daysWritten > 0) {
await fetch(
`${supabaseUrl()}/rest/v1/integrations?tenant_id=eq.${encodeURIComponent(tenantId)}&provider=in.(ga4,search_console)`,
{
method: 'PATCH',
headers: {
...headers,
'Content-Type': 'application/json',
Prefer: 'return=minimal',
},
body: JSON.stringify({ last_sync_at: new Date().toISOString() }),
}
);
}
results.push({ tenantId, ...r });
} catch (e) {
results.push({