/**
*
*/
package net.conselldemallorca.helium.core.model.service;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import net.conselldemallorca.helium.core.model.dao.AlertaDao;
import net.conselldemallorca.helium.core.model.dao.ExpedientDao;
import net.conselldemallorca.helium.core.model.dao.FestiuDao;
import net.conselldemallorca.helium.core.model.dao.RegistreDao;
import net.conselldemallorca.helium.core.model.dao.TerminiDao;
import net.conselldemallorca.helium.core.model.dao.TerminiIniciatDao;
import net.conselldemallorca.helium.core.model.hibernate.Alerta;
import net.conselldemallorca.helium.core.model.hibernate.Alerta.AlertaPrioritat;
import net.conselldemallorca.helium.core.model.hibernate.Expedient;
import net.conselldemallorca.helium.core.model.hibernate.Festiu;
import net.conselldemallorca.helium.core.model.hibernate.Termini;
import net.conselldemallorca.helium.core.model.hibernate.TerminiIniciat;
import net.conselldemallorca.helium.core.model.hibernate.TerminiIniciat.TerminiIniciatEstat;
import net.conselldemallorca.helium.core.util.GlobalProperties;
import net.conselldemallorca.helium.jbpm3.integracio.JbpmHelper;
import net.conselldemallorca.helium.jbpm3.integracio.JbpmProcessInstance;
import net.conselldemallorca.helium.jbpm3.integracio.JbpmTask;
/**
* Servei per gestionar els terminis dels expedients
*
* @author Limit Tecnologies <limit@limit.es>
*/
@Service
public class TerminiService {
private TerminiDao terminiDao;
private TerminiIniciatDao terminiIniciatDao;
private FestiuDao festiuDao;
private RegistreDao registreDao;
private ExpedientDao expedientDao;
private AlertaDao alertaDao;
private JbpmHelper jbpmDao;
private MessageSource messageSource;
public TerminiIniciat iniciar(
Long terminiId,
String processInstanceId,
Date data,
boolean esDataFi) {
Termini termini = terminiDao.getById(terminiId, false);
TerminiIniciat terminiIniciat = terminiIniciatDao.findAmbTerminiIdIProcessInstanceId(
terminiId,
processInstanceId);
if (terminiIniciat == null) {
return iniciar(
terminiId,
processInstanceId,
data,
termini.getAnys(),
termini.getMesos(),
termini.getDies(),
esDataFi);
} else {
return iniciar(
terminiId,
processInstanceId,
data,
terminiIniciat.getAnys(),
terminiIniciat.getMesos(),
terminiIniciat.getDies(),
esDataFi);
}
}
public TerminiIniciat iniciar(
Long terminiId,
String processInstanceId,
Date data,
int anys,
int mesos,
int dies,
boolean esDataFi) {
Termini termini = terminiDao.getById(terminiId, false);
TerminiIniciat terminiIniciat = terminiIniciatDao.findAmbTerminiIdIProcessInstanceId(
terminiId,
processInstanceId);
if (terminiIniciat == null) {
if (esDataFi) {
Date dataInici = getDataIniciTermini(
data,
anys,
mesos,
dies,
termini.isLaborable());
terminiIniciat = new TerminiIniciat(
termini,
anys,
mesos,
dies,
processInstanceId,
dataInici,
data);
} else {
Date dataFi = getDataFiTermini(
data,
anys,
mesos,
dies,
termini.isLaborable());
terminiIniciat = new TerminiIniciat(
termini,
anys,
mesos,
dies,
processInstanceId,
data,
dataFi);
}
} else {
if (esDataFi) {
Date dataInici = getDataIniciTermini(
data,
anys,
mesos,
dies,
termini.isLaborable());
terminiIniciat.setDataInici(dataInici);
terminiIniciat.setDataFi(data);
} else {
Date dataFi = getDataFiTermini(
data,
anys,
mesos,
dies,
termini.isLaborable());
terminiIniciat.setDataInici(data);
terminiIniciat.setDataFi(dataFi);
}
terminiIniciat.setDataAturada(null);
terminiIniciat.setDataCancelacio(null);
terminiIniciat.setDies(dies);
terminiIniciat.setMesos(mesos);
terminiIniciat.setAnys(anys);
resumeTimers(terminiIniciat);
}
Long expedientId = getExpedientForProcessInstanceId(processInstanceId).getId();
if (expedientId != null) {
registreDao.crearRegistreIniciarTermini(
getExpedientForProcessInstanceId(processInstanceId).getId(),
processInstanceId,
terminiId.toString(),
SecurityContextHolder.getContext().getAuthentication().getName());
}
return terminiIniciatDao.saveOrUpdate(terminiIniciat);
}
public void pausar(Long terminiIniciatId, Date data) {
TerminiIniciat terminiIniciat = terminiIniciatDao.getById(terminiIniciatId, false);
if (terminiIniciat.getDataInici() == null)
throw new net.conselldemallorca.helium.core.model.exception.IllegalStateException( getMessage("error.terminiService.noIniciat") );
terminiIniciat.setDataAturada(data);
suspendTimers(terminiIniciat);
String processInstanceId = terminiIniciat.getProcessInstanceId();
Long expedientId = getExpedientForProcessInstanceId(processInstanceId).getId();
if (expedientId != null) {
registreDao.crearRegistreAturarTermini(
getExpedientForProcessInstanceId(processInstanceId).getId(),
processInstanceId,
terminiIniciat.getTermini().getId().toString(),
SecurityContextHolder.getContext().getAuthentication().getName());
}
}
public void continuar(Long terminiIniciatId, Date data) {
TerminiIniciat terminiIniciat = terminiIniciatDao.getById(terminiIniciatId, false);
if (terminiIniciat.getDataAturada() == null)
throw new net.conselldemallorca.helium.core.model.exception.IllegalStateException( getMessage("error.terminiService.noPausat") );
int diesAturat = terminiIniciat.getNumDiesAturadaActual(data);
terminiIniciat.setDiesAturat(terminiIniciat.getDiesAturat() + diesAturat);
terminiIniciat.setDataAturada(null);
resumeTimers(terminiIniciat);
String processInstanceId = terminiIniciat.getProcessInstanceId();
Long expedientId = getExpedientForProcessInstanceId(processInstanceId).getId();
if (expedientId != null) {
registreDao.crearRegistreReprendreTermini(
getExpedientForProcessInstanceId(processInstanceId).getId(),
processInstanceId,
terminiIniciat.getTermini().getId().toString(),
SecurityContextHolder.getContext().getAuthentication().getName());
}
}
public void cancelar(Long terminiIniciatId, Date data) {
TerminiIniciat terminiIniciat = terminiIniciatDao.getById(terminiIniciatId, false);
if (terminiIniciat.getDataInici() == null)
throw new net.conselldemallorca.helium.core.model.exception.IllegalStateException( getMessage("error.terminiService.noIniciat") );
terminiIniciat.setDataCancelacio(data);
suspendTimers(terminiIniciat);
String processInstanceId = terminiIniciat.getProcessInstanceId();
Long expedientId = getExpedientForProcessInstanceId(processInstanceId).getId();
if (expedientId != null) {
registreDao.crearRegistreCancelarTermini(
getExpedientForProcessInstanceId(processInstanceId).getId(),
processInstanceId,
terminiIniciat.getTermini().getId().toString(),
SecurityContextHolder.getContext().getAuthentication().getName());
}
}
public Date getDataFiTermini(
Date inici,
int anys,
int mesos,
int dies,
boolean laborable) {
Calendar dataFi = Calendar.getInstance();
dataFi.setTime(inici); //inicialitzam la data final amb la data d'inici
// Afegim els anys i mesos
if (anys > 0) {
dataFi.add(Calendar.YEAR, anys);
dataFi.add(Calendar.DAY_OF_YEAR, -1);
}
if (mesos > 0) {
dataFi.add(Calendar.MONTH, mesos);
dataFi.add(Calendar.DAY_OF_YEAR, -1);
}
if (dies > 0) {
// Depenent de si el termini és laborable o no s'afegiran més o manco dies
if (laborable) {
sumarDies(dataFi, dies);
} else {
dataFi.add(Calendar.DATE, dies - 1);
// Si el darrer dia cau en festiu es passa al dia laborable següent
sumarDies(dataFi, 1);
}
// El termini en realitat acaba a les 23:59 del darrer dia
dataFi.set(Calendar.HOUR_OF_DAY, 23);
dataFi.set(Calendar.MINUTE, 59);
dataFi.set(Calendar.SECOND, 59);
dataFi.set(Calendar.MILLISECOND, 999);
}
return dataFi.getTime();
}
public Date getDataIniciTermini(
Date fi,
int anys,
int mesos,
int dies,
boolean laborable) {
Calendar dataInici = Calendar.getInstance();
dataInici.setTime(fi); //inicialitzam la data final amb la data d'inici
// Afegim els anys i mesos
if (anys > 0) {
dataInici.add(Calendar.YEAR, -anys);
dataInici.add(Calendar.DAY_OF_YEAR, -1);
}
if (mesos > 0) {
dataInici.add(Calendar.MONTH, -mesos);
dataInici.add(Calendar.DAY_OF_YEAR, -1);
}
if (dies > 0) {
// Depenent de si el termini és laborable o no s'afegiran més o manco dies
if (laborable) {
sumarDies(dataInici, -dies);
} else {
dataInici.add(Calendar.DATE, -dies + 1);
// Si el darrer dia cau en festiu es passa al dia laborable següent
sumarDies(dataInici, -1);
}
// El termini en realitat s'inicia a les 00:00h
dataInici.set(Calendar.HOUR_OF_DAY, 0);
dataInici.set(Calendar.MINUTE, 0);
dataInici.set(Calendar.SECOND, 0);
dataInici.set(Calendar.MILLISECOND, 0);
}
return dataInici.getTime();
}
public List<TerminiIniciat> findIniciatsAmbProcessInstanceId(String processInstanceId) {
return terminiIniciatDao.findAmbProcessInstanceId(processInstanceId);
}
public TerminiIniciat findIniciatAmbTerminiIdIProcessInstanceId(
Long terminiId,
String processInstanceId) {
return terminiIniciatDao.findAmbTerminiIdIProcessInstanceId(terminiId, processInstanceId);
}
public List<TerminiIniciat> findIniciatsAmbTaskInstanceIds(String[] taskInstanceIds) {
if (taskInstanceIds == null || taskInstanceIds.length == 0)
return new ArrayList<TerminiIniciat>();
return terminiIniciatDao.findAmbTaskInstanceIds(taskInstanceIds);
}
public void configurarTerminiIniciatAmbDadesJbpm(
Long terminiIniciatId,
String taskInstanceId,
Long timerId) {
TerminiIniciat terminiIniciat = terminiIniciatDao.getById(terminiIniciatId, false);
terminiIniciat.setTaskInstanceId(taskInstanceId);
if (timerId != null)
terminiIniciat.afegirTimerId(timerId.longValue());
}
public Festiu getFestiuById(Long id) {
return festiuDao.getById(id, false);
}
public Festiu createFestiu(Festiu entity) {
festiuDao.modificacioFestius();
return festiuDao.saveOrUpdate(entity);
}
public Festiu updateFestiu(Festiu entity) {
festiuDao.modificacioFestius();
return festiuDao.merge(entity);
}
public void deleteFestiu(Long id) {
festiuDao.modificacioFestius();
Festiu vell = getFestiuById(id);
if (vell != null) {
festiuDao.delete(id);
}
}
public List<Festiu> findFestiuAmbAny(int any) {
return festiuDao.findAmbAny(any);
}
public Festiu findFestiuAmbData(Date data) {
return festiuDao.findAmbData(data);
}
@Scheduled(cron="0 */10 * * * *")
public void comprovarTerminisIniciats() {
logger.debug("Inici de la comprovació de terminis");
List<TerminiIniciat> iniciatsActiusAlertesPrevies = terminiIniciatDao.findIniciatsAmbAlertesPrevies();
List<TerminiIniciat> iniciatsActiusAlertesFinals = terminiIniciatDao.findIniciatsAmbAlertesFinals();
for (TerminiIniciat terminiIniciat: iniciatsActiusAlertesFinals) {
if (terminiIniciat.getTaskInstanceId() != null && terminiIniciat.getEstat() == TerminiIniciatEstat.CADUCAT) {
esborrarAlertesAntigues(terminiIniciat);
JbpmTask task = jbpmDao.getTaskById(terminiIniciat.getTaskInstanceId());
if (task.getAssignee() != null) {
crearAlertaAmbTerminiAssociat(terminiIniciat, task.getAssignee(), getExpedientPerTask(task));
} else {
for (String actor: task.getPooledActors())
crearAlertaAmbTerminiAssociat(terminiIniciat, actor, getExpedientPerTask(task));
}
terminiIniciat.setAlertaFinal(true);
} else if(terminiIniciat.getEstat() == TerminiIniciatEstat.CADUCAT) {
esborrarAlertesAntigues(terminiIniciat);
Expedient expedient = getExpedientForProcessInstanceId(
terminiIniciat.getProcessInstanceId());
if (expedient != null && expedient.getResponsableCodi() != null) {
crearAlertaAmbTerminiAssociat(
terminiIniciat,
expedient.getResponsableCodi(),
expedient);
}
terminiIniciat.setAlertaFinal(true);
}
}
for (TerminiIniciat terminiIniciat: iniciatsActiusAlertesPrevies) {
if (terminiIniciat.getTaskInstanceId() != null && terminiIniciat.getEstat() == TerminiIniciatEstat.AVIS) {
JbpmTask task = jbpmDao.getTaskById(terminiIniciat.getTaskInstanceId());
if (task.getAssignee() != null) {
crearAlertaAmbTerminiAssociat(terminiIniciat, task.getAssignee(), getExpedientPerTask(task));
} else {
for (String actor: task.getPooledActors())
crearAlertaAmbTerminiAssociat(terminiIniciat, actor, getExpedientPerTask(task));
}
terminiIniciat.setAlertaPrevia(true);
} else if (terminiIniciat.getEstat() == TerminiIniciatEstat.AVIS) {
Expedient expedient = getExpedientForProcessInstanceId(
terminiIniciat.getProcessInstanceId());
if (expedient != null && expedient.getResponsableCodi() != null) {
crearAlertaAmbTerminiAssociat(
terminiIniciat,
expedient.getResponsableCodi(),
expedient);
}
terminiIniciat.setAlertaPrevia(true);
}
}
logger.debug("Fi de la comprovació de terminis");
}
public void modificarTerminiIniciat(
Long terminiIniciatId,
Date dataInici,
int anys,
int mesos,
int dies) {
TerminiIniciat terminiIniciat = terminiIniciatDao.getById(terminiIniciatId, false);
if (terminiIniciat != null) {
boolean modificat = false;
if (terminiIniciat.getDataInici().getTime() != dataInici.getTime()) {
terminiIniciat.setDataInici(dataInici);
modificat = true;
}
if (terminiIniciat.getAnys() != anys || terminiIniciat.getMesos() != mesos || terminiIniciat.getDies() != dies) {
terminiIniciat.setAnys(anys);
terminiIniciat.setMesos(mesos);
terminiIniciat.setDies(dies);
modificat = true;
}
if (modificat) {
terminiIniciat.setDataFi(
getDataFiTermini(
terminiIniciat.getDataInici(),
terminiIniciat.getAnys(),
terminiIniciat.getMesos(),
terminiIniciat.getDies(),
terminiIniciat.getTermini().isLaborable()));
String processInstanceId = terminiIniciat.getProcessInstanceId();
Long expedientId = getExpedientForProcessInstanceId(processInstanceId).getId();
if (expedientId != null) {
registreDao.crearRegistreAturarTermini(
getExpedientForProcessInstanceId(processInstanceId).getId(),
processInstanceId,
terminiIniciat.getTermini().getId().toString(),
SecurityContextHolder.getContext().getAuthentication().getName());
registreDao.crearRegistreIniciarTermini(
getExpedientForProcessInstanceId(processInstanceId).getId(),
processInstanceId,
terminiIniciat.getTermini().getId().toString(),
SecurityContextHolder.getContext().getAuthentication().getName());
}
}
}
}
@Autowired
public void setTerminiDao(TerminiDao terminiDao) {
this.terminiDao = terminiDao;
}
@Autowired
public void setTerminiIniciatDao(TerminiIniciatDao terminiIniciatDao) {
this.terminiIniciatDao = terminiIniciatDao;
}
@Autowired
public void setFestiuDao(FestiuDao festiuDao) {
this.festiuDao = festiuDao;
}
@Autowired
public void setRegistreDao(RegistreDao registreDao) {
this.registreDao = registreDao;
}
@Autowired
public void setExpedientDao(ExpedientDao expedientDao) {
this.expedientDao = expedientDao;
}
@Autowired
public void setAlertaDao(AlertaDao alertaDao) {
this.alertaDao = alertaDao;
}
@Autowired
public void setJbpmHelper(JbpmHelper jbpmDao) {
this.jbpmDao = jbpmDao;
}
@Autowired
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
private void sumarDies(Calendar cal, int numDies) {
int signe = (numDies < 0) ? -1 : 1;
int nd = (numDies < 0) ? -numDies : numDies;
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
List<Festiu> festius = festiuDao.findAll();
int diesLabs = 0;
while (diesLabs < nd) {
if (!esFestiu(cal, festius))
diesLabs ++;
cal.add(Calendar.DATE, signe);
}
cal.add(Calendar.DATE, -signe);
}
private boolean esFestiu(
Calendar cal,
List<Festiu> festius) {
int diasem = cal.get(Calendar.DAY_OF_WEEK);
for (int nolab: getDiesNoLaborables()) {
if (diasem == nolab)
return true;
}
for (Festiu festiu: festius) {
if (cal.getTime().compareTo(festiu.getData()) == 0)
return true;
}
return false;
}
private int[] getDiesNoLaborables() {
String nolabs = GlobalProperties.getInstance().getProperty("app.calendari.nolabs");
if (nolabs != null) {
String[] dies = nolabs.split(",");
int[] resposta = new int[dies.length];
for (int i = 0; i < dies.length; i++) {
resposta[i] = (Integer.parseInt(dies[i]) % 7) + 1;
}
return resposta;
}
return new int[0];
}
private Expedient getExpedientForProcessInstanceId(String processInstanceId) {
JbpmProcessInstance pi = jbpmDao.getRootProcessInstance(processInstanceId);
if (pi == null) {
return null;
}
return expedientDao.findAmbProcessInstanceId(pi.getId());
}
private void suspendTimers(TerminiIniciat terminiIniciat) {
long[] timerIds = terminiIniciat.getTimerIdsArray();
for (int i = 0; i < timerIds.length; i++)
jbpmDao.suspendTimer(
timerIds[i],
new Date(Long.MAX_VALUE));
}
private void resumeTimers(TerminiIniciat terminiIniciat) {
long[] timerIds = terminiIniciat.getTimerIdsArray();
for (int i = 0; i < timerIds.length; i++)
jbpmDao.resumeTimer(
timerIds[i],
terminiIniciat.getDataFi());
}
private Expedient getExpedientPerTask(JbpmTask task) {
JbpmProcessInstance rootProcessInstance = jbpmDao.getRootProcessInstance(task.getProcessInstanceId());
return expedientDao.findAmbProcessInstanceId(rootProcessInstance.getId());
}
private void crearAlertaAmbTerminiAssociat(
TerminiIniciat terminiIniciat,
String responsable,
Expedient expedient) {
logger.debug("Creació alerta per al termini " + terminiIniciat.getId() + " per al responsable " + responsable);
// Només crea alertes si l'expedient no està finalitzat
if (expedient.getDataFi() == null) {
AlertaPrioritat prioritat;
if (TerminiIniciatEstat.AVIS.equals(terminiIniciat.getEstat())) {
prioritat = AlertaPrioritat.NORMAL;
} else if (TerminiIniciatEstat.COMPLETAT_FORA.equals(terminiIniciat.getEstat())) {
prioritat = AlertaPrioritat.ALTA;
} else if (TerminiIniciatEstat.CADUCAT.equals(terminiIniciat.getEstat())) {
prioritat = AlertaPrioritat.MOLT_ALTA;
} else {
prioritat = AlertaPrioritat.BAIXA;
}
Alerta alerta = new Alerta(
new Date(),
responsable,
prioritat,
terminiIniciat.getTermini().getDefinicioProces().getEntorn());
alerta.setExpedient(expedient);
alerta.setTerminiIniciat(terminiIniciat);
alertaDao.saveOrUpdate(alerta);
}
}
private void esborrarAlertesAntigues(TerminiIniciat terminiIniciat) {
List<Alerta> antigues = alertaDao.findActivesAmbTerminiIniciatId(terminiIniciat.getId());
for (Alerta antiga: antigues) {
antiga.setDataEliminacio(new Date());
}
}
protected String getMessage(String key, Object[] vars) {
try {
return messageSource.getMessage(
key,
vars,
null);
} catch (NoSuchMessageException ex) {
return "???" + key + "???";
}
}
protected String getMessage(String key) {
return getMessage(key, null);
}
private static final Log logger = LogFactory.getLog(TerminiService.class);
}