E-mail de notificação de pendências de acerto
O Gestão do Ponto permite customizar os e-mails de notificação de pendências dos gestores e colaboradores. Eles são disparados através de serviços de terceiros e podem ser agendados:
Nome do Serviço | Descrição | Parâmetro |
---|---|---|
gestaoponto.NotificacaoPendenciasAcerto |
Envia e-mail para o Colaborador sinalizando a existência de pendências de Ponto nos últimos 40 dias. O sistema executa um cálculo para definir qual período será enviado como pendência, considerando o valor informado em Cálculos > Apuração > Definições > Gerais (guia Processos de Acerto, campo Limite dias Após fechamento do ponto). Exemplo:
|
String com a chave para autenticação do serviço |
gestaoponto.NotificacaoGestoresPonto | Envia e-mail com o resumo de pendências que estão com o gestor, incluindo as dos seus liderados | String com a chave para autenticação do serviço |
O agendamento dos serviços deve ser feito através de regras, onde a regra LSP implementada deve chamar um dos dois serviços de terceiro. A periodicidade de execução deve ser configurada de acordo com a necessidade.
Nota
Método List<ItemEmailPendencia> IDadosEmailGestor.montaListaPendencias:
- Se utilizada a rotina de chefias, não é necessário implementar a busca do liderado;
- Este método é disponibilizado somente para a classe DadosEmailGestorCustomizado.
public class DadosEmailGestorCustomizado extends DadosEmailGestor {
@Override
public List<ItemEmailPendencia> montaListaPendencias() {
String queryPendencias = "SELECT R066PEN.NUMEMP, R066PEN.TIPCOL, R066PEN.NUMCAD, R066PEN.DATAPU FROM R066PEN R066PEN WHERE R066PEN.SITPEN IN (3,4, 5) AND DATAPU BETWEEN ? AND ? ORDER BY NUMEMP, TIPCOL, NUMCAD";
DataAccessor dataAccessor = new DataAccessor(ContextSession.getSession());
// Executa o select para retornar os colaboradores que possuem pendência dos últimos 30 dias
IResultSet resultSet = dataAccessor.runQueryRS(queryPendencias, new LocalDate().minusDays(30), new LocalDate());
Map<Colaborador, Colaborador> cacheGestores = new HashMap<Colaborador, Colaborador>();
Map<Colaborador, ItemEmailPendencia> listaPendencias = new HashMap<Colaborador, ItemEmailPendencia>();
ItemEmailPendencia itemEmailGestor = null;
Map<Integer, IR044CAL> cacheCodigoCalculo = new HashMap<>();
Colaborador chefe = null;
while (resultSet.next()) {
Colaborador colaborador = new Colaborador(resultSet.getBigDecimal(0).intValue(), resultSet.getBigDecimal(1).intValue(), resultSet.getBigDecimal(2).intValue());
// Cria um cache de gestores por colaborador
if (!cacheGestores.containsKey(colaborador)) {
chefe = buscarChefe(colaborador);
cacheGestores.put(colaborador, chefe);
} else {
chefe = cacheGestores.get(colaborador);
}
IR044CAL codigoCalculo = null;
// Cria um cache de código de cálculo por empresa
if (cacheCodigoCalculo.get(colaborador.getNumEmp()) == null) {
codigoCalculo = buscarCodigoCalculo(colaborador.getNumEmp(), new LocalDate(2019, 3, 1));
cacheCodigoCalculo.put(colaborador.getNumEmp(), codigoCalculo);
} else {
codigoCalculo = cacheCodigoCalculo.get(colaborador.getNumEmp());
}
if(chefe != null) {
// Todo ItemEmailPendencia é um 'gestor' e dentro desse objeto deve ser preenchido os campos abaixo como
// Inicio e Fim do período, data limite de acertos as pendências dos liderados
itemEmailGestor = new ItemEmailPendencia(chefe.getNumEmp(), chefe.getTipCol(), chefe.getNumCad(), "nomeUsuarioChefe", "juan.wippel@senior.com.br", new ArrayList<PendenciaLiderado>());
if(!listaPendencias.containsKey(chefe)){
itemEmailGestor.setDataIniciPeriodoPendente(codigoCalculo.getIniApu());
itemEmailGestor.setDataFimPeriodoPendente(codigoCalculo.getFimApu());
itemEmailGestor.setDataLimite(codigoCalculo.getFimApu());
listaPendencias.put(chefe, itemEmailGestor);
} else {
itemEmailGestor = listaPendencias.get(chefe);
}
}
if (itemEmailGestor != null) {
//O objeto PendenciaLiderado é referente a pendência do liderado e deve ser adicionado ao ItemEmailPendencia(gestor)
PendenciaLiderado pendenciaLiderado = new PendenciaLiderado(colaborador.getNumEmp(), colaborador.getTipCol(), colaborador.getNumCad());
if(!itemEmailGestor.getPendencias().contains(pendenciaLiderado)) {
pendenciaLiderado.setNome(getEmailColaborador(colaborador));
itemEmailGestor.getPendencias().add(pendenciaLiderado);
itemEmailGestor.setQtdPendencias(1);
} else {
itemEmailGestor.setQtdPendencias(itemEmailGestor.getQtdPendencias() + 1);
}
}
}
return new ArrayList<ItemEmailPendencia>(listaPendencias.values());
}
/**
* Busca o chefe do colaborador passado como parâmetro
*
* @param liderado
* @return
*/
private Colaborador buscarChefe(Colaborador liderado) {
/**Implementar aqui a busca de chefe para o colaborador passado como parâmetro
* Pode-se utilizar cursores, selects, dependendo de como cada cliente define os chefes
* de seus colaboradores*/
return new Colaborador(3, 1, 5);
}
/**
* Busca o código de cálculo baseado nos parâmetros
*
* @param numEmp
* @param data
* @return
*/
private IR044CAL buscarCodigoCalculo(int numEmp, LocalDate data) {
/**Esse método é apenas uma sugestão, os parâmetros e sua implementação
* podem ser alterados para atender cada caso*/
ICursor<IR044CAL> crCodigoCalculo = CursorUtil.getCursor(IR044CAL.class);
MappedParamProvider params = new MappedParamProvider();
params.setParam("NumEmp", numEmp);
params.setParam("Data", data);
crCodigoCalculo.addFilter("NumEmp = :NumEmp and :Data between IniApu and FimApu", params);
crCodigoCalculo.open();
try {
if (crCodigoCalculo.first()) {
return crCodigoCalculo.read();
}
} finally {
crCodigoCalculo.close();
}
return null;
}
/**
* Busca o email do colaborador passado como parâmetro
*
* @param colaborador
* @return
*/
private String getEmailColaborador(Colaborador colaborador) {
MappedParamProvider params = new MappedParamProvider();
params.setParam("NumEmp", colaborador.getNumEmp());
params.setParam("TipCol", colaborador.getTipCol());
params.setParam("NumCad", colaborador.getNumCad());
ICursor<IColaboradorPonto> crColaborador = CursorUtil.getCursor(IColaboradorPonto.class);
crColaborador.addFilter("NumEmp = :NumEmp and TipCol = :TipCol and NumCad = :NumCad", params);
crColaborador.open();
try {
if (crColaborador.first()) {
return crColaborador.read().getNomFun();
}
} finally {
crColaborador.close();
}
return null;
}
}
public class DadosEmailLideradoCustomizado extends DadosEmailLiderado {
@Override
public List<ItemEmailPendencia> montaListaPendencias() {
String queryPendencias = "SELECT R066PEN.NUMEMP, R066PEN.TIPCOL, R066PEN.NUMCAD, R066PEN.DATAPU, R066PEN.DATEXP FROM R066PEN R066PEN WHERE R066PEN.SITPEN IN (3,4, 5) AND DATAPU BETWEEN ? AND ? ORDER BY NUMEMP, TIPCOL, NUMCAD";
DataAccessor dataAccessor = new DataAccessor(ContextSession.getSession());
// Executa o select para retornar os colaboradores que possuem pendência dos últimos 30 dias
IResultSet resultSet = dataAccessor.runQueryRS(queryPendencias, new LocalDate().minusDays(30), new LocalDate());
Map<Integer, IR044CAL> cacheCodigoCalculo = new HashMap<>();
IColaboradorPonto colaboradorPonto = null;
Map<Colaborador, ItemEmailPendencia> cacheLiderados = new HashMap<Colaborador, ItemEmailPendencia>();
while (resultSet.next()) {
Colaborador colaborador = new Colaborador(resultSet.getBigDecimal(0).intValue(), resultSet.getBigDecimal(1).intValue(), resultSet.getBigDecimal(2).intValue());
LocalDate datApu = resultSet.getDateTime(3).toLocalDate();
LocalDate datExp = resultSet.getDateTime(4).toLocalDate();
IR044CAL codigoCalculo = null;
// Cria um cache de código de cálculo por empresa
if (cacheCodigoCalculo.get(colaborador.getNumEmp()) == null) {
codigoCalculo = buscarCodigoCalculo(colaborador.getNumEmp(), new LocalDate(2019, 3, 1));
cacheCodigoCalculo.put(colaborador.getNumEmp(), codigoCalculo);
} else {
codigoCalculo = cacheCodigoCalculo.get(colaborador.getNumEmp());
}
ItemEmailPendencia itemEmailLiderado = cacheLiderados.get(colaborador);
if (itemEmailLiderado == null) {
MappedParamProvider params = new MappedParamProvider();
params.setParam("NumEmp", colaborador.getNumEmp());
params.setParam("TipCol", colaborador.getTipCol());
params.setParam("NumCad", colaborador.getNumCad());
ICursor<IColaboradorPonto> crColaborador = CursorUtil.getCursor(IColaboradorPonto.class);
crColaborador.addFilter("NumEmp=:NumEmp and TipCol=:TipCol and NumCad=:NumCad", params);
crColaborador.open();
try {
if (!crColaborador.first()) {
continue;
}
if (colaboradorPonto == null) {
colaboradorPonto = crColaborador.read();
} else {
crColaborador.read(colaboradorPonto);
}
} finally {
crColaborador.close();
}
// Cada ItemEmailPendencia é um colaborador
itemEmailLiderado = new ItemEmailPendencia(colaborador.getNumEmp(), colaborador.getTipCol(), colaborador.getNumCad(), colaboradorPonto.getNomFun(), colaboradorPonto.getEmaCom(), new ArrayList<PendenciaLiderado>());
itemEmailLiderado.setDataIniciPeriodoPendente(codigoCalculo.getIniApu());
itemEmailLiderado.setDataFimPeriodoPendente(codigoCalculo.getFimApu());
itemEmailLiderado.setDataLimite(codigoCalculo.getFimApu());
}
// PendenciaLiderado representa a pendência de um liderado e deve ser adicionado a lista de pendências do ItemEmailPendencia
PendenciaLiderado pendenciaLiderado = new PendenciaLiderado(colaborador.getNumEmp(), colaborador.getTipCol(), colaborador.getNumCad());
pendenciaLiderado.setDataPendencia(datApu);
pendenciaLiderado.setDataExpiracao(datExp);
itemEmailLiderado.getPendencias().add(pendenciaLiderado);
cacheLiderados.put(colaborador, itemEmailLiderado);
}
return new ArrayList<ItemEmailPendencia>(cacheLiderados.values());
}
/**
* Busca o código de cálculo baseado nos parâmetros
*
* @param numEmp
* @param data
* @return
*/
private IR044CAL buscarCodigoCalculo(int numEmp, LocalDate data) {
/**Esse método é apenas uma sugestão, os parâmetros e sua implementação
* podem ser alterados para atender cada caso*/
ICursor<IR044CAL> crCodigoCalculo = CursorUtil.getCursor(IR044CAL.class);
MappedParamProvider params = new MappedParamProvider();
params.setParam("NumEmp", numEmp);
params.setParam("Data", data);
crCodigoCalculo.addFilter("NumEmp = :NumEmp and :Data between IniApu and FimApu", params);
crCodigoCalculo.open();
try {
if (crCodigoCalculo.first()) {
return crCodigoCalculo.read();
}
} finally {
crCodigoCalculo.close();
}
return null;
}
}
Consulte mais informações sobre os web services disponíveis e as configurações de pós-instalação do sistema.
Template padrão de e-mail
O resultado da execução dos serviços é o envio de e-mail para os colaboradores com pendências.
Há pendência(s) de Acerto de Ponto de seu(s) liderados(s) referente ao período de [dd/mm/aaaa] à [dd/mm/aaaa]
Liderado(s) com pendência(s): 323 [nomes]
23323 [nomes]
A data limite para tratamento das pendências é [dd/mm/aaaa]
Para acessar as pendências clique aqui.
Observe os prazos para evitar impactos na folha de pagamento e oriente seu(s) liderado(s).
Você possui pendência(s) de Acerto de Ponto referente ao período de [dd/mm/aaaa] à [dd/mm/aaaa]
Data da pendência e Data limite [dd/mm/aaaa] [dd/mm/aaaa]
Para acessar as pendências clique aqui.
Observe os prazos para evitar impactos em sua folha de pagamento.
Modificar o template padrão
Para modificar o template padrão, crie uma classe Java Customizada no Ambiente de Customização (SeniorDeveloper), estendendo a classe de implementação padrão.
Nomes das classes para customização e implementação padrão de cada serviço:
Nome do Serviço | Classe Java Customizada | Classe Implementação Padrão |
---|---|---|
gestaoponto.NotificacaoPendenciasAcerto | custom.DadosEmailGestorCustomizado | DadosEmailLiderado |
gestaoponto.NotificacaoGestoresPonto | custom.DadosEmailLideradoCustomizado | DadosEmailGestor |
Cada classe customizada poderá conter os seguintes métodos:
Método | Definição |
---|---|
String getTitutloEmail() | Define em seu retorno qual o título do e-mail |
String getTemplateEmail() | Define em seu retorno qual o arquivo do template do e-mail que comporá o corpo do e-mail |
List<ItemEmailPendencia> IDadosEmailGestor.montaListaPendencias | Define como serão buscados o gestor e seus liderados |
Classe implementada:
public class DadosEmailGestorCustomizado extends DadosEmailGestor {
@Override
public String getTitutloEmail() {
return"Pendências acerto de ponto da empresa ABC";
}
@Override
public String getTemplateEmail() {
return"custom/TemplateEmailLideradoSenior.vm";
}
}
O template informado na classe é um arquivo texto na linguagem html que descreve como o corpo do e-mail será apresentado para o gestor/colaborador.
#macro(description $item) #pad($item.numcad) #end
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<style type="text/css">
p{font-family: Verdana;font-size: 12px;color: #000000;font-weight: normal;}
b.vermelho{font-family: Verdana;font-size: 12px;color: #FF0000;font-weight: bold;}
td.subTitulo{font-family: Verdana;font-size: 12px; color: #000000;font-weight: bold;text-align: left;padding: 3px;height: 15px;}
table{border-collapse: collapse;}
table td{padding: 0px;border: 1px solid #FFFFFF;}
td.dado {font-family: Verdana;font-size: 12px;color: #000000;font-weight: bold;text-align: left;padding-right: 5px;}
</style>
</head>
<body>
<p>Há pendência(s) de Acerto de Ponto de seu(s) liderados(s) referente ao período de <b>${itemEmailPendencia.dataIniciPeriodoPendente.toString("dd/MM/yyyy")}</b> à <b>${itemEmailPendencia.dataFimPeriodoPendente.toString("dd/MM/yyyy")}</b>.</p>
<p>Liderado(s) com pendência(s):
<p>
<table width="500px">
#foreach($item in $itemEmailPendencia.pendencias)
<tr>
<td class="dado">$item.NumCad</td>
<td class="dado">-</td>
<td class="dado">$item.Nome</td>
</tr>
#end
</table>
<p>A data limite para tratamento das pendências é <b class="vermelho">${itemEmailPendencia.dataLimite.toString("dd/MM/yyyy")}</b>.</p>
<p>Para acessar as pendências <a href="https://www62.senior.com.br/g6-ronda/?perspective=com.senior.apuracao.acerto.sintetico.acertoPontoTotais" target="_parent" class="lnk">clique aqui.</a></p>
<p>Observe os prazos para evitar impactos na folha de pagamento e oriente seu(s) liderado(s).</p>
</body>
</html>
#macro(description $item) #pad($item.numcad) #end
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<style type="text/css">
p{font-family: Verdana;font-size: 12px;color: #000000;font-weight: normal;}
td.subTitulo{font-family: Verdana;font-size: 12px; color: #000000;font-weight: bold;text-align: center;padding: 3px;height: 15px;}
td.subTituloVermelho{font-family: Verdana;font-size: 12px; color: #FF0000;font-weight: bold;text-align: center;padding: 3px;height: 15px;}
table{border-collapse: collapse;}
table td{padding: 0px;border: 1px solid #FFFFFF;}
td.dado {font-family: Verdana;font-size: 12px;color: #000000;font-weight: normal;text-align: center;padding: 3px;}
</style>
</head>
<body>
<p>Você possui pendência(s) de Acerto de Ponto referente(s) ao período de <b>${itemEmailPendencia.dataIniciPeriodoPendente.toString("dd/MM/yyyy")}</b> à <b>${itemEmailPendencia.dataFimPeriodoPendente.toString("dd/MM/yyyy")}</b>:</p>
<table width="270px">
<tr>
<td class="subtitulo" width="50%">Data da pendência</td>
<td class="subtituloVermelho" width="50%">Data limite</td>
</tr>
#foreach($item in $itemEmailPendencia.pendencias)
<tr>
<td class="dado">$item.dataPendencia.toString("dd/MM/yyyy")</td>
<td class="dado">$itemEmailPendencia.dataLimite.toString("dd/MM/yyyy")</td>
</tr>
#end
</table>
</body>
</html>
Nota
Algumas funções são utilizadas no template acima para obter as informações dinâmicas tais como: formatação de datas, dados dos colaboradores e estruturas de loops e condições. Mais detalhes da utilização da API podem ser obtidas no guia do Apache Velocity Project.