feat(c4): lançamento de pedido — catálogo, alçada por linha, POST /orders

- Prisma: Product + RepDiscountLimit + productCategory em OrderItem + migration
- Seed: 28 produtos (5 categorias) + alçadas user-001 (default 10%, bebidas 8%, perecíveis 5%)
- @sar/api-interface: ProductSummarySchema, ProductDetailSchema, ProductSyncRequestSchema, CreateOrderSchema
- API: CatalogModule (GET /catalog, GET /catalog/:id, POST /catalog/sync)
- API: POST /orders — valida alçada por linha/produto (OQ-2), idempotency-key (FR-4.3), desnorm cliente
- Web: NewOrderPage (3 steps: catálogo → desconto/obs → confirmação)
- Web: botão Novo Pedido na ClientDetailPage (desabilitado se financialStatus=blocked)
- Web: rota /pedidos/novo com search param clientId

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 23:45:11 +00:00
parent c36451dd33
commit 6769a0d82a
16 changed files with 1372 additions and 17 deletions

View File

@@ -91,3 +91,24 @@ export const OrderListResponseSchema = z.object({
limit: z.number().int().positive(),
});
export type OrderListResponse = z.infer<typeof OrderListResponseSchema>;
// ─── Create Order (POST /orders) ──────────────────────────────────────────────
export const CreateOrderItemSchema = z.object({
productCode: z.string().min(1),
productName: z.string().min(1),
productCategory: z.string().default('geral'),
quantity: z.number().positive(),
unitPrice: z.number().positive(),
discountPct: z.number().min(0).max(100).default(0),
});
export type CreateOrderItem = z.infer<typeof CreateOrderItemSchema>;
export const CreateOrderSchema = z.object({
clientId: z.string().uuid(),
discountPct: z.number().min(0).max(100).default(0), // desconto global do pedido
notes: z.string().optional(),
idempotencyKey: z.string().optional(),
items: z.array(CreateOrderItemSchema).min(1),
});
export type CreateOrder = z.infer<typeof CreateOrderSchema>;