- Catálogo: modal de detalhe centralizado (1100px) com identificação, estoque, preços base e lista de preços por pauta do representante (DISTINCT para evitar duplicatas) - Contrato: loteMulVenda promovido para ProdutoSummarySchema; PautaPrecoSchema adicionado - Pedido novo: valida lote múltiplo de venda — qtd inicial = lote, step = lote, InputNumber em erro quando inválido, alerta e bloqueio do submit - Consulta ERP: tela OrdersErpPage com listagem de pedidos do ERP (P/E), contrato PedidoErpConsulta, endpoint no orders.controller, rota e sidebar Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
86 lines
3.3 KiB
TypeScript
86 lines
3.3 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
// Contratos canônicos de C4 — Catálogo de Produtos.
|
|
// Consumidos pela API (output tipado) e pela Web (TanStack Query + parse).
|
|
// ADR 0006 revogado: produto lido diretamente de vw_produtos (ERP), sem sync.
|
|
|
|
// ─── Produto Summary (lista) ──────────────────────────────────────────────────
|
|
|
|
export const ProdutoSummarySchema = z.object({
|
|
idErp: z.number().int(),
|
|
codigo: z.string(),
|
|
descricao: z.string(),
|
|
unidade: z.string().nullable(),
|
|
vlPreco1: z.string(), // preço base (vw_produtos) ou preço da pauta selecionada
|
|
codGrupo: z.number().int().nullable(),
|
|
grupo: z.string().nullable(),
|
|
codSubgrupo: z.number().int().nullable(),
|
|
subgrupo: z.string().nullable(),
|
|
marca: z.string().nullable(),
|
|
ativo: z.number().int(),
|
|
qtdEstoque: z.string().nullable(),
|
|
listaParauta: z.number().int().nullable(),
|
|
loteMulVenda: z.number().int().nullable(),
|
|
});
|
|
|
|
export const PautaSchema = z.object({
|
|
idPauta: z.number().int(),
|
|
codigo: z.number().int(),
|
|
descricao: z.string(),
|
|
});
|
|
export type Pauta = z.infer<typeof PautaSchema>;
|
|
|
|
// ─── Forma de Pagamento (vw_formas_pagamento) ─────────────────────────────────
|
|
|
|
export const FormaPagamentoSchema = z.object({
|
|
codigo: z.number().int(),
|
|
descricao: z.string(),
|
|
numParcelas: z.number().int().nullable(),
|
|
txAcrescimo: z.string(),
|
|
});
|
|
export type FormaPagamento = z.infer<typeof FormaPagamentoSchema>;
|
|
export type ProdutoSummary = z.infer<typeof ProdutoSummarySchema>;
|
|
|
|
// ─── Produto Detail ───────────────────────────────────────────────────────────
|
|
|
|
export const PautaPrecoSchema = z.object({
|
|
idPauta: z.number().int(),
|
|
codigo: z.number().int(),
|
|
descricao: z.string(),
|
|
preco: z.string(),
|
|
});
|
|
export type PautaPreco = z.infer<typeof PautaPrecoSchema>;
|
|
|
|
export const ProdutoDetailSchema = ProdutoSummarySchema.extend({
|
|
referencia: z.string().nullable(),
|
|
descricaoDetalhada: z.string().nullable(),
|
|
vlPreco2: z.string().nullable(),
|
|
vlPreco3: z.string().nullable(),
|
|
aliqIpi: z.string().nullable(),
|
|
pesoLiquido: z.string().nullable(),
|
|
qtdVolume: z.string().nullable(),
|
|
precoComIpi: z.string().nullable(),
|
|
precoPromocional: z.string().nullable(),
|
|
pautaPrecos: z.array(PautaPrecoSchema),
|
|
});
|
|
export type ProdutoDetail = z.infer<typeof ProdutoDetailSchema>;
|
|
|
|
// ─── List query + response ────────────────────────────────────────────────────
|
|
|
|
export const ProdutoListQuerySchema = z.object({
|
|
q: z.string().optional(),
|
|
codGrupo: z.coerce.number().int().optional(),
|
|
idPauta: z.coerce.number().int().optional(),
|
|
page: z.coerce.number().int().positive().default(1),
|
|
limit: z.coerce.number().int().min(1).max(200).default(50),
|
|
});
|
|
export type ProdutoListQuery = z.infer<typeof ProdutoListQuerySchema>;
|
|
|
|
export const ProdutoListResponseSchema = z.object({
|
|
data: z.array(ProdutoSummarySchema),
|
|
total: z.number().int().nonnegative(),
|
|
page: z.number().int().positive(),
|
|
limit: z.number().int().positive(),
|
|
});
|
|
export type ProdutoListResponse = z.infer<typeof ProdutoListResponseSchema>;
|