refactor(api,web): remove fila de aprovacao e consolida painel do supervisor

Alcada agora e bloqueio duro no pedido (sem fluxo de aprovar/recusar):
remove ApprovalQueuePage, CarteirePage e rota /aprovacoes, absorvendo
carteira e acompanhamento de pedidos dentro do SupervisorPainel.
Colunas de desempenho por representante extraidas para componente
compartilhado (rep-performance-columns) entre gerente e supervisor.
Ajusta dashboard e orders (controller/service/contract) para o novo fluxo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 17:34:39 +00:00
parent ebf68523dd
commit 1ce8d96fea
20 changed files with 709 additions and 1560 deletions

View File

@@ -72,18 +72,13 @@ export const RepInativosSummarySchema = z.object({
});
export type RepInativosSummary = z.infer<typeof RepInativosSummarySchema>;
export const SupervisorDashboardSchema = z.object({
approvalQueue: z.array(PedidoSummarySchema),
pedidosDia: z.object({
count: z.number().int(),
total: z.number(),
countSemanaAnterior: z.number().int(),
totalSemanaAnterior: z.number(),
}),
inativosPorRep: z.array(RepInativosSummarySchema),
syncedAt: z.iso.datetime(),
// Detalhe dos clientes inativos (>30 dias sem compra) de um representante
export const RepInativosDetailSchema = z.object({
codVendedor: z.number().int(),
nomeVendedor: z.string().nullable(),
clientes: z.array(ClienteNaoPositivadoSchema),
});
export type SupervisorDashboard = z.infer<typeof SupervisorDashboardSchema>;
export type RepInativosDetail = z.infer<typeof RepInativosDetailSchema>;
// novosClientes: clientes da carteira cuja PRIMEIRA compra (historico todo)
// caiu no periodo selecionado
@@ -107,6 +102,30 @@ export const RankingRepSchema = z.object({
});
export type RankingRep = z.infer<typeof RankingRepSchema>;
export const SupervisorDashboardSchema = z.object({
pedidosDia: z.object({
count: z.number().int(),
total: z.number(),
countSemanaAnterior: z.number().int(),
totalSemanaAnterior: z.number(),
}),
inativosPorRep: z.array(RepInativosSummarySchema),
// Métricas do mês corrente, escopadas à equipe do supervisor
equipeMes: z
.object({
faturamento: z.number(),
pedidos: z.number().int(),
ticketMedio: z.number(),
metaTotal: z.number(),
pctMeta: z.number(),
})
.default({ faturamento: 0, pedidos: 0, ticketMedio: 0, metaTotal: 0, pctMeta: 0 }),
rankingReps: z.array(RankingRepSchema).default([]),
positivacaoReps: z.array(PositivacaoRepSchema).default([]),
syncedAt: z.iso.datetime(),
});
export type SupervisorDashboard = z.infer<typeof SupervisorDashboardSchema>;
// Clientes distintos positivados por dia do período (YYYY-MM-DD)
export const PositivacaoDiaSchema = z.object({
dia: z.string(),

View File

@@ -6,9 +6,9 @@ import { z } from 'zod';
// ─── Situa ────────────────────────────────────────────────────────────────────
// Ciclo de vida do pedido SAR:
// 0=Orçamento → 1=Ag. Aprovação (se desconto > alçada) → 2=Transmitido
// Estados que o SAR controla: Orçamento e Transmitido (1 é o gate de desconto).
// Ciclo de vida do pedido SAR: 0=Orçamento → 2=Transmitido.
// Desconto acima da alçada é bloqueio duro na transmissão — não há fila de
// aprovação. O valor 1 (Ag. Aprovação) é legado, mantido só para dados antigos.
// Após Transmitido, o status passa a refletir o ERP (Emitido/Cancelado/Aguardando…)
// — espelhado quando a integração existir.
export const SituaPedidoSchema = z.union([
@@ -170,17 +170,6 @@ export const CancelPedidoSchema = z.object({
});
export type CancelPedido = z.infer<typeof CancelPedidoSchema>;
export const AprovarPedidoSchema = z.object({
descontoPerc: z.number().min(0).max(100).optional(),
nota: z.string().optional(),
});
export type AprovarPedido = z.infer<typeof AprovarPedidoSchema>;
export const RecusarPedidoSchema = z.object({
motivo: z.string().min(1),
});
export type RecusarPedido = z.infer<typeof RecusarPedidoSchema>;
// ─── ERP Consulta ─────────────────────────────────────────────────────────────
export const PedidoErpConsultaItemSchema = z.object({