diff --git a/apps/api/src/app/dashboard/dashboard.service.ts b/apps/api/src/app/dashboard/dashboard.service.ts index fdcf0e3..6ad2075 100644 --- a/apps/api/src/app/dashboard/dashboard.service.ts +++ b/apps/api/src/app/dashboard/dashboard.service.ts @@ -418,6 +418,10 @@ export class DashboardService { dia: string; clientes: string; } + interface NovosClientesRow { + cod_vendedor: number; + novos: string; + } const [ statsRows, @@ -428,6 +432,7 @@ export class DashboardService { metaGrupoRows, realizadoGrupoRows, positivacaoDiariaRows, + novosClientesRows, ] = await Promise.all([ prisma.$queryRawUnsafe(` SELECT COUNT(*)::text AS count, COALESCE(SUM(total), 0)::text AS total @@ -535,6 +540,21 @@ export class DashboardService { GROUP BY dt_pedido::date ORDER BY dia `), + prisma.$queryRawUnsafe(` + SELECT c.cod_vendedor, COUNT(*)::text AS novos + FROM ( + SELECT id_cliente, MIN(dt_pedido) AS primeira_compra + FROM vw_pedidos_erp + WHERE id_empresa = ${idEmpresa} + AND situa NOT IN (1, 5) + GROUP BY id_cliente + ) f + JOIN (SELECT DISTINCT id_cliente, cod_vendedor FROM vw_clientes) c + ON c.id_cliente = f.id_cliente + WHERE f.primeira_compra >= '${monthStartStr}' + AND f.primeira_compra <= '${monthEndStr}' + GROUP BY c.cod_vendedor + `), ]); const pedidosMes = Number(statsRows[0]?.count ?? 0); @@ -585,6 +605,9 @@ export class DashboardService { const totalReps = new Set(rankingRows.map((r) => Number(r.cod_vendedor))).size; const metaTotal = Number(metaTotalRows[0]?.meta_total ?? 0); + const novosMap = new Map( + novosClientesRows.map((n) => [Number(n.cod_vendedor), Number(n.novos)]), + ); const positivacaoReps: PositivacaoRep[] = positivacaoRows.map((r) => { const total = Number(r.total_clientes); const positivados = Number(r.clientes_positivados); @@ -594,6 +617,7 @@ export class DashboardService { totalClientes: total, clientesPositivados: positivados, pctPositivacao: total > 0 ? Math.round((positivados / total) * 100) : 0, + novosClientes: novosMap.get(Number(r.cod_vendedor)) ?? 0, }; }); diff --git a/apps/web/src/cockpits/ger/GerPainel.tsx b/apps/web/src/cockpits/ger/GerPainel.tsx index 69ce83b..fbdcbe0 100644 --- a/apps/web/src/cockpits/ger/GerPainel.tsx +++ b/apps/web/src/cockpits/ger/GerPainel.tsx @@ -11,6 +11,7 @@ import { Skeleton, Space, Table, + Tag, Typography, } from 'antd'; import { useNavigate } from '@tanstack/react-router'; @@ -84,6 +85,21 @@ const positivacaoColumns: TableColumnsType = [ ), }, + { + title: 'Novos no mês', + key: 'novos', + width: 120, + align: 'center' as const, + sorter: (a: PositivacaoRep, b: PositivacaoRep) => a.novosClientes - b.novosClientes, + render: (_: unknown, row: PositivacaoRep) => + row.novosClientes > 0 ? ( + + +{row.novosClientes} + + ) : ( + + ), + }, { title: '% Positivação', dataIndex: 'pctPositivacao', @@ -643,9 +659,20 @@ export function GerPainel() { } extra={ - - {positivacaoReps.filter((r) => r.clientesPositivados > 0).length} reps com positivação - + + {positivacaoReps.reduce((acc, r) => acc + r.novosClientes, 0) > 0 && ( + + +{positivacaoReps.reduce((acc, r) => acc + r.novosClientes, 0)} novo + {positivacaoReps.reduce((acc, r) => acc + r.novosClientes, 0) !== 1 ? 's' : ''}{' '} + cliente + {positivacaoReps.reduce((acc, r) => acc + r.novosClientes, 0) !== 1 ? 's' : ''} no + período + + )} + + {positivacaoReps.filter((r) => r.clientesPositivados > 0).length} reps com positivação + + } > diff --git a/libs/shared/api-interface/src/lib/dashboard.contract.ts b/libs/shared/api-interface/src/lib/dashboard.contract.ts index a3f9d7e..cdc1fc2 100644 --- a/libs/shared/api-interface/src/lib/dashboard.contract.ts +++ b/libs/shared/api-interface/src/lib/dashboard.contract.ts @@ -85,7 +85,10 @@ export const SupervisorDashboardSchema = z.object({ }); export type SupervisorDashboard = z.infer; +// novosClientes: clientes da carteira cuja PRIMEIRA compra (historico todo) +// caiu no periodo selecionado export const PositivacaoRepSchema = z.object({ + novosClientes: z.number().int().default(0), codVendedor: z.number().int(), nomeVendedor: z.string().nullable(), totalClientes: z.number().int(),