Introdução
Nesse sexto post vou mostrar a criação das lógicas de lançamento de Conta Pagar e Conta Receber.
As lógicas de Conta Pagar e Conta Receber conterão os seguintes campos: Código, Descrição, Banco, Centro Custo, Categoria, Pessoa, Vencimento, Valor, Aberto. Mas são 2 lógicas distintas e podem até ser acessadas por usuários diferentes, por exemplo, departamentos de compras e vendas. Em uma empresa normalmente são pessoas diferentes que atuam nessas áreas. Então nesse caso vou criar uma lógica com o nome de Lançamento e criar um campo a mais para identificar o tipo da conta (Pagar ou Receber). Eu poderia usar outra abordagem como criar uma classe abstrata e fazer a implementação dessas lógicas estendendo dessa classe, mas vou utilizar a primeira solução. Segue a definição dessa lógica no package-info.java:
@JArchGenerateLogicCrud(nameSubPackage = "lancamento",
master = @JArchGenerateMaster(name = "Lançamento", tableName = "tb_lancamento",
fields = {
@JArchGenerateField(fieldName = "codigo", fieldTable = "cd_lancamento", description = "Código",
type = FieldType.CODE, codeLookup = true, required = true,
search = @JArchGenerateSearch(row = 1, column = 1, span = 3),
xhtml = @JArchGenerateXhtml(rowDataXhtml = 1, columnDataXhtml = 1, showDataTableList = true)),
@JArchGenerateField(fieldName = "descricao", fieldTable = "ds_lancamento", description = "Descrição",
type = FieldType.DESCRIPTION, descriptionLookup = true, required = true,
search = @JArchGenerateSearch(row = 1, column = 2, span = 9),
xhtml = @JArchGenerateXhtml(rowDataXhtml = 1, columnDataXhtml = 2, showDataTableList = true)),
@JArchGenerateField(fieldName = "banco", fieldTable = "id_banco", description = "Banco",
type = FieldType.ENTITY, required = true, search = {},
xhtml = @JArchGenerateXhtml(rowDataXhtml = 2, columnDataXhtml = 4, showDataTableList = false)),
@JArchGenerateField(fieldName = "centroCusto", fieldTable = "id_centrocusto", description = "Centro Custo",
type = FieldType.ENTITY, required = true, search = {},
xhtml = @JArchGenerateXhtml(rowDataXhtml = 3, columnDataXhtml = 1, showDataTableList = false)),
@JArchGenerateField(fieldName = "categoria", fieldTable = "id_categoria", description = "Categoria",
type = FieldType.ENTITY, required = true, search = {},
xhtml = @JArchGenerateXhtml(rowDataXhtml = 4, columnDataXhtml = 1, showDataTableList = false)),
@JArchGenerateField(fieldName = "pessoa", fieldTable = "id_pessoa", description = "Pessoa",
type = FieldType.ENTITY, required = true, search = {},
xhtml = @JArchGenerateXhtml(rowDataXhtml = 5, columnDataXhtml = 1, showDataTableList = false)),
@JArchGenerateField(fieldName = "vencimento", fieldTable = "dt_vencimento", description = "Vencimento",
type = FieldType.DATE, required = true,
search = @JArchGenerateSearch(row = 2, column = 1, span = 3),
xhtml = @JArchGenerateXhtml(rowDataXhtml = 6, columnDataXhtml = 1, showDataTableList = true)),
@JArchGenerateField(fieldName = "valor", fieldTable = "vl_lancamento", description = "Valor",
type = FieldType.MONEY, required = true,
search = @JArchGenerateSearch(row = 2, column = 2, span = 3),
xhtml = @JArchGenerateXhtml(rowDataXhtml = 6, columnDataXhtml = 2, showDataTableList = true)),
@JArchGenerateField(fieldName = "aberto", fieldTable = "sn_aberto", description = "Aberto",
type = FieldType.BOOLEAN, search = {}, xhtml = {}),
@JArchGenerateField(fieldName = "tipoLancamento", fieldTable = "tp_lancamento", description = "Tipo Lançamento",
type = FieldType.TYPE, required = true, search = {}, xhtml = {}),
}
)
)
Algumas observações nessa definição acima:
1.) Estou adicionando os campos Banco, Centro Custo, Categoria e Pessoa com o tipo FieldType.ENTITY. Esse tipo vai criar no XHTML o componente e:lookup.
2.) Os campos Vencimento (FieldType.DATE) e Valor (FieldType.MONEY) vai gerar um duplo filtro pra cada campo. O JARCH quando gera o código e os tipos DATE e MONEY são utilizados como pesquisa ele cria dois campos para poder usar como intervalo.
3.) Como vou utilizar esse caso de uso para 2 lógicas diferentes (Pagar e Receber) então estou criando um campo para identificação do tipo da lógica (tipoLancamento). Esse campo é do tipo TYPE então o JARCH vai gerar um ENUM e um Converter JPA para esse atributo.
E executando o MAVEN com CLEAN COMPILE PACKAGE via IDE ou linha de comando temos:
Olhando os arquivos gerados temos um Converter JPA e um ENUM conforme:
TipoLancamentoJpaConverter.java


