# Padrão de telas do IOD ERP

Este documento define o padrão obrigatório para telas de consulta e cadastro do IOD ERP. Novas telas devem partir desta estrutura para manter a mesma experiência de uso em todos os módulos.

## 1. Estrutura da tela

Toda tela de cadastro deve conter, nesta ordem:

1. cabeçalho fixo do ERP com empresa atual;
2. identificação do módulo e código da tela;
3. título, descrição curta e ação primária `Novo registro`;
4. área de alertas;
5. card de consulta com busca dinâmica, contador e ferramentas do grid;
6. DataGrid dentro de `.table-wrap`;
7. cortina de cadastro vinculada à própria aba da tela.

Símbolos e ícones identificadores são exclusivos do menu lateral, dos submenus e da busca de telas. Títulos, nomes de telas e abas da área de trabalho devem usar somente texto e, quando aplicável, o código da tela.

O cabeçalho nunca deve possuir nome de empresa fixo. A view deve carregar o `sidebar.php`, que resolve o `CompanyContext`, disponibiliza `$currentCompanyName` e publica `window.ERP_COMPANY_ID`. O texto deve exibir o nome fantasia cadastrado e usar a razão social somente como alternativa. Todas as APIs da tela devem operar com esse mesmo identificador de empresa.

O formulário deve abrir com `dialog.show()` para que o `AppDrawer` o transforme em cortina não modal. Isso permite trocar de aba sem perder dados digitados. O fechamento deve usar `AppDrawer.close(dialog)` quando o componente estiver disponível, preservando a confirmação de alterações não salvas.

### Comportamento do foco

- Ao abrir um cadastro pelo botão `Novo`, a tela pode posicionar o foco no primeiro campo útil para agilizar a digitação.
- Ao abrir um registro pela ação `Editar`, nenhum campo do formulário deve receber foco automaticamente. O operador deve escolher explicitamente qual informação deseja alterar.
- Não usar `autofocus` nos campos das cortinas. Quando necessário para um registro novo, aplicar foco via JavaScript somente quando o objeto editado for nulo, por exemplo: `if (!item) firstField.focus()`.
- O `AppDrawer` aplica essa proteção globalmente às ações de edição, mas cada tela também deve evitar chamadas incondicionais a `.focus()` no método que abre o formulário.

## 2. Barra de consulta

Markup mínimo:

```html
<div class="toolbar">
    <label class="search">
        <span>⌕</span>
        <input id="search" type="search" placeholder="Código ou descrição..." autocomplete="off">
    </label>
    <div class="grid-tools">
        <span id="result-count" class="count"></span>
        <button id="export-grid" class="tool-button">⇩ Exportar</button>
        <button id="print-grid" class="tool-button">▣ Imprimir</button>
    </div>
</div>
```

A busca deve reagir ao evento `input`. Consultas remotas devem usar debounce entre 250 e 300 ms; dados já carregados podem ser filtrados imediatamente. A busca textual deve ignorar diferenças entre maiúsculas e minúsculas.

## 3. Cabeçalhos do DataGrid

Cada coluna precisa de uma chave estável em `data-column-key`. Essa chave é usada para salvar ordem e visibilidade por usuário.

```html
<table id="records-grid">
    <thead>
        <tr>
            <th data-column-key="codigo" data-type="number">Código</th>
            <th data-column-key="descricao">Descrição</th>
            <th data-column-key="status">Status</th>
            <th class="actions" data-column-key="acoes">Ações</th>
        </tr>
    </thead>
    <tbody id="record-list"></tbody>
</table>
```

Regras dos atributos:

- `data-column-key`: obrigatório, único e permanente dentro do grid;
- `data-type="number"`: obrigatório para códigos e valores numéricos, habilitando comparações corretas;
- `data-default-hidden="true"`: oculta uma coluna no padrão inicial, mantendo-a no seletor;
- `data-sortable="false"`: permitido somente quando a coluna não puder ser ordenada;
- `data-filterable="false"`: permitido somente quando a coluna não puder ser filtrada;
- `class="actions"`: obrigatório na coluna de ações; ela não pode ser ocultada, filtrada ou exportada.

As células numéricas ou formatadas devem informar o valor bruto em `data-value`:

```html
<td data-value="149.9">R$ 149,90</td>
```

## 4. Inicialização obrigatória

