feat(api,web): edicao de orcamento e cancelamento com motivo

- PATCH /orders/:id edita orcamento (situa 0): substitui itens,
  recalcula totais, valida alcada do dono do pedido; depois de
  transmitido nao e mais editavel (400)
- Menu "Editar orcamento" abre o lancamento pre-carregado
  (/pedidos/novo?editar=id) com cliente, itens, pauta, forma de
  pagamento, obs e endereco; salvar faz PATCH em vez de POST
- Detalhe do pedido passa a incluir idPauta/codFormapag e
  codGrupo/codSubgrupo por item (teto de desconto na edicao)
- Cancelar pedido abre card com motivo (select) + descricao livre;
  gravado em motivo_recusa e no historico (ASCII: banco ERP e LATIN1,
  em-dash quebrava o UPDATE)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 19:16:55 +00:00
parent 35fd773f14
commit 1e11de7f31
5 changed files with 361 additions and 49 deletions

View File

@@ -40,6 +40,10 @@ export const PedidoItemSchema = z.object({
precoUnitario: z.string(),
descontoPerc: z.string(),
total: z.string(),
// Grupo/subgrupo do produto (vw_produtos) — edição do orçamento usa para o
// teto de desconto. Ausente em pedidos ERP.
codGrupo: z.number().int().nullable().optional(),
codSubgrupo: z.number().int().nullable().optional(),
});
export type PedidoItem = z.infer<typeof PedidoItemSchema>;
@@ -89,6 +93,9 @@ export const PedidoDetailSchema = PedidoSummarySchema.extend({
pedFlex: z.string(),
formaPagamento: z.string().nullable().optional(),
endEntrega: z.string().nullable().optional(),
// Pauta/forma de pagamento do pedido SAR — edição do orçamento pré-carrega
idPauta: z.number().int().nullable().optional(),
codFormapag: z.number().int().nullable().optional(),
aprovadoPor: z.number().int().nullable(),
aprovadoEm: z.iso.datetime().nullable(),
motivoRecusa: z.string().nullable(),
@@ -149,6 +156,17 @@ export const CreatePedidoSchema = z.object({
});
export type CreatePedido = z.infer<typeof CreatePedidoSchema>;
// Edição de orçamento (situa 0): mesmo shape da criação, sem idempotencyKey
export const UpdatePedidoSchema = CreatePedidoSchema.omit({ idempotencyKey: true });
export type UpdatePedido = z.infer<typeof UpdatePedidoSchema>;
// Cancelamento com motivo obrigatório + descrição livre opcional
export const CancelPedidoSchema = z.object({
motivo: z.string().min(1).max(60),
descricao: z.string().max(500).optional(),
});
export type CancelPedido = z.infer<typeof CancelPedidoSchema>;
export const AprovarPedidoSchema = z.object({
descontoPerc: z.number().min(0).max(100).optional(),
nota: z.string().optional(),