quarta-feira, 7 de outubro de 2020

Versão 20.9.0-Final

 

Introdução

Nesse post vou mostrar as principais novidades da versão 20.9.0, algumas correções e pequenas alterações.

Implementações

Segue abaixo as implementações dessa versão:
- Adicionado  no DataDetail o método refresh()
- Adicionado no e:tabBody os facets bottomLeft, bottomCenter e bottomRight
- Adicionado a anotação @JArchParameterFilterSystem para configurar uma Collection<String> quer será filtrado os sistemas nos parâmetros
- Implementação do campo de Ordenação na tela de lista de tarefas do BPM
- Adicionado propriedades de paginação na taskList.xhtml e no IBaseListTaskAction
- Adicionado novo tipo de dados CHIPS no FieldType, para utilização do component chips do Primefaces

Alterações

Além das implementações descritas acima foram feitas algumas alterações:
- Depreciado o atributo attributes em @JArchValidExclusives, utilizar o atributo fields em seu lugar
- Refatoração no DataDetail para não ser necessário passar o entityMaster (exceção do createDataModelFrom)
- Ajuste na LazyDataModelPaginator para tratar o getRowKey() e getRowData()
- Removido métodos depreciados no JsfUtils

Correções

Além das alterações descritas acima esta versão contempla algumas correções:
- Corrigido o CrudManager para quando for disparado os eventos de alteração dentro da mesma transação do INSERT não ocorrer erro de NullPointerException
- Correção no @JArchValidRequiredOneOfManyField para colocar os nomes do labels de cada campo na mensagem de erro

Conclusão

Essa versão contempla algumas melhorias e correções. É recomendável a atualização para essa nova versão.

Até mais,

quinta-feira, 3 de setembro de 2020

Versão 20.8.0-Final

Introdução

Nesse post vou mostrar as principais novidades da versão 20.8.0, algumas correções e pequenas alterações.

Implementações

Segue abaixo as implementações dessa versão:
- Adicionado novo evento @JArchEventSearchConfig para interceptar o ISearch depois de configurado
- Adicionado o método estático getInstance() no UserInformation

Alterações

Além das implementações descritas acima foram feitas algumas alterações:
- Ajuste na geração da mensagem via BeanValidation para não adicionar os fields quando for setado o atributo message
- Depreciado o clazzEntity do @JArchSearchField, utilizar o atributo classEntity
- Depreciado o clazzEntity do @JArchColumnDataTable, utilizar o atributo classEntity
- Depreciado o clazzEntity do @JArchSearchFieldCheckbox, utilizar o atributo classEntity
- Depreciado o clazzEntity do @JArchSearchFieldCombobox, utilizar o atributo classEntity
- Depreciado o clazzEntity do @JArchSearchFieldComboboxCommandJpa, utilizar o atributo classEntity
- Removido o atributo tenant das anotações e adicionado o atributo enable para ser especificado um classe que implemente Supplier<Boolean> (Para habilitar ou desabilitar em tempo de execução)
- Depreciado o attribute do @JArchSearchField, utilizar o atributo field
- Depreciado o attribute do @JArchSearchFieldCheckbox, utilizar o atributo field
- Depreciado o attribute do @JArchSearchFieldCombobox, utilizar o atributo field
- Depreciado o attribute do @JArchSearchLookup, utilizar o atributo field
- Depreciado o attribute do @JArchColumnDataTable, utilizar o atributo field
- Depreciado o attributeOrId do @JArchColumnDataTableShow, utilizar o atributo fieldOrId
- Depreciado o attributeItems e attributeShow do @JArchSearchFieldCombobox, utilizar o atributo fieldItems e fieldShow
- Depreciado  attributeItems, attributeShow e attributeCommandJpa do @JArchSearchFieldComboboxCommandJpa, utilizar o atributo fieldItems, fieldShow e fieldCommandJpa
- Removido os métodos exportaExcel e exportaPdf do BaseListAction que estavam depreciados desde 2018
- Removido do webSocket.js do carregamento no templateBaseV2.xhtml, quem precisar utilizar basta somente adicionar em sua página

Correções

Além das alterações descritas acima esta versão contempla algumas correções:
- Correção no componente e:lookup que não estava efetuando o filtro na tela de pesquisa
- Correção na geração do código para o tamanho do tipo Boolean ser igual 1
- Correção na chamada do @JArchCrudDataAfterSave que estava duplicando quando a definição do método estava na própria classe

Conclusão

Essa versão contempla algumas melhorias e correções. É recomendável a atualização para essa nova versão.

Até mais,

terça-feira, 25 de agosto de 2020

Contas Pagar/Receber - Parte XXVIII - Pequenos Ajustes e Refatorações

