/* * 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.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.coa.businessobject.Account; import org.kuali.kfs.coa.businessobject.Chart; import org.kuali.kfs.coa.businessobject.ProjectCode; import org.kuali.kfs.coa.businessobject.SubAccount; import org.kuali.kfs.module.tem.TemConstants; import org.kuali.kfs.module.tem.TemKeyConstants; import org.kuali.kfs.module.tem.TemPropertyConstants; import org.kuali.kfs.module.tem.TemPropertyConstants.TemProfileProperties; import org.kuali.kfs.module.tem.businessobject.TemProfile; import org.kuali.kfs.module.tem.businessobject.TemProfileAccount; import org.kuali.kfs.module.tem.businessobject.TemProfileArranger; import org.kuali.kfs.module.tem.service.TemProfileService; import org.kuali.kfs.module.tem.service.TravelService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.KFSPropertyConstants; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.rice.kim.api.identity.Person; import org.kuali.rice.kim.api.identity.PersonService; import org.kuali.rice.kns.document.MaintenanceDocument; import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; import org.kuali.rice.kns.service.DataDictionaryService; import org.kuali.rice.krad.bo.PersistableBusinessObject; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; public class TemProfileRule extends MaintenanceDocumentRuleBase{ protected static final String TRAVEL_ARRANGERS_SECTION_ID = "TemProfileArrangers"; protected volatile static TemProfileService temProfileService; protected volatile static DataDictionaryService dataDictionaryService; /** * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#dataDictionaryValidate(org.kuali.rice.kns.document.MaintenanceDocument) */ @Override protected boolean dataDictionaryValidate(MaintenanceDocument document) { BusinessObjectService businessObjectService = getBusinessObjectService(); TemProfile profile = (TemProfile) document.getNewMaintainableObject().getBusinessObject(); TravelService travelService = SpringContext.getBean(TravelService.class); boolean success = true; List<String> paths = GlobalVariables.getMessageMap().getErrorPath(); Map<String,Object> fieldValues = new HashMap<String,Object>(); paths.add("document"); paths.add("newMaintainableObject"); if (!StringUtils.isEmpty(profile.getPhoneNumber())){ String errorMessage = travelService.validatePhoneNumber(profile.getCountryCode(), profile.getPhoneNumber(), TemKeyConstants.ERROR_PHONE_NUMBER); if (!StringUtils.isBlank(errorMessage)) { GlobalVariables.getMessageMap().putError(TemProfileProperties.PHONE_NUMBER, errorMessage, new String[] { "Phone Number"}); success = false; } } if (!StringUtils.isEmpty(profile.getDefaultChartCode())){ fieldValues.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, profile.getDefaultChartCode()); List<Chart> chartList = (List<Chart>) businessObjectService.findMatching(Chart.class, fieldValues); if (chartList.size() == 0){ GlobalVariables.getMessageMap().putError(TemPropertyConstants.TemProfileProperties.DEFAULT_CHART_CODE, TemKeyConstants.ERROR_TEM_PROFILE_CHART_NOT_EXIST, profile.getDefaultChartCode()); success = false; } } else{ profile.setChart(null); } if (success && !StringUtils.isEmpty(profile.getDefaultAccount())){ fieldValues.put(KFSPropertyConstants.ACCOUNT_NUMBER, profile.getDefaultAccount()); List<Account> accountList = (List<Account>) businessObjectService.findMatching(Account.class, fieldValues); if (accountList.size() == 0){ GlobalVariables.getMessageMap().putError(TemPropertyConstants.TemProfileProperties.DEFAULT_ACCOUNT_NUMBER, TemKeyConstants.ERROR_TEM_PROFILE_ACCOUNT_NOT_EXIST, profile.getDefaultAccount()); success = false; } } else{ profile.setAccount(null); } if (success && !StringUtils.isEmpty(profile.getDefaultSubAccount())){ fieldValues.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER, profile.getDefaultSubAccount()); List<SubAccount> subAccountList = (List<SubAccount>) businessObjectService.findMatching(SubAccount.class, fieldValues); if (subAccountList.size() == 0){ GlobalVariables.getMessageMap().putError(TemPropertyConstants.TemProfileProperties.DEFAULT_SUB_ACCOUNT_NUMBER, TemKeyConstants.ERROR_TEM_PROFILE_SUB_ACCOUNT_NOT_EXIST, profile.getDefaultSubAccount()); success = false; } } else{ profile.setSubAccount(null); } if (!StringUtils.isEmpty(profile.getDefaultProjectCode())){ fieldValues.clear(); fieldValues.put(KFSConstants.GENERIC_CODE_PROPERTY_NAME, profile.getDefaultProjectCode()); List<ProjectCode> subAccountList = (List<ProjectCode>) businessObjectService.findMatching(ProjectCode.class, fieldValues); if (subAccountList.size() == 0){ GlobalVariables.getMessageMap().putError(TemPropertyConstants.TemProfileProperties.DEFAULT_PROJECT_CODE, TemKeyConstants.ERROR_TEM_PROFILE_PROJECT_CODE_NOT_EXIST, profile.getDefaultProjectCode()); success = false; } } else{ profile.setProject(null); } for (int i=0;i<profile.getAccounts().size();i++){ paths.add(TemPropertyConstants.TemProfileProperties.ACCOUNTS + "[" + i + "]"); TemProfileAccount account = profile.getAccounts().get(i); paths.remove(paths.size()-1); } //Arranger section validation if(profile.getArrangers() != null){ int arrangerPrimaryCount = 0; Set<String> arrangerId = new HashSet<String>(); for (TemProfileArranger arranger : profile.getArrangers()){ if(arranger.getPrimary()){ arrangerPrimaryCount++; } arrangerId.add(arranger.getPrincipalName()); paths.add(TemPropertyConstants.TemProfileProperties.ARRANGERS); paths.remove(paths.size()-1); } //check for multiple primary arrangers; only 1 primary allowed. if(arrangerPrimaryCount > 1){ GlobalVariables.getMessageMap().putError(TemPropertyConstants.TemProfileProperties.ARRANGERS, TemKeyConstants.ERROR_TEM_PROFILE_ARRANGER_PRIMARY); success = false; } //check for duplicate arrangers if(profile.getArrangers().size() != arrangerId.size()){ GlobalVariables.getMessageMap().putError(TemPropertyConstants.TemProfileProperties.ARRANGERS, TemKeyConstants.ERROR_TEM_PROFILE_ARRANGER_DUPLICATE); success = false; } } paths.clear(); success = success && super.dataDictionaryValidate(document); if(success){ Person user = GlobalVariables.getUserSession().getPerson(); profile.setUpdatedBy(user.getPrincipalName()); Date current = new Date(); profile.setLastUpdate(new java.sql.Date(current.getTime())); } return success; } /** * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomAddCollectionLineBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument, java.lang.String, org.kuali.rice.kns.bo.PersistableBusinessObject) */ @Override public boolean processCustomAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName, PersistableBusinessObject line) { TemProfile profile = (TemProfile)document.getNewMaintainableObject().getBusinessObject(); //set other arranger as primary false if the new arranger is the primary if (line instanceof TemProfileArranger){ TemProfileArranger arranger = (TemProfileArranger)line; //check that the arranger's org is under the initiator's if (TemConstants.NONEMP_TRAVELER_TYP_CD.equals(profile.getTravelerTypeCode())) { TravelService travelService = SpringContext.getBean(TravelService.class); String initiatorId = document.getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId(); final Person initiator = SpringContext.getBean(PersonService.class).getPerson(initiatorId); } if (arranger.getPrimary()){ for (TemProfileArranger tempArranger : ((TemProfile)document.getNewMaintainableObject().getBusinessObject()).getArrangers()){ tempArranger.setPrimary(false); } if (TemConstants.NONEMP_TRAVELER_TYP_CD.equals(profile.getTravelerTypeCode())) { String profileChart = profile.getHomeDeptChartOfAccountsCode(); String profileOrg = profile.getHomeDeptOrgCode(); final Person arrangerPerson = SpringContext.getBean(PersonService.class).getPerson(arranger.getPrincipalId()); String primaryDeptCode[] = arrangerPerson.getPrimaryDepartmentCode().split("-"); if(primaryDeptCode != null && primaryDeptCode.length == 2){ profile.setHomeDeptChartOfAccountsCode(primaryDeptCode[0]); profile.setHomeDeptOrgCode(primaryDeptCode[1]); } } } } // check for CreditCardAgency accounts else if (line instanceof TemProfileAccount){ TemProfileAccount account = (TemProfileAccount) line; return checkNewTemProfileAccount(profile, account); } return super.processCustomAddCollectionLineBusinessRules(document, collectionName, line); } /** * Performs rules against a new TEM Profile account * * @param account * @return */ protected boolean checkNewTemProfileAccount(TemProfile temProfile, TemProfileAccount account) { boolean success = true; //minimum length if (!StringUtils.isBlank(account.getAccountNumber())){ final Integer minLength = getDataDictionaryService().getAttributeMaxLength(TemProfile.class, TemPropertyConstants.TemProfileProperties.ACCOUNT_NUMBER); if (minLength != null && account.getAccountNumber().length() < minLength.intValue()) { final String label = getDataDictionaryService().getAttributeLabel(TemProfile.class, TemPropertyConstants.TemProfileProperties.ACCOUNT_NUMBER); String errorMessage[] = null; errorMessage = new String[] { label, minLength.toString() }; GlobalVariables.getMessageMap().putError(TemPropertyConstants.TemProfileProperties.ACCOUNT_NUMBER, KFSKeyConstants.ERROR_MIN_LENGTH, errorMessage); success = false; } //do not duplicate an existing account in the system if (doesProfileAccountMatchExisting(temProfile, account)){ if (account.getCreditCardOrAgencyCode() != null) { account.refreshReferenceObject(TemPropertyConstants.CREDIT_CARD_AGENCY); } GlobalVariables.getMessageMap().putError(TemPropertyConstants.TemProfileProperties.ACCOUNT_NUMBER, TemKeyConstants.ERROR_TEM_PROFILE_ACCOUNT_ID_DUPLICATE, new String[] { account.getCreditCardAgency().getCreditCardOrAgencyName(), account.getAccountNumber() }); success = false; } } return success; } /** * Checks if the given newAccount matches - by account number and credit card agency - an already existing profile account on the profile * @param profile the profile with existing profile accounts * @param newAccount the account to see if it exists among the existing accounts * @return true if the newAccount is already on the profile; false otherwise */ protected boolean doesProfileAccountMatchExisting(TemProfile profile, TemProfileAccount newAccount) { if (profile.getAccounts() == null || profile.getAccounts().isEmpty()) { return getTemProfileService().doesProfileAccountExist(newAccount, profile); } for (TemProfileAccount existingAccount : profile.getAccounts()) { if (StringUtils.equals(existingAccount.getAccountNumber(), newAccount.getAccountNumber()) && StringUtils.equals(existingAccount.getCreditCardOrAgencyCode(), newAccount.getCreditCardOrAgencyCode())) { return true; } } return getTemProfileService().doesProfileAccountExist(newAccount, profile); } /** * Checks that, if the profile represents a non-employee, the profile has an active arranger * @param profile the profile to check * @return true if the profile passed the validation, false otherwise */ protected boolean checkActiveArrangersForNonEmployees(TemProfile profile) { boolean success = true; if (profile != null && getTemProfileService().isProfileNonEmploye(profile)) { // we've got a non-employee. let's see if they have at least one active arranger if (!getTemProfileService().hasActiveArrangers(profile)) { GlobalVariables.getMessageMap().putErrorForSectionId(TRAVEL_ARRANGERS_SECTION_ID, TemKeyConstants.ERROR_TEM_PROFILE_NONEMPLOYEE_MUST_HAVE_ACTIVE_ARRANGER); success = false; } } return success; } /** * Checks that, if the profile represents a non-employee, the profile has an email address * @param profile the profile to check * @return true if the profile passed the validation, false otherwise */ protected boolean checkEmailAddressForNonEmployees(TemProfile profile) { boolean success = true; if (profile != null && getTemProfileService().isProfileNonEmploye(profile)) { // we've got a non-employee. let's see if they have an email address if (StringUtils.isBlank(profile.getEmailAddress())) { GlobalVariables.getMessageMap().putError("document.newMaintainableObject."+TemPropertyConstants.TemProfileProperties.EMAIL_ADDRESS, TemKeyConstants.ERROR_TEM_PROFILE_NONEMPLOYEE_MUST_HAVE_EMAIL); success = false; } } return success; } @Override protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) { boolean success = true; TemProfile profile = (TemProfile) document.getNewMaintainableObject().getBusinessObject(); if (ObjectUtils.isNotNull(profile.getHomeDeptOrg())){ if (!profile.getHomeDeptOrg().isActive()) { putFieldError(TemProfileProperties.HOME_DEPARTMENT, TemKeyConstants.ERROR_TEM_PROFILE_ORGANIZATION_INACTIVE, profile.getHomeDeptChartOfAccountsCode()+"-"+profile.getHomeDeptOrgCode()); success = false; } } success &= checkActiveArrangersForNonEmployees(profile); success &= checkEmailAddressForNonEmployees(profile); return success; } protected BusinessObjectService getBusinessObjectService() { return SpringContext.getBean(BusinessObjectService.class); } protected TemProfileService getTemProfileService() { if (temProfileService == null) { temProfileService = SpringContext.getBean(TemProfileService.class); } return temProfileService; } @Override protected DataDictionaryService getDataDictionaryService() { if (dataDictionaryService == null) { dataDictionaryService = SpringContext.getBean(DataDictionaryService.class); } return dataDictionaryService; } }