Nível 0 · Fundamentos · Módulo 01
Seu primeiro CRUD sem código
Duração estimada: 2h a 3h
Você vai sair sabendo
- →Entender o que é o Dicionário da Aplicação e por que ele existe
- →Criar tabelas e colunas no banco sem escrever SQL
- →Escolher a referência certa para cada tipo de campo
- →Montar uma janela com cabeçalho e linhas e publicá-la no menu
Checkpoint: 0 de 7
Antes de começar
- Módulo 00 concluído: servidor rodando e login como
Systemfuncionando. - Deixe o
psqlaberto num terminal, conectado ao banco. Você vai conferir no banco cada coisa que criar na tela:
psql -h localhost -U adempiere idempiere
O que você vai construir
A primeira versão do projeto que acompanha todo o guia: o controle de visitas técnicas da GardenWorld. Uma janela com:
- Visita (cabeçalho): cliente, técnico responsável, data, tipo de visita e se é urgente
- Linhas: produtos usados na visita, com quantidade
Sem nenhuma linha de Java. Nos próximos módulos, o mesmo projeto ganha regras, código, relatórios e fluxo de aprovação.
O Dicionário da Aplicação, em 1 minuto
No iDempiere, telas, campos, validações e menus não são programados: são cadastrados. Tudo isso fica em tabelas do próprio banco, com prefixo AD_ (de Application Dictionary). Quando você abre uma janela, o iDempiere lê essas definições e monta a tela na hora.
Consequências práticas:
- Um CRUD completo (listar, filtrar, criar, editar, excluir, anexar, auditar, exportar) sai de graça ao cadastrar a janela.
- Mudar um rótulo ou esconder um campo não exige compilar nem reiniciar.
- O código Java fica reservado para as regras de negócio, que vêm a partir do módulo 04.
O Dicionário só pode ser alterado no perfil System. Entre com System / System e escolha o perfil System Administrator.
Passo a passo
1. Tipo de entidade: diga de quem é a customização
Conceito: todo registro do Dicionário tem um Entity Type (tipo de entidade). Ele diz a quem aquilo pertence: D é o core do iDempiere, e cada plugin ou customização deve ter o seu. É o que permite separar o que é seu do que é do core, exportar só o seu trabalho e gerar as classes Java no pacote certo (módulo 04).
Abra a janela Entity Type e crie:
| Campo | Valor |
|---|---|
| Entity Type | EDU |
| Name | Guia iDempiere |
Salve. Se o EDU não aparecer nas listas dos próximos passos, saia e entre de novo: a lista de tipos de entidade fica em cache.
2. Tabela da visita
Conceito: a janela Table and Column (Tabela e Coluna) é a definição de uma tabela do banco dentro do Dicionário. Você cadastra a tabela e as colunas ali, e o iDempiere gera o CREATE TABLE e o ALTER TABLE.
Abra Table and Column e crie um registro:
| Campo | Valor |
|---|---|
| DB Table Name | EDU_Visita |
| Name | Visita Técnica |
| Data Access Level | Client+Organization |
| Entity Type | EDU |
Salve. Agora clique na engrenagem (processos) e rode Create/Complete Table. Na janela de parâmetros, deixe marcado só Create KeyColumn e confirme.
Esse processo cadastra a chave primária (EDU_Visita_ID), a coluna de UUID (EDU_Visita_UU) e as colunas padrão que toda tabela do iDempiere tem:
| Coluna | Para quê |
|---|---|
AD_Client_ID | Empresa (tenant) dona do registro |
AD_Org_ID | Organização dentro da empresa |
IsActive | Desativar sem excluir |
Created, CreatedBy | Quando e quem criou |
Updated, UpdatedBy | Quando e quem alterou por último |
Ainda não existe nada no banco. Confira no psql:
\d edu_visita
-- Did not find any relation named "edu_visita".
O processo só criou a definição. A tabela física nasce ao sincronizar a primeira coluna (passo 6).
3. Elemento: o significado de um campo
Conceito: um Element (elemento) define o nome da coluna no banco e o rótulo que o usuário vê, com as traduções. Colunas com o mesmo elemento, em qualquer tabela, têm o mesmo nome e o mesmo rótulo. Por isso, antes de criar um elemento, procure se o core já tem um: C_BPartner_ID, Description, Qty e M_Product_ID já existem e são reaproveitados.
Na janela Element, crie três elementos novos, todos com Entity Type EDU:
| DB Column Name | Name | Print Text |
|---|---|---|
EDU_DataVisita | Data da Visita | Data |
EDU_TipoVisita | Tipo de Visita | Tipo |
EDU_IsUrgente | Urgente | Urgente |
Convenção: colunas booleanas começam com Is, e colunas que apontam para outra tabela terminam com _ID. O iDempiere depende dessa segunda regra: é pelo sufixo _ID que ele descobre a tabela referenciada.
4. Validação dinâmica: filtrar o que aparece
Conceito: uma Dynamic Validation é um trecho de WHERE aplicado a um campo de referência. Serve para mostrar só os registros que fazem sentido.
No cliente, só interessam parceiros que são clientes. Abra Validation Rules (Regras de Validação) e crie:
| Campo | Valor |
|---|---|
| Name | EDU - Somente Clientes |
| Type | SQL |
| Validation code | C_BPartner.IsCustomer='Y' |
| Entity Type | EDU |
Você vai usar essa regra na coluna C_BPartner_ID, no passo 6.
Para o técnico não é preciso criar nada. O core já tem uma referência pronta, AD_User - Internal, que lista só usuários ligados a funcionários ou representantes de vendas. Validação dinâmica filtra uma referência; uma referência de tabela já pode vir filtrada de fábrica. Antes de criar, procure o que o core já oferece.
5. Lista de valores fixos
Conceito: uma referência do tipo List tem as opções cadastradas no Dicionário. No banco fica gravado só o código (IN); o usuário vê o nome (Instalação), já traduzido.
Abra a janela Reference e crie:
| Campo | Valor |
|---|---|
| Name | EDU_TipoVisita |
| Validation Type | List Validation |
| Entity Type | EDU |
Na aba List Validation, cadastre:
| Search Key | Name |
|---|---|
IN | Instalação |
MA | Manutenção |
OR | Orçamento |
Essa referência vai no campo Reference Key da coluna EDU_TipoVisita, no próximo passo.
6. Colunas da visita e a escolha da referência
Conceito: a Reference (referência) de uma coluna define duas coisas ao mesmo tempo: o tipo de dado no banco e o componente de tela. É a decisão mais importante ao criar uma coluna.
As referências que você vai usar agora:
| Referência | Tela | Banco | Quando usar |
|---|---|---|---|
| String | caixa de texto | VARCHAR | texto curto |
| Date | calendário | TIMESTAMP | datas |
| Yes-No | checkbox | CHAR(1) Y/N | booleanos |
| List | lista suspensa | VARCHAR | opções fixas definidas no Dicionário |
| Table Direct | lista suspensa | NUMERIC (FK) | o nome da coluna é igual ao da tabela + _ID (C_BPartner_ID → C_BPartner) e há poucos registros |
| Table | lista suspensa | NUMERIC (FK) | o nome da coluna não bate com a tabela (SalesRep_ID → AD_User); o campo Reference Key aponta uma referência que diz qual é a tabela |
| Search | campo com lupa | NUMERIC (FK) | a tabela tem muitos registros; abre uma janela de busca em vez de carregar tudo numa lista |
Na aba Column da tabela EDU_Visita, crie as colunas abaixo. Depois de salvar cada uma, clique em Synchronize Column: é esse botão que roda o ALTER TABLE no banco (na primeira vez, o CREATE TABLE).
| DB Column Name | Reference | Detalhes |
|---|---|---|
C_BPartner_ID | Search | Mandatory. Dynamic Validation: EDU - Somente Clientes |
SalesRep_ID | Table | Reference Key: AD_User - Internal |
EDU_DataVisita | Date | Mandatory. Default Logic: @#Date@ |
EDU_TipoVisita | List | Length: 2. Mandatory. Reference Key: EDU_TipoVisita |
EDU_IsUrgente | Yes-No | Default Logic: N |
Description | String | Length: 255 |
Em C_BPartner_ID e EDU_DataVisita, marque também Identifier (Sequence 1 e 2). O identificador é o que aparece quando outra tela aponta para este registro: em vez de 1000001, o usuário vê Joe Block_2026-09-23.
Agora confira no psql:
\d edu_visita
A tabela existe, com as colunas padrão e as suas.
7. Tabela das linhas
Repita o passo 2 para a tabela EDU_VisitaLinha (Name Linha da Visita, mesmo Access Level e Entity Type) e rode o Create/Complete Table com Create KeyColumn.
Crie as colunas:
| DB Column Name | Reference | Detalhes |
|---|---|---|
EDU_Visita_ID | Table Direct | Mandatory. Parent link column marcado |
Line | Integer | Mandatory. Default Logic: @SQL=SELECT COALESCE(MAX(Line),0)+10 FROM EDU_VisitaLinha WHERE EDU_Visita_ID=@EDU_Visita_ID@ |
M_Product_ID | Search | Mandatory. Identifier |
Qty | Quantity | Mandatory. Default Logic: 1 |
Description | String | Length: 255 |
Parent link column diz ao iDempiere que esta coluna liga a linha ao cabeçalho. É ela que faz a aba de linhas mostrar só as linhas da visita selecionada.
A Default Logic de Line numera as linhas de 10 em 10, como fazem os pedidos do core. Com @SQL=, o valor padrão vem de uma consulta.
8. A janela
Conceito: uma Window (janela) tem uma ou mais Tabs (abas), e cada aba mostra os Fields (campos) de uma tabela. O Tab Level (nível) define a hierarquia: nível 0 é o cabeçalho, nível 1 é filho do nível 0, e assim por diante.
Abra Window, Tab and Field e crie:
| Campo | Valor |
|---|---|
| Name | Visita Técnica |
| Window Type | Maintain |
| Entity Type | EDU |
Na aba Tab, crie duas abas:
| Name | Table | Tab Level | Sequence |
|---|---|---|---|
| Visita | EDU_Visita | 0 | 10 |
| Linhas | EDU_VisitaLinha | 1 | 20 |
Em cada aba, clique em Create Fields. O iDempiere cria um campo para cada coluna da tabela.
O rótulo de cada campo vem do elemento. O elemento SalesRep_ID do core se chama Sales Representative, mas aqui ele é o técnico. Para trocar o rótulo só nesta janela, abra o campo na aba Field, desmarque Centrally maintained e mude o Name para Técnico. O elemento do core continua intacto.
Para organizar a tela, use a engrenagem da aba e abra o Tab Editor: arraste os campos até a posição desejada. Deixe Cliente e Data na primeira linha, Tipo, Técnico e Urgente na segunda, e Description ocupando a largura toda.
Por fim, volte a Table and Column e preencha o campo Window das duas tabelas com Visita Técnica. É isso que faz o zoom (clicar num campo que aponta para uma visita e abrir a janela certa) funcionar.
9. Menu e acesso
Abra a janela Menu e crie:
| Campo | Valor |
|---|---|
| Name | Visita Técnica |
| Action | Window |
| Window | Visita Técnica |
| Entity Type | EDU |
Salve e, na árvore do menu, arraste a entrada para dentro de uma pasta (por exemplo, Partner Relations). Não deixe itens soltos na raiz: um menu desorganizado é o primeiro sinal de uma instalação malcuidada.
A janela ainda não aparece para o GardenAdmin porque o perfil dele não tem acesso a ela. Saia do System, entre como GardenAdmin, rode o processo Role Access Update e depois saia e entre de novo.
10. Teste
Como GardenAdmin, abra Visita Técnica e cadastre uma visita:
- No Cliente, clique na lupa. Só clientes aparecem (confirme que fornecedores ficam de fora).
- Escolha o Tipo, marque Urgente e salve.
- Vá para a aba Linhas e adicione dois produtos. Repare que
Linevem preenchido com 10 e depois 20. - Volte ao cabeçalho e veja o que vem de graça: busca, histórico de alterações, anexos, exportação e modo grade.
Confira no banco:
SELECT v.edu_visita_id, bp.name, v.edu_tipovisita, v.edu_isurgente
FROM edu_visita v JOIN c_bpartner bp USING (c_bpartner_id);
Checkpoint
Erros comuns
| Sintoma | Causa provável | Correção |
|---|---|---|
| A tabela não existe no banco | Nenhuma coluna foi sincronizada | Clique em Synchronize Column em qualquer coluna |
| Erro ao sincronizar coluna obrigatória | A tabela já tem registros e a coluna não tem valor padrão | Preencha Default Logic e sincronize de novo |
| A janela não aparece no menu | Faltou o Role Access Update ou o novo login | Rode o processo como GardenAdmin e entre de novo |
| A aba Linhas mostra linhas de todas as visitas | EDU_Visita_ID sem Parent link column | Marque o campo e recrie os campos da aba |
| A lista de técnicos vem vazia | Nenhum usuário está ligado a um parceiro marcado como funcionário ou representante de vendas | Na janela Business Partner, marque Employee ou Sales Representative no parceiro do usuário |
| O lookup mostra números em vez de nomes | A tabela referenciada não tem Identifier | Marque o identificador nas colunas certas |
O EDU não aparece nas listas de Entity Type | Cache | Saia e entre de novo |
@SQL= da coluna Line dá erro | Erro de digitação no SQL | Teste a consulta no psql, trocando @EDU_Visita_ID@ por um ID real |
Desafio
Adicione à visita um campo Endereço de Atendimento que aponte para os endereços do parceiro (C_BPartner_Location_ID) e mostre apenas os endereços do cliente escolhido no cabeçalho.
Dica: a validação dinâmica pode usar o valor de outro campo da mesma tela com @NomeDaColuna@. Procure antes se o core já tem uma regra pronta para isso.
Referência
Campos importantes da coluna
| Campo | Efeito |
|---|---|
| Mandatory | NOT NULL no banco e obrigatório na tela. Se marcado depois que a coluna já tem dados, vale só na tela |
| Updatable | Se desmarcado, o valor não pode mudar depois de salvo |
| Identifier | Compõe o texto que representa o registro em outras telas |
| Parent link column | Liga a aba filha à aba pai |
| Default Logic | Valor inicial (constante, @variável@ ou @SQL=) |
| Synchronize Column | Aplica a definição no banco (CREATE/ALTER TABLE) |
Para remover uma coluna do banco, rode o processo Drop Database Column na aba Column antes de apagar o registro. Se apagar só o registro, a coluna fica órfã no banco.
Tipos de janela
| Window Type | Comportamento |
|---|---|
| Maintain | Cadastros: mostra todos os registros |
| Transaction | Movimentos: ao abrir, mostra só os pendentes ou alterados recentemente |
| Query Only | Somente leitura |
Atalho: Create Window, Tab and Field from Table
Depois de dominar o caminho manual, o processo Create Window, Tab and Field from Table, na janela Table and Column, cria janela, aba e menu de uma vez. Use o atalho só depois de ter feito o caminho manual pelo menos uma vez: quando algo der errado, você vai precisar saber o que ele fez.
Mais referências
A lista completa (Amount, Integer, Number, Text Long, Image, Button, Location, Chosen Multiple Selection e outras) está na janela Reference, filtrando por Validation Type = DataType.
Próximo módulo
02 · Janelas inteligentes: contexto e lógicas: campos que aparecem, somem, travam ou se preenchem conforme o que o usuário faz.