Introdução
Nesse vigésimo oitavo post vou fazer algumas refatorações e pequenos ajustes na aplicação. 

Correção Aprovação
Nossa aplicação está ocorrendo um erro quando uma conta é aprovada, esse problema está ocorrendo porque utilizei o momento errado de interceptar o evento da ação dinâmica. No LancamentoObserver existe o seguinte método:
LancamentoObserver.java:

private void avaliacao(@Observes @JArchEventDynamicBefore(Constant.ID_AVALIAR_LANCAMENTO)                      LancamentoEntity lancamento, UserInformation userInformation,                      TaskService taskService) {
UsuarioEntity usuarioLogado = userInformation.get(UsuarioEntity.class);

String variavelAprovacao;

if (usuarioLogado.getCargo() == CargoType.SUPERVISOR) {
variavelAprovacao = "aprovadoSupervisor";
} else if (usuarioLogado.getCargo() == CargoType.GERENTE) {
variavelAprovacao = "aprovadoGerente";
} else {
variavelAprovacao = "aprovadoDiretor";
}

taskService.complete(lancamento.getTask().get().getId(),
Map.of(variavelAprovacao, lancamento.isAprovado(),
"valorLancamento", lancamento.getValor().doubleValue()));
}
Vou alterar o @JArchEventDynamicBefore para @JArchEventDynamicAfter:

private void avaliacao(@Observes @JArchEventDynamicAfter(Constant.ID_AVALIAR_LANCAMENTO)                      LancamentoEntity lancamento, UserInformation userInformation,                      TaskService taskService) {
UsuarioEntity usuarioLogado = userInformation.get(UsuarioEntity.class);

String variavelAprovacao;

if (usuarioLogado.getCargo() == CargoType.SUPERVISOR) {
variavelAprovacao = "aprovadoSupervisor";
} else if (usuarioLogado.getCargo() == CargoType.GERENTE) {
variavelAprovacao = "aprovadoGerente";
} else {
variavelAprovacao = "aprovadoDiretor";
}

taskService.complete(lancamento.getTask().get().getId(),
Map.of(variavelAprovacao, lancamento.isAprovado(),
"valorLancamento", lancamento.getValor().doubleValue()));
}
Ordem Download Comprovante
Na tela de lista de lançamentos o atributo order está setado como 3 conflitando com o a ação dinâmica de avaliar conta, vou alterar o valor para 4:
LancamentoListAction.java:

@JArchDynamicDownload(id = "idDownloadComprovanteBaixa", labelMenu = "label.comprovanteBaixa", 
    order = 4, elDisabled = "#{(l -> l.aberto)(lancamento)}")
public StreamedContent downloadComprovanteBaixa(LancamentoEntity lancamento) {
return getFacade().downloadComprovanteBaixa(lancamento);
}
Refatoração init() do LancamentoListAction
O método init() no LancamentoListAction apesar de bem escrito e legível podemos melhorar usa leitura refatorando em pequenos métodos. Atualmente o método está implementado da seguinte maneira:
LancamentoListAction.java:

