feat(reports): sales hasData existence flag (service + route)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 10:12:54 +02:00
parent 68da165b37
commit 8b7099c4c1
2 changed files with 17 additions and 0 deletions

View File

@@ -20,6 +20,7 @@ import {
getClosingThisMonth,
getRecentWins,
getLostReasonBreakdown,
salesHasData,
} from '@/lib/services/reports/sales.service';
/**
@@ -87,6 +88,7 @@ export const GET = withAuth(
recentWins,
lostReasonBreakdown,
priorKpis,
hasData,
] = await Promise.all([
getSalesKpis(ctx.portId, range),
getPipelineFunnel(ctx.portId),
@@ -105,6 +107,7 @@ export const GET = withAuth(
// with the main batch (depends only on the derived priorBounds);
// resolves to null when the toggle is off so we pay nothing.
priorBounds ? getSalesKpis(ctx.portId, priorBounds) : Promise.resolve(null),
salesHasData(ctx.portId),
]);
const comparison =
@@ -134,6 +137,7 @@ export const GET = withAuth(
closingThisMonth,
recentWins,
lostReasonBreakdown,
hasData,
range: {
from: range.from.toISOString(),
to: range.to.toISOString(),

View File

@@ -1663,6 +1663,19 @@ async function fetchNewLeads(
return { total, bySource };
}
/**
* Window-independent existence check: does this port have any interest at
* all? Drives the Sales report-level empty state.
*/
export async function salesHasData(portId: string): Promise<boolean> {
const rows = await db
.select({ one: sql<number>`1` })
.from(interests)
.where(eq(interests.portId, portId))
.limit(1);
return rows.length > 0;
}
// Re-export so the active-interest helper is available to callers that
// want to add their own constraints layered onto the same predicate.
export { activeInterestsWhere };