/** * Axelor Business Solutions * * Copyright (C) 2016 Axelor (<http://axelor.com>). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.axelor.apps.hr.service.leave; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.joda.time.LocalDate; import org.joda.time.LocalDateTime; import com.axelor.apps.base.db.DayPlanning; import com.axelor.apps.base.db.WeeklyPlanning; import com.axelor.apps.base.service.DurationService; import com.axelor.apps.base.service.administration.GeneralService; import com.axelor.apps.base.service.weeklyplanning.WeeklyPlanningService; import com.axelor.apps.crm.db.Event; import com.axelor.apps.crm.db.repo.EventRepository; import com.axelor.apps.crm.service.EventService; import com.axelor.apps.hr.db.Employee; import com.axelor.apps.hr.db.HRConfig; import com.axelor.apps.hr.db.LeaveLine; import com.axelor.apps.hr.db.LeaveReason; import com.axelor.apps.hr.db.LeaveRequest; import com.axelor.apps.hr.db.PublicHolidayPlanning; import com.axelor.apps.hr.db.repo.LeaveLineRepository; import com.axelor.apps.hr.db.repo.LeaveReasonRepository; import com.axelor.apps.hr.db.repo.LeaveRequestRepository; import com.axelor.apps.hr.exception.IExceptionMessage; import com.axelor.apps.hr.service.publicHoliday.PublicHolidayService; import com.axelor.auth.AuthUtils; import com.axelor.auth.db.User; import com.axelor.exception.AxelorException; import com.axelor.exception.db.IException; import com.axelor.i18n.I18n; import com.axelor.inject.Beans; import com.axelor.rpc.ActionRequest; import com.axelor.rpc.ActionResponse; import com.google.inject.Inject; import com.google.inject.persist.Transactional; public class LeaveService { protected DurationService durationService; protected LeaveLineRepository leaveLineRepo; protected WeeklyPlanningService weeklyPlanningService; protected EventService eventService; protected EventRepository eventRepo; protected PublicHolidayService publicHolidayService; protected LeaveRequestRepository leaveRequestRepo; @Inject public LeaveService(DurationService durationService, LeaveLineRepository leaveLineRepo, WeeklyPlanningService weeklyPlanningService, EventService eventService, EventRepository eventRepo,PublicHolidayService publicHolidayService, LeaveRequestRepository leaveRequestRepo ){ this.durationService = durationService; this.leaveLineRepo = leaveLineRepo; this.weeklyPlanningService = weeklyPlanningService; this.eventService = eventService; this.eventRepo = eventRepo; this.publicHolidayService = publicHolidayService; this.leaveRequestRepo = leaveRequestRepo; } public BigDecimal computeDuration(LeaveRequest leave) throws AxelorException{ if(leave.getFromDate()!=null && leave.getToDate()!=null){ Employee employee = leave.getUser().getEmployee(); if(employee == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_USER_EMPLOYEE),leave.getUser().getName()), IException.CONFIGURATION_ERROR); } WeeklyPlanning weeklyPlanning = employee.getPlanning(); if(weeklyPlanning == null){ HRConfig conf = leave.getCompany().getHrConfig(); if(conf != null){ weeklyPlanning = conf.getWeeklyPlanning(); } } if(weeklyPlanning == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.EMPLOYEE_PLANNING),employee.getName()), IException.CONFIGURATION_ERROR); } PublicHolidayPlanning publicHolidayPlanning = employee.getPublicHolidayPlanning(); if(publicHolidayPlanning == null){ HRConfig conf = leave.getCompany().getHrConfig(); if(conf != null){ publicHolidayPlanning = conf.getPublicHolidayPlanning(); } } BigDecimal duration = BigDecimal.ZERO; //If the leave request is only for 1 day if(leave.getFromDate().isEqual(leave.getToDate())){ if(leave.getStartOnSelect() == leave.getEndOnSelect()){ if(leave.getStartOnSelect() == LeaveRequestRepository.SELECT_MORNING){ duration = duration.add(new BigDecimal(weeklyPlanningService.workingDayValueWithSelect(weeklyPlanning, leave.getFromDate(), true, false))); } else{ duration = duration.add(new BigDecimal(weeklyPlanningService.workingDayValueWithSelect(weeklyPlanning, leave.getFromDate(), false, true))); } } else{ duration = duration.add(new BigDecimal(weeklyPlanningService.workingDayValueWithSelect(weeklyPlanning, leave.getFromDate(), true, true))); } } //Else if it's on several days else{ duration = duration.add(new BigDecimal(this.computeStartDateWithSelect(leave.getFromDate(), leave.getStartOnSelect(), weeklyPlanning))); LocalDate itDate = new LocalDate(leave.getFromDate().plusDays(1)); while(!itDate.isEqual(leave.getToDate()) && !itDate.isAfter(leave.getToDate())){ duration = duration.add(new BigDecimal(weeklyPlanningService.workingDayValue(weeklyPlanning, itDate))); itDate = itDate.plusDays(1); } duration = duration.add(new BigDecimal(this.computeEndDateWithSelect(leave.getToDate(), leave.getEndOnSelect(), weeklyPlanning))); } if(publicHolidayPlanning != null){ duration = duration.subtract(Beans.get(PublicHolidayService.class).computePublicHolidayDays(leave.getFromDate(),leave.getToDate(), weeklyPlanning, publicHolidayPlanning)); } if(duration.compareTo(BigDecimal.ZERO) < 0){ duration.equals(BigDecimal.ZERO); } return duration; } else{ return BigDecimal.ZERO; } } @Transactional(rollbackOn = {AxelorException.class, Exception.class}) public void manageSentLeaves(LeaveRequest leave) throws AxelorException{ Employee employee = leave.getUser().getEmployee(); if(employee == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_USER_EMPLOYEE),leave.getUser().getName()), IException.CONFIGURATION_ERROR); } LeaveLine leaveLine = leaveLineRepo.all().filter("self.employee = ?1 AND self.leaveReason = ?2", employee,leave.getLeaveReason()).fetchOne(); if(leaveLine == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_LINE),employee.getName(),leave.getLeaveReason().getLeaveReason()), IException.CONFIGURATION_ERROR); } if(leave.getInjectConsumeSelect() == LeaveRequestRepository.SELECT_CONSUME){ leaveLine.setDaysToValidate(leaveLine.getDaysToValidate().subtract(leave.getDuration())); } else{ leaveLine.setDaysToValidate(leaveLine.getDaysToValidate().add(leave.getDuration())); } leaveLineRepo.save(leaveLine); } @Transactional(rollbackOn = {AxelorException.class, Exception.class}) public void manageValidLeaves(LeaveRequest leave) throws AxelorException{ Employee employee = leave.getUser().getEmployee(); if(employee == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_USER_EMPLOYEE),leave.getUser().getName()), IException.CONFIGURATION_ERROR); } LeaveLine leaveLine = leaveLineRepo.all().filter("self.employee = ?1 AND self.leaveReason = ?2", employee,leave.getLeaveReason()).fetchOne(); if(leaveLine == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_LINE),employee.getName(),leave.getLeaveReason().getLeaveReason()), IException.CONFIGURATION_ERROR); } if(leave.getInjectConsumeSelect() == LeaveRequestRepository.SELECT_CONSUME){ leaveLine.setQuantity(leaveLine.getQuantity().subtract(leave.getDuration())); if(leaveLine.getQuantity().compareTo(BigDecimal.ZERO) < 0 && !employee.getNegativeValueLeave()){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_ALLOW_NEGATIVE_VALUE_EMPLOYEE),employee.getName()), IException.CONFIGURATION_ERROR); } if(leaveLine.getQuantity().compareTo(BigDecimal.ZERO) < 0 && !leave.getLeaveReason().getAllowNegativeValue()){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_ALLOW_NEGATIVE_VALUE_REASON),leave.getLeaveReason().getLeaveReason()), IException.CONFIGURATION_ERROR); } leaveLine.setDaysToValidate(leaveLine.getDaysToValidate().add(leave.getDuration())); } else{ leaveLine.setQuantity(leaveLine.getQuantity().add(leave.getDuration())); leaveLine.setDaysToValidate(leaveLine.getDaysToValidate().subtract(leave.getDuration())); } leaveLineRepo.save(leaveLine); } @Transactional(rollbackOn = {AxelorException.class, Exception.class}) public void manageRefuseLeaves(LeaveRequest leave) throws AxelorException{ Employee employee = leave.getUser().getEmployee(); if(employee == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_USER_EMPLOYEE),leave.getUser().getName()), IException.CONFIGURATION_ERROR); } LeaveLine leaveLine = leaveLineRepo.all().filter("self.employee = ?1 AND self.leaveReason = ?2", employee,leave.getLeaveReason()).fetchOne(); if(leaveLine == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_LINE),employee.getName(),leave.getLeaveReason().getLeaveReason()), IException.CONFIGURATION_ERROR); } if(leave.getInjectConsumeSelect() == LeaveRequestRepository.SELECT_CONSUME){ leaveLine.setDaysToValidate(leaveLine.getDaysToValidate().add(leave.getDuration())); } else{ leaveLine.setDaysToValidate(leaveLine.getDaysToValidate().subtract(leave.getDuration())); } leaveLineRepo.save(leaveLine); } @Transactional(rollbackOn = {AxelorException.class, Exception.class}) public void manageCancelLeaves(LeaveRequest leave) throws AxelorException{ Employee employee = leave.getUser().getEmployee(); if(employee == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_USER_EMPLOYEE),leave.getUser().getName()), IException.CONFIGURATION_ERROR); } LeaveLine leaveLine = leaveLineRepo.all().filter("self.employee = ?1 AND self.leaveReason = ?2", employee,leave.getLeaveReason()).fetchOne(); if(leaveLine == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_LINE),employee.getName(),leave.getLeaveReason().getLeaveReason()), IException.CONFIGURATION_ERROR); } if(leave.getStatusSelect() == LeaveRequestRepository.STATUS_SELECT_VALIDATED){ if(leave.getInjectConsumeSelect() == LeaveRequestRepository.SELECT_CONSUME){ leaveLine.setQuantity(leaveLine.getQuantity().add(leave.getDuration())); } else{ leaveLine.setQuantity(leaveLine.getQuantity().subtract(leave.getDuration())); } } else if(leave.getStatusSelect() == LeaveRequestRepository.STATUS_SELECT_AWAITING_VALIDATION){ if(leave.getInjectConsumeSelect() == LeaveRequestRepository.SELECT_CONSUME){ leaveLine.setDaysToValidate(leaveLine.getDaysToValidate().add(leave.getDuration())); } else{ leaveLine.setDaysToValidate(leaveLine.getDaysToValidate().subtract(leave.getDuration())); } } leaveLineRepo.save(leaveLine); } public double computeStartDateWithSelect(LocalDate date, int select, WeeklyPlanning weeklyPlanning){ double value = 0; if(select == LeaveRequestRepository.SELECT_MORNING){ value = weeklyPlanningService.workingDayValue(weeklyPlanning, date); } else { DayPlanning dayPlanning = weeklyPlanningService.findDayPlanning(weeklyPlanning,date); if(dayPlanning != null && dayPlanning.getAfternoonFrom()!= null && dayPlanning.getAfternoonTo()!= null){ value = 0.5; } } return value; } public double computeEndDateWithSelect(LocalDate date, int select, WeeklyPlanning weeklyPlanning){ double value = 0; if(select == LeaveRequestRepository.SELECT_AFTERNOON){ value = weeklyPlanningService.workingDayValue(weeklyPlanning, date); } else { DayPlanning dayPlanning = weeklyPlanningService.findDayPlanning(weeklyPlanning,date); if(dayPlanning != null && dayPlanning.getMorningFrom()!= null && dayPlanning.getMorningTo()!= null){ value = 0.5; } } return value; } @Transactional public LeaveRequest createEvents(LeaveRequest leave) throws AxelorException{ Employee employee = leave.getUser().getEmployee(); if(employee == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.LEAVE_USER_EMPLOYEE),leave.getUser().getName()), IException.CONFIGURATION_ERROR); } WeeklyPlanning weeklyPlanning = employee.getPlanning(); if(weeklyPlanning == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.EMPLOYEE_PLANNING),employee.getName()), IException.CONFIGURATION_ERROR); } int startTimeHour = 0; int startTimeMin = 0; DayPlanning startDay = weeklyPlanningService.findDayPlanning(weeklyPlanning,leave.getFromDate()); DayPlanning endDay = weeklyPlanningService.findDayPlanning(weeklyPlanning,leave.getToDate()); if(leave.getStartOnSelect() == LeaveRequestRepository.SELECT_MORNING){ if(startDay != null && startDay.getMorningFrom() != null){ startTimeHour = startDay.getMorningFrom().getHourOfDay(); startTimeMin = startDay.getMorningFrom().getMinuteOfHour(); } else{ startTimeHour = 8; startTimeMin = 0; } } else{ if(startDay != null && startDay.getAfternoonFrom() != null){ startTimeHour = startDay.getAfternoonFrom().getHourOfDay(); startTimeMin = startDay.getAfternoonFrom().getMinuteOfHour(); } else{ startTimeHour = 14; startTimeMin = 0; } } LocalDateTime fromDateTime = new LocalDateTime(leave.getFromDate().getYear(),leave.getFromDate().getMonthOfYear(),leave.getFromDate().getDayOfMonth(),startTimeHour,startTimeMin); int endTimeHour = 0; int endTimeMin = 0; if(leave.getEndOnSelect() == LeaveRequestRepository.SELECT_MORNING){ if(endDay != null && endDay.getMorningTo() != null){ endTimeHour = endDay.getMorningTo().getHourOfDay(); endTimeMin = endDay.getMorningTo().getMinuteOfHour(); } else{ endTimeHour = 12; endTimeMin = 0; } } else{ if(endDay != null && endDay.getAfternoonTo() != null){ endTimeHour = endDay.getAfternoonTo().getHourOfDay(); endTimeMin = endDay.getAfternoonTo().getMinuteOfHour(); } else{ endTimeHour = 18; endTimeMin = 0; } } LocalDateTime toDateTime = new LocalDateTime(leave.getToDate().getYear(),leave.getToDate().getMonthOfYear(),leave.getToDate().getDayOfMonth(),endTimeHour,endTimeMin); Event event = eventService.createEvent(fromDateTime, toDateTime, leave.getUser(), leave.getComments(), EventRepository.TYPE_LEAVE, leave.getLeaveReason().getLeaveReason()+" "+leave.getUser().getFullName()); eventRepo.save(event); leave.setEvent(event); return leave; } public BigDecimal computeLeaveDays(LocalDate fromDate, LocalDate toDate, User user) throws AxelorException{ BigDecimal leaveDays = BigDecimal.ZERO; Employee employee = user.getEmployee(); List<LeaveRequest> leaveRequestList = leaveRequestRepo.all().filter("self.user = ?1 AND (self.statusSelect = ?2 OR self.statusSelect = ?5) AND ((?3 <= self.fromDate AND ?4 >= self.fromDate) OR (?3 <= self.toDate AND ?4 >= self.toDate) OR (?3 >= self.fromDate AND ?4 <= self.toDate))", user, LeaveRequestRepository.STATUS_SELECT_VALIDATED, fromDate, toDate, LeaveRequestRepository.STATUS_SELECT_AWAITING_VALIDATION).fetch(); for (LeaveRequest leaveRequest : leaveRequestList) { leaveDays.add(this.computeLeaveDaysByLeaveRequest(fromDate, toDate, leaveRequest, employee)); } return leaveDays; } public BigDecimal computeLeaveDaysByLeaveRequest(LocalDate fromDate, LocalDate toDate, LeaveRequest leaveRequest, Employee employee) throws AxelorException{ BigDecimal leaveDays = BigDecimal.ZERO; WeeklyPlanning weeklyPlanning = employee.getPlanning(); if(leaveRequest.getFromDate().equals(fromDate)){ leaveDays = leaveDays.add(new BigDecimal(this.computeStartDateWithSelect(fromDate, leaveRequest.getStartOnSelect(), weeklyPlanning))); } if(leaveRequest.getToDate().equals(toDate)){ leaveDays = leaveDays.add(new BigDecimal(this.computeEndDateWithSelect(toDate, leaveRequest.getEndOnSelect(), weeklyPlanning))); } LocalDate itDate = new LocalDate(fromDate); if(fromDate.isBefore(leaveRequest.getFromDate()) || fromDate.equals(leaveRequest.getFromDate())){ itDate = new LocalDate(leaveRequest.getFromDate().plusDays(1)); } while(!itDate.isEqual(leaveRequest.getToDate()) && !itDate.isAfter(toDate)){ leaveDays = leaveDays.add(new BigDecimal(weeklyPlanningService.workingDayValue(weeklyPlanning, itDate))); if(publicHolidayService.checkPublicHolidayDay(itDate, employee)){ leaveDays = leaveDays.subtract(BigDecimal.ONE); } itDate = itDate.plusDays(1); } return leaveDays; } public void getLeaveReason(ActionRequest request, ActionResponse response){ List<Map<String,String>> dataList = new ArrayList<Map<String,String>>(); try{ List<LeaveReason> leaveReasonList = Beans.get(LeaveReasonRepository.class).all().fetch(); for (LeaveReason leaveReason : leaveReasonList) { Map<String, String> map = new HashMap<String,String>(); map.put("name", leaveReason.getLeaveReason()); map.put("id", leaveReason.getId().toString()); dataList.add(map); } response.setData(dataList); } catch(Exception e){ response.setStatus(-1); response.setError(e.getMessage()); } } @Transactional public void insertLeave(ActionRequest request, ActionResponse response) throws AxelorException{ User user = AuthUtils.getUser(); LeaveReason leaveReason = Beans.get(LeaveReasonRepository.class).find(new Long(request.getData().get("leaveReason").toString())); if(user != null && leaveReason != null){ LeaveRequest leave = new LeaveRequest(); leave.setUser(user); leave.setCompany(user.getActiveCompany()); leave.setLeaveReason(leaveReason); leave.setRequestDate(Beans.get(GeneralService.class).getTodayDate()); leave.setFromDate(new LocalDate(request.getData().get("fromDate").toString())); leave.setStartOnSelect(new Integer(request.getData().get("startOn").toString())); leave.setToDate(new LocalDate(request.getData().get("toDate").toString())); leave.setEndOnSelect(new Integer(request.getData().get("endOn").toString())); leave.setDuration(this.computeDuration(leave)); leave.setStatusSelect(LeaveRequestRepository.STATUS_SELECT_AWAITING_VALIDATION); if(request.getData().get("comment") != null){ leave.setComments(request.getData().get("comment").toString()); } Beans.get(LeaveRequestRepository.class).save(leave); } } @Transactional public void cancelLeave(LeaveRequest leave){ if (leave.getEvent() != null){ Event event = leave.getEvent(); leave.setEvent(null); eventRepo.remove(eventRepo.find(event.getId())); } leave.setStatusSelect(LeaveRequestRepository.STATUS_SELECT_CANCELED); leaveRequestRepo.save(leave); } }