Nível 2 · Consulta e relatórios · Módulo 08
Consulta e navegação
Duração estimada: 2h a 3h
Você vai sair sabendo
- →Criar uma Info Window para buscar visitas
- →Tirar os textos do código e colocá-los em mensagens traduzíveis
- →Tornar uma regra configurável por empresa, com o System Configurator
- →Criar índices pelo Dicionário, para que viajem no 2Pack
- →Mostrar informação de contexto numa linha de status
- →Ligar e consultar o histórico de alterações de uma tabela
Checkpoint: 0 de 7
Antes de começar
- Módulo 07 concluído, com visitas de vários clientes e técnicos no banco.
- Este módulo é quase todo Dicionário. O Java aparece só no passo 3, para usar mensagens e configuração.
O que você vai construir
Com dezenas de visitas, a janela Visita Técnica deixa de ser o melhor jeito de encontrar alguma coisa. Neste módulo, você cuida de quem consulta:
- Uma Info Window: busca rápida de visitas, com filtros, que também serve de lookup.
- Mensagens no Dicionário: os erros do plugin passam a ser traduzíveis e editáveis sem recompilar.
- Uma configuração para a regra "visita concluída precisa de linha", que cada empresa pode ligar ou desligar.
- Um índice para as consultas que o plugin faz o tempo todo.
- Uma linha de status no cadastro do cliente: "3 visitas técnicas em aberto".
- O histórico de alterações das visitas.
Passo a passo
1. A Info Window
Conceito: uma Info Window é uma tela de busca: filtros em cima, resultado em grade embaixo. Não edita nada. Serve para o usuário encontrar registros e, a partir deles, abrir a janela ou rodar um processo.
Como System, na janela Info Window, crie:
| Campo | Valor |
|---|---|
| Name | Visitas Técnicas |
| Table | EDU_Visita |
| Sql FROM | EDU_Visita v INNER JOIN C_BPartner bp ON (bp.C_BPartner_ID=v.C_BPartner_ID) |
| Sql ORDER BY | v.EDU_DataVisita DESC |
| Entity Type | EDU |
| Window | Visita Técnica |
| Default | marcado |
O campo Window é o destino do zoom: o duplo clique numa linha abre a visita nessa janela. Default faz desta a Info Window padrão da tabela EDU_Visita.
Na aba Column, crie as colunas. Sql SELECT é a expressão, com o alias do FROM; Query Criteria marca as que viram filtro:
| Seq | Name | DB Column Name | Sql SELECT | Reference | Query Criteria | Detalhes |
|---|---|---|---|---|---|---|
| 10 | Visita | EDU_Visita_ID | v.EDU_Visita_ID | ID | Key column marcado, Displayed desmarcado | |
| 20 | Data | EDU_DataVisita | v.EDU_DataVisita | Date | sim | Range marcado |
| 30 | Cliente | C_BPartner_ID | v.C_BPartner_ID | Search | sim | Operador = |
| 40 | Nome do cliente | Name | bp.Name | String | sim | Operador Full Like |
| 50 | Técnico | SalesRep_ID | v.SalesRep_ID | Table | sim | Reference Key: AD_User - Internal |
| 60 | Tipo | EDU_TipoVisita | v.EDU_TipoVisita | List | sim | Reference Key: EDU_TipoVisita |
| 70 | Concluída | EDU_IsConcluida | v.EDU_IsConcluida | Yes-No | sim | Operador = |
Salve e clique em Validate, na aba Window. O iDempiere monta o SQL e testa no banco; se estiver certo, marca Valid. Uma Info Window inválida não abre.
Crie a entrada de menu com Action Info e Info Window Visitas Técnicas, e rode Role Access Update como GardenAdmin.
Teste como GardenAdmin: busque as visitas em aberto de um cliente, depois as de um técnico no mês. Dê duplo clique numa linha: a visita abre na janela.
2. Mensagens no Dicionário
Hoje o plugin tem dois textos em português escritos no Java. Isso tem três problemas: não dá para traduzir, não dá para corrigir sem recompilar e ninguém encontra o texto procurando no Dicionário.
Na janela Message, crie:
| Search Key | Message Type | Message Text |
|---|---|---|
EDU_VisitaSemLinhas | Error | Inclua pelo menos uma linha antes de concluir a visita. |
EDU_ClienteComVisitaAberta | Error | Este cliente tem visitas técnicas em aberto. Conclua as visitas antes de desativá-lo. |
EDU_VisitasEmAberto | Information | Visitas técnicas em aberto: {0} |
Entity Type EDU em todas. A terceira é para o passo 5. O {0} é um marcador do MessageFormat do Java.
3. Uma regra configurável
Conceito: o System Configurator guarda parâmetros que mudam o comportamento do sistema sem mexer no código. Cada parâmetro tem um nível: pode valer para o sistema todo, ou ser sobrescrito por empresa ou por organização.
Na janela System Configurator, crie:
| Campo | Valor |
|---|---|
| Name | EDU_VISITA_EXIGE_LINHA |
| Description | Y: só conclui visita com pelo menos uma linha. N: permite concluir sem linhas. |
| Configured Value | Y |
| Configuration Level | Client |
| Entity Type | EDU |
Com o nível Client, a GardenWorld pode ter o próprio registro com outro valor, e ele vale só para ela.
Agora o Java. Na MVisita, troque a regra de conclusão:
public static final String SYSCONFIG_EXIGE_LINHA = "EDU_VISITA_EXIGE_LINHA";
@Override
protected boolean beforeSave(boolean newRecord) {
if (getC_BPartner_Location_ID() <= 0
|| is_ValueChanged(COLUMNNAME_C_BPartner_ID) && !is_ValueChanged(COLUMNNAME_C_BPartner_Location_ID)) {
setC_BPartner_Location_ID(getEnderecoPadrao(getCtx(), getC_BPartner_ID(), get_TrxName()));
}
if (isEDU_IsConcluida()
&& is_ValueChanged(COLUMNNAME_EDU_IsConcluida)
&& MSysConfig.getBooleanValue(SYSCONFIG_EXIGE_LINHA, true, getAD_Client_ID())
&& getLinhas().isEmpty()) {
log.saveError("Error", Msg.getMsg(getCtx(), "EDU_VisitaSemLinhas"));
return false;
}
return true;
}
Imports: org.compiere.model.MSysConfig e org.compiere.util.Msg.
E no ClienteComVisitaAberta, do módulo 05:
if (temVisitaAberta)
throw new AdempiereException(Msg.getMsg(cliente.getCtx(), "EDU_ClienteComVisitaAberta"));
Dois detalhes:
- O valor padrão do
getBooleanValueétrue: se alguém apagar a configuração, a regra continua valendo. Escolha o padrão mais seguro. - O nome da configuração vira constante. Ele é usado no código e digitado no Dicionário; uma constante evita que os dois se desencontrem.
Reinicie o servidor e teste: com Y, a regra funciona como antes. Mude o valor para N, conclua uma visita sem linhas e veja passar. O valor é lido em cache: se a mudança não aparecer, use Cache Reset no menu. Volte para Y no fim.
4. Índices pelo Dicionário
O plugin consulta visitas por cliente e situação em três lugares: o event handler do módulo 05, o processo do módulo 06 e a linha de status do próximo passo. Com poucas visitas, tanto faz. Com cem mil, é a diferença entre instantâneo e travado.
Como System, na janela Table and Column, tabela EDU_Visita, aba Table Index:
| Campo | Valor |
|---|---|
| Name | EDU_Visita_Cliente |
| Unique | desmarcado |
| Entity Type | EDU |
Na aba Index Column:
| Sequence | Column |
|---|---|
| 10 | C_BPartner_ID |
| 20 | EDU_IsConcluida |
Volte à aba Table Index e clique em Index Validate. Confira no psql:
\d edu_visita
Pelo Dicionário, e não com CREATE INDEX direto no banco, pelo mesmo motivo da view do módulo 07: o índice vai no 2Pack junto com a tabela.
5. A linha de status no cliente
Conceito: uma Status Line executa uma consulta e mostra o resultado formatado por uma mensagem. Pode aparecer na barra de status de uma janela ou no painel de ajuda ao lado.
Na janela Status Line, crie:
| Campo | Valor |
|---|---|
| Name | EDU Visitas em aberto do cliente |
| Message | EDU_VisitasEmAberto |
| SQL Expression/Statement | SELECT COUNT(*) FROM EDU_Visita WHERE C_BPartner_ID=@C_BPartner_ID@ AND EDU_IsConcluida='N' AND IsActive='Y' |
| Entity Type | EDU |
Na aba Used In:
| Campo | Valor |
|---|---|
| Window | Business Partner |
| Tab | Business Partner |
| Status Line | marcado |
O @C_BPartner_ID@ é lido do contexto da janela, como nas lógicas do módulo 02. O resultado entra no lugar do {0} da mensagem.
Teste como GardenAdmin: abra Business Partner, navegue até um cliente com visitas e veja a contagem na barra de status. Mude de cliente e ela muda junto.
6. Histórico de alterações
Conceito: o iDempiere pode registrar cada mudança de valor, com usuário, data, valor antigo e novo. Vem desligado por padrão, tabela por tabela, porque ocupa espaço.
Na tabela EDU_Visita, marque Maintain Change Log e salve.
Como GardenAdmin:
- Abra uma visita, mude o Tipo e salve.
- Clique com o botão direito no campo Tipo e escolha Change Log. Aparece a mudança, com quem fez e quando.
- Para ver tudo o que mudou no sistema, use a janela Change Audit.
7. Commit
Inclua no Pack Out a Info Window (tipo Info Window), as três mensagens (tipo Message) e o item de menu. A tabela EDU_Visita entra de novo, porque ganhou índice e Maintain Change Log.
A Status Line e a configuração não têm tipo próprio: vão como Data, com a tabela e uma consulta em SQL Expression/Statement:
| Type | Table | SQL Expression/Statement |
|---|---|---|
| Data | AD_StatusLine | SELECT * FROM AD_StatusLine WHERE EntityType='EDU' |
| Data | AD_StatusLineUsedIn | SELECT * FROM AD_StatusLineUsedIn WHERE EntityType='EDU' |
| Data | AD_SysConfig | SELECT * FROM AD_SysConfig WHERE Name='EDU_VISITA_EXIGE_LINHA' |
Gere o 2Pack_1.0.4.zip.
git add .
git commit -m "Visitas 1.0.4: info window, mensagens, configuração, índice, status line e change log"
Checkpoint
Erros comuns
| Sintoma | Causa provável | Correção |
|---|---|---|
| A Info Window não abre, ou não aparece no menu | Valid desmarcado, ou faltou Role Access Update | Clique em Validate e leia o erro; rode o processo de acesso |
| Validate acusa erro de SQL | Alias do Sql SELECT diferente do Sql FROM | Use v. e bp. como no FROM |
| Duplo clique não abre a visita | Faltou Window na Info Window ou Key column na coluna do ID | Passo 1 |
A mensagem aparece como EDU_VisitaSemLinhas | A mensagem não existe ou a Search Key está diferente | Confira a Search Key, letra por letra |
| Mudei a configuração e nada aconteceu | Valor em cache | Cache Reset |
| Index Validate falha | Nome de índice já existe ou coluna errada | Confira no \d edu_visita |
| A linha de status não aparece | Status Line desmarcado em Used In, ou Window/Tab errados | Passo 5 |
| Não aparece Change Log no botão direito | Perfil sem Show Change Log, ou tabela sem Maintain Change Log | Passo 6 |
Desafio
Adicione à Info Window um processo: Gerar Visitas de Manutenção (módulo 06), na aba Process da Info Window. Depois, faça a linha de status mostrar também a data da próxima visita em aberto do cliente (dica: {1} na mensagem e uma segunda coluna no SELECT).
Referência
Níveis do System Configurator
| Configuration Level | Quem pode sobrescrever |
|---|---|
| System | Ninguém: vale o registro do System |
| Client | Cada empresa, com um registro próprio |
| Organization | Cada organização, com um registro próprio |
No código, o método recebe o nível mais específico que você conhece: getBooleanValue(nome, padrão), getBooleanValue(nome, padrão, AD_Client_ID) ou getBooleanValue(nome, padrão, AD_Client_ID, AD_Org_ID). Existem as mesmas variações para getValue, getIntValue e getBigDecimalValue.
Mensagens no código
| Situação | Como |
|---|---|
| Texto simples | Msg.getMsg(ctx, "Chave") |
| Com valores | Msg.getMsg(ctx, "Chave", new Object[] {valor}), com {0}, {1} na mensagem |
| Em exceção | new AdempiereException("@Chave@"): o texto entre arrobas é traduzido ao exibir |
Em beforeSave | log.saveError("Error", Msg.getMsg(getCtx(), "Chave")) |
Operadores da Info Column
=, !=, >, >=, <, <=, Like (começa com) e Full Like (contém). Para ignorar maiúsculas, use UPPER(bp.Name) no Sql SELECT. Colunas com Range pedem "de" e "até".
Próximo módulo
09 · Documentos e aprovação: a visita vira um documento, com número, status, completar, anular e aprovação.