feat(products): catálogos de Tipo/Grupo/Subgrupo/Marca/Unidade com submenu e dropdowns
Menu Produtos ganha submenu (AppShell agora suporta itens aninhados) para cadastrar Tipos/Grupos/Marcas/Unidades; Subgrupo é gerenciado a partir da tela do Grupo (sempre pertence a um). O cadastro de item passa a usar dropdowns desses catálogos em vez de texto livre — exatamente o que o comentário original da migration de products já previa como trabalho futuro. Backend: 5 tabelas de catálogo simples (mesmo padrão dos catálogos fiscais), products ganha as FKs correspondentes com backfill, e endpoints CRUD (sem exclusão física, active=false é o "apagar"). Corrige também um buraco de integridade real encontrado na integração: PATCH /v1/products/:id usava COALESCE para os campos de catálogo opcionais, então não dava para distinguir "não mexer" de "limpar" — trocar o Grupo de um produto sem tocar no Subgrupo deixava o vínculo antigo órfão e inconsistente, sem nenhuma validação pegando isso. Agora a atualização valida o estado efetivo resultante (bloqueia com 400 em vez de corromper o vínculo) e productSubgroupId: null limpa de verdade. Suíte: 95/95 verdes (92→95). pnpm turbo run typecheck build: 28/28. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -118,3 +118,14 @@ export function qaKey(label: string): string {
|
||||
// apps/api/src/roles/dto/create-role.dto.ts).
|
||||
return `qa_${label}_${rand}`.slice(0, 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* Random-suffixed display name, for fixtures backed by a case-insensitive
|
||||
* UNIQUE index with no delete endpoint (e.g. product_types/product_groups/
|
||||
* brands/units) — a hardcoded name would collide with a row left behind by
|
||||
* a previous run of this suite against the same shared dev database.
|
||||
*/
|
||||
export function qaName(label: string): string {
|
||||
const rand = Math.random().toString(36).slice(2, 8);
|
||||
return `${QA_PREFIX}${label} ${rand}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user