View Javadoc
1   /*
2    * Copyright 2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.module.cg.document.validation.impl;
17  
18  import java.sql.Date;
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.Collection;
22  import java.util.List;
23  
24  import org.apache.commons.lang.StringUtils;
25  import org.kuali.ole.module.cg.businessobject.Agency;
26  import org.kuali.ole.module.cg.businessobject.CGProjectDirector;
27  import org.kuali.ole.module.cg.businessobject.Primaryable;
28  import org.kuali.ole.sys.OLEConstants;
29  import org.kuali.ole.sys.OLEKeyConstants;
30  import org.kuali.ole.sys.OLEPropertyConstants;
31  import org.kuali.ole.sys.context.SpringContext;
32  import org.kuali.rice.kim.api.identity.CodedAttribute;
33  import org.kuali.rice.kim.api.identity.PersonService;
34  import org.kuali.rice.kim.api.role.RoleService;
35  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
36  import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
37  import org.kuali.rice.kns.service.DataDictionaryService;
38  import org.kuali.rice.krad.bo.BusinessObject;
39  import org.kuali.rice.krad.util.ObjectUtils;
40  
41  /**
42   * Rules for the Proposal/Award maintenance document.
43   */
44  public class CGMaintenanceDocumentRuleBase extends MaintenanceDocumentRuleBase {
45  
46      protected static final String PROJECT_DIRECTOR_DECEASED = "D";
47      protected static final String[] PROJECT_DIRECTOR_INVALID_STATUSES = { PROJECT_DIRECTOR_DECEASED };
48  
49      protected static final String AGENCY_TYPE_CODE_FEDERAL = "F";
50  
51      /**
52       * Checks to see if the end date is after the begin date
53       *
54       * @param begin
55       * @param end
56       * @param propertyName
57       * @return true if end is after begin, false otherwise
58       */
59      protected boolean checkEndAfterBegin(Date begin, Date end, String propertyName) {
60          boolean success = true;
61          if (ObjectUtils.isNotNull(begin) && ObjectUtils.isNotNull(end) && !end.after(begin)) {
62              putFieldError(propertyName, OLEKeyConstants.ERROR_ENDING_DATE_NOT_AFTER_BEGIN);
63              success = false;
64          }
65          return success;
66      }
67  
68      /**
69       * @param <E>
70       * @param primaryables
71       * @param elementClass
72       * @param collectionName
73       * @param boClass
74       * @return
75       */
76      protected <E extends Primaryable> boolean checkPrimary(Collection<E> primaryables, Class<E> elementClass, String collectionName, Class<? extends BusinessObject> boClass) {
77          boolean success = true;
78          int count = 0;
79          for (Primaryable p : primaryables) {
80              if (p.isPrimary()) {
81                  count++;
82              }
83          }
84          if (count != 1) {
85              success = false;
86              String elementLabel = SpringContext.getBean(DataDictionaryService.class).getCollectionElementLabel(boClass.getName(), collectionName, elementClass);
87              switch (count) {
88                  case 0:
89                      putFieldError(collectionName, OLEKeyConstants.ERROR_NO_PRIMARY, elementLabel);
90                      break;
91                  default:
92                      putFieldError(collectionName, OLEKeyConstants.ERROR_MULTIPLE_PRIMARY, elementLabel);
93              }
94  
95          }
96          return success;
97      }
98  
99      /**
100      * @param <T>
101      * @param projectDirectors
102      * @param elementClass
103      * @param collectionName
104      * @return
105      */
106     protected <T extends CGProjectDirector> boolean checkProjectDirectorsExist(List<T> projectDirectors, Class<T> elementClass, String collectionName) {
107         boolean success = true;
108         final String personUserPropertyName = OLEPropertyConstants.PROJECT_DIRECTOR + "." + OLEPropertyConstants.PERSON_USER_IDENTIFIER;
109         String label = SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(elementClass, personUserPropertyName);
110         int i = 0;
111         for (T pd : projectDirectors) {
112             String propertyName = collectionName + "[" + (i++) + "]." + personUserPropertyName;
113             String id = pd.getPrincipalId();
114             if (StringUtils.isBlank(id) || (SpringContext.getBean(PersonService.class).getPerson(id) == null)) {
115                 putFieldError(propertyName, OLEKeyConstants.ERROR_EXISTENCE, label);
116                 success = false;
117             }
118         }
119         return success;
120     }
121 
122     /**
123      * @param <T>
124      * @param projectDirectors
125      * @param elementClass
126      * @param collectionName
127      * @return
128      */
129     protected <T extends CGProjectDirector> boolean checkProjectDirectorsAreDirectors(List<T> projectDirectors, Class<T> elementClass, String collectionName) {
130         boolean success = true;
131         final String personUserPropertyName = OLEPropertyConstants.PROJECT_DIRECTOR + "." + OLEPropertyConstants.PERSON_USER_IDENTIFIER;
132         String label = SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(elementClass, personUserPropertyName);
133         RoleService roleService = KimApiServiceLocator.getRoleService();
134 
135         List<String> roleId = new ArrayList<String>();
136         roleId.add(roleService.getRoleIdByNamespaceCodeAndName(OLEConstants.CoreModuleNamespaces.OLE, OLEConstants.SysKimApiConstants.CONTRACTS_AND_GRANTS_PROJECT_DIRECTOR));
137 
138         int i = 0;
139         for (T pd : projectDirectors) {
140             String propertyName = collectionName + "[" + (i++) + "]." + personUserPropertyName;
141             String id = pd.getProjectDirector().getPrincipalId();
142             if (!roleService.principalHasRole(id, roleId, null)) {
143                 putFieldError(propertyName, OLEKeyConstants.ERROR_NOT_A_PROJECT_DIRECTOR, id);
144                 success = false;
145             }
146         }
147         return success;
148     }
149 
150 
151     /**
152      * This method takes in a collection of {@link ProjectDirector}s and reviews them to see if any have invalid states for being
153      * added to a {@link Proposal}. An example would be a status code of "D" which means "Deceased". Project Directors with a
154      * status of "D" cannot be added to a {@link Proposal} or {@link Award}.
155      *
156      * @param projectDirectors Collection of project directors to be reviewed.
157      * @param elementClass Type of object that the collection belongs to.
158      * @param propertyName Name of field that error will be attached to.
159      * @return True if all the project directors have valid statuses, false otherwise.
160      */
161     protected <T extends CGProjectDirector> boolean checkProjectDirectorsStatuses(List<T> projectDirectors, Class<T> elementClass, String propertyName) {
162         boolean success = true;
163         for (T pd : projectDirectors) {
164             String pdEmplStatusCode = pd.getProjectDirector().getEmployeeStatusCode();
165             if (StringUtils.isBlank(pdEmplStatusCode) || Arrays.asList(PROJECT_DIRECTOR_INVALID_STATUSES).contains(pdEmplStatusCode)) {
166                 String pdEmplStatusName = "INVALID STATUS CODE " + pdEmplStatusCode;
167                 if ( StringUtils.isNotBlank(pdEmplStatusCode) ) {
168                     CodedAttribute empStatus = KimApiServiceLocator.getIdentityService().getEmploymentStatus(pdEmplStatusCode);
169                     if ( empStatus != null ) {
170                         pdEmplStatusName = empStatus.getName();
171                     }
172                 }
173                 String[] errors = { pd.getProjectDirector().getName(), pdEmplStatusCode + " - " + pdEmplStatusName };
174                 putFieldError(propertyName, OLEKeyConstants.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, OLEKeyConstants.ERROR_AGENCY_EQUALS_FEDERAL_PASS_THROUGH_AGENCY);
194             putFieldError(fedPassThroughAgencyPropertyName, OLEKeyConstants.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, OLEPropertyConstants.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, OLEKeyConstants.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(OLEPropertyConstants.FEDERAL_PASS_THROUGH_AGENCY_NUMBER, OLEKeyConstants.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(OLEPropertyConstants.FEDERAL_PASS_THROUGH_AGENCY_NUMBER, OLEKeyConstants.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(OLEPropertyConstants.FEDERAL_PASS_THROUGH_AGENCY_NUMBER, OLEKeyConstants.ERROR_FPT_AGENCY_NUMBER_NOT_BLANK);
239                 success = false;
240             }
241         }
242 
243         return success;
244     }
245 
246 }
247