001 /* 002 * Copyright 2011 The Kuali Foundation. 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.kfs.module.cg.document.validation.impl; 017 018 import java.sql.Date; 019 import java.util.ArrayList; 020 import java.util.Arrays; 021 import java.util.Collection; 022 import java.util.Collections; 023 import java.util.HashMap; 024 import java.util.List; 025 026 import org.apache.commons.lang.StringUtils; 027 import org.kuali.kfs.module.cg.businessobject.Agency; 028 import org.kuali.kfs.module.cg.businessobject.CGProjectDirector; 029 import org.kuali.kfs.module.cg.businessobject.Primaryable; 030 import org.kuali.kfs.sys.KFSConstants; 031 import org.kuali.kfs.sys.KFSKeyConstants; 032 import org.kuali.kfs.sys.KFSPropertyConstants; 033 import org.kuali.kfs.sys.context.SpringContext; 034 import org.kuali.rice.kim.bo.reference.impl.EmploymentStatusImpl; 035 import org.kuali.rice.kim.service.PersonService; 036 import org.kuali.rice.kim.service.RoleManagementService; 037 import org.kuali.rice.kns.bo.BusinessObject; 038 import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; 039 import org.kuali.rice.kns.service.DataDictionaryService; 040 import org.kuali.rice.kns.util.ObjectUtils; 041 042 /** 043 * Rules for the Proposal/Award maintenance document. 044 */ 045 public class CGMaintenanceDocumentRuleBase extends MaintenanceDocumentRuleBase { 046 047 protected static final String PROJECT_DIRECTOR_DECEASED = "D"; 048 protected static final String[] PROJECT_DIRECTOR_INVALID_STATUSES = { PROJECT_DIRECTOR_DECEASED }; 049 050 protected static final String AGENCY_TYPE_CODE_FEDERAL = "F"; 051 052 /** 053 * Checks to see if the end date is after the begin date 054 * 055 * @param begin 056 * @param end 057 * @param propertyName 058 * @return true if end is after begin, false otherwise 059 */ 060 protected boolean checkEndAfterBegin(Date begin, Date end, String propertyName) { 061 boolean success = true; 062 if (ObjectUtils.isNotNull(begin) && ObjectUtils.isNotNull(end) && !end.after(begin)) { 063 putFieldError(propertyName, KFSKeyConstants.ERROR_ENDING_DATE_NOT_AFTER_BEGIN); 064 success = false; 065 } 066 return success; 067 } 068 069 /** 070 * @param <E> 071 * @param primaryables 072 * @param elementClass 073 * @param collectionName 074 * @param boClass 075 * @return 076 */ 077 protected <E extends Primaryable> boolean checkPrimary(Collection<E> primaryables, Class<E> elementClass, String collectionName, Class<? extends BusinessObject> boClass) { 078 boolean success = true; 079 int count = 0; 080 for (Primaryable p : primaryables) { 081 if (p.isPrimary()) { 082 count++; 083 } 084 } 085 if (count != 1) { 086 success = false; 087 String elementLabel = SpringContext.getBean(DataDictionaryService.class).getCollectionElementLabel(boClass.getName(), collectionName, elementClass); 088 switch (count) { 089 case 0: 090 putFieldError(collectionName, KFSKeyConstants.ERROR_NO_PRIMARY, elementLabel); 091 break; 092 default: 093 putFieldError(collectionName, KFSKeyConstants.ERROR_MULTIPLE_PRIMARY, elementLabel); 094 } 095 096 } 097 return success; 098 } 099 100 /** 101 * @param <T> 102 * @param projectDirectors 103 * @param elementClass 104 * @param collectionName 105 * @return 106 */ 107 protected <T extends CGProjectDirector> boolean checkProjectDirectorsExist(List<T> projectDirectors, Class<T> elementClass, String collectionName) { 108 boolean success = true; 109 final String personUserPropertyName = KFSPropertyConstants.PROJECT_DIRECTOR + "." + KFSPropertyConstants.PERSON_USER_IDENTIFIER; 110 String label = SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(elementClass, personUserPropertyName); 111 int i = 0; 112 for (T pd : projectDirectors) { 113 String propertyName = collectionName + "[" + (i++) + "]." + personUserPropertyName; 114 String id = pd.getPrincipalId(); 115 if (StringUtils.isBlank(id) || (SpringContext.getBean(PersonService.class).getPerson(id) == null)) { 116 putFieldError(propertyName, KFSKeyConstants.ERROR_EXISTENCE, label); 117 success = false; 118 } 119 } 120 return success; 121 } 122 123 /** 124 * @param <T> 125 * @param projectDirectors 126 * @param elementClass 127 * @param collectionName 128 * @return 129 */ 130 protected <T extends CGProjectDirector> boolean checkProjectDirectorsAreDirectors(List<T> projectDirectors, Class<T> elementClass, String collectionName) { 131 boolean success = true; 132 final String personUserPropertyName = KFSPropertyConstants.PROJECT_DIRECTOR + "." + KFSPropertyConstants.PERSON_USER_IDENTIFIER; 133 String label = SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(elementClass, personUserPropertyName); 134 RoleManagementService roleService = SpringContext.getBean(RoleManagementService.class); 135 136 List<String> roleId = new ArrayList<String>(); 137 roleId.add(roleService.getRoleIdByName(KFSConstants.ParameterNamespaces.KFS, KFSConstants.SysKimConstants.CONTRACTS_AND_GRANTS_PROJECT_DIRECTOR)); 138 139 int i = 0; 140 for (T pd : projectDirectors) { 141 String propertyName = collectionName + "[" + (i++) + "]." + personUserPropertyName; 142 String id = pd.getProjectDirector().getPrincipalId(); 143 if (!roleService.principalHasRole(id, roleId, null)) { 144 putFieldError(propertyName, KFSKeyConstants.ERROR_NOT_A_PROJECT_DIRECTOR, id); 145 success = false; 146 } 147 } 148 return success; 149 } 150 151 152 /** 153 * This method takes in a collection of {@link ProjectDirector}s and reviews them to see if any have invalid states for being 154 * added to a {@link Proposal}. An example would be a status code of "D" which means "Deceased". Project Directors with a 155 * status of "D" cannot be added to a {@link Proposal} or {@link Award}. 156 * 157 * @param projectDirectors Collection of project directors to be reviewed. 158 * @param elementClass Type of object that the collection belongs to. 159 * @param propertyName Name of field that error will be attached to. 160 * @return True if all the project directors have valid statuses, false otherwise. 161 */ 162 protected <T extends CGProjectDirector> boolean checkProjectDirectorsStatuses(List<T> projectDirectors, Class<T> elementClass, String propertyName) { 163 boolean success = true; 164 final String personUserPropertyName = KFSPropertyConstants.PROJECT_DIRECTOR + "." + KFSPropertyConstants.PERSON_USER_IDENTIFIER; 165 String label = SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(elementClass, personUserPropertyName); 166 for (T pd : projectDirectors) { 167 String pdEmplStatusCode = pd.getProjectDirector().getEmployeeStatusCode(); 168 HashMap<String, String> criteria = new HashMap<String, String>(); 169 criteria.put( "code", pdEmplStatusCode ); 170 if (StringUtils.isBlank(pdEmplStatusCode) || Arrays.asList(PROJECT_DIRECTOR_INVALID_STATUSES).contains(pdEmplStatusCode)) { 171 EmploymentStatusImpl empStatus = (EmploymentStatusImpl)getBoService().findByPrimaryKey(EmploymentStatusImpl.class, criteria); 172 String pdEmplStatusName = (empStatus != null)?empStatus.getName():"INVALID STATUS CODE " + pdEmplStatusCode; 173 String[] errors = { pd.getProjectDirector().getName(), pdEmplStatusCode + " - " + pdEmplStatusName }; 174 putFieldError(propertyName, KFSKeyConstants.ERROR_INVALID_PROJECT_DIRECTOR_STATUS, errors); 175 success = false; 176 } 177 } 178 return success; 179 } 180 181 /** 182 * This method checks to see if the two agency values passed in are the same {@link Agency}. The agency for a C&G document 183 * cannot be the same as the Federal Pass Through Agency for that same document. 184 * 185 * @param agency 186 * @param federalPassThroughAgency 187 * @param agencyPropertyName 188 * @return True if the agencies are not the same, false otherwise. 189 */ 190 protected boolean checkAgencyNotEqualToFederalPassThroughAgency(Agency agency, Agency federalPassThroughAgency, String agencyPropertyName, String fedPassThroughAgencyPropertyName) { 191 boolean success = true; 192 if (ObjectUtils.isNotNull(agency) && ObjectUtils.isNotNull(federalPassThroughAgency) && agency.equals(federalPassThroughAgency)) { 193 putFieldError(agencyPropertyName, KFSKeyConstants.ERROR_AGENCY_EQUALS_FEDERAL_PASS_THROUGH_AGENCY); 194 putFieldError(fedPassThroughAgencyPropertyName, KFSKeyConstants.ERROR_FEDERAL_PASS_THROUGH_AGENCY_EQUALS_AGENCY); 195 success = false; 196 } 197 return success; 198 } 199 200 /** 201 * Checks if the required federal pass through fields are filled in if the federal pass through indicator is yes. 202 * 203 * @return True if all the necessary rules regarding the federal pass through agency input fields are met, false otherwise. 204 */ 205 protected boolean checkFederalPassThrough(boolean federalPassThroughIndicator, Agency primaryAgency, String federalPassThroughAgencyNumber, Class propertyClass, String federalPassThroughIndicatorFieldName) { 206 boolean success = true; 207 208 // check if primary agency is federal 209 boolean primaryAgencyIsFederal = false; 210 211 if (ObjectUtils.isNotNull(primaryAgency)) { 212 primaryAgencyIsFederal = AGENCY_TYPE_CODE_FEDERAL.equalsIgnoreCase(primaryAgency.getAgencyTypeCode()); 213 } 214 215 String indicatorLabel = SpringContext.getBean(DataDictionaryService.class).getAttributeErrorLabel(propertyClass, federalPassThroughIndicatorFieldName); 216 String agencyLabel = SpringContext.getBean(DataDictionaryService.class).getAttributeErrorLabel(propertyClass, KFSPropertyConstants.FEDERAL_PASS_THROUGH_AGENCY_NUMBER); 217 218 if (primaryAgencyIsFederal) { 219 if (federalPassThroughIndicator) { 220 // fpt indicator should not be checked if primary agency is federal 221 putFieldError(federalPassThroughIndicatorFieldName, KFSKeyConstants.ERROR_PRIMARY_AGENCY_IS_FEDERAL_AND_FPT_INDICATOR_IS_CHECKED, new String[] { primaryAgency.getAgencyNumber(), AGENCY_TYPE_CODE_FEDERAL }); 222 success = false; 223 } 224 if (!StringUtils.isBlank(federalPassThroughAgencyNumber)) { 225 // fpt agency number should be blank if primary agency is federal 226 putFieldError(KFSPropertyConstants.FEDERAL_PASS_THROUGH_AGENCY_NUMBER, KFSKeyConstants.ERROR_PRIMARY_AGENCY_IS_FEDERAL_AND_FPT_AGENCY_IS_NOT_BLANK, new String[] { primaryAgency.getAgencyNumber(), AGENCY_TYPE_CODE_FEDERAL }); 227 success = false; 228 } 229 } 230 else { 231 if (federalPassThroughIndicator && StringUtils.isBlank(federalPassThroughAgencyNumber)) { 232 // fpt agency number is required if fpt indicator is checked 233 putFieldError(KFSPropertyConstants.FEDERAL_PASS_THROUGH_AGENCY_NUMBER, KFSKeyConstants.ERROR_FPT_AGENCY_NUMBER_REQUIRED); 234 success = false; 235 } 236 else if (!federalPassThroughIndicator && !StringUtils.isBlank(federalPassThroughAgencyNumber)) { 237 // fpt agency number should be blank if fpt indicator is not checked 238 putFieldError(KFSPropertyConstants.FEDERAL_PASS_THROUGH_AGENCY_NUMBER, KFSKeyConstants.ERROR_FPT_AGENCY_NUMBER_NOT_BLANK); 239 success = false; 240 } 241 } 242 243 return success; 244 } 245 246 } 247