package net.conselldemallorca.helium.v3.core.service;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import net.conselldemallorca.helium.core.helper.ConversioTipusHelper;
import net.conselldemallorca.helium.core.helper.ExpedientHelper;
import net.conselldemallorca.helium.core.helper.MessageHelper;
import net.conselldemallorca.helium.core.model.hibernate.DefinicioProces;
import net.conselldemallorca.helium.core.model.hibernate.Expedient;
import net.conselldemallorca.helium.core.model.hibernate.Festiu;
import net.conselldemallorca.helium.core.model.hibernate.Registre;
import net.conselldemallorca.helium.core.model.hibernate.Termini;
import net.conselldemallorca.helium.core.model.hibernate.TerminiIniciat;
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.v3.core.api.dto.FestiuDto;
import net.conselldemallorca.helium.v3.core.api.dto.TerminiDto;
import net.conselldemallorca.helium.v3.core.api.dto.TerminiIniciatDto;
import net.conselldemallorca.helium.v3.core.api.exception.NoTrobatException;
import net.conselldemallorca.helium.v3.core.api.exception.ValidacioException;
import net.conselldemallorca.helium.v3.core.api.service.TerminiService;
import net.conselldemallorca.helium.v3.core.repository.DefinicioProcesRepository;
import net.conselldemallorca.helium.v3.core.repository.ExpedientRepository;
import net.conselldemallorca.helium.v3.core.repository.FestiuRepository;
import net.conselldemallorca.helium.v3.core.repository.RegistreRepository;
import net.conselldemallorca.helium.v3.core.repository.TerminiIniciatRepository;
import net.conselldemallorca.helium.v3.core.repository.TerminiRepository;
/**
* Servei per gestionar els terminis dels expedients
*
* @author Limit Tecnologies <limit@limit.es>
*/
@Service("terminiServiceV3")
public class TerminiServiceImpl implements TerminiService {
@Resource
private TerminiRepository terminiRepository;
@Resource
private FestiuRepository festiuRepository;
@Resource
private MessageHelper messageHelper;
@Resource
private TerminiIniciatRepository terminiIniciatRepository;
@Resource
private RegistreRepository registreRepository;
@Resource
private ExpedientRepository expedientRepository;
@Resource
private JbpmHelper jbpmHelper;
@Resource
private ConversioTipusHelper conversioTipusHelper;
@Resource
private DefinicioProcesRepository definicioProcesRepository;
@Resource
private ExpedientHelper expedientHelper;
@Transactional(readOnly=true)
@Override
public List<TerminiDto> findTerminisAmbProcessInstanceId(String processInstanceId) {
JbpmProcessInstance pi = jbpmHelper.getProcessInstance(processInstanceId);
if (pi == null)
throw new NoTrobatException(JbpmProcessInstance.class, processInstanceId);
if (pi.getProcessInstance() == null)
return null;
DefinicioProces definicioProces = definicioProcesRepository.findByJbpmId(pi.getProcessDefinitionId());
if (definicioProces == null)
throw new NoTrobatException(DefinicioProces.class, pi.getProcessDefinitionId());
return conversioTipusHelper.convertirList(
terminiRepository.findByDefinicioProcesId(definicioProces.getId()),
TerminiDto.class);
}
@Transactional(readOnly=true)
@Override
public List<TerminiIniciatDto> findIniciatsAmbProcessInstanceId(String processInstanceId) {
List<TerminiIniciat> terminiIniciats = terminiIniciatRepository.findByProcessInstanceId(processInstanceId);
return conversioTipusHelper.convertirList(terminiIniciats, TerminiIniciatDto.class);
}
@Transactional(readOnly=true)
@Override
public TerminiIniciatDto findIniciatAmbId(Long id) {
TerminiIniciat termini = terminiIniciatRepository.findById(id);
if (termini == null)
throw new NoTrobatException(TerminiIniciat.class, id);
return conversioTipusHelper.convertir(termini, TerminiIniciatDto.class);
}
private 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();
}
@Transactional
@Override
public TerminiIniciatDto iniciar(
Long terminiId,
Long expedientId,
Date data,
boolean esDataFi) {
Expedient expedient = expedientRepository.findOne(expedientId);
if (expedient == null)
throw new NoTrobatException(Expedient.class, expedientId);
Termini termini = terminiRepository.findOne(terminiId);
if (termini == null)
throw new NoTrobatException(Termini.class, terminiId);
TerminiIniciat terminiIniciat = terminiIniciatRepository.findById(terminiId);
if (terminiIniciat == null) {
return iniciar(
terminiId,
expedient,
data,
termini.getAnys(),
termini.getMesos(),
termini.getDies(),
esDataFi);
} else {
return iniciar(
terminiId,
expedient,
data,
terminiIniciat.getAnys(),
terminiIniciat.getMesos(),
terminiIniciat.getDies(),
esDataFi);
}
}
private 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();
}
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 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 = festiuRepository.findAll();
int diesLabs = 0;
while (diesLabs < nd) {
if (!esFestiu(cal, festius))
diesLabs ++;
cal.add(Calendar.DATE, signe);
}
cal.add(Calendar.DATE, -signe);
}
private TerminiIniciatDto iniciar(
Long terminiId,
Expedient expedient,
Date data,
int anys,
int mesos,
int dies,
boolean esDataFi) {
Termini termini = terminiRepository.findOne(terminiId);
TerminiIniciat terminiIniciat = terminiIniciatRepository.findById(terminiId);
if (termini == null)
termini = terminiIniciat.getTermini();
if (terminiIniciat == null) {
if (esDataFi) {
Date dataInici = getDataIniciTermini(
data,
anys,
mesos,
dies,
termini.isLaborable());
terminiIniciat = new TerminiIniciat(
termini,
anys,
mesos,
dies,
expedient.getProcessInstanceId(),
dataInici,
data);
} else {
Date dataFi = getDataFiTermini(
data,
anys,
mesos,
dies,
termini.isLaborable());
terminiIniciat = new TerminiIniciat(
termini,
anys,
mesos,
dies,
expedient.getProcessInstanceId(),
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);
}
crearRegistreTermini(
expedient.getId(),
expedient.getProcessInstanceId(),
Registre.Accio.INICIAR,
SecurityContextHolder.getContext().getAuthentication().getName());
TerminiIniciat terminiObj = terminiIniciatRepository.save(terminiIniciat);
return conversioTipusHelper.convertir(terminiObj, TerminiIniciatDto.class);
}
@Transactional
@Override
public void pausar(Long terminiIniciatId, Date data) {
TerminiIniciat terminiIniciat = terminiIniciatRepository.findById(terminiIniciatId);
if (terminiIniciat == null)
throw new NoTrobatException(TerminiIniciat.class, terminiIniciatId);
if (terminiIniciat.getDataInici() == null)
throw new ValidacioException( messageHelper.getMessage("error.terminiService.noIniciat") );
terminiIniciat.setDataAturada(data);
suspendTimers(terminiIniciat);
String processInstanceId = terminiIniciat.getProcessInstanceId();
Expedient expedient = expedientHelper.findExpedientByProcessInstanceId(processInstanceId);
if (expedient != null) {
crearRegistreTermini(
expedient.getId(),
processInstanceId,
Registre.Accio.ATURAR,
SecurityContextHolder.getContext().getAuthentication().getName());
}
}
@Transactional
@Override
public void continuar(Long terminiIniciatId, Date data) {
TerminiIniciat terminiIniciat = terminiIniciatRepository.findById(terminiIniciatId);
if (terminiIniciat == null)
throw new NoTrobatException(TerminiIniciat.class, terminiIniciatId);
if (terminiIniciat.getDataAturada() == null)
throw new ValidacioException( messageHelper.getMessage("error.terminiService.noPausat") );
int diesAturat = terminiIniciat.getNumDiesAturadaActual(data);
terminiIniciat.setDiesAturat(terminiIniciat.getDiesAturat() + diesAturat);
terminiIniciat.setDataAturada(null);
resumeTimers(terminiIniciat);
String processInstanceId = terminiIniciat.getProcessInstanceId();
Expedient expedient = expedientHelper.findExpedientByProcessInstanceId(processInstanceId);
if (expedient != null) {
crearRegistreTermini(
expedient.getId(),
processInstanceId,
Registre.Accio.REPRENDRE,
SecurityContextHolder.getContext().getAuthentication().getName());
}
}
@Transactional
@Override
public void cancelar(Long terminiIniciatId, Date data) throws IllegalStateException {
TerminiIniciat terminiIniciat = terminiIniciatRepository.findById(terminiIniciatId);
if (terminiIniciat == null)
throw new NoTrobatException(TerminiIniciat.class, terminiIniciatId);
if (terminiIniciat.getDataInici() == null)
throw new ValidacioException( messageHelper.getMessage("error.terminiService.noIniciat") );
terminiIniciat.setDataCancelacio(data);
suspendTimers(terminiIniciat);
String processInstanceId = terminiIniciat.getProcessInstanceId();
Expedient expedient = expedientHelper.findExpedientByProcessInstanceId(processInstanceId);
if (expedient != null) {
crearRegistreTermini(
expedient.getId(),
processInstanceId,
Registre.Accio.CANCELAR,
SecurityContextHolder.getContext().getAuthentication().getName());
}
}
private TerminiIniciatDto iniciar(
Long terminiId,
Long expedientId,
Date data,
int anys,
int mesos,
int dies,
boolean esDataFi) {
Expedient expedient = expedientRepository.findOne(expedientId);
return iniciar(
terminiId,
expedient,
data,
anys,
mesos,
dies,
esDataFi);
}
@Transactional
@Override
public void modificar(Long terminiId, Long expedientId, Date inicio, int anys, int mesos, int dies, boolean equals) {
cancelar(terminiId, new Date());
iniciar(
terminiId,
expedientId,
inicio,
anys,
mesos,
dies,
equals);
}
@Transactional(readOnly=true)
@Override
public List<FestiuDto> findFestiuAmbAny(int any) {
return conversioTipusHelper.convertirList(
festiuRepository.findByAny(any),
FestiuDto.class);
}
@Transactional
@Override
public void createFestiu(String data) throws Exception {
Festiu festiu = new Festiu();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
festiu.setData(sdf.parse(data));
festiuRepository.save(festiu);
}
@Transactional
@Override
public void deleteFestiu(String data) throws ValidacioException, Exception {
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Festiu festiu = festiuRepository.findByData(sdf.parse(data));
if (festiu != null) {
festiuRepository.delete(festiu);
} else {
throw new ValidacioException("No s'ha trobat el dia festiu");
}
}
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 void suspendTimers(TerminiIniciat terminiIniciat) {
for (long timerId : terminiIniciat.getTimerIdsArray())
jbpmHelper.suspendTimer(timerId, new Date(Long.MAX_VALUE));
}
private void resumeTimers(TerminiIniciat terminiIniciat) {
for (long timerId : terminiIniciat.getTimerIdsArray())
jbpmHelper.resumeTimer(timerId, terminiIniciat.getDataFi());
}
private Registre crearRegistreTermini(
Long expedientId,
String processInstanceId,
Registre.Accio accio,
String responsableCodi) {
Registre registre = new Registre(
new Date(),
expedientId,
responsableCodi.toString(),
accio,
Registre.Entitat.TERMINI,
expedientId.toString());
registre.setProcessInstanceId(processInstanceId);
return registreRepository.save(registre);
}
}