Source Code Cross Referenced for KualiAccountAttribute.java in  » ERP-CRM-Financial » Kuali-Financial-System » org » kuali » workflow » attribute » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » Kuali Financial System » org.kuali.workflow.attribute 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2006-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:
017:        package org.kuali.workflow.attribute;
018:
019:        import java.util.ArrayList;
020:        import java.util.Collections;
021:        import java.util.HashMap;
022:        import java.util.HashSet;
023:        import java.util.Iterator;
024:        import java.util.List;
025:        import java.util.Map;
026:        import java.util.Set;
027:
028:        import javax.xml.xpath.XPath;
029:        import javax.xml.xpath.XPathConstants;
030:        import javax.xml.xpath.XPathExpressionException;
031:
032:        import org.apache.commons.lang.StringUtils;
033:        import org.apache.commons.lang.builder.EqualsBuilder;
034:        import org.apache.commons.lang.builder.HashCodeBuilder;
035:        import org.apache.log4j.Logger;
036:        import org.kuali.core.bo.DocumentHeader;
037:        import org.kuali.core.bo.user.UuId;
038:        import org.kuali.core.lookup.LookupUtils;
039:        import org.kuali.core.service.DataDictionaryService;
040:        import org.kuali.core.service.UniversalUserService;
041:        import org.kuali.core.util.KualiDecimal;
042:        import org.kuali.core.util.ObjectUtils;
043:        import org.kuali.kfs.KFSConstants;
044:        import org.kuali.kfs.KFSPropertyConstants;
045:        import org.kuali.kfs.context.SpringContext;
046:        import org.kuali.module.chart.bo.Account;
047:        import org.kuali.module.chart.bo.Chart;
048:        import org.kuali.module.chart.bo.Delegate;
049:        import org.kuali.module.chart.service.AccountService;
050:        import org.kuali.workflow.KualiWorkflowUtils;
051:        import org.w3c.dom.Document;
052:        import org.w3c.dom.Element;
053:        import org.w3c.dom.Node;
054:        import org.w3c.dom.NodeList;
055:
056:        import edu.iu.uis.eden.WorkflowServiceErrorImpl;
057:        import edu.iu.uis.eden.engine.RouteContext;
058:        import edu.iu.uis.eden.exception.EdenUserNotFoundException;
059:        import edu.iu.uis.eden.plugin.attributes.RoleAttribute;
060:        import edu.iu.uis.eden.plugin.attributes.WorkflowAttribute;
061:        import edu.iu.uis.eden.routeheader.DocumentContent;
062:        import edu.iu.uis.eden.routetemplate.ResolvedQualifiedRole;
063:        import edu.iu.uis.eden.routetemplate.Role;
064:        import edu.iu.uis.eden.user.AuthenticationUserId;
065:        import edu.iu.uis.eden.user.UserId;
066:        import edu.iu.uis.eden.util.Utilities;
067:
068:        /**
069:         * KualiAccountAttribute which should be used when using Accounts to do routing
070:         */
071:        public class KualiAccountAttribute implements  RoleAttribute,
072:                WorkflowAttribute {
073:
074:            static final long serialVersionUID = 1000;
075:
076:            private static Logger LOG = Logger
077:                    .getLogger(KualiAccountAttribute.class);
078:
079:            private static final String FIN_COA_CD_KEY = "fin_coa_cd";
080:
081:            private static final String ACCOUNT_NBR_KEY = "account_nbr";
082:
083:            private static final String FDOC_TOTAL_DOLLAR_AMOUNT_KEY = "fdoc_ttl_dlr_amt";
084:
085:            private static final String FISCAL_OFFICER_ROLE_KEY = "FISCAL-OFFICER";
086:
087:            private static final String FISCAL_OFFICER_ROLE_LABEL = "Fiscal Officer";
088:
089:            private static final String FISCAL_OFFICER_PRIMARY_DELEGATE_ROLE_KEY = "FISCAL-OFFICER-PRIMARY-DELEGATE";
090:
091:            private static final String FISCAL_OFFICER_PRIMARY_DELEGATE_ROLE_LABEL = "Fiscal Officer Primary Delegate";
092:
093:            private static final String FISCAL_OFFICER_SECONDARY_DELEGATE_ROLE_KEY = "FISCAL-OFFICER-SECONDARY-DELEGATE";
094:
095:            private static final String FISCAL_OFFICER_SECONDARY_DELEGATE_ROLE_LABEL = "Fiscal Officer Secondary Delegate";
096:
097:            private static final String ACCOUNT_SUPERVISOR_ROLE_KEY = "ACCOUNT-SUPERVISOR";
098:
099:            private static final String ACCOUNT_SUPERVISOR_ROLE_LABEL = "Account Supervisor";
100:
101:            private static final String ACCOUNT_ATTRIBUTE = "KUALI_ACCOUNT_ATTRIBUTE";
102:
103:            private static final String ROLE_STRING_DELIMITER = "~!~!~";
104:
105:            // below map is used to signify that a document will route to delegates based on a different document type's code
106:            private static final Map<String, String> DOCUMENT_TYPE_TRANSLATION = new HashMap<String, String>();
107:            static {
108:                DOCUMENT_TYPE_TRANSLATION
109:                        .put(
110:                                KualiWorkflowUtils.ACCOUNTS_PAYABLE_CREDIT_MEMO_DOCUMENT_TYPE,
111:                                KualiWorkflowUtils.ACCOUNTS_PAYABLE_PAYMENT_REQUEST_DOCUMENT_TYPE);
112:            }
113:
114:            private String finCoaCd;
115:
116:            private String accountNbr;
117:
118:            private String totalDollarAmount;
119:
120:            private boolean required;
121:
122:            /**
123:             * No arg constructor
124:             */
125:            public KualiAccountAttribute() {
126:            }
127:
128:            /**
129:             * Constructor that takes chart, account, and total dollar amount
130:             * 
131:             * @param finCoaCd
132:             * @param accountNbr
133:             * @param totalDollarAmount
134:             */
135:            public KualiAccountAttribute(String finCoaCd, String accountNbr,
136:                    String totalDollarAmount) {
137:                this .finCoaCd = LookupUtils.forceUppercase(Account.class,
138:                        "chartOfAccountsCode", finCoaCd);
139:                this .accountNbr = LookupUtils.forceUppercase(Account.class,
140:                        "accountNumber", accountNbr);
141:                this .totalDollarAmount = totalDollarAmount;
142:            }
143:
144:            /**
145:             * return the universal set of role names provided by this attribute
146:             */
147:            public List getRoleNames() {
148:                List roles = new ArrayList();
149:                roles.add(new Role(this .getClass(), FISCAL_OFFICER_ROLE_KEY,
150:                        FISCAL_OFFICER_ROLE_LABEL));
151:                roles.add(new Role(this .getClass(),
152:                        FISCAL_OFFICER_PRIMARY_DELEGATE_ROLE_KEY,
153:                        FISCAL_OFFICER_PRIMARY_DELEGATE_ROLE_LABEL));
154:                roles.add(new Role(this .getClass(),
155:                        FISCAL_OFFICER_SECONDARY_DELEGATE_ROLE_KEY,
156:                        FISCAL_OFFICER_SECONDARY_DELEGATE_ROLE_LABEL));
157:                roles.add(new Role(this .getClass(),
158:                        ACCOUNT_SUPERVISOR_ROLE_KEY,
159:                        ACCOUNT_SUPERVISOR_ROLE_LABEL));
160:                return roles;
161:            }
162:
163:            /**
164:             * return whether or not this attribute is required
165:             * 
166:             * @return
167:             */
168:            public boolean isRequired() {
169:                return required;
170:            }
171:
172:            /**
173:             * simple setter
174:             * 
175:             * @param required
176:             */
177:            public void setRequired(boolean required) {
178:                this .required = required;
179:            }
180:
181:            /**
182:             * simple getter for the rule extension values
183:             * 
184:             * @return
185:             */
186:            public List getRuleExtensionValues() {
187:                return Collections.EMPTY_LIST;
188:            }
189:
190:            /**
191:             * method to validate the routing data, need to determine if this should actually be implemented to throw errors or anything
192:             * like that.
193:             * 
194:             * @param paramMap
195:             * @return
196:             */
197:            public List validateRoutingData(Map paramMap) {
198:                List errors = new ArrayList();
199:                if (isRequired()) {
200:                    this .finCoaCd = LookupUtils.forceUppercase(Account.class,
201:                            "chartOfAccountsCode", (String) paramMap
202:                                    .get(FIN_COA_CD_KEY));
203:                    this .accountNbr = LookupUtils.forceUppercase(Account.class,
204:                            "accountNumber", (String) paramMap
205:                                    .get(ACCOUNT_NBR_KEY));
206:                    this .totalDollarAmount = (String) paramMap
207:                            .get(FDOC_TOTAL_DOLLAR_AMOUNT_KEY);
208:                    validateAccount(errors);
209:                    if (StringUtils.isNotBlank(this .totalDollarAmount)
210:                            && !KualiDecimal.isNumeric(this .totalDollarAmount)) {
211:                        errors
212:                                .add(new WorkflowServiceErrorImpl(
213:                                        "Total Dollar Amount is invalid.",
214:                                        "routetemplate.accountattribute.totaldollaramount.invalid"));
215:                    }
216:                }
217:                return errors;
218:            }
219:
220:            private void validateAccount(List errors) {
221:                if (StringUtils.isBlank(this .finCoaCd)
222:                        || StringUtils.isBlank(this .accountNbr)) {
223:                    errors.add(new WorkflowServiceErrorImpl(
224:                            "Account is required.",
225:                            "routetemplate.accountattribute.account.required"));
226:                    return;
227:                }
228:                Account account = SpringContext.getBean(AccountService.class)
229:                        .getByPrimaryIdWithCaching(finCoaCd, accountNbr);
230:                if (account == null) {
231:                    errors.add(new WorkflowServiceErrorImpl(
232:                            "Account is invalid.",
233:                            "routetemplate.accountattribute.account.invalid"));
234:                }
235:            }
236:
237:            /**
238:             * method to validate the rule data, since this is a role attribute, there is no rule data
239:             * 
240:             * @param paramMap
241:             * @return
242:             */
243:            public List validateRuleData(Map paramMap) {
244:                return new ArrayList();
245:            }
246:
247:            /**
248:             * method to actually construct the docContent that will be appended to this documents contents
249:             * 
250:             * @return
251:             */
252:            public String getDocContent() {
253:                if (Utilities.isEmpty(getFinCoaCd())
254:                        || Utilities.isEmpty(getAccountNbr())) {
255:                    return "";
256:                }
257:                return new StringBuffer(
258:                        KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_PREFIX
259:                                + "<chart>")
260:                        .append(getFinCoaCd())
261:                        .append("</chart><accountNumber>")
262:                        .append(getAccountNbr())
263:                        .append("</accountNumber><totalDollarAmount>")
264:                        .append(getTotalDollarAmount())
265:                        .append(
266:                                "</totalDollarAmount>"
267:                                        + KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_SUFFIX)
268:                        .toString();
269:            }
270:
271:            public String getAttributeLabel() {
272:                return "";
273:            }
274:
275:            /**
276:             * return true since this is a rule attribute, and if there are no routing records returned, then there was no valid mapping in
277:             * the docContent for a given role.
278:             * 
279:             * @param docContent
280:             * @param ruleExtensions
281:             * @return
282:             */
283:            public boolean isMatch(DocumentContent docContent,
284:                    List ruleExtensions) {
285:                return true;
286:            }
287:
288:            /**
289:             * This method is used by the workflow report to allow the user to fill in some arbitrary values for the routable contents of an
290:             * example document, and then to run the report to generate a virtual route log of who the document would route to, etc.
291:             * 
292:             * @return
293:             */
294:            public List getRoutingDataRows() {
295:                List rows = new ArrayList();
296:                rows.add(KualiWorkflowUtils.buildTextRowWithLookup(Chart.class,
297:                        KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME,
298:                        FIN_COA_CD_KEY));
299:                Map fieldConversionMap = new HashMap();
300:                fieldConversionMap.put(
301:                        KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME,
302:                        FIN_COA_CD_KEY);
303:                rows.add(KualiWorkflowUtils.buildTextRowWithLookup(
304:                        Account.class,
305:                        KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME,
306:                        ACCOUNT_NBR_KEY, fieldConversionMap));
307:
308:                // List fields = new ArrayList();
309:                // fields.add(new Field("Total Dollar Amount", "", Field.TEXT, false, FDOC_TOTAL_DOLLAR_AMOUNT_KEY, "", null, null));
310:                // rows.add(new Row(fields));
311:                rows.add(KualiWorkflowUtils.buildTextRow(DocumentHeader.class,
312:                        KFSPropertyConstants.FINANCIAL_DOCUMENT_TOTAL_AMOUNT,
313:                        FDOC_TOTAL_DOLLAR_AMOUNT_KEY));
314:
315:                return rows;
316:            }
317:
318:            /**
319:             * simple getter which returns empty
320:             * 
321:             * @return
322:             */
323:            public List getRuleRows() {
324:                return Collections.EMPTY_LIST;
325:            }
326:
327:            /**
328:             * simple getter which returns the account number
329:             * 
330:             * @return
331:             */
332:            public String getAccountNbr() {
333:                return accountNbr;
334:            }
335:
336:            /**
337:             * simple setter that takes the account number
338:             * 
339:             * @param accountNbr
340:             */
341:            public void setAccountNbr(String accountNbr) {
342:                this .accountNbr = accountNbr;
343:            }
344:
345:            /**
346:             * simple getter which returns the chart
347:             * 
348:             * @return
349:             */
350:            public String getFinCoaCd() {
351:                return finCoaCd;
352:            }
353:
354:            /**
355:             * simple setter which takes the chart
356:             * 
357:             * @param finCoaCd
358:             */
359:            public void setFinCoaCd(String finCoaCd) {
360:                this .finCoaCd = finCoaCd;
361:            }
362:
363:            /**
364:             * simple getter which returns the total dollar amount
365:             * 
366:             * @return
367:             */
368:            public String getTotalDollarAmount() {
369:                return totalDollarAmount;
370:            }
371:
372:            /**
373:             * simple setter which takes the total dollar amount
374:             * 
375:             * @param totalDollarAmount
376:             */
377:            public void setTotalDollarAmount(String totalDollarAmount) {
378:                this .totalDollarAmount = totalDollarAmount;
379:            }
380:
381:            private String getQualifiedRoleString(FiscalOfficerRole role) {
382:                return new StringBuffer(getNullSafeValue(role.roleName))
383:                        .append(ROLE_STRING_DELIMITER).append(
384:                                getNullSafeValue(role.chart)).append(
385:                                ROLE_STRING_DELIMITER).append(
386:                                getNullSafeValue(role.accountNumber)).append(
387:                                ROLE_STRING_DELIMITER).append(
388:                                getNullSafeValue(role.totalDollarAmount))
389:                        .append(ROLE_STRING_DELIMITER).append(
390:                                getNullSafeValue(role.fiscalOfficerId))
391:                        .toString();
392:            }
393:
394:            private static FiscalOfficerRole getUnqualifiedFiscalOfficerRole(
395:                    String qualifiedRole) {
396:                String[] values = qualifiedRole
397:                        .split(ROLE_STRING_DELIMITER, -1);
398:                if (values.length != 5) {
399:                    throw new RuntimeException(
400:                            "Invalid qualifiedRole, expected 5 encoded values: "
401:                                    + qualifiedRole);
402:                }
403:                FiscalOfficerRole role = new FiscalOfficerRole(values[0]);
404:                role.chart = getNullableString(values[1]);
405:                role.accountNumber = getNullableString(values[2]);
406:                role.totalDollarAmount = getNullableString(values[3]);
407:                role.fiscalOfficerId = getNullableString(values[4]);
408:                return role;
409:            }
410:
411:            private static String getNullSafeValue(String value) {
412:                return (value == null ? "" : value);
413:            }
414:
415:            private static String getNullableString(String value) {
416:                if (StringUtils.isEmpty(value)) {
417:                    return null;
418:                }
419:                return value;
420:            }
421:
422:            private static String getQualifiedAccountSupervisorRoleString(
423:                    String roleName, String accountSupervisorySystemsId) {
424:                return new StringBuffer(roleName).append(ROLE_STRING_DELIMITER)
425:                        .append(accountSupervisorySystemsId).toString();
426:            }
427:
428:            private static String getUnqualifiedAccountSupervisorIdFromString(
429:                    String qualifiedRole) {
430:                return qualifiedRole.split(ROLE_STRING_DELIMITER)[1];
431:            }
432:
433:            /**
434:             * Encodes the qualified role names for Fiscal Officer and Account Supervisor routing.
435:             */
436:            public List getQualifiedRoleNames(String roleName,
437:                    DocumentContent docContent)
438:                    throws EdenUserNotFoundException {
439:                String newMaintPrefix = KualiWorkflowUtils.NEW_MAINTAINABLE_PREFIX;
440:                String oldMaintPrefix = KualiWorkflowUtils.OLD_MAINTAINABLE_PREFIX;
441:                try {
442:                    List qualifiedRoleNames = new ArrayList();
443:                    XPath xpath = KualiWorkflowUtils.getXPath(docContent
444:                            .getDocument());
445:                    String docTypeName = docContent.getRouteContext()
446:                            .getDocument().getDocumentType().getName();
447:                    if (FISCAL_OFFICER_ROLE_KEY.equals(roleName)
448:                            || FISCAL_OFFICER_PRIMARY_DELEGATE_ROLE_KEY
449:                                    .equals(roleName)
450:                            || FISCAL_OFFICER_SECONDARY_DELEGATE_ROLE_KEY
451:                                    .equals(roleName)) {
452:                        Set fiscalOfficers = new HashSet();
453:                        if (((Boolean) xpath
454:                                .evaluate(
455:                                        KualiWorkflowUtils
456:                                                .xstreamSafeXPath(KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX
457:                                                        + KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_XPATH_PREFIX),
458:                                        docContent.getDocument(),
459:                                        XPathConstants.BOOLEAN)).booleanValue()) {
460:                            String chart = xpath
461:                                    .evaluate(
462:                                            KualiWorkflowUtils
463:                                                    .xstreamSafeXPath(KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX
464:                                                            + KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_XPATH_PREFIX
465:                                                            + "/chart"),
466:                                            docContent.getDocument());
467:                            String accountNumber = xpath
468:                                    .evaluate(
469:                                            KualiWorkflowUtils
470:                                                    .xstreamSafeXPath(KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX
471:                                                            + KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_XPATH_PREFIX
472:                                                            + "/accountNumber"),
473:                                            docContent.getDocument());
474:                            String totalDollarAmount = xpath
475:                                    .evaluate(
476:                                            KualiWorkflowUtils
477:                                                    .xstreamSafeXPath(KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX
478:                                                            + KualiWorkflowUtils.XML_REPORT_DOC_CONTENT_XPATH_PREFIX
479:                                                            + "/totalDollarAmount"),
480:                                            docContent.getDocument());
481:                            FiscalOfficerRole role = new FiscalOfficerRole(
482:                                    roleName);
483:                            role.chart = chart;
484:                            role.accountNumber = accountNumber;
485:                            role.totalDollarAmount = totalDollarAmount;
486:                            fiscalOfficers.add(role);
487:                        } else if (KualiWorkflowUtils.ACCOUNT_DOC_TYPE
488:                                .equals(docTypeName)) {
489:                            // 1) If this is a new account, it routes to the fiscal
490:                            // officer specified on the new account
491:                            // 2) If this is an account edit and the fiscal officer
492:                            // hasn't changed, route to the fiscal officer on the
493:                            // account
494:                            // 3) If this is an account edit and the fiscal officer HAS
495:                            // changed, route to the old fiscal officer and the new
496:                            // fiscal officer
497:                            // ...
498:                            // This logic crystallizes down to the following:
499:                            // Route on all unique fiscal officers on the document.
500:                            // Dont route to the same person twice.
501:                            //
502:                            String newFiscalOfficerId = KualiWorkflowUtils
503:                                    .xstreamSafeEval(
504:                                            xpath,
505:                                            newMaintPrefix
506:                                                    + KFSPropertyConstants.ACCOUNT_FISCAL_OFFICER_SYSTEM_IDENTIFIER,
507:                                            docContent.getDocument());
508:                            String oldFiscalOfficerId = KualiWorkflowUtils
509:                                    .xstreamSafeEval(
510:                                            xpath,
511:                                            oldMaintPrefix
512:                                                    + KFSPropertyConstants.ACCOUNT_FISCAL_OFFICER_SYSTEM_IDENTIFIER,
513:                                            docContent.getDocument());
514:                            String foChartCode = KualiWorkflowUtils
515:                                    .xstreamSafeEval(
516:                                            xpath,
517:                                            newMaintPrefix
518:                                                    + KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME,
519:                                            docContent.getDocument());
520:                            String foAccountNumber = KualiWorkflowUtils
521:                                    .xstreamSafeEval(
522:                                            xpath,
523:                                            newMaintPrefix
524:                                                    + KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME,
525:                                            docContent.getDocument());
526:                            if (StringUtils.isNotBlank(newFiscalOfficerId)) {
527:                                fiscalOfficers.add(new FiscalOfficerRole(
528:                                        roleName, newFiscalOfficerId,
529:                                        foChartCode, foAccountNumber));
530:                            }
531:                            if (StringUtils.isNotBlank(oldFiscalOfficerId)) {
532:                                if (!oldFiscalOfficerId
533:                                        .equalsIgnoreCase(newFiscalOfficerId)) {
534:                                    fiscalOfficers.add(new FiscalOfficerRole(
535:                                            roleName, oldFiscalOfficerId,
536:                                            foChartCode, foAccountNumber));
537:                                }
538:                            }
539:                            if (fiscalOfficers.isEmpty()) {
540:                                throw new RuntimeException(
541:                                        "No Fiscal Officers were found in this Account Maintenance Document. Routing cannot continue without Fiscal Officers.");
542:                            }
543:                        } else if (KualiWorkflowUtils.SUB_ACCOUNT_DOC_TYPE
544:                                .equals(docTypeName)
545:                                || KualiWorkflowUtils.SUB_OBJECT_DOC_TYPE
546:                                        .equals(docTypeName)
547:                                || KualiWorkflowUtils.ACCOUNT_DEL_DOC_TYPE
548:                                        .equals(docTypeName)) {
549:                            String foChartCode = KualiWorkflowUtils
550:                                    .xstreamSafeEval(
551:                                            xpath,
552:                                            newMaintPrefix
553:                                                    + KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME,
554:                                            docContent.getDocument());
555:                            String foAccountNumber = KualiWorkflowUtils
556:                                    .xstreamSafeEval(
557:                                            xpath,
558:                                            newMaintPrefix
559:                                                    + KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME,
560:                                            docContent.getDocument());
561:                            fiscalOfficers.add(new FiscalOfficerRole(roleName,
562:                                    foChartCode, foAccountNumber));
563:                        } else if (KualiWorkflowUtils.SUB_OBJECT_CODE_CHANGE_DOC_TYPE
564:                                .equals(docTypeName)) {
565:                            // route to the fiscal officers of the accounts on the AccountGlobalDetails
566:                            NodeList accountGlobalDetails = (NodeList) xpath
567:                                    .evaluate(
568:                                            KualiWorkflowUtils.ACCOUNT_GLOBAL_DETAILS_XPATH,
569:                                            docContent.getDocument(),
570:                                            XPathConstants.NODESET);
571:                            if (accountGlobalDetails != null) {
572:                                for (int index = 0; index < accountGlobalDetails
573:                                        .getLength(); index++) {
574:                                    Element accountGlobalDetail = (Element) accountGlobalDetails
575:                                            .item(index);
576:                                    String chartOfAccountsCode = getChildElementValue(
577:                                            accountGlobalDetail,
578:                                            KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME);
579:                                    String accountNumber = getChildElementValue(
580:                                            accountGlobalDetail,
581:                                            KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME);
582:                                    fiscalOfficers.add(new FiscalOfficerRole(
583:                                            roleName, chartOfAccountsCode,
584:                                            accountNumber));
585:                                }
586:                            }
587:                        } else {
588:                            if (!KualiWorkflowUtils
589:                                    .isTargetLineOnly(docTypeName)) {
590:                                NodeList sourceLineNodes = (NodeList) xpath
591:                                        .evaluate(
592:                                                KualiWorkflowUtils
593:                                                        .xstreamSafeXPath(KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX
594:                                                                + KualiWorkflowUtils
595:                                                                        .getSourceAccountingLineClassName(docTypeName)),
596:                                                docContent.getDocument(),
597:                                                XPathConstants.NODESET);
598:                                String totalDollarAmount = String
599:                                        .valueOf(calculateTotalDollarAmount(docContent
600:                                                .getDocument()));
601:                                fiscalOfficers.addAll(getFiscalOfficerCriteria(
602:                                        xpath, sourceLineNodes, roleName,
603:                                        totalDollarAmount));
604:                            }
605:                            if (!KualiWorkflowUtils
606:                                    .isSourceLineOnly(docTypeName)) {
607:                                NodeList targetLineNodes = (NodeList) xpath
608:                                        .evaluate(
609:                                                KualiWorkflowUtils
610:                                                        .xstreamSafeXPath(KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX
611:                                                                + KualiWorkflowUtils
612:                                                                        .getTargetAccountingLineClassName(docTypeName)),
613:                                                docContent.getDocument(),
614:                                                XPathConstants.NODESET);
615:                                String totalDollarAmount = String
616:                                        .valueOf(calculateTotalDollarAmount(docContent
617:                                                .getDocument()));
618:                                fiscalOfficers.addAll(getFiscalOfficerCriteria(
619:                                        xpath, targetLineNodes, roleName,
620:                                        totalDollarAmount));
621:                            }
622:                        }
623:                        for (Iterator iterator = fiscalOfficers.iterator(); iterator
624:                                .hasNext();) {
625:                            FiscalOfficerRole role = (FiscalOfficerRole) iterator
626:                                    .next();
627:                            qualifiedRoleNames
628:                                    .add(getQualifiedRoleString(role));
629:                        }
630:                    } else if (ACCOUNT_SUPERVISOR_ROLE_KEY.equals(roleName)) {
631:                        Set<String> super visors = getAccountSupervisorIds(
632:                                docTypeName, xpath, docContent);
633:                        for (String accountSupervisorId : super visors) {
634:                            qualifiedRoleNames
635:                                    .add(getQualifiedAccountSupervisorRoleString(
636:                                            roleName, accountSupervisorId));
637:                        }
638:                    }
639:                    return qualifiedRoleNames;
640:                } catch (Exception e) {
641:                    throw new RuntimeException(e);
642:                }
643:            }
644:
645:            /**
646:             * Retrieves a Set of account supervisor Ids that should be routed to for the given document content.
647:             */
648:            private Set<String> getAccountSupervisorIds(String docTypeName,
649:                    XPath xpath, DocumentContent docContent) throws Exception {
650:                Set<String> super visors = new HashSet<String>();
651:                List<String> accountXPaths = new ArrayList<String>();
652:                String super visorProperty = "accountsSupervisorySystemsIdentifier";
653:                // Account Maintenance Document - route to Account Supervisor of account on new maintainable
654:                if (docTypeName.equals(KualiWorkflowUtils.ACCOUNT_DOC_TYPE)) {
655:                    accountXPaths
656:                            .add(KualiWorkflowUtils
657:                                    .xstreamSafeXPath(KualiWorkflowUtils.NEW_MAINTAINABLE_PREFIX_NTS));
658:                }
659:                // Sub Object Code Change Document - route to Account Supervisor of accounts on AccountGlobalDetails
660:                else if (docTypeName
661:                        .equals(KualiWorkflowUtils.SUB_OBJECT_CODE_CHANGE_DOC_TYPE)) {
662:                    accountXPaths
663:                            .add(KualiWorkflowUtils.ACCOUNT_GLOBAL_DETAILS_XPATH);
664:                }
665:                for (String accountXPath : accountXPaths) {
666:                    NodeList accountNodes = (NodeList) xpath.evaluate(
667:                            accountXPath, docContent.getDocument(),
668:                            XPathConstants.NODESET);
669:                    for (int index = 0; index < accountNodes.getLength(); index++) {
670:                        Element accountElement = (Element) accountNodes
671:                                .item(index);
672:                        String chartOfAccountsCode = getChildElementValue(
673:                                accountElement,
674:                                KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME);
675:                        String accountNumber = getChildElementValue(
676:                                accountElement,
677:                                KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME);
678:                        if (!StringUtils.isBlank(accountNumber)
679:                                && !StringUtils.isBlank(chartOfAccountsCode)) {
680:                            Account account = SpringContext.getBean(
681:                                    AccountService.class)
682:                                    .getByPrimaryIdWithCaching(
683:                                            chartOfAccountsCode, accountNumber);
684:                            if (account != null
685:                                    && !StringUtils
686:                                            .isBlank(account
687:                                                    .getAccountsSupervisorySystemsIdentifier())) {
688:                                super visors
689:                                        .add(account
690:                                                .getAccountsSupervisorySystemsIdentifier());
691:                            }
692:                        }
693:                    }
694:                }
695:                return super visors;
696:            }
697:
698:            private String getChildElementValue(Element element,
699:                    String childTagName) {
700:                NodeList nodes = element.getChildNodes();
701:                for (int index = 0; index < nodes.getLength(); index++) {
702:                    Node node = nodes.item(index);
703:                    if (Node.ELEMENT_NODE == node.getNodeType()
704:                            && node.getNodeName().equals(childTagName)) {
705:                        return node.getFirstChild().getNodeValue();
706:                    }
707:                }
708:                return null;
709:            }
710:
711:            private static String calculateTotalDollarAmount(Document document)
712:                    throws XPathExpressionException {
713:                KualiDecimal sum = KualiWorkflowUtils
714:                        .getFinancialDocumentTotalAmount(document);
715:                if (ObjectUtils.isNull(sum)) {
716:                    sum = KualiDecimal.ZERO;
717:                }
718:                return sum.toString();
719:            }
720:
721:            private static Set getFiscalOfficerCriteria(XPath xpath,
722:                    NodeList accountingLineNodes, String roleName,
723:                    String totalDollarAmount) throws XPathExpressionException {
724:                Set fiscalOfficers = new HashSet();
725:                for (int i = 0; i < accountingLineNodes.getLength(); i++) {
726:                    Node accountingLineNode = accountingLineNodes.item(i);
727:                    FiscalOfficerRole role = new FiscalOfficerRole(roleName);
728:                    role.chart = xpath
729:                            .evaluate(
730:                                    KualiWorkflowUtils.XSTREAM_MATCH_RELATIVE_PREFIX
731:                                            + KFSConstants.CHART_OF_ACCOUNTS_CODE_PROPERTY_NAME,
732:                                    accountingLineNode);
733:                    role.accountNumber = xpath
734:                            .evaluate(
735:                                    KualiWorkflowUtils.XSTREAM_MATCH_RELATIVE_PREFIX
736:                                            + KFSConstants.ACCOUNT_NUMBER_PROPERTY_NAME,
737:                                    accountingLineNode);
738:                    role.totalDollarAmount = totalDollarAmount;
739:                    fiscalOfficers.add(role);
740:                }
741:                return fiscalOfficers;
742:            }
743:
744:            /**
745:             * Resolves the qualified roles for Fiscal Officers, their delegates, and account supervisors.
746:             */
747:            public ResolvedQualifiedRole resolveQualifiedRole(
748:                    RouteContext context, String roleName, String qualifiedRole)
749:                    throws EdenUserNotFoundException {
750:                try {
751:                    List members = new ArrayList();
752:                    String workfowDocumentType = context.getDocument()
753:                            .getDocumentType().getName();
754:                    if ((DOCUMENT_TYPE_TRANSLATION
755:                            .containsKey(workfowDocumentType))
756:                            && (DOCUMENT_TYPE_TRANSLATION
757:                                    .get(workfowDocumentType) != null)) {
758:                        workfowDocumentType = DOCUMENT_TYPE_TRANSLATION
759:                                .get(workfowDocumentType);
760:                    }
761:                    String kualiDocumentType = SpringContext.getBean(
762:                            DataDictionaryService.class)
763:                            .getDocumentTypeCodeByTypeName(workfowDocumentType);
764:                    String annotation = "";
765:                    if (FISCAL_OFFICER_ROLE_KEY.equals(roleName)) {
766:                        FiscalOfficerRole role = getUnqualifiedFiscalOfficerRole(qualifiedRole);
767:                        annotation = (role.accountNumber == null ? ""
768:                                : "Routing to account number "
769:                                        + role.accountNumber);
770:                        UserId fiscalOfficerId = getFiscalOfficerId(role);
771:                        if (fiscalOfficerId != null) {
772:                            members.add(fiscalOfficerId);
773:                        }
774:                    } else if (FISCAL_OFFICER_PRIMARY_DELEGATE_ROLE_KEY
775:                            .equals(roleName)) {
776:                        FiscalOfficerRole role = getUnqualifiedFiscalOfficerRole(qualifiedRole);
777:                        UserId primaryDelegate = getPrimaryDelegation(role,
778:                                kualiDocumentType);
779:                        if (primaryDelegate != null) {
780:                            members.add(primaryDelegate);
781:                        }
782:                    } else if (FISCAL_OFFICER_SECONDARY_DELEGATE_ROLE_KEY
783:                            .equals(roleName)) {
784:                        FiscalOfficerRole role = getUnqualifiedFiscalOfficerRole(qualifiedRole);
785:                        members.addAll(getSecondaryDelegations(role,
786:                                kualiDocumentType));
787:                    } else if (ACCOUNT_SUPERVISOR_ROLE_KEY.equals(roleName)) {
788:                        String accountSupervisorId = getUnqualifiedAccountSupervisorIdFromString(qualifiedRole);
789:                        annotation = "Routing to Account Supervisor";
790:                        String super visorNetworkId = SpringContext.getBean(
791:                                UniversalUserService.class).getUniversalUser(
792:                                new UuId(accountSupervisorId))
793:                                .getPersonUserIdentifier();
794:                        if (!StringUtils.isEmpty(super visorNetworkId)) {
795:                            members.add(new AuthenticationUserId(
796:                                    super visorNetworkId));
797:                        } else {
798:                            LOG.info("No active account supervisor found.");
799:                        }
800:                    }
801:                    return new ResolvedQualifiedRole(roleName, members,
802:                            annotation);
803:                } catch (Exception e) {
804:                    throw new RuntimeException(
805:                            "KualiAccountAttribute encountered exception while attempting to resolve qualified role",
806:                            e);
807:                }
808:            }
809:
810:            private static AuthenticationUserId getFiscalOfficerId(
811:                    FiscalOfficerRole role) throws Exception {
812:                String fiscalOfficerNetworkId = null;
813:
814:                // if we already have an ID, validate it, and then we're done
815:                if (StringUtils.isNotBlank(role.fiscalOfficerId)) {
816:                    try {
817:                        fiscalOfficerNetworkId = SpringContext.getBean(
818:                                UniversalUserService.class).getUniversalUser(
819:                                new UuId(role.fiscalOfficerId))
820:                                .getPersonUserIdentifier();
821:                    } catch (org.kuali.core.exceptions.UserNotFoundException e) {
822:                        // do nothing, but leave fiscalOfficerNetworkId blank, which will get caught after this
823:                    }
824:                    if (StringUtils.isBlank(fiscalOfficerNetworkId)) {
825:                        throw new RuntimeException(
826:                                "FiscalOfficer with UniversalID: "
827:                                        + role.fiscalOfficerId
828:                                        + " was not "
829:                                        + "found in UniversalUsers.  Routing cannot continue.");
830:                    } else {
831:                        return new AuthenticationUserId(fiscalOfficerNetworkId);
832:                    }
833:                }
834:
835:                // if we dont have an ID, but we do have a chart/account, then hit Kuali to retrieve current FO
836:                if (StringUtils.isNotBlank(role.chart)
837:                        && StringUtils.isNotBlank(role.accountNumber)) {
838:                    Account account = SpringContext.getBean(
839:                            AccountService.class).getByPrimaryIdWithCaching(
840:                            role.chart, role.accountNumber);
841:                    if (account != null) {
842:                        if (account.getAccountFiscalOfficerUser() != null) {
843:                            fiscalOfficerNetworkId = account
844:                                    .getAccountFiscalOfficerUser()
845:                                    .getPersonUserIdentifier();
846:                        }
847:                    }
848:                }
849:
850:                // if we cant find a FiscalOfficer, then something is wrong, so throw an exception
851:                if (StringUtils.isBlank(fiscalOfficerNetworkId)) {
852:                    LOG
853:                            .warn(new StringBuffer(
854:                                    "Could not locate the fiscal officer for the given account ")
855:                                    .append(role.accountNumber).append(
856:                                            " / fiscal officer uid ").append(
857:                                            role.fiscalOfficerId).toString());
858:                    throw new RuntimeException(
859:                            new StringBuffer(
860:                                    "Could not locate the fiscal officer for the given account ")
861:                                    .append(role.accountNumber).append(
862:                                            " / fiscal officer uid ").append(
863:                                            role.fiscalOfficerId).toString());
864:                }
865:                return new AuthenticationUserId(fiscalOfficerNetworkId);
866:            }
867:
868:            /**
869:             * Returns a the UserId of the primary delegation on the given FiscalOfficerRole. If the given role doesn't have an account
870:             * number or there is no primary delegate, returns null.
871:             * 
872:             * @throws RuntimeException if there is more than one primary delegation on the given account
873:             */
874:            private static UserId getPrimaryDelegation(FiscalOfficerRole role,
875:                    String fisDocumentType) throws Exception {
876:                UserId primaryDelegateId = null;
877:                if (role.accountNumber != null) {
878:                    Delegate delegateExample = new Delegate();
879:                    delegateExample.setChartOfAccountsCode(role.chart);
880:                    delegateExample.setAccountNumber(role.accountNumber);
881:                    delegateExample
882:                            .setFinancialDocumentTypeCode(fisDocumentType);
883:                    Delegate primaryDelegate = SpringContext.getBean(
884:                            AccountService.class)
885:                            .getPrimaryDelegationByExample(delegateExample,
886:                                    role.totalDollarAmount);
887:                    if (primaryDelegate != null) {
888:                        primaryDelegateId = new AuthenticationUserId(
889:                                primaryDelegate.getAccountDelegate()
890:                                        .getPersonUserIdentifier());
891:                    }
892:                }
893:                return primaryDelegateId;
894:            }
895:
896:            /**
897:             * Returns a list of UserIds for all secondary delegations on the given FiscalOfficerRole. If the given role doesn't have an
898:             * account number or there are no delegations, returns an empty list.
899:             */
900:            private static List getSecondaryDelegations(FiscalOfficerRole role,
901:                    String fisDocumentType) throws Exception {
902:                List members = new ArrayList();
903:                if (role.accountNumber != null) {
904:                    Delegate delegateExample = new Delegate();
905:                    delegateExample.setChartOfAccountsCode(role.chart);
906:                    delegateExample.setAccountNumber(role.accountNumber);
907:                    delegateExample
908:                            .setFinancialDocumentTypeCode(fisDocumentType);
909:                    Iterator secondaryDelegations = SpringContext.getBean(
910:                            AccountService.class)
911:                            .getSecondaryDelegationsByExample(delegateExample,
912:                                    role.totalDollarAmount).iterator();
913:                    while (secondaryDelegations.hasNext()) {
914:                        members.add(new AuthenticationUserId(
915:                                ((Delegate) secondaryDelegations.next())
916:                                        .getAccountDelegate()
917:                                        .getPersonUserIdentifier()));
918:                    }
919:                }
920:                return members;
921:            }
922:
923:            /**
924:             * A helper class which defines a Fiscal Officer role. Implements an equals() and hashCode() method so that it can be used in a
925:             * Set to prevent the generation of needless duplicate requests.
926:             */
927:            private static class FiscalOfficerRole {
928:
929:                public String roleName;
930:
931:                public String fiscalOfficerId;
932:
933:                public String chart;
934:
935:                public String accountNumber;
936:
937:                public String totalDollarAmount;
938:
939:                public FiscalOfficerRole(String roleName) {
940:                    this .roleName = roleName;
941:                }
942:
943:                public FiscalOfficerRole(String roleName,
944:                        String fiscalOfficerId, String chart,
945:                        String accountNumber) {
946:                    this .roleName = roleName;
947:                    this .fiscalOfficerId = fiscalOfficerId;
948:                    this .chart = chart;
949:                    this .accountNumber = accountNumber;
950:                }
951:
952:                public FiscalOfficerRole(String roleName, String chart,
953:                        String accountNumber) {
954:                    this .roleName = roleName;
955:                    this .chart = chart;
956:                    this .accountNumber = accountNumber;
957:                }
958:
959:                @Override
960:                public boolean equals(Object object) {
961:                    if (object instanceof  FiscalOfficerRole) {
962:                        FiscalOfficerRole role = (FiscalOfficerRole) object;
963:                        return new EqualsBuilder().append(roleName,
964:                                role.roleName).append(fiscalOfficerId,
965:                                role.fiscalOfficerId).append(chart, role.chart)
966:                                .append(accountNumber, role.accountNumber)
967:                                .append(totalDollarAmount,
968:                                        role.totalDollarAmount).isEquals();
969:                    }
970:                    return false;
971:                }
972:
973:                @Override
974:                public int hashCode() {
975:                    return new HashCodeBuilder().append(roleName).append(
976:                            fiscalOfficerId).append(chart)
977:                            .append(accountNumber).append(totalDollarAmount)
978:                            .hashCode();
979:                }
980:
981:            }
982:
983:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.