package net.sourceforge.fenixedu.applicationTier.Servico.assiduousness; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Set; import net.sourceforge.fenixedu.applicationTier.FenixService; import net.sourceforge.fenixedu.applicationTier.strategy.assiduousness.CalculateDailyWorkSheetStrategyFactory; import net.sourceforge.fenixedu.applicationTier.strategy.assiduousness.strategys.ICalculateDailyWorkSheetStrategy; import net.sourceforge.fenixedu.dataTransferObject.assiduousness.AssiduousnessExportChoices; import net.sourceforge.fenixedu.dataTransferObject.assiduousness.AssiduousnessMonthlyResume; import net.sourceforge.fenixedu.dataTransferObject.assiduousness.WorkDaySheet; import net.sourceforge.fenixedu.domain.assiduousness.Assiduousness; import net.sourceforge.fenixedu.domain.assiduousness.AssiduousnessClosedMonth; import net.sourceforge.fenixedu.domain.assiduousness.AssiduousnessRecord; import net.sourceforge.fenixedu.domain.assiduousness.AssiduousnessRecordMonthIndex; import net.sourceforge.fenixedu.domain.assiduousness.ClosedMonth; import net.sourceforge.fenixedu.domain.assiduousness.Leave; import net.sourceforge.fenixedu.domain.assiduousness.Schedule; import net.sourceforge.fenixedu.domain.assiduousness.WorkSchedule; import net.sourceforge.fenixedu.domain.assiduousness.util.ScheduleClockingType; import org.joda.time.DateMidnight; import org.joda.time.DateTime; import org.joda.time.Duration; import org.joda.time.Interval; import org.joda.time.LocalDate; import pt.ist.fenixWebFramework.security.accessControl.Checked; import pt.ist.fenixWebFramework.services.Service; public class ReadMonthResume extends FenixService { @Checked("RolePredicates.PERSONNEL_SECTION_PREDICATE") @Service public static List run(AssiduousnessExportChoices assiduousnessExportChoices) { ClosedMonth closedMonth = ClosedMonth.getClosedMonth(assiduousnessExportChoices.getYearMonth()); List assiduousnessMonthlyResumeList = new ArrayList(); if (closedMonth == null) { HashMap> assiduousnessRecords = getAssiduousnessRecord( assiduousnessExportChoices.getBeginDate(), assiduousnessExportChoices.getEndDate().plusDays(1)); for (Assiduousness assiduousness : assiduousnessExportChoices.getAssiduousnesses()) { if (assiduousness.isStatusActive(assiduousnessExportChoices.getBeginDate(), assiduousnessExportChoices .getEndDate())) { assiduousnessMonthlyResumeList.add(getMonthAssiduousnessBalance(assiduousness, assiduousnessRecords .get(assiduousness), assiduousnessExportChoices.getBeginDate(), assiduousnessExportChoices .getEndDate())); } } } else { for (Assiduousness assiduousness : assiduousnessExportChoices.getAssiduousnesses()) { for (AssiduousnessClosedMonth assiduousnessClosedMonth : closedMonth.getAssiduousnessClosedMonths(assiduousness)) { if (assiduousnessClosedMonth != null) { AssiduousnessMonthlyResume assiduousnessMonthlyResume = new AssiduousnessMonthlyResume( assiduousnessClosedMonth); assiduousnessMonthlyResumeList.add(assiduousnessMonthlyResume); } } } } Collections.sort(assiduousnessMonthlyResumeList, AssiduousnessMonthlyResume.COMPARATOR_BY_EMPLOYEE_NUMBER); return assiduousnessMonthlyResumeList; } private static AssiduousnessMonthlyResume getMonthAssiduousnessBalance(Assiduousness assiduousness, List assiduousnessRecords, LocalDate beginDate, LocalDate endDate) { LocalDate lowerBeginDate = beginDate.minusDays(8); HashMap workScheduleMap = assiduousness.getWorkSchedulesBetweenDates(lowerBeginDate, endDate); DateTime init = getInit(lowerBeginDate, workScheduleMap); DateTime end = getEnd(endDate, workScheduleMap); HashMap> clockingsMap = getClockingsMap(assiduousnessRecords, workScheduleMap, init, end); HashMap> leavesMap = getLeavesMap(assiduousnessRecords, beginDate, endDate); Duration totalBalance = Duration.ZERO; Duration totalComplementaryWeeklyRestBalance = Duration.ZERO; Duration totalWeeklyRestBalance = Duration.ZERO; Duration holidayRest = Duration.ZERO; Duration extra125 = Duration.ZERO; Duration extra150 = Duration.ZERO; Duration nightWork = Duration.ZERO; Duration unjustified = Duration.ZERO; LocalDate today = new LocalDate(); for (LocalDate thisDay = beginDate; thisDay.isBefore(endDate.plusDays(1)); thisDay = thisDay.plusDays(1)) { if (thisDay.isBefore(today)) { WorkDaySheet workDaySheet = new WorkDaySheet(); workDaySheet.setDate(thisDay); final Schedule schedule = assiduousness.getSchedule(thisDay); if (schedule != null && assiduousness.isStatusActive(thisDay, thisDay)) { final boolean isDayHoliday = assiduousness.isHoliday(thisDay); final WorkSchedule workSchedule = workScheduleMap.get(thisDay); workDaySheet.setWorkSchedule(workSchedule); workDaySheet.setAssiduousnessRecords(getDayClockings(clockingsMap, thisDay)); List leavesList = getDayLeaves(leavesMap, thisDay); workDaySheet.setLeaves(leavesList); ICalculateDailyWorkSheetStrategy calculateDailyWorkSheetStrategy = CalculateDailyWorkSheetStrategyFactory .getInstance().getCalculateDailyWorkSheetStrategy(thisDay); workDaySheet = calculateDailyWorkSheetStrategy.calculateDailyBalance(assiduousness, workDaySheet, isDayHoliday); if (workSchedule != null && !isDayHoliday) { Duration thisDayBalance = workDaySheet.getBalanceTime().toDurationFrom(new DateMidnight()); if (!workSchedule.getWorkScheduleType().getScheduleClockingType().equals( ScheduleClockingType.NOT_MANDATORY_CLOCKING)) { totalBalance = totalBalance.plus(thisDayBalance); } nightWork = nightWork.plus(setNightExtraWork(workDaySheet)); Duration[] extraWork = setExtraWork(workDaySheet, thisDayBalance); extra125 = extra125.plus(extraWork[0]); extra150 = extra150.plus(extraWork[1]); unjustified = unjustified.plus(setUnjustified(workDaySheet)); } else { totalComplementaryWeeklyRestBalance = totalComplementaryWeeklyRestBalance.plus(workDaySheet .getComplementaryWeeklyRest()); totalWeeklyRestBalance = totalWeeklyRestBalance.plus(workDaySheet.getWeeklyRest()); holidayRest = holidayRest.plus(workDaySheet.getHolidayRest()); } } } } AssiduousnessMonthlyResume assiduousnessMonthlyResume = new AssiduousnessMonthlyResume(assiduousness.getEmployee(), totalBalance, totalWeeklyRestBalance, totalComplementaryWeeklyRestBalance, holidayRest, nightWork, unjustified); return assiduousnessMonthlyResume; } private static HashMap> getLeavesMap(List assiduousnessRecords, LocalDate beginDate, LocalDate endDate) { HashMap> leavesMap = new HashMap>(); if (assiduousnessRecords != null) { for (AssiduousnessRecord record : assiduousnessRecords) { if (record.isLeave() && !record.isAnulated()) { LocalDate endLeaveDay = record.getDate().toLocalDate().plusDays(1); if (((Leave) record).getEndLocalDate() != null) { endLeaveDay = ((Leave) record).getEndLocalDate().plusDays(1); } for (LocalDate leaveDay = record.getDate().toLocalDate(); leaveDay.isBefore(endLeaveDay); leaveDay = leaveDay .plusDays(1)) { if (((Leave) record).getAplicableWeekDays() == null || ((Leave) record).getAplicableWeekDays().contains(leaveDay.toDateTimeAtMidnight())) { List leaveList = leavesMap.get(leaveDay); if (leaveList == null) { leaveList = new ArrayList(); } leaveList.add((Leave) record); leavesMap.put(leaveDay, leaveList); } } } } } return leavesMap; } private static HashMap> getClockingsMap(List assiduousnessRecords, HashMap workScheduleMap, DateTime init, DateTime end) { HashMap> clockingsMap = new HashMap>(); if (assiduousnessRecords != null) { final List clockings = new ArrayList(assiduousnessRecords); Collections.sort(clockings, AssiduousnessRecord.COMPARATOR_BY_DATE); for (AssiduousnessRecord record : clockings) { if (record.isClocking() || record.isMissingClocking()) { LocalDate clockDay = record.getDate().toLocalDate(); if (WorkSchedule.overlapsSchedule(record.getDate(), workScheduleMap) == 0) { if (clockingsMap.get(clockDay.minusDays(1)) != null && clockingsMap.get(clockDay.minusDays(1)).size() % 2 != 0) { clockDay = clockDay.minusDays(1); } } else if (WorkSchedule.overlapsSchedule(record.getDate(), workScheduleMap) < 0) { clockDay = clockDay.minusDays(1); } List clocks = clockingsMap.get(clockDay); if (clocks == null) { clocks = new ArrayList(); } clocks.add(record); clockingsMap.put(clockDay, clocks); } } } return clockingsMap; } private static Duration setUnjustified(WorkDaySheet workDaySheet) { Duration thisDayUnjustified = workDaySheet.getUnjustifiedTime(); if (thisDayUnjustified == null) { thisDayUnjustified = Duration.ZERO; } return thisDayUnjustified; } private static Duration[] setExtraWork(WorkDaySheet workDaySheet, Duration thisDayBalance) { Duration[] result = new Duration[] { Duration.ZERO, Duration.ZERO }; Duration thisDayUnjustified = workDaySheet.getUnjustifiedTime(); if (thisDayUnjustified == null) { thisDayUnjustified = Duration.ZERO; } Duration hourDuration = new Duration(3600000); // TODO Duration thisDayExtraWork = thisDayBalance; ignore unjustified Duration thisDayExtraWork = thisDayBalance.plus(thisDayUnjustified); if (!thisDayExtraWork.equals(Duration.ZERO)) { if (thisDayExtraWork.isLongerThan(hourDuration)) { result[1] = thisDayExtraWork.minus(hourDuration); result[0] = hourDuration; } else if (thisDayExtraWork.isLongerThan(Duration.ZERO)) { result[0] = thisDayExtraWork; } } return result; } private static Duration setNightExtraWork(WorkDaySheet workDaySheet) { if (!workDaySheet.getIrregular() && workDaySheet.getTimeline() != null) { final Duration midHour = new Duration(1800000); Duration extraWorkDuration = workDaySheet.getTimeline().calculateWorkPeriodDurationBetweenDates( workDaySheet.getDate().toDateTime(Assiduousness.defaultStartNightWorkDay), workDaySheet.getDate().toDateTime(Assiduousness.defaultEndNightWorkDay).plusDays(1)); if (!extraWorkDuration.equals(Duration.ZERO)) { if (!extraWorkDuration.isShorterThan(midHour)) { return extraWorkDuration; } } } return Duration.ZERO; } private static List getDayLeaves(HashMap> leavesMap, LocalDate thisDay) { List leavesList = leavesMap.get(thisDay); if (leavesList == null) { leavesList = new ArrayList(); } Collections.sort(leavesList, Leave.COMPARATORY_BY_DATE); return leavesList; } private static List getDayClockings(HashMap> clockingsMap, LocalDate thisDay) { List clockingsList = clockingsMap.get(thisDay); if (clockingsList == null) { clockingsList = new ArrayList(); } Collections.sort(clockingsList, AssiduousnessRecord.COMPARATOR_BY_DATE); return clockingsList; } private static DateTime getEnd(LocalDate endDate, HashMap workScheduleMap) { DateTime end = endDate.toDateTime(Assiduousness.defaultEndWorkDay); WorkSchedule endWorkSchedule = workScheduleMap.get(endDate); if (endWorkSchedule != null) { end = endDate.toDateTime(endWorkSchedule.getWorkScheduleType().getWorkTime()).plus( endWorkSchedule.getWorkScheduleType().getWorkTimeDuration()); if (endWorkSchedule.getWorkScheduleType().isWorkTimeNextDay()) { end = end.plusDays(2); } } return end; } private static DateTime getInit(LocalDate lowerBeginDate, HashMap workScheduleMap) { DateTime init = lowerBeginDate.toDateTime(Assiduousness.defaultStartWorkDay); WorkSchedule beginWorkSchedule = workScheduleMap.get(lowerBeginDate); if (beginWorkSchedule != null) { init = lowerBeginDate.toDateTime(beginWorkSchedule.getWorkScheduleType().getWorkTime()); } return init; } private static HashMap> getAssiduousnessRecord(LocalDate beginDate, LocalDate endDate) { HashMap> assiduousnessLeaves = new HashMap>(); Interval interval = new Interval(beginDate.toDateTimeAtStartOfDay(), Assiduousness.defaultEndWorkDay.toDateTime(endDate .toDateMidnight())); Set assiduousnessRecordList = AssiduousnessRecordMonthIndex.getAssiduousnessRecordBetweenDates( interval.getStart(), interval.getEnd()); for (AssiduousnessRecord assiduousnessRecord : assiduousnessRecordList) { if (assiduousnessRecord.isLeave() && !assiduousnessRecord.isAnulated()) { Interval leaveInterval = new Interval(assiduousnessRecord.getDate(), ((Leave) assiduousnessRecord).getEndDate() .plusSeconds(1)); if (leaveInterval.overlaps(interval)) { List leavesList = assiduousnessLeaves.get(assiduousnessRecord.getAssiduousness()); if (leavesList == null) { leavesList = new ArrayList(); } leavesList.add(assiduousnessRecord); assiduousnessLeaves.put(assiduousnessRecord.getAssiduousness(), leavesList); } } else if ((assiduousnessRecord.isClocking() || assiduousnessRecord.isMissingClocking()) && (!assiduousnessRecord.isAnulated())) { if (interval.contains(assiduousnessRecord.getDate().getMillis())) { List list = assiduousnessLeaves.get(assiduousnessRecord.getAssiduousness()); if (list == null) { list = new ArrayList(); } list.add(assiduousnessRecord); assiduousnessLeaves.put(assiduousnessRecord.getAssiduousness(), list); } } } return assiduousnessLeaves; } }