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:
@@ -20,6 +20,7 @@ import {
|
|||||||
getClosingThisMonth,
|
getClosingThisMonth,
|
||||||
getRecentWins,
|
getRecentWins,
|
||||||
getLostReasonBreakdown,
|
getLostReasonBreakdown,
|
||||||
|
salesHasData,
|
||||||
} from '@/lib/services/reports/sales.service';
|
} from '@/lib/services/reports/sales.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,6 +88,7 @@ export const GET = withAuth(
|
|||||||
recentWins,
|
recentWins,
|
||||||
lostReasonBreakdown,
|
lostReasonBreakdown,
|
||||||
priorKpis,
|
priorKpis,
|
||||||
|
hasData,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
getSalesKpis(ctx.portId, range),
|
getSalesKpis(ctx.portId, range),
|
||||||
getPipelineFunnel(ctx.portId),
|
getPipelineFunnel(ctx.portId),
|
||||||
@@ -105,6 +107,7 @@ export const GET = withAuth(
|
|||||||
// with the main batch (depends only on the derived priorBounds);
|
// with the main batch (depends only on the derived priorBounds);
|
||||||
// resolves to null when the toggle is off so we pay nothing.
|
// resolves to null when the toggle is off so we pay nothing.
|
||||||
priorBounds ? getSalesKpis(ctx.portId, priorBounds) : Promise.resolve(null),
|
priorBounds ? getSalesKpis(ctx.portId, priorBounds) : Promise.resolve(null),
|
||||||
|
salesHasData(ctx.portId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const comparison =
|
const comparison =
|
||||||
@@ -134,6 +137,7 @@ export const GET = withAuth(
|
|||||||
closingThisMonth,
|
closingThisMonth,
|
||||||
recentWins,
|
recentWins,
|
||||||
lostReasonBreakdown,
|
lostReasonBreakdown,
|
||||||
|
hasData,
|
||||||
range: {
|
range: {
|
||||||
from: range.from.toISOString(),
|
from: range.from.toISOString(),
|
||||||
to: range.to.toISOString(),
|
to: range.to.toISOString(),
|
||||||
|
|||||||
@@ -1663,6 +1663,19 @@ async function fetchNewLeads(
|
|||||||
return { total, bySource };
|
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
|
// Re-export so the active-interest helper is available to callers that
|
||||||
// want to add their own constraints layered onto the same predicate.
|
// want to add their own constraints layered onto the same predicate.
|
||||||
export { activeInterestsWhere };
|
export { activeInterestsWhere };
|
||||||
|
|||||||
Reference in New Issue
Block a user