/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * 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 org.kuali.kfs.module.tem.document.validation.impl; import java.math.BigDecimal; import org.kuali.kfs.module.tem.TemConstants.PerDiemType; import org.kuali.kfs.module.tem.TemKeyConstants; import org.kuali.kfs.module.tem.TemPropertyConstants; import org.kuali.kfs.module.tem.businessobject.ActualExpense; import org.kuali.kfs.module.tem.document.TravelDocument; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent; import org.kuali.rice.krad.service.DataDictionaryService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; public class TravelDocumentActualExpenseDetailLineValidation extends TemDocumentExpenseLineValidation implements ActualExpenseDetailValidation { protected ActualExpense actualExpenseForValidation; protected ActualExpense actualExpenseDetailForValidation; protected DataDictionaryService dataDictionaryService; /** * @see org.kuali.kfs.sys.document.validation.Validation#validate(org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent) */ @Override public boolean validate(AttributedDocumentEvent event) { TravelDocument travelDocument = (TravelDocument) event.getDocument(); boolean success = validateDetail(travelDocument); return success; } /** * Validate expense detail rules * * 1. expense detail mileage rule * 2. expense detail amount is non-zero * 3. expense detail does not exceed parent (threshold) for non-mileage expense * * @param actualExpense * @param actualExpenseDetail * @param travelDocument * @return */ public boolean validateDetail(TravelDocument travelDocument){ boolean success = getDictionaryValidationService().isBusinessObjectValid(getActualExpenseDetailForValidation(), ""); if (success) { //validate mileage success &= validateMileageRules(travelDocument); //validate lodging success &= validateLodgingRules(travelDocument); //validate expense detail amount is negative if (getActualExpenseDetailForValidation().getExpenseAmount().isNegative()) { GlobalVariables.getMessageMap().putError(TemPropertyConstants.EXPENSE_AMOUNT, TemKeyConstants.ERROR_TEM_DETAIL_LESS_THAN_ZERO); success = false; } //for non-mileage expense detail if (!getActualExpenseDetailForValidation().isMileage()){ // Determine if the detail is an amount that doesn't go over the threshold if (getActualExpenseForValidation().getExpenseAmount().isLessThan(getActualExpenseForValidation().getTotalDetailExpenseAmount())) { GlobalVariables.getMessageMap().putError(TemPropertyConstants.EXPENSE_AMOUNT, TemKeyConstants.ERROR_TEM_DETAIL_GREATER_THAN_EXPENSE); success = false; } } } //info for non-one currency if (success && !getActualExpenseDetailForValidation().getCurrencyRate().equals(BigDecimal.ONE)) { GlobalVariables.getMessageMap().putInfo(TemPropertyConstants.EXPENSE_AMOUNT, TemKeyConstants.INFO_TEM_IMPORT_CURRENCY_CONVERSION); } return success; } /** * This method validates following rules * * 1.Validates whether miles & mileage rate / other mileage rate is entered * 2.Validates other mileage rate with the max rate configured in mileage table, if other mileage rate is specified * * @param actualExpense * @param document * @return boolean */ protected boolean validateMileageRules(TravelDocument document) { boolean valid = true; if (getActualExpenseDetailForValidation().isMileage()) { // Check to see if miles & mileage rate/other mileage rate is entered final java.sql.Date effectiveDate = document.getEffectiveDateForMileageRate(getActualExpenseDetailForValidation()); valid = (ObjectUtils.isNotNull(getActualExpenseDetailForValidation().getMiles()) && getActualExpenseDetailForValidation().getMiles() > 0 && (ObjectUtils.isNotNull(getActualExpenseDetailForValidation().getMileageRate(effectiveDate)) || (ObjectUtils.isNotNull(getActualExpenseDetailForValidation().getMileageOtherRate()) && getActualExpenseDetailForValidation().getMileageOtherRate().compareTo(BigDecimal.ZERO) > 0))); if (valid) { if (ObjectUtils.isNotNull(getActualExpenseDetailForValidation().getMileageOtherRate())) { BigDecimal maxMileageRate = getMaxMileageRate(); if (getActualExpenseDetailForValidation().getMileageOtherRate().compareTo(maxMileageRate) > 0) { GlobalVariables.getMessageMap().putError(TemPropertyConstants.TEM_ACTUAL_EXPENSE_MILES, TemKeyConstants.ERROR_ACTUAL_EXPENSE_OTHER_MILEAGE_RATE_EXCEED, getActualExpenseDetailForValidation().getMileageOtherRate().toString(), maxMileageRate.toString()); valid = false; } } } else { String label = getDataDictionaryService().getAttributeLabel(ActualExpense.class, TemPropertyConstants.TEM_ACTUAL_EXPENSE_MILES) + ", " + getDataDictionaryService().getAttributeLabel(ActualExpense.class, TemPropertyConstants.TEM_ACTUAL_EXPENSE_MILE_RATE) + " or " + getDataDictionaryService().getAttributeLabel(ActualExpense.class, TemPropertyConstants.TEM_ACTUAL_EXPENSE_MILE_OTHER_RATE); GlobalVariables.getMessageMap().putError(TemPropertyConstants.TEM_ACTUAL_EXPENSE_MILES, KFSKeyConstants.ERROR_REQUIRED, label); } // check that there's no per diem for the same day if (isPerDiemMileageEntered(getActualExpenseDetailForValidation().getExpenseDate(), document.getPerDiemExpenses())) { valid &= addPerDiemError(PerDiemType.mileage, false); } } return valid; } /** * If the actual expense detail line being validated is lodging, checks rules upon that * @param document the travel document that the actual expense detail is being added to * @return true if validation succeeded, false otherwise */ protected boolean validateLodgingRules(TravelDocument document) { boolean valid = true; if (getActualExpenseDetailForValidation().isLodging()) { // check if there's a per diem the next day if (isPerDiemLodgingEntered(getActualExpenseDetailForValidation().getExpenseDate(), document.getPerDiemExpenses())) { valid &= addPerDiemError(PerDiemType.lodging, false); } } return valid; } public ActualExpense getActualExpenseForValidation() { return actualExpenseForValidation; } @Override public void setActualExpenseForValidation(ActualExpense actualExpenseForValidation) { this.actualExpenseForValidation = actualExpenseForValidation; } public ActualExpense getActualExpenseDetailForValidation() { return actualExpenseDetailForValidation; } @Override public void setActualExpenseDetailForValidation(ActualExpense actualExpenseDetailForValidation) { this.actualExpenseDetailForValidation = actualExpenseDetailForValidation; } public DataDictionaryService getDataDictionaryService() { return dataDictionaryService; } public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { this.dataDictionaryService = dataDictionaryService; } }