```js
const grid = new DataGrid(document.querySelector('#records-grid'), {
    exportName: 'registros',
    title: 'Cadastro de Registros',
    advancedFilters: true,
    columnChooser: true,
});

document.querySelector('#print-grid').addEventListener('click', () => grid.print());
```

O próprio `DataGrid` conecta automaticamente o botão `#export-grid`. Não adicionar um listener chamando `exportCsv()` diretamente. Ao clicar em Exportar, o componente deve apresentar as opções PDF, CSV, HTML e TXT. Em todos os formatos, somente colunas visíveis e registros resultantes dos filtros atuais podem ser exportados; a coluna de ações nunca participa do arquivo.

Após qualquer renderização ou recarga do `<tbody>`, chamar obrigatoriamente:

```js
grid.refresh();
```

Isso reaplica filtros, ordem salva, visibilidade e classificação às novas linhas.

## 5. Recursos obrigatórios do grid

Todas as grids principais devem oferecer:

- busca dinâmica geral;
- classificação ao clicar no cabeçalho;
- filtros avançados por coluna;
- múltiplas condições combinadas com `E` ou `OU`;
- operadores textuais como contém, diferente, começa com e termina com;
- operadores numéricos como igual, diferente, maior e menor;
- seletor de colunas visíveis;
- movimentação por arrastar o cabeçalho;
- movimentação pelas setas do seletor de colunas;
- persistência da ordem e visibilidade por usuário e por grid;
- paginação com 10 registros por página como padrão e opções de 25, 50, 100 ou Total;
- seletor de página preenchido dinamicamente conforme a quantidade de resultados filtrados;
- confirmação antes de restaurar o padrão;
- menu de exportação com PDF, CSV, HTML e TXT, sempre considerando somente as linhas e colunas visíveis;
- impressão somente das linhas e colunas visíveis.

O `exportName` deve ser exclusivo por tela. Se o padrão inicial de colunas mudar, incrementar `preferenceVersion` para que configurações antigas não impeçam a aplicação do novo padrão:

```js
new DataGrid(table, {
    exportName: 'produtos',
    preferenceVersion: '3',
    advancedFilters: true,
    columnChooser: true,
});
```

## 6. Contador de resultados

O contador deve mostrar o total da consulta usando sempre os termos genéricos `registro` e `registros`, independentemente da entidade da tela: `1 registro`, `4 registros`. Não usar nomes como produtos, empresas, marcas ou tabelas. Quando houver filtros por coluna, deve mostrar a quantidade visível:

```js
table.addEventListener('datagrid:change', event => {
    if (grid.filters.size) {
        resultCount.textContent = `${event.detail.visible} de ${event.detail.total} registros`;
    }
});
```

## 7. Ações por registro

Toda linha da grid deve abrir a cortina do registro em modo de leitura ao ser clicada. Nesse modo, campos e seleções permanecem visíveis, mas não podem ser alterados. A linha também precisa ser acessível por teclado com `Enter` ou `Espaço`.

A coluna `Ações` exibe somente o botão de três pontos. Nesta primeira versão, ele executa a mesma abertura em modo de visualização; futuramente poderá apresentar outras ações contextuais:

```html
<button class="row-button record-more" aria-label="Visualizar registro" title="Visualizar registro">⋯</button>
```

Os comandos `Editar` e `Excluir` pertencem ao rodapé da cortina de visualização, nunca diretamente à grid. Eles devem ser exibidos apenas quando `ERP_PERMISSIONS` autorizar a operação. Ao selecionar `Editar`, a mesma cortina libera os campos sem fechá-la e sem posicionar foco automaticamente. A exclusão sempre exige confirmação visual antes de chamar a API.

O componente compartilhado `record-view.js` adapta as grids existentes a esse comportamento. Novas telas devem manter uma coluna `acoes` e disponibilizar internamente os identificadores do registro para que o componente possa abrir a visualização e acionar as operações autorizadas.

## 8. Campos de relacionamento

Seleções por Marca, Grupo, Subgrupo, Seção, Linha, Unidade, Produto e outros cadastros devem usar `data-searchable`:

```html
<select id="marca_id" data-searchable></select>
```

O componente pesquisa por código ou descrição. A criação rápida só deve ser habilitada com `data-can-create="true"` quando o usuário possuir permissão e houver uma tela de cadastro correspondente. Ao apagar o texto, o identificador interno deve ficar vazio.