@Converter(autoApply = true)
public class TipoLancamentoJpaConverter implements AttributeConverter<TipoLancamentoType, String> {
@Override
public String convertToDatabaseColumn(TipoLancamentoType valueEnum) {
return valueEnum == null ? null : valueEnum.getAbbreviation();
}
@Override
public TipoLancamentoType convertToEntityAttribute(String valueDataBase) {
return valueDataBase == null ? null : TipoLancamentoType.abbreviationToEnum(valueDataBase);
}
}
TipoLancamentoType.java
public enum TipoLancamentoType {
FILL_TYPE1("FT1", "label.fillType1"),
FILL_TYPE2("FT2", "label.fillType2"),
FILL_TYPE3("FT3", "label.fillType3");
private final String abbreviation;
private final String description;
TipoLancamentoType(String abbreviation, String description) {
this.abbreviation = abbreviation;
this.description = description;
}
public String getAbbreviation () {
return abbreviation;
}
public String getDescription () {
return BundleUtils.messageBundle(description);
}
public static TipoLancamentoType abbreviationToEnum(String abbreviation){
return Arrays.stream(values()).filter(m -> m.getAbbreviation().equals(abbreviation)).findAny().orElse(null);
}
public static Collection<TipoLancamentoType> getCollection() {
return Arrays.stream(values()).collect(Collectors.toCollection(ArrayList::new));
}
}
Agora vou ajustar o ENUM gerado anteriormente para colocar os tipos PAGAR e RECEBER:
public enum TipoLancamentoType {
PAGAR("PAG", "label.contaPagar"),
RECEBER("REC", "label.contaReceber");
private final String abbreviation;
private final String description;
TipoLancamentoType(String abbreviation, String description) {
this.abbreviation = abbreviation;
this.description = description;
}
public String getAbbreviation () {
return abbreviation;
}
public String getDescription () {
return BundleUtils.messageBundle(description);
}
public static TipoLancamentoType abbreviationToEnum(String abbreviation){
return Arrays.stream(values()).filter(m -> m.getAbbreviation().equals(abbreviation)).findAny().orElse(null);
}
public static Collection<TipoLancamentoType> getCollection() {
return Arrays.stream(values()).collect(Collectors.toCollection(ArrayList::new));
}
}
Agora vou ajustar o MenuAction para adicionar os itens de menu de Conta Pagar e Conta Receber no menu Lançamento. Repare que o link de ambos chamam a mesma página mas com conteudo do parâmetro tipo diferente:
menu.add(MenuBuilder
.newInstance()
.name(BundleUtils.messageBundle("label.lancamento"))
.addSubMenu(MenuBuilder
.newInstance()
.name(BundleUtils.messageBundle("label.contaPagar"))
.action("../lancamento/lancamentoList.jsf?tipo=PAG")
.build())
.addSubMenu(MenuBuilder
.newInstance()
.name(BundleUtils.messageBundle("label.contaReceber"))
.action("../lancamento/lancamentoList.jsf?tipo=REC")
.build())
.build());
Adicionado no bundle_pt_BR.properties as chaves label.contaPagar e label.contaReceber:
label.contaPagar=Conta Pagar
label.contaReceber=Conta Receber
Agora vou ajustar as Action's de Lista e Dados para saber trabalhar com parâmetro tipo recebido via URL:
LancamentoListAction.java: Vou definir um atributo com o nome de tipoLancamento do tipo TipoLancamentoType e preenche-lo na criação da instância da Action. Repare que também estou utilizando o método activeAndAddParamWhereJpa para filtrar os lançamentos somente do tipo dessa tela. Esse filtro foi definido no LancamentoEntity através da anotação @JArchWhereJpa do JARCH. O método getPageData() também foi alterado para passar o parâmetro para a tela de dados.
LancamentoListAction.java
@JArchViewScoped
public class LancamentoListAction extends CrudListAction<LancamentoEntity, LancamentoFacade> {
private TipoLancamentoType tipoLancamento;
@PostConstruct
private void init() {
tipoLancamento = TipoLancamentoType.abbreviationToEnum(JsfUtils.getParameterRequest("tipo"));
activeAndAddParamWhereJpa(LancamentoEntity.FILTRO_TIPO_LANCAMENTO, "tipoLancamento", tipoLancamento);
}
@Override
public String getPageData() {
return "lancamentoData.jsf?tipo=" + tipoLancamento.getAbbreviation();
}
public TipoLancamentoType getTipoLancamento() {
return tipoLancamento;
}
}
Segue a implementação do @JArchWhereJpa.
LancamentoEntity.java:
@JArchSearchWhereJpa(id = LancamentoEntity.FILTRO_TIPO_LANCAMENTO,
conditionWhereJpa = "lancamento.tipoLancamento = :tipoLancamento")
@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";
Na Action de dados também implementei a definição do tipo do lançamento (igual ao lista):
LancamentoDataAction.java:
@JArchViewScoped
public class LancamentoDataAction extends CrudDataAction<LancamentoEntity, LancamentoFacade> {
private TipoLancamentoType tipoLancamento;
@PostConstruct
private void init() {
tipoLancamento = TipoLancamentoType.abbreviationToEnum(JsfUtils.getParameterRequest("tipo"));
if (isStateInsert()) {
getEntity().setTipoLancamento(tipoLancamento);
}
}
@Override
public String getPageList() {
return "lancamentoList.jsf?tipo=" + tipoLancamento.getAbbreviation();
}
public TipoLancamentoType getTipoLancamento() {
return tipoLancamento;
}
}
E pra finalizar ajustar o lancamentoList.xhtml e lancamentoData.xhtml para mostrar os labels do tipo da conta selecionada pelo menu:
lancamentoList.xhtml:
lancamentoList.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:e="http://jarch.com.br/ui/extension">
<ui:composition template="/paginas/templates/templateListaV2.xhtml">
<ui:define name="panelBodyTemplateLista">
<e:form>
<e:divTitle
title="#{e:bundle('label.lista')} - #{lancamentoListAction.tipoLancamento.description}"
description="#{e:bundle('label.manter')} #{lancamentoListAction.tipoLancamento.description}"/>
<e:divListFilter
title="#{e:bundle('label.filtro')} - #{lancamentoListAction.tipoLancamento.description}"
actionList="#{lancamentoListAction}"
update="@(.list-datatable)"/>
<e:divListDatatable id="listEntityDataTableLancamento"
title="#{e:bundle('label.lista')} - #{lancamentoListAction.tipoLancamento.description}"
actionList="#{lancamentoListAction}" />
</e:form>
</ui:define>
</ui:composition>
</html>
lancamentoData.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:a="http://jarch.com.br/ui"
xmlns:e="http://jarch.com.br/ui/extension">
<ui:composition template="/paginas/templates/templateDadosV2.xhtml">
<ui:define name="panelBodyTemplateDados">
<e:form>
<e:divTitle
title="#{lancamentoDataAction.tipoLancamento.description} - #{lancamentoDataAction.labelAction}"
description="#{e:bundle('label.manter')} #{lancamentoDataAction.tipoLancamento.description}"/>
<e:divDataMaster
title="#{lancamentoDataAction.tipoLancamento.description}"
actionData="#{lancamentoDataAction}">
<a:panelGrid columns="2">
<h:panelGroup>
<a:outputLabel value="#{e:bundle('label.codigo')}" for="idLancamentoCodigo"/>
<br/>
<a:inputText id="idLancamentoCodigo" styleClass="input-code"
disabled="#{lancamentoDataAction.blockedMaster}"
label="#{e:bundle('label.codigo')}" value="#{lancamentoDataAction.entity.codigo}"
required="true"/>
</h:panelGroup>
Compilando e publicando a aplicação agora teremos:

Conclusão
Nesse post vimos como podemos reaproveitar lógicas com estruturas identicas, adicionar filtros adicionais dentro da Action de lista. O componente e:lookup otimiza e facilita a seleção de dados sem precisar implementar nada. No próximo post vamos explorar mais esses recursos.
Segue o link dessa da video aula desse post: https://youtu.be/Af9y4IFJGj0
Até mais,
Nenhum comentário:
Postar um comentário