/* * 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.coa.document.validation.impl; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.kuali.kfs.coa.identity.KfsKimDocumentAttributeData; import org.kuali.kfs.coa.identity.OrgReviewRole; import org.kuali.kfs.coa.service.OrgReviewRoleService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.kfs.sys.identity.KfsKimAttributes; import org.kuali.kfs.sys.util.KfsDateUtils; import org.kuali.rice.core.api.criteria.PredicateUtils; import org.kuali.rice.core.api.criteria.QueryByCriteria; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.kim.api.KimConstants; import org.kuali.rice.kim.api.common.delegate.DelegateMember; import org.kuali.rice.kim.api.role.DelegateMemberQueryResults; import org.kuali.rice.kim.api.role.RoleMember; import org.kuali.rice.kim.api.role.RoleMembership; import org.kuali.rice.kim.api.services.KimApiServiceLocator; import org.kuali.rice.kns.document.MaintenanceDocument; import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase; /** * This class represents the business rules for the maintenance of {@link AccountGlobal} business objects */ public class OrgReviewRoleRule extends MaintenanceDocumentRuleBase { private static final Logger LOG = Logger.getLogger(OrgReviewRoleRule.class); private transient static OrgReviewRoleService orgReviewRoleService; /** * Need to override to avoid the primary key check which (wrongly) assumes that the object's PKs can be found in the persistence service. * * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processGlobalSaveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument) */ @Override protected boolean processGlobalSaveDocumentBusinessRules(MaintenanceDocument document) { return dataDictionaryValidate(document); } @Override protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) { boolean valid = super.processCustomRouteDocumentBusinessRules(document); OrgReviewRole orr = (OrgReviewRole)document.getNewMaintainableObject().getBusinessObject(); if(!orr.hasAnyMember()){ valid = false; putFieldError( OrgReviewRole.PRINCIPAL_NAME_FIELD_NAME, KFSKeyConstants.NO_MEMBER_SELECTED); } else{ getOrgReviewRoleService().validateDocumentType(orr.getFinancialSystemDocumentTypeCode()); valid &= validateRoleMember(orr); valid &= validateAmounts(orr); valid &= validateDates(orr, document.isEdit()); // skip these validations if there are other fundamental problems if ( valid ) { if( orr.isDelegate() ) { valid &= validateDelegation(orr, document.isEdit()); } else { if ( !document.isEdit() ) { valid &= verifyUniqueRoleMembership(orr); } } } } return valid; } protected boolean validateDates( OrgReviewRole orr, boolean editingExistingRecord ) { boolean valid = true; Date today = KfsDateUtils.clearTimeFields(getDateTimeService().getCurrentDate()); Date startDate = orr.getActiveFromDate(); Date endDate = orr.getActiveToDate(); // we only need to validate the start date when creating a new record if ( !editingExistingRecord ) { if ( startDate == null ) { orr.setActiveFromDate(today); } else { if ( startDate.before(today) ) { String label = getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ACTIVE_FROM_DATE); putFieldError( OrgReviewRole.ACTIVE_FROM_DATE, "error.document.orgReview.invalidStartDate", label); valid = false; } } } // end date must be after start date at all times if ( endDate != null && startDate != null ) { if ( startDate.after(endDate) ) { String label = getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ACTIVE_TO_DATE); putFieldError(OrgReviewRole.ACTIVE_TO_DATE, "error.document.orgReview.invalidDates", label); valid = false; } } // end date must always be in the future if ( endDate != null && endDate.before(today) ) { String label = getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ACTIVE_TO_DATE); putFieldError(OrgReviewRole.ACTIVE_TO_DATE, "error.document.orgReview.invalidEndDate", label); valid = false; } return valid; } protected boolean validateRoleMember(OrgReviewRole orr){ boolean valid = true; if(StringUtils.isNotEmpty(orr.getPrincipalMemberPrincipalName())){ if (orr.getPerson() == null) { putFieldError(OrgReviewRole.PRINCIPAL_NAME_FIELD_NAME, "error.document.orgReview.invalidPrincipal" , getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.PRINCIPAL_NAME_FIELD_NAME) ); valid = false; } } if(StringUtils.isNotEmpty(orr.getRoleMemberRoleName())){ if ( StringUtils.equals( KFSConstants.SysKimApiConstants.ACCOUNTING_REVIEWER_ROLE_NAME, orr.getRoleMemberRoleName()) || StringUtils.equals( KFSConstants.SysKimApiConstants.ORGANIZATION_REVIEWER_ROLE_NAME, orr.getRoleMemberRoleName() ) ) { putFieldError(OrgReviewRole.ROLE_NAME_FIELD_NAME, "error.document.orgReview.recursiveRole" ); } else { if(orr.getRole() == null){ putFieldError(OrgReviewRole.ROLE_NAME_FIELD_NAME, "error.document.orgReview.invalidRole" , new String[] { getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ROLE_NAME_FIELD_NAME) , getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.ROLE_NAME_FIELD_NAMESPACE_CODE) } ); valid = false; } } } if(StringUtils.isNotEmpty(orr.getGroupMemberGroupName())){ if( orr.getGroup() == null ){ putFieldError(OrgReviewRole.GROUP_NAME_FIELD_NAME, "error.document.orgReview.invalidGroup" , new String[] { getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.GROUP_NAME_FIELD_NAME) , getDataDictionaryService().getAttributeLabel(OrgReviewRole.class, OrgReviewRole.GROUP_NAME_FIELD_NAMESPACE_CODE) } ); valid = false; } } return valid; } protected boolean verifyUniqueDelegationMember(OrgReviewRole orr) { for(String roleName: orr.getRoleNamesToConsider()){ String roleId = KimApiServiceLocator.getRoleService().getRoleIdByNamespaceCodeAndName( KFSConstants.SysKimApiConstants.ORGANIZATION_REVIEWER_ROLE_NAMESPACECODE, roleName); DelegateMemberQueryResults results = KimApiServiceLocator.getRoleService().findDelegateMembers( QueryByCriteria.Builder.fromPredicates( PredicateUtils.convertMapToPredicate(Collections.singletonMap(KimConstants.PrimaryKeyConstants.ROLE_MEMBER_ID, orr.getRoleMemberId())))); List<DelegateMember> roleDelegationMembers = results.getResults(); //validate if the newly entered delegation members are already assigned to the role if(roleDelegationMembers!=null && StringUtils.isNotBlank(orr.getMemberId()) && StringUtils.isNotBlank(orr.getRoleMemberId()) ) { for(DelegateMember delegationMember: roleDelegationMembers){ // ignore if retrieved the current delegation member if ( delegationMember.getDelegationMemberId().equals(orr.getDelegationMemberId() )) { continue; } if( orr.getMemberId().equals(delegationMember.getMemberId()) && StringUtils.isNotBlank(delegationMember.getRoleMemberId()) && doAttributesMatch(orr, delegationMember.getAttributes()) ){ putFieldError(orr.getMemberFieldName(), KFSKeyConstants.ALREADY_ASSIGNED_MEMBER); return false; } } } } return true; } protected boolean validateDelgationAmountsWithinRoleMemberBoundaries( OrgReviewRole orr ) { boolean valid = true; if(StringUtils.isNotEmpty(orr.getRoleMemberId())){ RoleMember roleMember = getOrgReviewRoleService().getRoleMemberFromKimRoleService(orr.getRoleMemberId()); List<KfsKimDocumentAttributeData> attributes = orr.getAttributeSetAsQualifierList(roleMember.getAttributes()); if(roleMember!=null && attributes!=null){ for(KfsKimDocumentAttributeData attribute: attributes){ if(KfsKimAttributes.FROM_AMOUNT.equals(attribute.getKimAttribute().getAttributeName())){ KualiDecimal roleMemberFromAmount = new KualiDecimal(attribute.getAttrVal()); if(orr.getFromAmount()!=null){ KualiDecimal inputFromAmount = orr.getFromAmount(); if((roleMemberFromAmount!=null && inputFromAmount==null) || (inputFromAmount!=null && inputFromAmount.isLessThan(roleMemberFromAmount))){ putFieldError(KfsKimAttributes.FROM_AMOUNT, KFSKeyConstants.FROM_AMOUNT_OUT_OF_RANGE); valid = false; } } } if(KfsKimAttributes.TO_AMOUNT.equals(attribute.getKimAttribute().getAttributeName())){ KualiDecimal roleMemberToAmount = new KualiDecimal(attribute.getAttrVal()); if(orr.getToAmount()!=null){ KualiDecimal inputToAmount = orr.getToAmount(); if((roleMemberToAmount!=null && inputToAmount==null) || (inputToAmount!=null && inputToAmount.isGreaterThan(roleMemberToAmount))){ putFieldError(KfsKimAttributes.TO_AMOUNT, KFSKeyConstants.TO_AMOUNT_OUT_OF_RANGE); valid = false; } } } } } } return valid; } protected boolean validateDelegation(OrgReviewRole orr, boolean isEdit){ boolean valid = true; if ( orr.getDelegationType() == null ) { putFieldError( OrgReviewRole.DELEGATION_TYPE_CODE, KFSKeyConstants.ERROR_REQUIRED, "Delegation Type Code"); valid = false; } if(!isEdit){ valid &= verifyUniqueDelegationMember(orr); } valid &= validateDelgationAmountsWithinRoleMemberBoundaries(orr); return valid; } protected boolean validateAmounts(OrgReviewRole orr){ boolean valid = true; if(orr.getFromAmount()!=null && orr.getToAmount()!=null && orr.getFromAmount().isGreaterThan(orr.getToAmount())){ putFieldError(KfsKimAttributes.FROM_AMOUNT, KFSKeyConstants.FROM_AMOUNT_GREATER_THAN_TO_AMOUNT); valid = false; } return valid; } /** * validate if the newly entered role members are already assigned to the role * * @param orr * @param isEdit * @return */ protected boolean verifyUniqueRoleMembership(OrgReviewRole orr){ for ( String roleName : orr.getRoleNamesToConsider() ) { String roleId = KimApiServiceLocator.getRoleService().getRoleIdByNamespaceCodeAndName( KFSConstants.SysKimApiConstants.ORGANIZATION_REVIEWER_ROLE_NAMESPACECODE, roleName); List<RoleMembership> roleMembershipInfoList = KimApiServiceLocator.getRoleService().getFirstLevelRoleMembers( Collections.singletonList(roleId)); String documentMemberId = orr.getMemberId(); if(roleMembershipInfoList!=null && StringUtils.isNotEmpty(documentMemberId) ){ for(RoleMembership roleMembershipInfo: roleMembershipInfoList){ // ignore if retrieved the current role member if ( roleMembershipInfo.getId().equals(orr.getRoleMemberId() )) { continue; } if( documentMemberId.equals(roleMembershipInfo.getMemberId()) && orr.getMemberType().equals(roleMembershipInfo.getType()) && doAttributesMatch(orr, roleMembershipInfo.getQualifier()) ) { putFieldError(orr.getMemberFieldName(), KFSKeyConstants.ALREADY_ASSIGNED_MEMBER); return false; } } } } return true; } protected boolean doAttributesMatch(OrgReviewRole orr, Map<String,String> attributeSet){ String docTypeName = orr.getFinancialSystemDocumentTypeCode(); String chartOfAccountCode = orr.getChartOfAccountsCode(); String organizationCode = orr.getOrganizationCode(); return StringUtils.equals(docTypeName, attributeSet.get(KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME)) && StringUtils.equals(chartOfAccountCode, attributeSet.get(KfsKimAttributes.CHART_OF_ACCOUNTS_CODE)) && StringUtils.equals(organizationCode, attributeSet.get(KfsKimAttributes.ORGANIZATION_CODE)); } protected OrgReviewRoleService getOrgReviewRoleService(){ if(orgReviewRoleService==null){ orgReviewRoleService = SpringContext.getBean( OrgReviewRoleService.class ); } return orgReviewRoleService; } }