## 9. Arquivos compartilhados

As telas devem carregar:

- `/assets/css/app.css`;
- `/assets/css/menu-groups.css`;
- `/assets/css/app-tabs.css`;
- `/assets/css/datagrid.css`;
- `/assets/js/menu.js`;
- `/assets/js/app-tabs.js`;
- `/assets/js/datagrid.js`.

Adicionar `searchable-select.css` e `searchable-select.js` quando houver campos de relacionamento pesquisáveis. Alterações em arquivos compartilhados devem incrementar o parâmetro `?v=` nas views para evitar cache desatualizado.

## 10. Notificações temporárias

Mensagens informativas que não exigem uma decisão do usuário devem usar o componente global `AppToast`. O alerta aparece no canto inferior da aplicação, entra de baixo para cima e desaparece automaticamente:

```js
AppToast.info('A tela está prevista, mas ainda não foi desenvolvida.', {
    title: 'Tela em desenvolvimento',
});
```

Também estão disponíveis `AppToast.success()` e `AppToast.error()`. Confirmações que exigem escolha do usuário, avisos de alterações não salvas e ações destrutivas continuam usando `AppConfirm` ou o diálogo de confirmação correspondente.

Todas as confirmações de operação concluída — salvar, cadastrar, atualizar ou excluir — devem usar `AppToast.success()` em todas as telas. Erros de validação devem permanecer junto ao campo ou dentro da cortina para que não desapareçam antes da correção.

Campos obrigatórios não preenchidos devem acionar `AppValidationAlert.show()`. O alerta usa o título **Preenchimento necessário**, entra de baixo para cima e desaparece automaticamente. Respostas HTTP `422` da API são encaminhadas globalmente para esse componente, enquanto a mensagem junto ao campo pode ser mantida como apoio.

## 11. Checklist para novas telas

- [ ] Código da tela registrado no catálogo e rota correta.
- [ ] Cadastros baseados em Pessoa usam código próprio do papel e sequência independente por empresa (Cliente, Fornecedor, Colaborador e Vendedor).
- [ ] Cabeçalho, margens, card e cortina seguem o padrão global.
- [ ] Cabeçalho mostra a empresa atual pelo `CompanyContext`, sem textos fixos.
- [ ] Busca geral dinâmica implementada.
- [ ] Todas as colunas possuem `data-column-key` estável.
- [ ] Colunas numéricas possuem `data-type="number"` e células usam `data-value`.
- [ ] `advancedFilters` e `columnChooser` estão habilitados.
- [ ] Ordem e visibilidade são salvas por usuário.
- [ ] Exportação, impressão e contador estão conectados.
- [ ] Paginação permite 10, 25, 50, 100 ou Total e seleção direta da página.
- [ ] `grid.refresh()` é chamado após renderizar dados.
- [ ] Ações têm ícone, `title` e `aria-label` claros.
- [ ] Clique na linha e botão de três pontos abrem a cortina em modo leitura.
- [ ] Editar e Excluir aparecem somente dentro da cortina e respeitam permissões.
- [ ] Exclusões e restauração de colunas exigem confirmação.
- [ ] Campos ausentes e validações HTTP 422 usam o alerta global de preenchimento necessário.
- [ ] Campos relacionados usam seleção pesquisável.
- [ ] Cadastros de Pessoa consultam CNPJ somente pelo botão explícito ao lado do documento; nunca automaticamente ao digitar ou sair do campo.
- [ ] Campos de CEP dos endereços principal e adicional consultam a API somente pelo botão explícito `Consultar CEP`.
- [ ] O flag Pessoa estrangeira permanece na aba Fiscal dos cadastros de Pessoa.
- [ ] Grades de endereços em cadastros de Pessoa permitem editar e excluir cada endereço; a edição reutiliza o formulário e não cria uma linha duplicada.
- [ ] Cadastros de Pessoa exibem o endereço principal integralmente e de forma fixa; somente endereços adicionais aparecem na grid inferior.
- [ ] Formulário preserva dados ao trocar de aba.
- [ ] Edição abre sem foco automático; foco inicial é permitido somente em novo registro.
- [ ] Layout foi verificado em desktop e mobile.
- [ ] Sintaxe e testes automatizados foram executados.
