View Javadoc
1   /*
2    * Copyright 2007-2009 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.coa.document.validation.impl;
17  
18  import java.util.Collections;
19  import java.util.Date;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.log4j.Logger;
25  import org.kuali.ole.coa.identity.OleKimDocumentAttributeData;
26  import org.kuali.ole.coa.identity.OrgReviewRole;
27  import org.kuali.ole.coa.service.OrgReviewRoleService;
28  import org.kuali.ole.sys.OLEConstants;
29  import org.kuali.ole.sys.OLEKeyConstants;
30  import org.kuali.ole.sys.context.SpringContext;
31  import org.kuali.ole.sys.identity.OleKimAttributes;
32  import org.kuali.ole.sys.util.KfsDateUtils;
33  import org.kuali.rice.core.api.criteria.PredicateUtils;
34  import org.kuali.rice.core.api.criteria.QueryByCriteria;
35  import org.kuali.rice.core.api.util.type.KualiDecimal;
36  import org.kuali.rice.kim.api.KimConstants;
37  import org.kuali.rice.kim.api.common.delegate.DelegateMember;
38  import org.kuali.rice.kim.api.role.DelegateMemberQueryResults;
39  import org.kuali.rice.kim.api.role.RoleMember;
40  import org.kuali.rice.kim.api.role.RoleMembership;
41  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
42  import org.kuali.rice.kns.document.MaintenanceDocument;
43  import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
44  
45  /**
46   * This class represents the business rules for the maintenance of {@link AccountGlobal} business objects
47   */
48  public class OrgReviewRoleRule extends MaintenanceDocumentRuleBase {
49      private static final Logger LOG = Logger.getLogger(OrgReviewRoleRule.class);
50  
51      private transient static OrgReviewRoleService orgReviewRoleService;
52  
53      /**
54       * Need to override to avoid the primary key check which (wrongly) assumes that the object's PKs can be found in the persistence service.
55       *
56       * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processGlobalSaveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
57       */
58      @Override
59      protected boolean processGlobalSaveDocumentBusinessRules(MaintenanceDocument document) {
60          return dataDictionaryValidate(document);
61      }
62  
63      @Override
64      protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
65          boolean valid = super.processCustomRouteDocumentBusinessRules(document);
66          OrgReviewRole orr = (OrgReviewRole)document.getNewMaintainableObject().getBusinessObject();
67          if(!orr.hasAnyMember()){
68              valid = false;
69              putFieldError( OrgReviewRole.PRINCIPAL_NAME_FIELD_NAME, OLEKeyConstants.NO_MEMBER_SELECTED);
70          } else{
71              getOrgReviewRoleService().validateDocumentType(orr.getFinancialSystemDocumentTypeCode());
72              valid &= validateRoleMember(orr);
73              valid &= validateAmounts(orr);
74              valid &= validateDates(orr, document.isEdit());
75              // skip these validations if there are other fundamental problems
76              if ( valid ) {
77                  if( orr.isDelegate() ) {
78                      valid &= validateDelegation(orr, document.isEdit());
79                  } else {
80                      if ( !document.isEdit() ) {
81                          valid &= verifyUniqueRoleMembership(orr);
82                      }
83                  }
84              }
85          }
86          return valid;
87      }
88  
89      protected boolean validateDates( OrgReviewRole orr, boolean editingExistingRecord ) {
90          boolean valid = true;
91          Date today = KfsDateUtils.clearTimeFields(getDateTimeService().getCurrentDate());
92          Date startDate = orr.getActiveFromDate();
93          Date endDate = orr.getActiveToDate();
94          // we only need to validate the start date when creating a new record
95          if ( !editingExistingRecord ) {
96              if ( startDate == null ) {
97                  orr.setActiveFromDate(today);
98              } else {
99                  if ( startDate.before(today) ) {
100                     String label = getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ACTIVE_FROM_DATE);
101                     putFieldError( OrgReviewRole.ACTIVE_FROM_DATE, "error.document.orgReview.invalidStartDate", label);
102                     valid = false;
103                 }
104             }
105         }
106         // end date must be after start date at all times
107         if ( endDate != null && startDate != null ) {
108             if ( startDate.after(endDate) ) {
109                 String label = getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ACTIVE_TO_DATE);
110                 putFieldError(OrgReviewRole.ACTIVE_TO_DATE, "error.document.orgReview.invalidDates", label);
111                 valid = false;
112             }
113         }
114         // end date must always be in the future
115         if ( endDate != null && endDate.before(today) ) {
116             String label = getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ACTIVE_TO_DATE);
117             putFieldError(OrgReviewRole.ACTIVE_TO_DATE, "error.document.orgReview.invalidEndDate", label);
118             valid = false;
119         }
120 
121         return valid;
122     }
123 
124     protected boolean validateRoleMember(OrgReviewRole orr){
125         boolean valid = true;
126         if(StringUtils.isNotEmpty(orr.getPrincipalMemberPrincipalName())){
127             if (orr.getPerson() == null) {
128                 putFieldError(OrgReviewRole.PRINCIPAL_NAME_FIELD_NAME, "error.document.orgReview.invalidPrincipal"
129                         , getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.PRINCIPAL_NAME_FIELD_NAME) );
130                 valid = false;
131             }
132         }
133         if(StringUtils.isNotEmpty(orr.getRoleMemberRoleName())){
134             if ( StringUtils.equals( OLEConstants.SysKimApiConstants.ACCOUNTING_REVIEWER_ROLE_NAME, orr.getRoleMemberRoleName())
135                     || StringUtils.equals( OLEConstants.SysKimApiConstants.ORGANIZATION_REVIEWER_ROLE_NAME, orr.getRoleMemberRoleName() ) ) {
136                 putFieldError(OrgReviewRole.ROLE_NAME_FIELD_NAME, "error.document.orgReview.recursiveRole" );
137             } else {
138                 if(orr.getRole() == null){
139                     putFieldError(OrgReviewRole.ROLE_NAME_FIELD_NAME, "error.document.orgReview.invalidRole"
140                             , new String[] {
141                                       getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ROLE_NAME_FIELD_NAME)
142                                     , getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ROLE_NAME_FIELD_NAMESPACE_CODE)
143                                     } );
144                     valid = false;
145                 }
146             }
147         }
148         if(StringUtils.isNotEmpty(orr.getGroupMemberGroupName())){
149             if( orr.getGroup() == null ){
150                 putFieldError(OrgReviewRole.GROUP_NAME_FIELD_NAME, "error.document.orgReview.invalidGroup"
151                         , new String[] {
152                                   getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.GROUP_NAME_FIELD_NAME)
153                                 , getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.GROUP_NAME_FIELD_NAMESPACE_CODE)
154                                 } );
155                 valid = false;
156             }
157         }
158         return valid;
159     }
160 
161     protected boolean verifyUniqueDelegationMember(OrgReviewRole orr) {
162         for(String roleName: orr.getRoleNamesToConsider()){
163             String roleId = KimApiServiceLocator.getRoleService().getRoleIdByNamespaceCodeAndName( OLEConstants.SysKimApiConstants.ORGANIZATION_REVIEWER_ROLE_NAMESPACECODE, roleName);
164             DelegateMemberQueryResults results = KimApiServiceLocator.getRoleService().findDelegateMembers(
165                     QueryByCriteria.Builder.fromPredicates( PredicateUtils.convertMapToPredicate(Collections.singletonMap(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID, orr.getRoleMemberId()))));
166             List<DelegateMember> roleDelegationMembers = results.getResults();
167 
168             //validate if the newly entered delegation members are already assigned to the role
169             if(roleDelegationMembers!=null){
170                 for(DelegateMember delegationMember: roleDelegationMembers){
171                     // ignore if retrieved the current delegation member
172                     if ( delegationMember.getDelegationMemberId().equals(orr.getDelegationMemberId() )) {
173                         continue;
174                     }
175                     boolean attributesUnique = areAttributesUnique(orr, delegationMember.getAttributes());
176                     if(!attributesUnique
177                             && StringUtils.isNotBlank(orr.getMemberId())
178                             && orr.getMemberId().equals(delegationMember.getMemberId())
179                             && (StringUtils.isNotBlank(orr.getRoleMemberId())
180                                     && StringUtils.isNotBlank(delegationMember.getRoleMemberId()))
181                             ){
182                        putFieldError(orr.getMemberFieldName(), OLEKeyConstants.ALREADY_ASSIGNED_MEMBER);
183                        return false;
184                     }
185                 }
186             }
187         }
188         return true;
189     }
190 
191     protected boolean validateDelgationAmountsWithinRoleMemberBoundaries( OrgReviewRole orr ) {
192         boolean valid = true;
193         if(StringUtils.isNotEmpty(orr.getRoleMemberId())){
194             RoleMember roleMember = getOrgReviewRoleService().getRoleMemberFromKimRoleService(orr.getRoleMemberId());
195             List<OleKimDocumentAttributeData> attributes = orr.getAttributeSetAsQualifierList(roleMember.getAttributes());
196             if(roleMember!=null && attributes!=null){
197                 for(OleKimDocumentAttributeData attribute: attributes){
198                     if(OleKimAttributes.FROM_AMOUNT.equals(attribute.getKimAttribute().getAttributeName())){
199                         KualiDecimal roleMemberFromAmount = new KualiDecimal(attribute.getAttrVal());
200                         if(orr.getFromAmount()!=null){
201                             KualiDecimal inputFromAmount = orr.getFromAmount();
202                             if((roleMemberFromAmount!=null && inputFromAmount==null) || (inputFromAmount!=null && inputFromAmount.isLessThan(roleMemberFromAmount))){
203                                 putFieldError(OleKimAttributes.FROM_AMOUNT, OLEKeyConstants.FROM_AMOUNT_OUT_OF_RANGE);
204                                 valid = false;
205                             }
206                         }
207                     }
208                     if(OleKimAttributes.TO_AMOUNT.equals(attribute.getKimAttribute().getAttributeName())){
209                         KualiDecimal roleMemberToAmount = new KualiDecimal(attribute.getAttrVal());
210                         if(orr.getToAmount()!=null){
211                             KualiDecimal inputToAmount = orr.getToAmount();
212                             if((roleMemberToAmount!=null && inputToAmount==null) || (inputToAmount!=null && inputToAmount.isGreaterThan(roleMemberToAmount))){
213                                 putFieldError(OleKimAttributes.TO_AMOUNT, OLEKeyConstants.TO_AMOUNT_OUT_OF_RANGE);
214                                 valid = false;
215                             }
216                         }
217                     }
218                 }
219             }
220         }
221         return valid;
222     }
223 
224     protected boolean validateDelegation(OrgReviewRole orr, boolean isEdit){
225         boolean valid = true;
226 
227         if ( orr.getDelegationType() == null  ) {
228             putFieldError( OrgReviewRole.DELEGATION_TYPE_CODE, OLEKeyConstants.ERROR_REQUIRED, "Delegation Type Code");
229             valid = false;
230         }
231 
232         if(!isEdit){
233             valid &= verifyUniqueDelegationMember(orr);
234         }
235 
236         valid &= validateDelgationAmountsWithinRoleMemberBoundaries(orr);
237         return valid;
238     }
239 
240     protected boolean validateAmounts(OrgReviewRole orr){
241         boolean valid = true;
242         if(orr.getFromAmount()!=null && orr.getToAmount()!=null && orr.getFromAmount().isGreaterThan(orr.getToAmount())){
243             putFieldError(OleKimAttributes.FROM_AMOUNT, OLEKeyConstants.FROM_AMOUNT_GREATER_THAN_TO_AMOUNT);
244             valid = false;
245         }
246         return valid;
247     }
248 
249     /**
250      * validate if the newly entered role members are already assigned to the role
251      *
252      * @param orr
253      * @param isEdit
254      * @return
255      */
256     protected boolean verifyUniqueRoleMembership(OrgReviewRole orr){
257         for ( String roleName : orr.getRoleNamesToConsider() ) {
258             String roleId = KimApiServiceLocator.getRoleService().getRoleIdByNamespaceCodeAndName(
259                     OLEConstants.SysKimApiConstants.ORGANIZATION_REVIEWER_ROLE_NAMESPACECODE, roleName);
260             List<RoleMembership> roleMembershipInfoList = KimApiServiceLocator.getRoleService().getFirstLevelRoleMembers( Collections.singletonList(roleId));
261             if(roleMembershipInfoList!=null){
262                 for(RoleMembership roleMembershipInfo: roleMembershipInfoList){
263                     // ignore if retrieved the current role member
264                     if ( roleMembershipInfo.getId().equals(orr.getRoleMemberId() )) {
265                         continue;
266                     }
267                     String memberId = orr.getMemberId();
268                     boolean attributesUnique = areAttributesUnique(orr, roleMembershipInfo.getQualifier());
269                     if(!attributesUnique && StringUtils.isNotEmpty(memberId) && memberId.equals(roleMembershipInfo.getMemberId()) &&
270                             orr.getMemberType().equals(roleMembershipInfo.getType())){
271                        putFieldError(orr.getMemberFieldName(), OLEKeyConstants.ALREADY_ASSIGNED_MEMBER);
272                        return false;
273                     }
274                 }
275             }
276         }
277         return true;
278     }
279 
280     protected boolean areAttributesUnique(OrgReviewRole orr, Map<String,String> attributeSet){
281         String docTypeName = orr.getFinancialSystemDocumentTypeCode();
282         String chartOfAccountCode = orr.getChartOfAccountsCode();
283         String organizationCode = orr.getOrganizationCode();
284         boolean uniqueAttributes =
285             !StringUtils.equals(docTypeName, attributeSet.get(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME)) ||
286             !StringUtils.equals(chartOfAccountCode, attributeSet.get(OleKimAttributes.CHART_OF_ACCOUNTS_CODE)) ||
287             !StringUtils.equals(organizationCode, attributeSet.get(OleKimAttributes.ORGANIZATION_CODE));
288         return uniqueAttributes;
289     }
290 
291     protected OrgReviewRoleService getOrgReviewRoleService(){
292         if(orgReviewRoleService==null){
293             orgReviewRoleService = SpringContext.getBean( OrgReviewRoleService.class );
294         }
295         return orgReviewRoleService;
296     }
297 }