Introdução
Nesse décimo segundo post vou dedicar totalmente para fazer alguns ajustes na aplicação. Serão algumas pequenas melhorias no produto em si e também na codificação.
Ajustando Coluna Pessoa
A aplicação agora tem a opção do usuário utilizar os dados do Banco, Centro Custo, Categoria e Pessoa. Mas independente do parâmetro nossa tela de lançamento está mostrando a pessoa no grid de pesquisa:
Vou ajustar a aplicação para somente mostrar a coluna pessoa se o parâmetro ParametroUtilizaPessoa estiver como true. No LancamentoListAction vou carregar o parâmetro e ocultar a coluna caso o parametro esteja configurado como false.
LancamentoListAction.java:
@JArchDynamicShowDataAction(id = "idCancelarBaixaLancamento", labelMenu = "label.cancelarBaixa", labelButton = "label.cancelarBaixa", nameMethodDataAction = "cancelaBaixaLancamento", confirmation = true, headerConfirmation = "message.cancelarBaixa", messageConfirmation = "message.confirmarCancelamentoBaixaDessaConta", order = 2, elDisabled = "#{(l -> l.aberto)(lancamento)}")
@JArchViewScoped
public class LancamentoListAction extends CrudListAction<LancamentoEntity, LancamentoFacade> {
@JArchParameter
@Inject
private ParametroUtilizaPessoa parametroUtilizaPessoa;
/** Código Ocultado **\
@PostConstruct
private void init() {/** Código Ocultado **\if (!parametroUtilizaPessoa.getValue()) {
getColumnDataTable("pessoa.nome").ifPresent(c -> c.hide());
}
}
Alteração Pessoa na Conta
A aplicação está configurada para incrementar o código por pessoa. Então não posso permitir que seja alterado a pessoa depois que a conta foi incluÃda, porque o código não vai estar de acordo com a regra de incrementação por pessoa. Então vou implementar uma crÃtica no evento de alteração de pessoa:
LancamentoObserver.java
private void naoPermiteAlteracaoPessoa(@Observes @JArchEventChangeField("pessoa") LancamentoEntity lancamento) {
throw new ValidationException(BundleUtils.messageBundle("message.alteracaoPessoaNaoPermitidaDevidoRegraCodigo"));
}
bundle_pt_BR.properties:
message.alteracaoPessoaNaoPermitidaDevidoRegraCodigo=Altera\u00E7\u00E3o de Pessoa n\u00E3o permitida devido a regra \ de c\u00F3digo
Agora se tentar alterar uma pessoa (com o parametro de pessoa ativo) temos o seguinte resultado:
Mas ainda posso melhorar mais, vou desabilitar os dados da pessoa quando for alteração.
lancamentoData.xhtml:
<a:panelGrid columns="1" rendered="#{lancamentoDataAction.utilizaPessoa}">
<h:panelGroup>
<e:lookup id="idLancamentoPessoa" labelUnique="#{e:bundle('label.pessoa')}"
header="#{e:bundle('label.pessoa')}" value="#{lancamentoDataAction.entity.pessoa}"
actionFilterSelect="#{pessoaFilterSelectAction}"
disabled="#{lancamentoDataAction.blockedMaster or lancamentoDataAction.stateChange}"
required="true" createExtensionInternal="true" widthCode="120" typeCode="cpf-cnpj"/>
</h:panelGroup>
</a:panelGrid>
Repare que no atributo disabled eu adicionei o "or lancamentoDataAction.stateChange" na expression language. Mas agora que bloqueamos a tela não precisamos mais da implementação do observer ?A resposta é SIM, precisamos do observer, porque o observer é a garantia de não haver a alteração. O bloqueio impede a alteração pela tela de lançamento, mas pode existir alguma implementação de alteração via código, ou até mesmo outra tela. O observer sempre deve ser implementado para garantir essa integridade.
Segue o print do campo pessoa desabilitado: (print com multitenant que não está habilitado a pessoa)
Correção nos Alertas
Quando fiz a implementação dos Alerts para mostrar alertas de quantidade de contas pagar vencido/ vencendo eu esqueci de adicionar o filtro de contas em aberto. No método getAlerts() no LevantamentoFacade, onde verifica as contas a pagar vencido está implementado dessa maneira:
LancamentoFacade.java
long contasPagarVencido = clientJpaql()
.where()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.lessThan(LancamentoEntity_.vencimento, LocalDate.now())
.collect()
.count();
Vou corrigir adicionando o filtro de aberto:
long contasPagarVencido = clientJpaql()
.where()
.equalsTo(LancamentoEntity_.aberto, true)
.and()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.lessThan(LancamentoEntity_.vencimento, LocalDate.now())
.collect()
.count();
E a mesma coisa no vencendo, esta assim:
long contasPagarVencendo = clientJpaql()
.where()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.equalsTo(LancamentoEntity_.vencimento, LocalDate.now())
.collect()
.count();
Vou corrigir adicionando o filtro de aberto:
long contasPagarVencendo = clientJpaql()
.where()
.equalsTo(LancamentoEntity_.aberto, true)
.and()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.equalsTo(LancamentoEntity_.vencimento, LocalDate.now())
.collect()
.count();
Enxugando Alerts
A implementação do método getAlerts() no LancamentoFacade apesar de bem simples tem mais código do que o necessário. Atualmente está assim:
LancamentoFacade.java:
public Alerts getAlerts() {
Alerts alerts = new Alerts();
long contasPagarVencido = clientJpaql()
.where()
.equalsTo(LancamentoEntity_.aberto, true)
.and()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.lessThan(LancamentoEntity_.vencimento, LocalDate.now())
.collect()
.count();
if (contasPagarVencido > 0) {
alerts.add(AlertBuilder
.newInstance()
.danger()
.title(BundleUtils.messageBundle("label.pagarVencido"))
.description(contasPagarVencido + " " + BundleUtils.messageBundle("label.contaPagar"))
.build());
}
long contasPagarVencendo = clientJpaql()
.where()
.equalsTo(LancamentoEntity_.aberto, true)
.and()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.equalsTo(LancamentoEntity_.vencimento, LocalDate.now())
.collect()
.count();
if (contasPagarVencendo > 0) {
alerts.add(AlertBuilder
.newInstance()
.warning()
.title(BundleUtils.messageBundle("label.pagarVencendo"))
.description(contasPagarVencendo + " " + BundleUtils.messageBundle("label.contaPagar"))
.build());
}
return alerts;
}
Vou refatorar esse método movendo ele para AlertaFacade no pacote alerta, porque não faz parte do caso de uso Lançamento gerar alertas:
AlertaFacade.java:
public class AlertaFacade {
@Inject
private LancamentoFacade lancamentoFacade;
public Alerts getAlerts() {
Alerts alerts = new Alerts();
long contasPagarVencido = lancamentoFacade.contaPagarAbertoAte(LocalDate.now().minusDays(1)).size();
if (contasPagarVencido > 0) {
alerts.add(AlertBuilder
.newInstance()
.danger()
.title(BundleUtils.messageBundle("label.pagarVencido"))
.description(contasPagarVencido + " " + BundleUtils.messageBundle("label.contaPagar"))
.build());
}
long contasPagarVencendo = lancamentoFacade.contaPagarAbertoEm(LocalDate.now()).size();
if (contasPagarVencendo > 0) {
alerts.add(AlertBuilder
.newInstance()
.warning()
.title(BundleUtils.messageBundle("label.pagarVencendo"))
.description(contasPagarVencendo + " " + BundleUtils.messageBundle("label.contaPagar"))
.build());
}
return alerts;
}
}
Refatorei o levantamento de contas pagar vencida e contas pagar vencendo, criando métodos dentro do LancamentoFacade para que possam ser reaproveitados (vou reaproveita-los em breve).
LancamentoFacade.java:
public Collection<LancamentoEntity> contaPagarAbertoAte(LocalDate vencimento) {
return clientJpaql()
.where()
.equalsTo(LancamentoEntity_.aberto, true)
.and()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.lessOrEqualsThan(LancamentoEntity_.vencimento, vencimento)
.collect()
.list();
}
public Collection<LancamentoEntity> contaPagarAbertoEm(LocalDate vencimento) {
return clientJpaql()
.where()
.equalsTo(LancamentoEntity_.aberto, true)
.and()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.equalsTo(LancamentoEntity_.vencimento, vencimento)
.collect()
.list();
}
Enxugando Messages
A implementação do método getMessages() no LancamentoFacade apesar de bem simples tem mais código do que o necessário. Atualmente está assim:
LancamentoFacade.java:
public Messages getMessages() {
Messages messages = new Messages();
Collection<LancamentoEntity> contasPagar = clientJpaql()
.where()
.equalsTo(LancamentoEntity_.tipoLancamento, TipoLancamentoType.PAGAR)
.and()
.lessOrEqualsThan(LancamentoEntity_.vencimento, LocalDate.now())
.and()
.equalsTo(LancamentoEntity_.aberto, true)
.collect()
.list();
contasPagar
.stream()
.filter(l -> l.getVencimento().isBefore(LocalDate.now()))
.sorted(Comparator.comparing(LancamentoEntity::getVencimento).reversed())
.forEach(l -> messages.add(MessageBuilder.newInstance()
.code(l.getId())
.danger()
.title(BundleUtils.messageBundle("label.pagarVencido"))
.description(DateUtils.formatddMMyyyy(l.getVencimento()) + " " + l.getDescricao())
.build()));
contasPagar
.stream()
.filter(l -> l.getVencimento().isEqual(LocalDate.now()))
.sorted(Comparator.comparing(LancamentoEntity::getVencimento).reversed())
.forEach(l -> messages.add(MessageBuilder.newInstance()
.code(l.getId())
.warning()
.title(BundleUtils.messageBundle("label.pagarVencendo"))
.description(DateUtils.formatddMMyyyy(l.getVencimento()) + " " + l.getDescricao())
.build()));
return messages;
}
Vou remover esse método para a classe MensagemFacade no pacote mensagem:
MensagemFacade.java:
public class MensagemFacade {
@Inject
private LancamentoFacade lancamentoFacade;
public Messages getMessages() {
Messages messages = new Messages();
Collection<LancamentoEntity> contasPagar = lancamentoFacade.contaPagarAbertoAte(LocalDate.now());
contasPagar
.stream()
.filter(l -> l.isVencendo())
.sorted(Comparator.comparing(LancamentoEntity::getVencimento).reversed())
.forEach(l -> messages.add(MessageBuilder.newInstance()
.code(l.getId())
.warning()
.title(BundleUtils.messageBundle("label.pagarVencendo"))
.description(DateUtils.formatddMMyyyy(l.getVencimento()) + " " + l.getDescricao())
.build()));
contasPagar
.stream()
.filter(l -> l.isVencido())
.sorted(Comparator.comparing(LancamentoEntity::getVencimento).reversed())
.forEach(l -> messages.add(MessageBuilder.newInstance()
.code(l.getId())
.danger()
.title(BundleUtils.messageBundle("label.pagarVencido"))
.description(DateUtils.formatddMMyyyy(l.getVencimento()) + " " + l.getDescricao())
.build()));
return messages;
}
}
Nessa refatoração além de mover o método getMessages() para o MensagemFacade eu reutilizei o método contaPagarAbertoAte do LancamentoFacade. Implementei também os métodos isVencido() e isVencendo() no LancamentoEntity, porque estamos usando O.O. É responsabilidade da classe LancamentoEntity saber se o lançamento está vencido ou vencendo.
LancamentoEntity.java:
public boolean isVencido() {
return aberto && vencimento.isBefore(LocalDate.now());
}
public boolean isVencendo() {
return aberto && vencimento.isEqual(LocalDate.now());
}
Agora preciso acertar o SessionListener para usar os métodos do AlertaFacade e MensagemFacade.
SessionListener.java:
@WebListener
public class SessionListener implements HttpSessionListener {
@Inject
private SessionInformation sessionInformation;
@Inject
private AlertaFacade alertaFacade;
@Inject
private MensagemFacade mensagemFacade;
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
sessionInformation.put("alerts", alertaFacade.getAlerts());
sessionInformation.put("messages", mensagemFacade.getMessages());
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
//
}
}
Atualizando Alertas e Mensagens
Atualmente a aplicação só está atualizando os alertas e mensagens quando loga na aplicação. Vou acertar para que seja atualizado os alertas e as mensagens quando houver qualquer tipo de evento de CRUD no lançamento:
LancamentoObserver.java:
private void alertaMensagem(@Observes @JArchEventInsertChange(momentPersistMerge = AFTER) LancamentoEntity lancamento, AlertaFacade alertaFacade, MensagemFacade mensagemFacade) {
alertaFacade.atualizaAlertaSessao();
mensagemFacade.atualizaMensagemSessao();
}
private void alertaMensagemExclusao(@Observes @JArchEventDelete(momentRemove = AFTER) LancamentoEntity lancamento, AlertaFacade alertaFacade, MensagemFacade mensagemFacade) {
alertaFacade.atualizaAlertaSessao();
mensagemFacade.atualizaMensagemSessao();
}
Refatorei também as classes AlertaFacade e MensagemFacade adicionando os métodos para atualizar a sessão.
AlertaFacade.java:
public void atualizaAlertaSessao() {
sessionInformation.put("alerts", getAlerts());
}
MensagemFacade.java:
public void atualizaMensagemSessao() {
sessionInformation.put("messages", getMessages());
}
E refatorei também o SessionListener para utilizar esses métodos:
SessionListener.java:
@WebListener
public class SessionListener implements HttpSessionListener {
@Inject
private AlertaFacade alertaFacade;
@Inject
private MensagemFacade mensagemFacade;
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
alertaFacade.atualizaAlertaSessao();
mensagemFacade.atualizaMensagemSessao();
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
//
}
}
Agora sempre que uma conta for incluÃda, alterada ou excluÃda a lista de alertas e mensagens serão atualizadas.
Link Alertas
Vou ajustar agora o link de alertas para abrir a tela de lançamento quando clicado no item. Por exemplo, se clicar no item de contas vencidas somente será mostrado as contas vencidas.
AlertaFacade.java:
public Alerts getAlerts() {
Alerts alerts = new Alerts();
long contasPagarVencido = lancamentoFacade.contaPagarAbertoAte(LocalDate.now().minusDays(1)).size();
if (contasPagarVencido > 0) {
alerts.add(AlertBuilder
.newInstance()
.danger()
.title(BundleUtils.messageBundle("label.pagarVencido"))
.description(contasPagarVencido + " " + BundleUtils.messageBundle("label.contaPagar"))
.link("../lancamento/lancamentoList.jsf?tipo=" + PAGAR + "&status=" + StatusLancamentoType.VENCIDO)
.build());
}
long contasPagarVencendo = lancamentoFacade.contaPagarAbertoEm(LocalDate.now()).size();
if (contasPagarVencendo > 0) {
alerts.add(AlertBuilder
.newInstance()
.warning()
.title(BundleUtils.messageBundle("label.pagarVencendo"))
.description(contasPagarVencendo + " " + BundleUtils.messageBundle("label.contaPagar"))
.link("../lancamento/lancamentoList.jsf?tipo=" + PAGAR + "&status=" + StatusLancamentoType.VENCENDO)
.build());
}
return alerts;
}
Agora estou adicionado o link no builder passando o filtro de tipo e status. Agora preciso alterar o LancamentoListAction para interpretar esses parâmetros. Atente que agora estou usando o enumerado no parâmetro tipo e estou usando um novo enumerado para passar o status. Agora vou refatorar o LancamentoListAction para ler os novos parâmetros.
LancamentoListAction.java:
@PostConstruct
private void init() {
deactiveWhereJpa(LancamentoEntity.FILTRO_VENCIDO);
deactiveWhereJpa(LancamentoEntity.FILTRO_VENCENDO);
tipoLancamento = TipoLancamentoType.valueOf(JsfUtils.getParameterRequest("tipo"));
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_TIPO_LANCAMENTO, "tipoLancamento", tipoLancamento);
String statusParam = JsfUtils.getParameterRequest("status");
if (statusParam != null) {
StatusLancamentoType status = StatusLancamentoType.valueOf(statusParam);
if (StatusLancamentoType.VENCIDO.equals(status)) {
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_VENCIDO, "dataSistema", LocalDate.now());
} else if (StatusLancamentoType.VENCENDO.equals(status)) {
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_VENCENDO, "dataSistema", LocalDate.now());
}
}
if (!parametroUtilizaPessoa.getValue()) {
getColumnDataTable("pessoa.nome").ifPresent(c -> c.hide());
}
}
Estou ativando os filtros de acordo com o status passado. Então preciso implementar o filtro no LancamentoEntity.
LancamentoEntity.java:
@JArchOrderBy(fields = @JArchOrderByField(value = "id", desc = true))
@JArchSearchWhereJpa(id = LancamentoEntity.FILTRO_TIPO_LANCAMENTO,
conditionWhereJpa = "lancamento.tipoLancamento = :tipoLancamento")
@JArchSearchWhereJpa(id = LancamentoEntity.FILTRO_VENCIDO,
conditionWhereJpa = "lancamento.vencimento < :dataSistema")
@JArchSearchWhereJpa(id = LancamentoEntity.FILTRO_VENCENDO,
conditionWhereJpa = "lancamento.vencimento = :dataSistema")
@JArchLookup(codeAttribute = "codigo", descriptionAttribute = "descricao")
@Audited
@Table(name = "tb_lancamento",
indexes = {
@Index(columnList = "cd_lancamento", name = "dx_lancamentocdlan"),
@Index(columnList = "ds_lancamento", name = "dx_lancamentodslan"),
@Index(columnList = "dt_vencimento", name = "dx_lancamentodtven"),
@Index(columnList = "vl_lancamento", name = "dx_lancamentovllan")
})
@Entity(name = "lancamento")
@SequenceGenerator(name = "LancamentoIdSequence", sequenceName = "sq_idlancamento", allocationSize = 1)
public class LancamentoEntity extends CrudMultiTenantEntity {
public static final String FILTRO_TIPO_LANCAMENTO = "lancamentoEntity.filtroTipoLancamento";
public static final String FILTRO_VENCIDO = "lancamentoEntity.filtroVencido";
public static final String FILTRO_VENCENDO = "lancamentoEntity.filtroVencendo";
Novo enumerado:
StatusLancamentoType.java:
public enum StatusLancamentoType {
VENCIDO, VENCENDO, VENCER;
}
Como mudou o parâmetro tipo na chamada do link da página de lançamento, preciso fazer mais alguns ajustes, primeiro deles é acertar o método que retorna a pagina de lista:
LancamentoDataAction.java:
@Override
public String getPageList() {
return "lancamentoList.jsf?tipo=" + tipoLancamento;
}
Na pagina de Bem Vindo, no link dos card's do dashboard preciso ajustar também para passar os parâmetros corretos.
bemVindo.xhtml:
<e:dashboardUnity icon="fa fa-money fa-5x"
classMinHeight="h100"
styleIcon="color: red"
title="#{bemVindoAction.quantidadeContaPagar}"
labelButtonLink="#{e:bundle('label.acessar')}"
link="../lancamento/lancamentoList.jsf?tipo=PAGAR"
descriptionLink="#{e:bundle('message.acessarPagina')}"/>
<e:dashboardUnity icon="fa fa-money fa-5x"
classMinHeight="h100"
styleIcon="color: orange"
title="#{bemVindoAction.quantidadeContaPago}"
labelButtonLink="#{e:bundle('label.acessar')}"
link="../lancamento/lancamentoList.jsf?tipo=PAGAR"
descriptionLink="#{e:bundle('message.acessarPagina')}"/>
<e:dashboardUnity icon="fa fa-money fa-5x"
classMinHeight="h100"
styleIcon="color: blue"
title="#{bemVindoAction.quantidadeContaReceber}"
labelButtonLink="#{e:bundle('label.acessar')}"
link="../lancamento/lancamentoList.jsf?tipo=RECECER"
descriptionLink="#{e:bundle('message.acessarPagina')}"/>
<e:dashboardUnity icon="fa fa-money fa-5x"
classMinHeight="h100"
styleIcon="color: green"
title="#{bemVindoAction.quantidadeContaRecebido}"
labelButtonLink="#{e:bundle('label.acessar')}"
link="../lancamento/lancamentoList.jsf?tipo=RECEBER"
descriptionLink="#{e:bundle('message.acessarPagina')}"/>
Também preciso ajustar o MenuAction passando o tipo correto:
MenuAction.java:
menu.add(MenuBuilder
.newInstance()
.name(BundleUtils.messageBundle("label.lancamento"))
.addSubMenu(MenuBuilder
.newInstance()
.name(BundleUtils.messageBundle("label.contaPagar"))
.action("../lancamento/lancamentoList.jsf?tipo=" + TipoLancamentoType.PAGAR)
.build())
.addSubMenu(MenuBuilder
.newInstance()
.name(BundleUtils.messageBundle("label.contaReceber"))
.action("../lancamento/lancamentoList.jsf?tipo=" + TipoLancamentoType.RECEBER)
.build())
.build());
Agora clicando no item do menu alerta será direcionado direto pra página de lista de lançamento com os registros filtrados:
Link Mensagens
Vou ajustar agora o link de mensagens para abrir a tela de lançamento quando clicado no item. Vou adicionar o filtro por ID no link da mensagem, abrindo somente com aquele registro:
MensagemFacade.java:
public Messages getMessages() {
Messages messages = new Messages();
Collection<LancamentoEntity> contasPagar = lancamentoFacade.contaPagarAbertoAte(LocalDate.now());
contasPagar
.stream()
.filter(l -> l.isVencendo())
.sorted(Comparator.comparing(LancamentoEntity::getVencimento).reversed())
.forEach(l -> messages.add(MessageBuilder.newInstance()
.code(l.getId())
.warning()
.title(BundleUtils.messageBundle("label.pagarVencendo"))
.description(DateUtils.formatddMMyyyy(l.getVencimento()) + " " + l.getDescricao())
.link("../lancamento/lancamentoList.jsf?tipo=" + TipoLancamentoType.PAGAR + "&id=" + l.getId())
.build()));
contasPagar
.stream()
.filter(l -> l.isVencido())
.sorted(Comparator.comparing(LancamentoEntity::getVencimento).reversed())
.forEach(l -> messages.add(MessageBuilder.newInstance()
.code(l.getId())
.danger()
.title(BundleUtils.messageBundle("label.pagarVencido"))
.description(DateUtils.formatddMMyyyy(l.getVencimento()) + " " + l.getDescricao())
.link("../lancamento/lancamentoList.jsf?tipo=" + TipoLancamentoType.PAGAR + "&id=" + l.getId())
.build()));
return messages;
}
LancamentoListAction.java:
@PostConstruct
private void init() {
deactiveWhereJpa(LancamentoEntity.FILTRO_VENCIDO);
deactiveWhereJpa(LancamentoEntity.FILTRO_VENCENDO);
deactiveWhereJpa(LancamentoEntity.FILTRO_ID);
tipoLancamento = TipoLancamentoType.valueOf(JsfUtils.getParameterRequest("tipo"));
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_TIPO_LANCAMENTO, "tipoLancamento", tipoLancamento);
String statusParam = JsfUtils.getParameterRequest("status");
if (statusParam != null) {
StatusLancamentoType status = StatusLancamentoType.valueOf(statusParam);
if (StatusLancamentoType.VENCIDO.equals(status)) {
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_VENCIDO, "dataSistema", LocalDate.now());
} else if (StatusLancamentoType.VENCENDO.equals(status)) {
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_VENCENDO, "dataSistema", LocalDate.now());
}
}
String id = JsfUtils.getParameterRequest("id");
if (id != null) {
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_ID, "id", Long.valueOf(id));
}
if (!parametroUtilizaPessoa.getValue()) {
getColumnDataTable("pessoa.nome").ifPresent(c -> c.hide());
}
}
Agora vou adicionar o filtro de ID no LancamentoEntity:
LancamentoEntity:
@JArchOrderBy(fields = @JArchOrderByField(value = "id", desc = true))
@JArchSearchWhereJpa(id = LancamentoEntity.FILTRO_TIPO_LANCAMENTO,
conditionWhereJpa = "lancamento.tipoLancamento = :tipoLancamento")
@JArchSearchWhereJpa(id = LancamentoEntity.FILTRO_VENCIDO,
conditionWhereJpa = "lancamento.vencimento < :dataSistema")
@JArchSearchWhereJpa(id = LancamentoEntity.FILTRO_VENCENDO,
conditionWhereJpa = "lancamento.vencimento = :dataSistema")
@JArchSearchWhereJpa(id = LancamentoEntity.FILTRO_ID,
conditionWhereJpa = "lancamento.id = :id")
@JArchLookup(codeAttribute = "codigo", descriptionAttribute = "descricao")
@Audited
@Table(name = "tb_lancamento",
indexes = {
@Index(columnList = "cd_lancamento", name = "dx_lancamentocdlan"),
@Index(columnList = "ds_lancamento", name = "dx_lancamentodslan"),
@Index(columnList = "dt_vencimento", name = "dx_lancamentodtven"),
@Index(columnList = "vl_lancamento", name = "dx_lancamentovllan")
})
@Entity(name = "lancamento")
@SequenceGenerator(name = "LancamentoIdSequence", sequenceName = "sq_idlancamento", allocationSize = 1)
public class LancamentoEntity extends CrudMultiTenantEntity {
public static final String FILTRO_TIPO_LANCAMENTO = "lancamentoEntity.filtroTipoLancamento";
public static final String FILTRO_VENCIDO = "lancamentoEntity.filtroVencido";
public static final String FILTRO_VENCENDO = "lancamentoEntity.filtroVencendo";
public static final String FILTRO_ID = "lancamentoEntity.filtroId";
Agora ao clicar no item de mensagem abre a tela de lista filtrado na conta selecionado:
Filtro Vencimento e Valor
Na tela de lançamento vou alterar o filtro de vencimento e valor para que o combobox fique desabilitado:
LancamentoListAction.java:
@PostConstruct
private void init() {
deactiveWhereJpa(LancamentoEntity.FILTRO_VENCIDO);
deactiveWhereJpa(LancamentoEntity.FILTRO_VENCENDO);
deactiveWhereJpa(LancamentoEntity.FILTRO_ID);
tipoLancamento = TipoLancamentoType.valueOf(JsfUtils.getParameterRequest("tipo"));
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_TIPO_LANCAMENTO, "tipoLancamento", tipoLancamento);
String statusParam = JsfUtils.getParameterRequest("status");
if (statusParam != null) {
StatusLancamentoType status = StatusLancamentoType.valueOf(statusParam);
if (StatusLancamentoType.VENCIDO.equals(status)) {
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_VENCIDO, "dataSistema", LocalDate.now());
} else if (StatusLancamentoType.VENCENDO.equals(status)) {
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_VENCENDO, "dataSistema", LocalDate.now());
}
}
String id = JsfUtils.getParameterRequest("id");
if (id != null) {
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_ID, "id", Long.valueOf(id));
}
if (!parametroUtilizaPessoa.getValue()) {
getColumnDataTable("pessoa.nome").ifPresent(c -> c.hide());
}
getFieldSearch("vencimentoInicio").ifPresent(f -> f.disabledCondition(true));
getFieldSearch("vencimentoFim").ifPresent(f -> f.disabledCondition(true));
getFieldSearch("valorInicio").ifPresent(f -> f.disabledCondition(true));
getFieldSearch("valorFim").ifPresent(f -> f.disabledCondition(true));
}
O getFieldSearch acima está buscando o campo pelo ID porque como existe mais de uma campo com o mesmo atributo foi necessário colocar um ID pra eles. Segue a implementação:
package-info.java:
@JArchSearchTab(order = 1,
searchFields = {
@JArchSearchField(clazzEntity = LancamentoEntity.class, attribute = "codigo", label = "label.codigo", type = FieldType.CODE, row = 1, column = 1, span = 3),
@JArchSearchField(clazzEntity = LancamentoEntity.class, attribute = "descricao", label = "label.descricao", type = FieldType.DESCRIPTION, row = 1, column = 2, span = 9),
@JArchSearchField(clazzEntity = LancamentoEntity.class, id = "vencimentoInicio", attribute = "vencimento", label = "label.vencimento", type = FieldType.DATE, condition = ConditionSearchType.LARGER_EQUAL, row = 2, column = 1, span = 3),
@JArchSearchField(clazzEntity = LancamentoEntity.class, id = "vencimentoFim", attribute = "vencimento", label = "label.vencimento", type = FieldType.DATE, condition = ConditionSearchType.LESS_EQUAL, row = 2, column = 2, span = 3),
@JArchSearchField(clazzEntity = LancamentoEntity.class, id = "valorInicio", attribute = "valor", label = "label.valor", type = FieldType.MONEY, condition = ConditionSearchType.LARGER_EQUAL, row = 2, column = 2, span = 3),
@JArchSearchField(clazzEntity = LancamentoEntity.class, id = "valorFim", attribute = "valor", label = "label.valor", type = FieldType.MONEY, condition = ConditionSearchType.LESS_EQUAL, row = 2, column = 3, span = 3),
})
@JArchColumnDataTable(clazzEntity = LancamentoEntity.class, attribute ="codigo", title = "label.codigo", width = 90, type = FieldType.CODE)
@JArchColumnDataTable(clazzEntity = LancamentoEntity.class, attribute ="descricao", title = "label.descricao", width = 270, type = FieldType.DESCRIPTION)
@JArchColumnDataTable(clazzEntity = LancamentoEntity.class, attribute ="pessoa.nome", title = "label.pessoa", width = 270, type = FieldType.NAME)
@JArchColumnDataTable(clazzEntity = LancamentoEntity.class, attribute ="aberto", title = "label.aberto", width = 60, type = FieldType.BOOLEAN)
@JArchColumnDataTable(clazzEntity = LancamentoEntity.class, attribute ="vencimento", title = "label.vencimento", width = 90, type = FieldType.DATE)
@JArchColumnDataTable(clazzEntity = LancamentoEntity.class, attribute ="valor", title = "label.valor", width = 100, type = FieldType.MONEY)
package br.com.jarch.contas.client.lancamento;
Executando o código acima:
Repare que agora os combobox de Vencimento e Valor estão desabilitados.
Evento Login
O levantamento de alertas e mensagens está sendo feito no momento da criação da sessão no SessionListener. Quando a aplicação possuà somente um tenant não tem problema, mas quando mais de um é usado o resultado não será o correto. Porque no momento da criação da sessão o tenant ainda não foi configurado pelo JARCH. Para corrigir isso vamos interceptar o evento de login e implementar a atualização das informações de alertas e mensagens nele. Vou criar um Observer de login no pacote de login.
LoginObserver.java:
public class LoginObserver {
private void login(@Observes @JArchEventLoginAfter IUser user, AlertaFacade alertaFacade, MensagemFacade mensagemFacade) {
alertaFacade.atualizaAlertaSessao();
mensagemFacade.atualizaMensagemSessao();
}
}
Conclusão
Nesse post fiz diversas refatorações para reaproveitamento do código, fiz também alguns ajustes de lógica, melhoria nos alertas e mensagens, desabilitei o combobox para pesquisa por intervalo (vencimento e valor), e por último mostrei o evento de login. No próximo post vou continuar com a implementação do sistema utilizando recursos do JARCH.
Segue o link dessa video aula: https://youtu.be/khX-efWuWlA
Até mais,
Nenhum comentário:
Postar um comentário