package org.synyx.urlaubsverwaltung.web.overtime; import org.joda.time.DateMidnight; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import org.synyx.urlaubsverwaltung.core.overtime.Overtime; import org.synyx.urlaubsverwaltung.core.overtime.OvertimeService; import org.synyx.urlaubsverwaltung.core.settings.SettingsService; import org.synyx.urlaubsverwaltung.core.settings.WorkingTimeSettings; import org.synyx.urlaubsverwaltung.core.util.CalcUtil; import java.math.BigDecimal; import java.util.Optional; /** * Validates overtime record. * * @author Aljona Murygina - murygina@synyx.de */ @Component public class OvertimeValidator implements Validator { private static final int MAX_CHARS = 200; private static final String ERROR_MANDATORY = "error.entry.mandatory"; private static final String ERROR_MAX_CHARS = "error.entry.tooManyChars"; private static final String ERROR_INVALID_PERIOD = "error.entry.invalidPeriod"; private static final String ERROR_MAX_OVERTIME = "overtime.data.numberOfHours.error.maxOvertime"; private static final String ERROR_MIN_OVERTIME = "overtime.data.numberOfHours.error.minOvertime"; private static final String ERROR_OVERTIME_DEACTIVATED = "overtime.record.error.deactivated"; private static final String ATTRIBUTE_START_DATE = "startDate"; private static final String ATTRIBUTE_END_DATE = "endDate"; private static final String ATTRIBUTE_NUMBER_OF_HOURS = "numberOfHours"; private static final String ATTRIBUTE_COMMENT = "comment"; private final OvertimeService overtimeService; private final SettingsService settingsService; @Autowired public OvertimeValidator(OvertimeService overtimeService, SettingsService settingsService) { this.overtimeService = overtimeService; this.settingsService = settingsService; } @Override public boolean supports(Class<?> clazz) { return OvertimeForm.class.equals(clazz); } @Override public void validate(Object target, Errors errors) { OvertimeForm overtimeForm = (OvertimeForm) target; WorkingTimeSettings settings = settingsService.getSettings().getWorkingTimeSettings(); if (!settings.isOvertimeActive()) { errors.reject(ERROR_OVERTIME_DEACTIVATED); // if overtime management is deactivated, no need to execute further validation return; } validatePeriod(overtimeForm, errors); validateNumberOfHours(overtimeForm, errors); validateMaximumOvertimeNotReached(settings, overtimeForm, errors); validateComment(overtimeForm, errors); } private void validatePeriod(OvertimeForm overtimeForm, Errors errors) { DateMidnight startDate = overtimeForm.getStartDate(); DateMidnight endDate = overtimeForm.getEndDate(); validateDateNotNull(startDate, ATTRIBUTE_START_DATE, errors); validateDateNotNull(endDate, ATTRIBUTE_END_DATE, errors); if (startDate != null && endDate != null && endDate.isBefore(startDate)) { errors.rejectValue(ATTRIBUTE_END_DATE, ERROR_INVALID_PERIOD); } } private void validateDateNotNull(DateMidnight date, String field, Errors errors) { // may be that date field is null because of cast exception, than there is already a field error if (date == null && !errors.hasFieldErrors(field)) { errors.rejectValue(field, ERROR_MANDATORY); } } private void validateNumberOfHours(OvertimeForm overtimeForm, Errors errors) { BigDecimal numberOfHours = overtimeForm.getNumberOfHours(); // may be that number of hours field is null because of cast exception, than there is already a field error if (numberOfHours == null && !errors.hasFieldErrors(ATTRIBUTE_NUMBER_OF_HOURS)) { errors.rejectValue(ATTRIBUTE_NUMBER_OF_HOURS, ERROR_MANDATORY); } } private void validateMaximumOvertimeNotReached(WorkingTimeSettings settings, OvertimeForm overtimeForm, Errors errors) { BigDecimal numberOfHours = overtimeForm.getNumberOfHours(); if (numberOfHours != null) { BigDecimal maximumOvertime = new BigDecimal(settings.getMaximumOvertime()); BigDecimal minimumOvertime = new BigDecimal(settings.getMinimumOvertime()); if (CalcUtil.isZero(maximumOvertime)) { errors.reject(ERROR_OVERTIME_DEACTIVATED); return; } BigDecimal leftOvertime = overtimeService.getLeftOvertimeForPerson(overtimeForm.getPerson()); Integer overtimeRecordId = overtimeForm.getId(); if (overtimeRecordId != null) { Optional<Overtime> overtimeRecordOptional = overtimeService.getOvertimeById(overtimeRecordId); if (overtimeRecordOptional.isPresent()) { leftOvertime = leftOvertime.subtract(overtimeRecordOptional.get().getHours()); } } // left overtime + overtime record must not be greater than maximum overtime if (leftOvertime.add(numberOfHours).compareTo(maximumOvertime) > 0) { errors.rejectValue(ATTRIBUTE_NUMBER_OF_HOURS, ERROR_MAX_OVERTIME, new Object[] { maximumOvertime }, null); } // left overtime + overtime record must be greater than minimum overtime // minimum overtime are missing hours (means negative) if (leftOvertime.add(numberOfHours).compareTo(minimumOvertime.negate()) < 0) { errors.rejectValue(ATTRIBUTE_NUMBER_OF_HOURS, ERROR_MIN_OVERTIME, new Object[] { minimumOvertime }, null); } } } private void validateComment(OvertimeForm overtimeForm, Errors errors) { String comment = overtimeForm.getComment(); if (StringUtils.hasText(comment) && comment.length() > MAX_CHARS) { errors.rejectValue(ATTRIBUTE_COMMENT, ERROR_MAX_CHARS); } } }