001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.workflow.module.purap.attribute;
017:
018: import java.util.ArrayList;
019: import java.util.Arrays;
020: import java.util.Collections;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Set;
025:
026: import org.kuali.core.util.KualiDecimal;
027: import org.kuali.core.util.ObjectUtils;
028: import org.kuali.kfs.context.SpringContext;
029: import org.kuali.kfs.service.ParameterService;
030: import org.kuali.module.purap.PurapParameterConstants;
031: import org.kuali.module.purap.document.RequisitionDocument;
032: import org.kuali.workflow.KualiWorkflowUtils;
033:
034: import edu.iu.uis.eden.EdenConstants;
035: import edu.iu.uis.eden.Id;
036: import edu.iu.uis.eden.actiontaken.ActionTakenValue;
037: import edu.iu.uis.eden.engine.RouteContext;
038: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
039: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
040: import edu.iu.uis.eden.routetemplate.ResolvedQualifiedRole;
041: import edu.iu.uis.eden.routetemplate.Role;
042: import edu.iu.uis.eden.routetemplate.UnqualifiedRoleAttribute;
043: import edu.iu.uis.eden.workgroup.GroupNameId;
044:
045: /**
046: * A document should stop in the Separation of Duties Route Node if the following two conditions are met:
047: * <ol>
048: * <li>The total amount of the document is greater or equal to the Separation of Duties application parameter amount
049: * <li>The document was not routed for Approval or Completion to more than the user who routed the document
050: * </ol>
051: * In Workflow the rule above means any of the following scenarios do not require Separation of Duties routing (assuming that the
052: * routing of the document still applies as an Action Taken of COMPLETE):<br>
053: * <br>
054: * <ol>
055: * <li>The total number of unique people who have had an APPROVE or COMPLETE action on the document is more than 1 (keep in mind
056: * that the 'Route' action on a document generates a COMPLETE action taken)
057: * <li>The total amount of the document is less than or equal to the Separation of Duties application parameter amount
058: * </ol>
059: * EPIC RULE (these cases will route to separation of duties group):<br> - (totalCost > appSettingCost) && (0 approvals taken on
060: * the document)<br> - (totalCost > appSettingCost) && (one approval taken on the document) && (approval is by initiator user)
061: */
062: public class KualiSeparationOfDutiesRoleAttribute extends
063: UnqualifiedRoleAttribute {
064: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
065: .getLogger(KualiSeparationOfDutiesRoleAttribute.class);
066:
067: private static final String SEPARATION_OF_DUTIES_ROLE_KEY = "SEPARATION_OF_DUTIES";
068: private static final String SEPARATION_OF_DUTIES_ROLE_LABEL = "Separation of Duties Reviewer";
069:
070: private static final Role ROLE = new Role(
071: KualiSeparationOfDutiesRoleAttribute.class,
072: SEPARATION_OF_DUTIES_ROLE_KEY,
073: SEPARATION_OF_DUTIES_ROLE_LABEL);
074: private static final List<Role> ROLES;
075: static {
076: ArrayList<Role> roles = new ArrayList<Role>(1);
077: roles.add(ROLE);
078: ROLES = Collections.unmodifiableList(roles);
079: }
080:
081: /**
082: * @see edu.iu.uis.eden.routetemplate.UnqualifiedRoleAttribute#getRoleNames()
083: */
084: @Override
085: public List<Role> getRoleNames() {
086: return ROLES;
087: }
088:
089: /**
090: * TODO delyea - documentation
091: *
092: * @param routeContext the RouteContext
093: * @param roleName the role name
094: * @return a ResolvedQualifiedRole
095: */
096: @Override
097: public ResolvedQualifiedRole resolveRole(RouteContext routeContext,
098: String roleName) throws EdenUserNotFoundException {
099: DocumentRouteHeaderValue document = routeContext.getDocument();
100: Set documentReviewers = new HashSet();
101: // get a list of all people who have approved or completed this document in it's routing lifespan
102: // currently this will get the COMPLETE request that the router of the document
103: for (Iterator iter = document.getActionsTaken().iterator(); iter
104: .hasNext();) {
105: ActionTakenValue actionTaken = (ActionTakenValue) iter
106: .next();
107: if ((actionTaken.getActionTaken()
108: .equals(EdenConstants.ACTION_TAKEN_APPROVED_CD))
109: || (actionTaken.getActionTaken()
110: .equals(EdenConstants.ACTION_TAKEN_COMPLETED_CD))) {
111: documentReviewers.add(actionTaken.getWorkflowUser()
112: .getWorkflowUserId().getWorkflowId());
113: }
114: }
115: // if document has been approved or completed by more than one person... no need for separation of duties
116: if (documentReviewers.size() > 1) {
117: return null;
118: }
119: ParameterService parameterService = SpringContext
120: .getBean(ParameterService.class);
121: KualiDecimal maxAllowedAmount = new KualiDecimal(
122: parameterService
123: .getParameterValue(
124: RequisitionDocument.class,
125: PurapParameterConstants.WorkflowParameters.RequisitionDocument.SEPARATION_OF_DUTIES_DOLLAR_AMOUNT));
126: // if app param amount is greater than or equal to documentTotalAmount... no need for separation of duties
127: KualiDecimal totalAmount = KualiWorkflowUtils
128: .getFinancialDocumentTotalAmount(routeContext);
129: if (ObjectUtils.isNotNull(maxAllowedAmount)
130: && ObjectUtils.isNotNull(totalAmount)
131: && (maxAllowedAmount.compareTo(totalAmount) >= 0)) {
132: return null;
133: }
134: String workgroupName = parameterService
135: .getParameterValue(
136: RequisitionDocument.class,
137: PurapParameterConstants.WorkflowParameters.RequisitionDocument.SEPARATION_OF_DUTIES_WORKGROUP_NAME);
138: return new ResolvedQualifiedRole(
139: SEPARATION_OF_DUTIES_ROLE_LABEL, Arrays
140: .asList(new Id[] { new GroupNameId(
141: workgroupName) }));
142: }
143: }
|