@PostConstruct
private void init() {
if (isStartedWorkFlow()) {
Long idLancamento = Long.valueOf(getTask().get().getBusinessKey());
LancamentoEntity lancamento = getFacade().find(idLancamento);
tipoLancamento = lancamento.getTipoLancamento();
callActionDynamic(idLancamento, Constant.ID_AVALIAR_LANCAMENTO);
return;
}

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));
}
Vou começar refatorando pelo primeiro IF onde verificar se a chamada foi feito via lista de tarefa (BPM).
@PostConstruct
private void init() {
if (isStartedWorkFlow()) {
chamaAvalicaoConta();
return;
}

private void chamaAvalicaoConta() {
Long idLancamento = Long.valueOf(getTask().get().getBusinessKey());
LancamentoEntity lancamento = getFacade().find(idLancamento);
tipoLancamento = lancamento.getTipoLancamento();
callActionDynamic(idLancamento, Constant.ID_AVALIAR_LANCAMENTO);
}
Agora vou refatorar também onde está limpando os filtros:
@PostConstruct
private void init() {
if (isStartedWorkFlow()) {
chamaAvalicaoConta();
return;
}

limpaFiltros();

private void limpaFiltros() {
deactiveWhereJpa(LancamentoEntity.FILTRO_VENCIDO);
deactiveWhereJpa(LancamentoEntity.FILTRO_VENCENDO);
deactiveWhereJpa(LancamentoEntity.FILTRO_ID);
}
Agora vou ajustar o filtro de tipo de lancamento:
@PostConstruct
private void init() {
if (isStartedWorkFlow()) {
chamaAvalicaoConta();
return;
}

limpaFiltros();

configuraFiltroTipoLancamento();

private void configuraFiltroTipoLancamento() {
tipoLancamento = TipoLancamentoType.valueOf(JsfUtils.getParameterRequest("tipo"));
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_TIPO_LANCAMENTO, "tipoLancamento", tipoLancamento);
}
Agora vou ajustar o filtro de status:
@PostConstruct
private void init() {
if (isStartedWorkFlow()) {
chamaAvalicaoConta();
return;
}

limpaFiltros();

configuraFiltroTipoLancamento();

configuraFiltroStatus();

private void configuraFiltroStatus() {
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());
}
}
}
Agora o filtro por ID:
@PostConstruct
private void init() {
if (isStartedWorkFlow()) {
chamaAvalicaoConta();
return;
}

limpaFiltros();

configuraFiltroTipoLancamento();

configuraFiltroStatus();

configuraFiltroId();
private void configuraFiltroId() {
String id = JsfUtils.getParameterRequest("id");
if (id != null) {
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_ID, "id", Long.valueOf(id));
}
}
Agora configuração de visualização da coluna nome da pessoa no datatable:
@PostConstruct
private void init() {
if (isStartedWorkFlow()) {
chamaAvalicaoConta();
return;
}

limpaFiltros();

configuraFiltroTipoLancamento();

configuraFiltroStatus();

configuraFiltroId();

configuraVisualizacaoColunaPessoa();
private void configuraVisualizacaoColunaPessoa() {
if (!parametroUtilizaPessoa.getValue()) {
getColumnDataTable("pessoa.nome").ifPresent(c -> c.hide());
}
}
E por último o bloqueio das condições de datas e valores na div de pesquisa:
@PostConstruct
private void init() {
if (isStartedWorkFlow()) {
chamaAvalicaoConta();
return;
}

limpaFiltros();

configuraFiltroTipoLancamento();

configuraFiltroStatus();

configuraFiltroId();

configuraVisualizacaoColunaPessoa();

desabilitaCondicaoIntervalo();
}
private void desabilitaCondicaoIntervalo() {
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));
}
Conclusão
Nesse post fiz algumas melhorias no código. Melhorias no código devem ser frequentemente aplicadas, principamente quando o código sofre constantes alterações ou implementações. Uma boa prática de programação é sempre manter o código mais simples possível, ser auto documentado, utilização de boas práticas de programação orientada a objetos, buscando sempre a coesão e desacoplamento.

Segue o link dessa video aula: https://youtu.be/pSWQI6Qka3c

Até mais,

quinta-feira, 6 de agosto de 2020

Contas Pagar/Receber - Parte XXVII - Eliminando Task Chamar Atenção

Introdução
Nesse vigésimo sétimo post vou fazer que a Task de Chamar Atenção (Supervisor e Gerente) deixe de existir quando o usuário (Supervisor ou Gerente) finalizar a Task de avaliação. 

Task Chamar Atenção
Nas tarefas de Avaliar Conta tanto do Supervisor quanto do Gerente existe uma evento de borda de Timer que gera uma Task de Chamar Atenção caso o prazo estipulado seja atingido. Atualmente deixei configurado como 5 minutos, caso o usuário responsável pela Task não finalize dentro do prazo é gerado uma Task para seu superior lhe chamar a atenção. Depois que essa Task de Chamar Atenção é criada, mesmo o usuário finalizando a Task de Avaliar Conta, a Task de Chamar Atenção ainda continua existindo na lista de tarefas do seu superior. Para resolver isso vou criar um outro evento de borda para que quando a variável de aprovação for adicionada ao fluxo essa tarefa deixa de existir. Vou fazer essa implementação primeiro na Task de Chamar Atenção Supervisor:
  

Repare que utilizei o componente Conditional Boundary, preenchi o campo Variable Name com aprovadoSupervisor, Condition Type como Expression e Expression com a EL #{aprovadoSupervisor ne null}. 
Agora vou fazer a mesma coisa com a task Chamar Atenção Gerente:

Executei o mesmo procedimento, somente alterando o nome da variável de aprovadoSupervisor para aprovadoGerente.

Com essa implementação, agora mesmo após a criação da tarefa de Chamar Atenção, quando o usuário finalizar a tarefa de Avaliar Conta a Task de Chamar Atenção vai deixar de existir.

Conclusão
Nesse post eu utilizei o evento de borda de condição para eliminar a Task de Chamar Atenção quando o usuário finalizar a avaliação da conta.

Segue o link dessa video aula: https://youtu.be/p_XejiN_lF4

Até mais,

Versão 23.3.0-Final

      Introdução Nesse post vou mostrar as principais novidades da versão 23.3.0, algumas correções e pequenas alterações. Alterações Além d...