0001: /*
0002: * Copyright 2006-2007 The Kuali Foundation.
0003: *
0004: * Licensed under the Educational Community License, Version 1.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.opensource.org/licenses/ecl1.php
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.kuali.workflow.attribute;
0018:
0019: import java.util.ArrayList;
0020: import java.util.Collections;
0021: import java.util.Comparator;
0022: import java.util.HashMap;
0023: import java.util.HashSet;
0024: import java.util.Iterator;
0025: import java.util.List;
0026: import java.util.Map;
0027: import java.util.Set;
0028:
0029: import javax.xml.xpath.XPath;
0030: import javax.xml.xpath.XPathConstants;
0031:
0032: import org.apache.commons.lang.StringUtils;
0033: import org.apache.log4j.Logger;
0034: import org.kuali.core.bo.DocumentHeader;
0035: import org.kuali.core.lookup.LookupUtils;
0036: import org.kuali.core.util.FieldUtils;
0037: import org.kuali.core.util.KualiDecimal;
0038: import org.kuali.core.util.ObjectUtils;
0039: import org.kuali.core.workflow.attribute.WorkflowLookupableImpl;
0040: import org.kuali.kfs.KFSConstants;
0041: import org.kuali.kfs.KFSPropertyConstants;
0042: import org.kuali.kfs.bo.SourceAccountingLine;
0043: import org.kuali.kfs.context.SpringContext;
0044: import org.kuali.module.chart.bo.Account;
0045: import org.kuali.module.chart.bo.Chart;
0046: import org.kuali.module.chart.bo.Org;
0047: import org.kuali.module.chart.service.AccountService;
0048: import org.kuali.module.chart.service.OrganizationService;
0049: import org.kuali.workflow.KualiWorkflowUtils;
0050: import org.w3c.dom.Document;
0051: import org.w3c.dom.Element;
0052: import org.w3c.dom.Node;
0053: import org.w3c.dom.NodeList;
0054:
0055: import edu.iu.uis.eden.WorkflowServiceErrorImpl;
0056: import edu.iu.uis.eden.doctype.DocumentType;
0057: import edu.iu.uis.eden.engine.RouteContext;
0058: import edu.iu.uis.eden.lookupable.Field;
0059: import edu.iu.uis.eden.lookupable.Row;
0060: import edu.iu.uis.eden.plugin.attributes.MassRuleAttribute;
0061: import edu.iu.uis.eden.plugin.attributes.WorkflowAttribute;
0062: import edu.iu.uis.eden.routeheader.DocumentContent;
0063: import edu.iu.uis.eden.routetemplate.RuleBaseValues;
0064: import edu.iu.uis.eden.routetemplate.RuleExtension;
0065: import edu.iu.uis.eden.routetemplate.RuleExtensionValue;
0066: import edu.iu.uis.eden.util.Utilities;
0067:
0068: /**
0069: * KualiOrgReviewAttribute should be used when using Orgs and thier inner details to do routing.
0070: */
0071: public class KualiOrgReviewAttribute implements WorkflowAttribute,
0072: MassRuleAttribute {
0073:
0074: static final long serialVersionUID = 1000;
0075:
0076: private static Logger LOG = Logger
0077: .getLogger(KualiOrgReviewAttribute.class);
0078:
0079: public static final String FIN_COA_CD_KEY = "fin_coa_cd";
0080:
0081: public static final String ORG_CD_KEY = "org_cd";
0082:
0083: public static final String FROM_AMOUNT_KEY = "fromAmount";
0084:
0085: public static final String TO_AMOUNT_KEY = "toAmount";
0086:
0087: private static final String TOTAL_AMOUNT_KEY = "totalAmount";
0088:
0089: public static final String OVERRIDE_CD_KEY = "overrideCd";
0090:
0091: private static final String ORG_REVIEW_ATTRIBUTE = "KUALI_ORG_REVIEW_ATTRIBUTE";
0092:
0093: private static Map ORGS = new HashMap();
0094:
0095: private static final String DOCUMENT_CHART_ORG_VALUES_KEY = "organizations";
0096:
0097: private String finCoaCd;
0098:
0099: private String orgCd;
0100:
0101: private String toAmount;
0102:
0103: private String fromAmount;
0104:
0105: private String overrideCd;
0106:
0107: private String totalDollarAmount;
0108:
0109: private boolean required;
0110:
0111: private List ruleRows;
0112:
0113: private List routingDataRows;
0114:
0115: /**
0116: * TODO clean the rest of the field defs up once chart is working this code up no arg constructor, which will initialize the
0117: * fields and rows of the attribute
0118: */
0119: public KualiOrgReviewAttribute() {
0120: List fields = new ArrayList();
0121:
0122: ruleRows = new ArrayList();
0123: ruleRows.add(getChartRowUsingKualiWorkflowUtils());
0124: ruleRows.add(getOrgRowUsingKualiWorkflowUtils());
0125: ruleRows.add(getOverrideCodeRowUsingKualiWorkflowUtils());
0126:
0127: fields = new ArrayList();
0128: fields.add(new Field("From Amount", "", Field.TEXT, true,
0129: FROM_AMOUNT_KEY, "", null, null, FROM_AMOUNT_KEY));
0130: ruleRows.add(new Row(fields));
0131: fields = new ArrayList();
0132: fields.add(new Field("To Amount", "", Field.TEXT, true,
0133: TO_AMOUNT_KEY, "", null, null, TO_AMOUNT_KEY));
0134: ruleRows.add(new Row(fields));
0135:
0136: routingDataRows = new ArrayList();
0137: routingDataRows.add(getChartRowUsingKualiWorkflowUtils());
0138: routingDataRows.add(getOrgRowUsingKualiWorkflowUtils());
0139: routingDataRows
0140: .add(getOverrideCodeRowUsingKualiWorkflowUtils());
0141:
0142: // fields = new ArrayList();
0143: // fields.add(new Field("Total Amount", "", Field.TEXT, true, TOTAL_AMOUNT_KEY, "", null, null, TOTAL_AMOUNT_KEY));
0144: // routingDataRows.add(new Row(fields));
0145: routingDataRows.add(KualiWorkflowUtils.buildTextRow(
0146: DocumentHeader.class,
0147: KFSPropertyConstants.FINANCIAL_DOCUMENT_TOTAL_AMOUNT,
0148: TOTAL_AMOUNT_KEY));
0149: }
0150:
0151: /**
0152: * This method produces a chart row.
0153: *
0154: * @return
0155: * @deprecated Use getChartRowUsingKualiWorkflowUtils() instead
0156: */
0157: public edu.iu.uis.eden.lookupable.Row getChartRow() {
0158: org.kuali.core.web.ui.Field kualiChartField = FieldUtils
0159: .getPropertyField(
0160: Chart.class,
0161: KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME,
0162: false);
0163: List chartFields = new ArrayList();
0164: chartFields.add(new Field(kualiChartField.getFieldLabel(),
0165: KualiWorkflowUtils.getHelpUrl(kualiChartField),
0166: Field.TEXT, true, FIN_COA_CD_KEY, kualiChartField
0167: .getPropertyValue(), kualiChartField
0168: .getFieldValidValues(), WorkflowLookupableImpl
0169: .getLookupableImplName(Chart.class),
0170: FIN_COA_CD_KEY));
0171: chartFields
0172: .add(new Field(
0173: "",
0174: "",
0175: Field.QUICKFINDER,
0176: false,
0177: "",
0178: "",
0179: null,
0180: WorkflowLookupableImpl
0181: .getLookupableName(
0182: WorkflowLookupableImpl
0183: .getLookupableImplName(Chart.class),
0184: new StringBuffer(
0185: WorkflowLookupableImpl.LOOKUPABLE_IMPL_NAME_PREFIX)
0186: .append(
0187: KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME)
0188: .append(":").append(
0189: FIN_COA_CD_KEY)
0190: .toString())));
0191: return new Row(chartFields);
0192: }
0193:
0194: public edu.iu.uis.eden.lookupable.Row getChartRowUsingKualiWorkflowUtils() {
0195: return KualiWorkflowUtils.buildTextRowWithLookup(Chart.class,
0196: KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME,
0197: FIN_COA_CD_KEY);
0198: }
0199:
0200: /**
0201: * This method produces an org row.
0202: *
0203: * @return
0204: * @deprecated Use getOrgRowUsingKualiWorkflowUtils() instead
0205: */
0206: public edu.iu.uis.eden.lookupable.Row getOrgRow() {
0207: org.kuali.core.web.ui.Field kualiOrgField = FieldUtils
0208: .getPropertyField(Org.class,
0209: KFSConstants.ORGANIZATION_CODE_PROPERTY_NAME,
0210: false);
0211: List orgFields = new ArrayList();
0212: orgFields.add(new Field(kualiOrgField.getFieldLabel(),
0213: KualiWorkflowUtils.getHelpUrl(kualiOrgField),
0214: Field.TEXT, true, ORG_CD_KEY, kualiOrgField
0215: .getPropertyValue(), kualiOrgField
0216: .getFieldValidValues(), WorkflowLookupableImpl
0217: .getLookupableImplName(Org.class), ORG_CD_KEY));
0218: orgFields
0219: .add(new Field(
0220: "",
0221: "",
0222: Field.QUICKFINDER,
0223: false,
0224: "",
0225: "",
0226: null,
0227: WorkflowLookupableImpl
0228: .getLookupableName(
0229: WorkflowLookupableImpl
0230: .getLookupableImplName(Org.class),
0231: new StringBuffer("")
0232: .append(
0233: WorkflowLookupableImpl.LOOKUPABLE_IMPL_NAME_PREFIX)
0234: .append(
0235: KFSConstants.ORGANIZATION_CODE_PROPERTY_NAME)
0236: .append(":")
0237: .append(ORG_CD_KEY)
0238: .append(",")
0239: .append(
0240: WorkflowLookupableImpl.LOOKUPABLE_IMPL_NAME_PREFIX)
0241: .append(
0242: KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME)
0243: .append(":").append(
0244: FIN_COA_CD_KEY)
0245: .toString())));
0246: return new Row(orgFields);
0247: }
0248:
0249: public edu.iu.uis.eden.lookupable.Row getOrgRowUsingKualiWorkflowUtils() {
0250: Map fieldConversionMap = new HashMap();
0251: fieldConversionMap.put(
0252: KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME,
0253: FIN_COA_CD_KEY);
0254: return KualiWorkflowUtils.buildTextRowWithLookup(Org.class,
0255: KFSConstants.ORGANIZATION_CODE_PROPERTY_NAME,
0256: ORG_CD_KEY, fieldConversionMap);
0257: }
0258:
0259: /**
0260: * This method produces an overrideCode row.
0261: *
0262: * @return
0263: * @deprecated Use getOverrideCodeRowUsingKualiWorkflowUtils() instead
0264: */
0265: public edu.iu.uis.eden.lookupable.Row getOverrideCodeRow() {
0266: org.kuali.core.web.ui.Field kualiOverrideCodeField;
0267: kualiOverrideCodeField = FieldUtils.getPropertyField(
0268: SourceAccountingLine.class, "overrideCode", false);
0269: List orgFields = new ArrayList();
0270: orgFields.add(new Field(kualiOverrideCodeField.getFieldLabel(),
0271: KualiWorkflowUtils.getHelpUrl(kualiOverrideCodeField),
0272: Field.TEXT, true, OVERRIDE_CD_KEY,
0273: kualiOverrideCodeField.getPropertyValue(),
0274: kualiOverrideCodeField.getFieldValidValues(), null,
0275: OVERRIDE_CD_KEY));
0276: return new Row(orgFields);
0277: }
0278:
0279: public edu.iu.uis.eden.lookupable.Row getOverrideCodeRowUsingKualiWorkflowUtils() {
0280: return KualiWorkflowUtils.buildTextRow(
0281: SourceAccountingLine.class, "overrideCode",
0282: OVERRIDE_CD_KEY);
0283: }
0284:
0285: /**
0286: * constructor that takes the chart, org, which calls the no arg constructor
0287: *
0288: * @param finCoaCd
0289: * @param orgCd
0290: */
0291: public KualiOrgReviewAttribute(String finCoaCd, String orgCd) {
0292: this ();
0293: this .finCoaCd = LookupUtils.forceUppercase(Org.class,
0294: "chartOfAccountsCode", finCoaCd);
0295: this .orgCd = LookupUtils.forceUppercase(Org.class,
0296: "organizationCode", orgCd);
0297: }
0298:
0299: public List getRuleExtensionValues() {
0300: List extensions = new ArrayList();
0301: extensions.add(new RuleExtensionValue(FIN_COA_CD_KEY,
0302: this .finCoaCd));
0303: extensions.add(new RuleExtensionValue(ORG_CD_KEY, this .orgCd));
0304: if (!StringUtils.isBlank(this .fromAmount)) {
0305: extensions.add(new RuleExtensionValue(FROM_AMOUNT_KEY,
0306: this .fromAmount));
0307: }
0308: if (!StringUtils.isBlank(this .toAmount)) {
0309: extensions.add(new RuleExtensionValue(TO_AMOUNT_KEY,
0310: this .toAmount));
0311: }
0312: if (!StringUtils.isBlank(this .overrideCd)) {
0313: extensions.add(new RuleExtensionValue(OVERRIDE_CD_KEY,
0314: this .overrideCd));
0315: }
0316: return extensions;
0317: }
0318:
0319: /**
0320: * @see edu.iu.uis.eden.plugin.attributes.WorkflowAttribute#validateRuleData(java.util.Map)
0321: */
0322: public List validateRuleData(Map paramMap) {
0323: List errors = new ArrayList();
0324: this .finCoaCd = LookupUtils.forceUppercase(Org.class,
0325: "chartOfAccountsCode", (String) paramMap
0326: .get(FIN_COA_CD_KEY));
0327: this .orgCd = LookupUtils.forceUppercase(Org.class,
0328: "organizationCode", (String) paramMap.get(ORG_CD_KEY));
0329: this .fromAmount = (String) paramMap.get(FROM_AMOUNT_KEY);
0330: this .toAmount = (String) paramMap.get(TO_AMOUNT_KEY);
0331: this .overrideCd = LookupUtils.forceUppercase(
0332: SourceAccountingLine.class, "overrideCode",
0333: (String) paramMap.get(OVERRIDE_CD_KEY));
0334: if (isRequired()) {
0335: validateOrg(errors);
0336: if (StringUtils.isNotBlank(toAmount)
0337: && !StringUtils.isNumeric(toAmount)) {
0338: errors
0339: .add(new WorkflowServiceErrorImpl(
0340: "To Amount is invalid.",
0341: "routetemplate.dollarrangeattribute.toamount.invalid"));
0342: }
0343: if (StringUtils.isNotBlank(fromAmount)
0344: && !StringUtils.isNumeric(fromAmount)) {
0345: errors
0346: .add(new WorkflowServiceErrorImpl(
0347: "From Amount is invalid.",
0348: "routetemplate.dollarrangeattribute.fromamount.invalid"));
0349: }
0350: }
0351: return errors;
0352: }
0353:
0354: public List validateRoutingData(Map paramMap) {
0355: List errors = new ArrayList();
0356: this .finCoaCd = LookupUtils.forceUppercase(Org.class,
0357: "chartOfAccountsCode", (String) paramMap
0358: .get(FIN_COA_CD_KEY));
0359: this .orgCd = LookupUtils.forceUppercase(Org.class,
0360: "organizationCode", (String) paramMap.get(ORG_CD_KEY));
0361: this .totalDollarAmount = (String) paramMap
0362: .get(TOTAL_AMOUNT_KEY);
0363: this .overrideCd = LookupUtils.forceUppercase(
0364: SourceAccountingLine.class, "overrideCode",
0365: (String) paramMap.get(OVERRIDE_CD_KEY));
0366: if (isRequired()) {
0367: validateOrg(errors);
0368: if (!StringUtils.isNumeric(this .totalDollarAmount)) {
0369: errors.add(new WorkflowServiceErrorImpl(
0370: "Total Amount is invalid.", ""));
0371: }
0372: }
0373: return errors;
0374: }
0375:
0376: private void validateOrg(List errors) {
0377: if (StringUtils.isBlank(this .finCoaCd)
0378: || StringUtils.isBlank(this .orgCd)) {
0379: errors
0380: .add(new WorkflowServiceErrorImpl(
0381: "Chart/org is required.",
0382: "routetemplate.chartorgattribute.chartorg.required"));
0383: } else {
0384: Org org = SpringContext.getBean(OrganizationService.class)
0385: .getByPrimaryIdWithCaching(finCoaCd, orgCd);
0386: if (org == null) {
0387: errors
0388: .add(new WorkflowServiceErrorImpl(
0389: "Chart/org is invalid.",
0390: "routetemplate.chartorgattribute.chartorg.invalid"));
0391: }
0392: }
0393: }
0394:
0395: /**
0396: * @see edu.iu.uis.eden.plugin.attributes.WorkflowAttribute#getDocContent()
0397: */
0398: public String getDocContent() {
0399: if (Utilities.isEmpty(getFinCoaCd())
0400: || Utilities.isEmpty(getOrgCd())) {
0401: return "";
0402: }
0403: return new StringBuffer(
0404: KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_PREFIX
0405: + "<chart>")
0406: .append(getFinCoaCd())
0407: .append("</chart><org>")
0408: .append(getOrgCd())
0409: .append("</org><totalDollarAmount>")
0410: .append(getTotalDollarAmount())
0411: .append("</totalDollarAmount><overrideCode>")
0412: .append(getOverrideCd())
0413: .append(
0414: "</overrideCode>"
0415: + KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_SUFFIX)
0416: .toString();
0417: }
0418:
0419: public String getAttributeLabel() {
0420: return "";
0421: }
0422:
0423: /**
0424: * Actual matching logic is handled in filterNonMatchingRules where the List of rules is narrowed down to those that should
0425: * fire.
0426: *
0427: * @see #filterNonMatchingRules(RouteContext, List)
0428: * @see edu.iu.uis.eden.plugin.attributes.WorkflowAttribute#isMatch(java.lang.String, java.util.List)
0429: */
0430: public boolean isMatch(DocumentContent docContent,
0431: List ruleExtensions) {
0432: return true;
0433: }
0434:
0435: /**
0436: * Filters the List of Rules by those that will match and then sorts the List with those that have Orgs at the bottom of the
0437: * hierarchy first. This will allow for requests generated by rules at the bottom of the hierarchy to be activated first. We've
0438: * collapsed this method and isMatch into one to allow for optimal sorting (i.e. we only sort the rules that actually match and
0439: * don't have to fetch every Org in the hierarchy to sort the full List of Rules).
0440: */
0441: public List filterNonMatchingRules(RouteContext routeContext,
0442: List rules) {
0443: List filteredRules = new ArrayList();
0444: DocumentType documentType = routeContext.getDocument()
0445: .getDocumentType();
0446: Set chartOrgValues = populateFromDocContent(documentType,
0447: routeContext.getDocumentContent(), routeContext);
0448: for (Iterator iterator = rules.iterator(); iterator.hasNext();) {
0449: RuleBaseValues rule = (RuleBaseValues) iterator.next();
0450: List ruleExtensions = rule.getRuleExtensions();
0451: this .finCoaCd = LookupUtils.forceUppercase(Org.class,
0452: "chartOfAccountsCode", getRuleExtentionValue(
0453: FIN_COA_CD_KEY, ruleExtensions));
0454: this .orgCd = LookupUtils.forceUppercase(Org.class,
0455: "organizationCode", getRuleExtentionValue(
0456: ORG_CD_KEY, ruleExtensions));
0457: this .fromAmount = getRuleExtentionValue(FROM_AMOUNT_KEY,
0458: ruleExtensions);
0459: this .toAmount = getRuleExtentionValue(TO_AMOUNT_KEY,
0460: ruleExtensions);
0461: this .overrideCd = LookupUtils.forceUppercase(
0462: SourceAccountingLine.class, "overrideCode",
0463: getRuleExtentionValue(OVERRIDE_CD_KEY,
0464: ruleExtensions));
0465: if (ruleMatches(rule, chartOrgValues, routeContext)) {
0466: filteredRules.add(rule);
0467: }
0468: }
0469: Collections.sort(filteredRules, new ChartOrgRuleComparator(
0470: chartOrgValues));
0471: return filteredRules;
0472: }
0473:
0474: /**
0475: * Determines if the given Rule matches the document data by comparing the Org, total dollar amount, and override code.
0476: */
0477: protected boolean ruleMatches(RuleBaseValues rule,
0478: Set chartOrgValues, RouteContext routeContext) {
0479: boolean matchesOrg = false;
0480: for (Iterator iter = chartOrgValues.iterator(); iter.hasNext();) {
0481: Org org = (Org) iter.next();
0482: if (org.getChartOfAccountsCode().equals(this .getFinCoaCd())
0483: && org.getOrganizationCode()
0484: .equals(this .getOrgCd())) {
0485: matchesOrg = true;
0486: break;
0487: }
0488: }
0489:
0490: if (!matchesOrg) {
0491: return false;
0492: }
0493:
0494: Float documentAmount = getAmount(routeContext.getDocument()
0495: .getDocumentType(), routeContext.getDocumentContent());
0496: if (documentAmount != null) {
0497: Float ruleFromAmount = null;
0498: Float ruleToAmount = null;
0499: if (!StringUtils.isBlank(fromAmount)) {
0500: ruleFromAmount = new Float(fromAmount);
0501: if (ruleFromAmount.floatValue() > documentAmount
0502: .floatValue()) {
0503: return false;
0504: }
0505: }
0506: if (!StringUtils.isBlank(toAmount)) {
0507: ruleToAmount = new Float(toAmount);
0508: if (ruleToAmount.floatValue() < documentAmount
0509: .floatValue()) {
0510: return false;
0511: }
0512: }
0513: }
0514:
0515: if (this .overrideCd != null) {
0516: String docOverrideCd = getOverrideCd(routeContext
0517: .getDocument().getDocumentType(), routeContext
0518: .getDocumentContent());
0519: if (!this .overrideCd.equalsIgnoreCase(docOverrideCd)) {
0520: return false;
0521: }
0522: }
0523: return true;
0524: }
0525:
0526: /**
0527: * This method is a recursive method that will retrive reports to orgs to build up the hierarchy of organizations
0528: *
0529: * @param chartOrgSet
0530: * @param chartOrg
0531: */
0532: private void buildOrgReviewHierarchy(int counter, Set chartOrgSet,
0533: Org startOrg) {
0534: LOG.info("buildOrgReviewHierarchy iteration: " + counter);
0535: // this will cause NPEs, so we dont let it through
0536: if (startOrg == null) {
0537: throw new IllegalArgumentException(
0538: "Parameter value for startOrg passed in was null.");
0539: }
0540:
0541: // we're done if the reportsToOrg is the same as the Org, ie we're at the top of the Org hiearchy
0542: if (startOrg.getChartOfAccountsCode().equalsIgnoreCase(
0543: startOrg.getReportsToChartOfAccountsCode())) {
0544: if (startOrg.getOrganizationCode().equalsIgnoreCase(
0545: startOrg.getReportsToOrganizationCode())) {
0546: return;
0547: }
0548: }
0549: Org reportsToOrg = SpringContext.getBean(
0550: OrganizationService.class).getByPrimaryIdWithCaching(
0551: startOrg.getReportsToChartOfAccountsCode(),
0552: startOrg.getReportsToOrganizationCode());
0553: if (reportsToOrg == null) {
0554: throw new RuntimeException("Org "
0555: + startOrg.getChartOfAccountsCode() + "-"
0556: + startOrg.getOrganizationCode()
0557: + " has a reportsToOrganization ("
0558: + startOrg.getReportsToChartOfAccountsCode() + "-"
0559: + startOrg.getReportsToOrganizationCode() + ") "
0560: + " that does not exist in the system.");
0561: }
0562: chartOrgSet.add(reportsToOrg);
0563: buildOrgReviewHierarchy(++counter, chartOrgSet, reportsToOrg);
0564: }
0565:
0566: private String getRuleExtentionValue(String key, List ruleExtensions) {
0567: for (Iterator iter = ruleExtensions.iterator(); iter.hasNext();) {
0568: RuleExtension extension = (RuleExtension) iter.next();
0569: if (extension.getRuleTemplateAttribute().getRuleAttribute()
0570: .getClassName().equals(this .getClass().getName())) {
0571: for (Iterator iterator = extension.getExtensionValues()
0572: .iterator(); iterator.hasNext();) {
0573: RuleExtensionValue value = (RuleExtensionValue) iterator
0574: .next();
0575: if (value.getKey().equals(key)) {
0576: return value.getValue();
0577: }
0578: }
0579: }
0580: }
0581: return null;
0582: }
0583:
0584: /**
0585: * this method will take the document content, and populate a list of OrgReviewAttribute objects that also contain the rollup in
0586: * terms of organizational hierarchy as well.
0587: *
0588: * @param docContent
0589: * @return a list of OrgReviewAttribute objects that are contained in the doc, or roll up to able by one that is contained in
0590: * the document
0591: */
0592: private Set populateFromDocContent(DocumentType docType,
0593: DocumentContent docContent, RouteContext routeContext) {
0594: Set chartOrgValues = null;
0595: if (routeContext.getParameters().containsKey(
0596: DOCUMENT_CHART_ORG_VALUES_KEY)) {
0597: chartOrgValues = (Set) routeContext.getParameters().get(
0598: DOCUMENT_CHART_ORG_VALUES_KEY);
0599: } else {
0600: chartOrgValues = new HashSet();
0601: NodeList nodes = null;
0602: XPath xpath = KualiWorkflowUtils.getXPath(docContent
0603: .getDocument());
0604: try {
0605: String chart = null;
0606: String org = null;
0607: boolean isReport = ((Boolean) xpath
0608: .evaluate(
0609: new StringBuffer(
0610: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0611: .append(
0612: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0613: .append(
0614: KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_XPATH_PREFIX)
0615: .append(
0616: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0617: .toString(), docContent
0618: .getDocument(),
0619: XPathConstants.BOOLEAN)).booleanValue();
0620: if (isReport) {
0621: chart = xpath
0622: .evaluate(
0623: new StringBuffer(
0624: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0625: .append(
0626: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0627: .append("chart")
0628: .append(
0629: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0630: .toString(), docContent
0631: .getDocument());
0632: org = xpath
0633: .evaluate(
0634: new StringBuffer(
0635: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0636: .append(
0637: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0638: .append("org")
0639: .append(
0640: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0641: .toString(), docContent
0642: .getDocument());
0643: } else if (KualiWorkflowUtils.ACCOUNT_DOC_TYPE
0644: .equals(docType.getName())
0645: || KualiWorkflowUtils.FIS_USER_DOC_TYPE
0646: .equals(docType.getName())
0647: || KualiWorkflowUtils.PROJECT_CODE_DOC_TYPE
0648: .equals(docType.getName())) {
0649: chart = xpath
0650: .evaluate(
0651: new StringBuffer(
0652: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0653: .append(
0654: KualiWorkflowUtils.NEW_MAINTAINABLE_PREFIX)
0655: .append(
0656: KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME)
0657: .append(
0658: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0659: .toString(), docContent
0660: .getDocument());
0661: org = xpath
0662: .evaluate(
0663: new StringBuffer(
0664: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0665: .append(
0666: KualiWorkflowUtils.NEW_MAINTAINABLE_PREFIX)
0667: .append(
0668: KFSConstants.ORGANIZATION_CODE_PROPERTY_NAME)
0669: .append(
0670: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0671: .toString(), docContent
0672: .getDocument());
0673: } else if (KualiWorkflowUtils.ORGANIZATION_DOC_TYPE
0674: .equals(docType.getName())) {
0675: chart = xpath
0676: .evaluate(
0677: new StringBuffer(
0678: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0679: .append(
0680: KualiWorkflowUtils.NEW_MAINTAINABLE_PREFIX)
0681: .append("finCoaCd")
0682: .append(
0683: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0684: .toString(), docContent
0685: .getDocument());
0686: org = xpath
0687: .evaluate(
0688: new StringBuffer(
0689: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0690: .append(
0691: KualiWorkflowUtils.NEW_MAINTAINABLE_PREFIX)
0692: .append("orgCd")
0693: .append(
0694: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0695: .toString(), docContent
0696: .getDocument());
0697: } else if (KualiWorkflowUtils.SUB_ACCOUNT_DOC_TYPE
0698: .equals(docType.getName())
0699: || KualiWorkflowUtils.ACCOUNT_DEL_DOC_TYPE
0700: .equals(docType.getName())
0701: || KualiWorkflowUtils.SUB_OBJECT_DOC_TYPE
0702: .equals(docType.getName())) {
0703: // these documents don't have the organization code on them so it must be looked up
0704: chart = xpath
0705: .evaluate(
0706: new StringBuffer(
0707: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0708: .append(
0709: KualiWorkflowUtils.NEW_MAINTAINABLE_PREFIX)
0710: .append(
0711: KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME)
0712: .append(
0713: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0714: .toString(), docContent
0715: .getDocument());
0716: String accountNumber = xpath
0717: .evaluate(
0718: new StringBuffer(
0719: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0720: .append(
0721: KualiWorkflowUtils.NEW_MAINTAINABLE_PREFIX)
0722: .append(
0723: KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME)
0724: .append(
0725: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0726: .toString(), docContent
0727: .getDocument());
0728: Account account = SpringContext.getBean(
0729: AccountService.class)
0730: .getByPrimaryIdWithCaching(chart,
0731: accountNumber);
0732: org = account.getOrganizationCode();
0733: } else if (KualiWorkflowUtils.C_G_AWARD_DOC_TYPE
0734: .equals(docType.getName())
0735: || KualiWorkflowUtils.C_G_PROPOSAL_DOC_TYPE
0736: .equals(docType.getName())) {
0737: chart = xpath
0738: .evaluate(
0739: new StringBuffer(
0740: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0741: .append(
0742: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0743: .append("routingChart")
0744: .append(
0745: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0746: .toString(), docContent
0747: .getDocument());
0748: org = xpath
0749: .evaluate(
0750: new StringBuffer(
0751: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0752: .append(
0753: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0754: .append("routingOrg")
0755: .append(
0756: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0757: .toString(), docContent
0758: .getDocument());
0759: } else if (KualiWorkflowUtils.USER_DOC_TYPE
0760: .equals(docType.getName())) {
0761: // TODO: fix this xpath to use the central stuff after document xml is modified to remove string element
0762: chart = xpath
0763: .evaluate(
0764: "//newMaintainableObject/businessObject/moduleProperties/entry[string=\"chart\"]/map/entry[string=\"chartOfAccountsCode\"]/string[2]",
0765: docContent.getDocument());
0766: org = xpath
0767: .evaluate(
0768: "//newMaintainableObject/businessObject/moduleProperties/entry[string=\"chart\"]/map/entry[string=\"organizationCode\"]/string[2]",
0769: docContent.getDocument());
0770: } else if (KualiWorkflowUtils.CHART_ORG_WORKGROUP_DOC_TYPE
0771: .equals(docType.getName())) {
0772: chart = xpath
0773: .evaluate(
0774: "//workgroup/extensions/extension/data[@key='"
0775: + KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME
0776: + "']", docContent
0777: .getDocument());
0778: org = xpath
0779: .evaluate(
0780: "//workgroup/extensions/extension/data[@key='"
0781: + KFSConstants.ORGANIZATION_CODE_PROPERTY_NAME
0782: + "']", docContent
0783: .getDocument());
0784: }
0785: if (!StringUtils.isEmpty(chart)
0786: && !StringUtils.isEmpty(org)) {
0787: Org docOrg = SpringContext.getBean(
0788: OrganizationService.class)
0789: .getByPrimaryIdWithCaching(chart, org);
0790: if (docOrg == null) {
0791: throw new RuntimeException(
0792: "Org declared on the document cannot be found in the system, routing cannot continue.");
0793: }
0794: // possibly duplicate add, but this is safe in a HashSet
0795: chartOrgValues.add(docOrg);
0796: buildOrgReviewHierarchy(0, chartOrgValues, docOrg);
0797: } else {
0798: // now look at the global documents
0799: List<Org> globalDocOrgs = getGlobalDocOrgs(docType
0800: .getName(), xpath, docContent);
0801: for (Org globalOrg : globalDocOrgs) {
0802: chartOrgValues.add(globalOrg);
0803: buildOrgReviewHierarchy(0, chartOrgValues,
0804: globalOrg);
0805: }
0806: String xpathExp = null;
0807: if (KualiWorkflowUtils
0808: .isMaintenanceDocument(docType)) {
0809: xpathExp = new StringBuffer(
0810: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0811: .append(
0812: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0813: .append("kualiUser")
0814: .append(
0815: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0816: .toString();
0817: } else if (KualiWorkflowUtils.KRA_BUDGET_DOC_TYPE
0818: .equalsIgnoreCase(docType.getName())
0819: || KualiWorkflowUtils.KRA_ROUTING_FORM_DOC_TYPE
0820: .equalsIgnoreCase(docType.getName())) {
0821: xpathExp = new StringBuffer(
0822: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0823: .append(
0824: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0825: .append("chartOrg")
0826: .append(
0827: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0828: .toString();
0829: } else {
0830: if (KualiWorkflowUtils.isSourceLineOnly(docType
0831: .getName())) {
0832: xpathExp = new StringBuffer(
0833: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0834: .append(
0835: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0836: .append(
0837: KualiWorkflowUtils
0838: .getSourceAccountingLineClassName(docType
0839: .getName()))
0840: .append("/account")
0841: .append(
0842: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0843: .toString();
0844: } else if (KualiWorkflowUtils
0845: .isTargetLineOnly(docType.getName())) {
0846: xpathExp = new StringBuffer(
0847: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0848: .append(
0849: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0850: .append(
0851: KualiWorkflowUtils
0852: .getTargetAccountingLineClassName(docType
0853: .getName()))
0854: .append("/account")
0855: .append(
0856: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0857: .toString();
0858: } else {
0859: xpathExp = new StringBuffer(
0860: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0861: .append(
0862: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0863: .append(
0864: KualiWorkflowUtils
0865: .getSourceAccountingLineClassName(docType
0866: .getName()))
0867: .append("/account")
0868: .append(
0869: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0870: .append(" | ")
0871: .append(
0872: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
0873: .append(
0874: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
0875: .append(
0876: KualiWorkflowUtils
0877: .getTargetAccountingLineClassName(docType
0878: .getName()))
0879: .append("/account")
0880: .append(
0881: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
0882: .toString();
0883: }
0884: }
0885: nodes = (NodeList) xpath.evaluate(xpathExp,
0886: docContent.getDocument(),
0887: XPathConstants.NODESET);
0888: for (int i = 0; i < nodes.getLength(); i++) {
0889: Node accountingLineNode = nodes.item(i);
0890: // TODO: xstreamsafe should be handling this, but is not, therefore this code block
0891: String referenceString = xpath.evaluate(
0892: "@reference", accountingLineNode);
0893: if (!StringUtils.isEmpty(referenceString)) {
0894: accountingLineNode = (Node) xpath.evaluate(
0895: referenceString,
0896: accountingLineNode,
0897: XPathConstants.NODE);
0898: }
0899: String finCoaCd = xpath
0900: .evaluate(
0901: KualiWorkflowUtils.XSTREAM_MATCH_RELATIVE_PREFIX
0902: + KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME,
0903: accountingLineNode);
0904: String orgCd = xpath
0905: .evaluate(
0906: KualiWorkflowUtils.XSTREAM_MATCH_RELATIVE_PREFIX
0907: + KFSConstants.ORGANIZATION_CODE_PROPERTY_NAME,
0908: accountingLineNode);
0909: if (!StringUtils.isEmpty(finCoaCd)
0910: && !StringUtils.isEmpty(orgCd)) {
0911: Org organization = SpringContext.getBean(
0912: OrganizationService.class)
0913: .getByPrimaryIdWithCaching(
0914: finCoaCd, orgCd);
0915: chartOrgValues.add(organization);
0916: buildOrgReviewHierarchy(0, chartOrgValues,
0917: organization);
0918: }
0919: }
0920: }
0921: } catch (Exception e) {
0922: throw new RuntimeException(e);
0923: }
0924: routeContext.getParameters().put(
0925: DOCUMENT_CHART_ORG_VALUES_KEY, chartOrgValues);
0926: }
0927: return chartOrgValues;
0928: }
0929:
0930: private List<Org> getGlobalDocOrgs(String docTypeName, XPath xpath,
0931: DocumentContent docContent) throws Exception {
0932: List<Org> orgs = new ArrayList<Org>();
0933: if (KualiWorkflowUtils.ACCOUNT_CHANGE_DOC_TYPE
0934: .equals(docTypeName)
0935: || KualiWorkflowUtils.ACCOUNT_DELEGATE_GLOBAL_DOC_TYPE
0936: .equals(docTypeName)
0937: || KualiWorkflowUtils.SUB_OBJECT_CODE_CHANGE_DOC_TYPE
0938: .equals(docTypeName)) {
0939: NodeList accountGlobalDetails = (NodeList) xpath.evaluate(
0940: KualiWorkflowUtils.ACCOUNT_GLOBAL_DETAILS_XPATH,
0941: docContent.getDocument(), XPathConstants.NODESET);
0942: for (int index = 0; index < accountGlobalDetails
0943: .getLength(); index++) {
0944: Element accountGlobalDetail = (Element) accountGlobalDetails
0945: .item(index);
0946: String chartOfAccountsCode = getChildElementValue(
0947: accountGlobalDetail,
0948: KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME);
0949: String accountNumber = getChildElementValue(
0950: accountGlobalDetail,
0951: KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME);
0952: Account account = SpringContext.getBean(
0953: AccountService.class)
0954: .getByPrimaryIdWithCaching(chartOfAccountsCode,
0955: accountNumber);
0956: orgs.add(account.getOrganization());
0957: }
0958: } else if (KualiWorkflowUtils.ORG_REVERSION_CHANGE_DOC_TYPE
0959: .equals(docTypeName)) {
0960: NodeList orgReversionChangeDetails = (NodeList) xpath
0961: .evaluate(
0962: KualiWorkflowUtils.ORG_REVERSION_GLOBALS_XPATH,
0963: docContent.getDocument(),
0964: XPathConstants.NODESET);
0965: for (int index = 0; index < orgReversionChangeDetails
0966: .getLength(); index++) {
0967: Element orgReversionChangeDetail = (Element) orgReversionChangeDetails
0968: .item(index);
0969: String chartOfAccountsCode = getChildElementValue(
0970: orgReversionChangeDetail,
0971: KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME);
0972: String orgCode = getChildElementValue(
0973: orgReversionChangeDetail,
0974: KFSConstants.ORGANIZATION_CODE_PROPERTY_NAME);
0975: Org org = SpringContext.getBean(
0976: OrganizationService.class)
0977: .getByPrimaryIdWithCaching(chartOfAccountsCode,
0978: orgCode);
0979: orgs.add(org);
0980: }
0981: }
0982: return orgs;
0983: }
0984:
0985: private String getChildElementValue(Element element,
0986: String childTagName) {
0987: NodeList nodes = element.getChildNodes();
0988: for (int index = 0; index < nodes.getLength(); index++) {
0989: Node node = nodes.item(index);
0990: if (Node.ELEMENT_NODE == node.getNodeType()
0991: && node.getNodeName().equals(childTagName)) {
0992: return node.getFirstChild().getNodeValue();
0993: }
0994: }
0995: return null;
0996: }
0997:
0998: private String getOverrideCd(DocumentType docType,
0999: DocumentContent docContent) {
1000: try {
1001: XPath xpath = KualiWorkflowUtils.getXPath(docContent
1002: .getDocument());
1003: boolean isReport = ((Boolean) xpath
1004: .evaluate(
1005: new StringBuffer(
1006: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
1007: .append(
1008: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
1009: .append(
1010: KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_XPATH_PREFIX)
1011: .append(
1012: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
1013: .toString(), docContent
1014: .getDocument(),
1015: XPathConstants.BOOLEAN)).booleanValue();
1016: if (isReport) {
1017: return xpath
1018: .evaluate(
1019: new StringBuffer(
1020: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
1021: .append(
1022: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
1023: .append(
1024: KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_XPATH_PREFIX)
1025: .append("/overrideCode")
1026: .append(
1027: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
1028: .toString(), docContent
1029: .getDocument());
1030: }
1031: String xpathExp = null;
1032: do {
1033: if (KualiWorkflowUtils.isMaintenanceDocument(docType)) {
1034: return null;
1035: } else {
1036: if (KualiWorkflowUtils.isSourceLineOnly(docType
1037: .getName())) {
1038: xpathExp = new StringBuffer(
1039: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
1040: .append(
1041: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
1042: .append(
1043: KualiWorkflowUtils
1044: .getSourceAccountingLineClassName(docType
1045: .getName()))
1046: .append("/overrideCode")
1047: .append(
1048: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
1049: .toString();
1050: break;
1051: } else if (KualiWorkflowUtils
1052: .isTargetLineOnly(docType.getName())) {
1053: xpathExp = new StringBuffer(
1054: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
1055: .append(
1056: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
1057: .append(
1058: KualiWorkflowUtils
1059: .getTargetAccountingLineClassName(docType
1060: .getName()))
1061: .append("/overrideCode")
1062: .append(
1063: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
1064: .toString();
1065: break;
1066: } else {
1067: xpathExp = new StringBuffer(
1068: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
1069: .append(
1070: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
1071: .append(
1072: KualiWorkflowUtils
1073: .getSourceAccountingLineClassName(docType
1074: .getName()))
1075: .append("/overrideCode")
1076: .append(
1077: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
1078: .append(" | ")
1079: .append(
1080: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
1081: .append(
1082: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
1083: .append(
1084: KualiWorkflowUtils
1085: .getTargetAccountingLineClassName(docType
1086: .getName()))
1087: .append("/overrideCode")
1088: .append(
1089: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
1090: .toString();
1091: break;
1092: }
1093: }
1094:
1095: } while (docType != null);
1096:
1097: return xpath.evaluate(xpathExp, docContent.getDocument());
1098:
1099: } catch (Exception e) {
1100: LOG.error(
1101: "Caught excpeption getting document override code",
1102: e);
1103: throw new RuntimeException(e);
1104: }
1105:
1106: }
1107:
1108: /**
1109: * Method returns the absolute value of the document's total
1110: */
1111: private Float getAmount(DocumentType docType,
1112: DocumentContent docContent) {
1113: try {
1114: Document doc = docContent.getDocument();
1115: XPath xpath = KualiWorkflowUtils.getXPath(doc);
1116: boolean isReport = ((Boolean) xpath
1117: .evaluate(
1118: new StringBuffer(
1119: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
1120: .append(
1121: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
1122: .append(
1123: KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_XPATH_PREFIX)
1124: .append(
1125: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
1126: .toString(), docContent
1127: .getDocument(),
1128: XPathConstants.BOOLEAN)).booleanValue();
1129: if (isReport) {
1130: String floatVal = xpath
1131: .evaluate(
1132: new StringBuffer(
1133: KualiWorkflowUtils.XSTREAM_SAFE_PREFIX)
1134: .append(
1135: KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX)
1136: .append(
1137: KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_XPATH_PREFIX)
1138: .append("/totalDollarAmount")
1139: .append(
1140: KualiWorkflowUtils.XSTREAM_SAFE_SUFFIX)
1141: .toString(), docContent
1142: .getDocument());
1143: if (StringUtils.isNumeric(floatVal)
1144: && StringUtils.isNotEmpty(floatVal)) {
1145: return new Float(floatVal);
1146: } else {
1147: return new Float(0);
1148: }
1149: }
1150: if (KualiWorkflowUtils.isMaintenanceDocument(docType)) {
1151: return null;
1152: } else if (KualiWorkflowUtils.KRA_BUDGET_DOC_TYPE
1153: .equalsIgnoreCase(docType.getName())
1154: || KualiWorkflowUtils.KRA_ROUTING_FORM_DOC_TYPE
1155: .equalsIgnoreCase(docType.getName())) {
1156: return null;
1157: }
1158: KualiDecimal value = KualiWorkflowUtils
1159: .getFinancialDocumentTotalAmount(doc);
1160: if (ObjectUtils.isNull(value)) {
1161: throw new RuntimeException(
1162: "Didn't find amount for document "
1163: + docContent.getRouteContext()
1164: .getDocument()
1165: .getRouteHeaderId());
1166: }
1167: return value.abs().floatValue();
1168: } catch (Exception e) {
1169: LOG.error("Caught excpeption getting document amount", e);
1170: throw new RuntimeException(e);
1171: }
1172: }
1173:
1174: /**
1175: * simple getter for the rule rows
1176: */
1177: public List getRuleRows() {
1178: return ruleRows;
1179: }
1180:
1181: /**
1182: * simple getter for the routing data rows
1183: */
1184: public List getRoutingDataRows() {
1185: return routingDataRows;
1186: }
1187:
1188: /**
1189: * simple getter for fincoacd
1190: *
1191: * @return String
1192: */
1193: public String getFinCoaCd() {
1194: return this .finCoaCd;
1195: }
1196:
1197: /**
1198: * simple setter for fincoacd
1199: *
1200: * @param finCoaCd
1201: */
1202: public void setFinCoaCd(String finCoaCd) {
1203: this .finCoaCd = finCoaCd;
1204: }
1205:
1206: /**
1207: * simple getter for org code
1208: *
1209: * @return String
1210: */
1211: public String getOrgCd() {
1212: return this .orgCd;
1213: }
1214:
1215: /**
1216: * simple setter for org code
1217: *
1218: * @param orgCd
1219: */
1220: public void setOrgCd(String orgCd) {
1221: this .orgCd = orgCd;
1222: }
1223:
1224: public String getTotalDollarAmount() {
1225: return totalDollarAmount;
1226: }
1227:
1228: public void setTotalDollarAmount(String totalDollarAmount) {
1229: this .totalDollarAmount = totalDollarAmount;
1230: }
1231:
1232: public String getOverrideCd() {
1233: return overrideCd;
1234: }
1235:
1236: public void setOverrideCd(String overrideCd) {
1237: this .overrideCd = overrideCd;
1238: }
1239:
1240: /**
1241: * simple getter for required
1242: */
1243: public boolean isRequired() {
1244: return required;
1245: }
1246:
1247: /**
1248: * simple setter for required
1249: */
1250: public void setRequired(boolean required) {
1251: this .required = required;
1252: }
1253:
1254: /**
1255: * Sorts RuleBaseValues by Orgs with the Orgs at the bottom of the hierarchy first.
1256: */
1257: private class ChartOrgRuleComparator implements
1258: Comparator<RuleBaseValues> {
1259:
1260: private Set chartOrgs;
1261:
1262: public ChartOrgRuleComparator(Set chartOrgs) {
1263: this .chartOrgs = chartOrgs;
1264: }
1265:
1266: public int compare(RuleBaseValues rule1, RuleBaseValues rule2) {
1267: String chart1 = rule1.getRuleExtensionValue(FIN_COA_CD_KEY)
1268: .getValue();
1269: String chart2 = rule2.getRuleExtensionValue(FIN_COA_CD_KEY)
1270: .getValue();
1271: String org1 = rule1.getRuleExtensionValue(ORG_CD_KEY)
1272: .getValue();
1273: String org2 = rule2.getRuleExtensionValue(ORG_CD_KEY)
1274: .getValue();
1275: Org docOrg1 = SpringContext.getBean(
1276: OrganizationService.class)
1277: .getByPrimaryIdWithCaching(chart1, org1);
1278: Org docOrg2 = SpringContext.getBean(
1279: OrganizationService.class)
1280: .getByPrimaryIdWithCaching(chart2, org2);
1281: int distanceFromRoot1 = getDistanceFromRoot(docOrg1);
1282: int distanceFromRoot2 = getDistanceFromRoot(docOrg2);
1283: if (distanceFromRoot1 == distanceFromRoot2) {
1284: // if they are the same, compare names
1285: return (chart1 + "-" + org1).compareTo(chart2 + "-"
1286: + org2);
1287: }
1288: // sort descending
1289: return new Integer(distanceFromRoot2)
1290: .compareTo(new Integer(distanceFromRoot1));
1291: }
1292:
1293: private int getDistanceFromRoot(Org org) {
1294: if (org.getChartOfAccountsCode().equalsIgnoreCase(
1295: org.getReportsToChartOfAccountsCode())) {
1296: if (org.getOrganizationCode().equalsIgnoreCase(
1297: org.getReportsToOrganizationCode())) {
1298: return 0;
1299: }
1300: }
1301: Org reportsToOrg = SpringContext.getBean(
1302: OrganizationService.class)
1303: .getByPrimaryIdWithCaching(
1304: org.getReportsToChartOfAccountsCode(),
1305: org.getReportsToOrganizationCode());
1306: if (reportsToOrg == null) {
1307: throw new RuntimeException("Org "
1308: + org.getChartOfAccountsCode() + "-"
1309: + org.getOrganizationCode()
1310: + " has a reportsToOrganization ("
1311: + org.getReportsToChartOfAccountsCode() + "-"
1312: + org.getReportsToOrganizationCode() + ") "
1313: + " that does not exist in the system.");
1314: }
1315: return 1 + getDistanceFromRoot(reportsToOrg);
1316: }
1317:
1318: }
1319:
1320: }
|