Source Code Cross Referenced for LaborExpenseTransferDocumentRules.java in  » ERP-CRM-Financial » Kuali-Financial-System » org » kuali » module » labor » rules » 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.module.labor.rules 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2007 The Kuali Foundation.
003:         * 
004:         * Licensed under the Educational Community License, Version 1.0 (the "License");
005:         * you may not use this file except in compliance with the License.
006:         * You may obtain a copy of the License at
007:         * 
008:         * http://www.opensource.org/licenses/ecl1.php
009:         * 
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS,
012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         * See the License for the specific language governing permissions and
014:         * limitations under the License.
015:         */
016:        package org.kuali.module.labor.rules;
017:
018:        import static org.kuali.kfs.bo.AccountingLineOverride.CODE.EXPIRED_ACCOUNT;
019:        import static org.kuali.kfs.bo.AccountingLineOverride.CODE.EXPIRED_ACCOUNT_AND_NON_FRINGE_ACCOUNT_USED;
020:        import static org.kuali.kfs.bo.AccountingLineOverride.CODE.NON_FRINGE_ACCOUNT_USED;
021:
022:        import java.util.ArrayList;
023:        import java.util.HashMap;
024:        import java.util.Iterator;
025:        import java.util.List;
026:        import java.util.Map;
027:        import java.util.Set;
028:        import java.util.Map.Entry;
029:
030:        import org.apache.commons.lang.StringUtils;
031:        import org.kuali.core.document.Document;
032:        import org.kuali.core.service.BusinessObjectService;
033:        import org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper;
034:        import org.kuali.core.util.KualiDecimal;
035:        import org.kuali.kfs.KFSConstants;
036:        import org.kuali.kfs.KFSKeyConstants;
037:        import org.kuali.kfs.KFSPropertyConstants;
038:        import org.kuali.kfs.bo.AccountingLine;
039:        import org.kuali.kfs.bo.Options;
040:        import org.kuali.kfs.context.SpringContext;
041:        import org.kuali.kfs.document.AccountingDocument;
042:        import org.kuali.kfs.rules.AccountingDocumentRuleBase;
043:        import org.kuali.kfs.service.OptionsService;
044:        import org.kuali.module.chart.bo.Account;
045:        import org.kuali.module.labor.LaborConstants;
046:        import org.kuali.module.labor.LaborKeyConstants;
047:        import org.kuali.module.labor.LaborPropertyConstants;
048:        import org.kuali.module.labor.bo.ExpenseTransferAccountingLine;
049:        import org.kuali.module.labor.bo.ExpenseTransferSourceAccountingLine;
050:        import org.kuali.module.labor.bo.LedgerBalance;
051:        import org.kuali.module.labor.document.LaborExpenseTransferDocumentBase;
052:        import org.kuali.module.labor.document.LaborLedgerPostingDocument;
053:        import org.kuali.module.labor.rule.GenerateLaborLedgerPendingEntriesRule;
054:        import org.kuali.module.labor.util.ObjectUtil;
055:
056:        /**
057:         * Business rule(s) applicable to Labor Expense Transfer documents.
058:         */
059:        public class LaborExpenseTransferDocumentRules extends
060:                AccountingDocumentRuleBase
061:                implements 
062:                GenerateLaborLedgerPendingEntriesRule<LaborLedgerPostingDocument> {
063:            /**
064:             * Updates an accounting line
065:             * 
066:             * @param accountingDocument document to be processed
067:             * @param originalAccountingLine accounting line with old data
068:             * @param updatedAccountingLine accounting line with the new data
069:             * @return boolean
070:             * @see org.kuali.kfs.rules.AccountingDocumentRuleBase#processCustomUpdateAccountingLineBusinessRules(org.kuali.kfs.document.AccountingDocument,
071:             *      org.kuali.kfs.bo.AccountingLine, org.kuali.kfs.bo.AccountingLine)
072:             */
073:            @Override
074:            protected boolean processCustomUpdateAccountingLineBusinessRules(
075:                    AccountingDocument accountingDocument,
076:                    AccountingLine originalAccountingLine,
077:                    AccountingLine updatedAccountingLine) {
078:                return processCustomAddAccountingLineBusinessRules(
079:                        accountingDocument, updatedAccountingLine);
080:            }
081:
082:            /**
083:             * Adds an accounting line
084:             * 
085:             * @param accountingDocument document to be processed
086:             * @param originalAccountingLine accounting line with old data
087:             * @param updatedAccountingLine accounting line with the new data
088:             * @return boolean
089:             * @see org.kuali.kfs.rules.AccountingDocumentRuleBase#processCustomAddAccountingLineBusinessRules(org.kuali.kfs.document.AccountingDocument,
090:             *      org.kuali.kfs.bo.AccountingLine)
091:             */
092:            @Override
093:            protected boolean processCustomAddAccountingLineBusinessRules(
094:                    AccountingDocument accountingDocument,
095:                    AccountingLine accountingLine) {
096:                boolean isValid = super 
097:                        .processCustomAddAccountingLineBusinessRules(
098:                                accountingDocument, accountingLine);
099:
100:                if (!isValid) {
101:                    return false;
102:                }
103:
104:                // not allow the duplicate source accounting line in the document
105:                if (isDuplicateSourceAccountingLine(accountingDocument,
106:                        accountingLine)) {
107:                    reportError(
108:                            KFSPropertyConstants.SOURCE_ACCOUNTING_LINES,
109:                            LaborKeyConstants.ERROR_DUPLICATE_SOURCE_ACCOUNTING_LINE);
110:                    return false;
111:                }
112:
113:                // determine if an expired account can be used to accept amount transfer
114:                boolean canExpiredAccountBeUsed = canExpiredAccountBeUsed(accountingLine);
115:                if (!canExpiredAccountBeUsed) {
116:                    reportError(KFSPropertyConstants.ACCOUNT,
117:                            KFSKeyConstants.ERROR_ACCOUNT_EXPIRED);
118:                    return false;
119:                }
120:
121:                // verify if the accounts in target accounting lines accept fringe benefits
122:                if (!isAccountAcceptFringeBenefit(accountingLine)) {
123:                    reportError(KFSPropertyConstants.TARGET_ACCOUNTING_LINES,
124:                            LaborKeyConstants.ERROR_ACCOUNT_NOT_ACCEPT_FRINGES,
125:                            accountingLine.getAccount()
126:                                    .getReportsToChartOfAccountsCode(),
127:                            accountingLine.getAccount()
128:                                    .getReportsToAccountNumber());
129:                    return false;
130:                }
131:
132:                return true;
133:            }
134:
135:            /**
136:             * Route a document
137:             * 
138:             * @param document the document to be routed
139:             * @return boolean
140:             * @see org.kuali.kfs.rules.AccountingDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.core.document.Document)
141:             */
142:            @Override
143:            protected boolean processCustomRouteDocumentBusinessRules(
144:                    Document document) {
145:                LOG.info("started processCustomRouteDocumentBusinessRules");
146:
147:                LaborExpenseTransferDocumentBase expenseTransferDocument = (LaborExpenseTransferDocumentBase) document;
148:                List sourceLines = expenseTransferDocument
149:                        .getSourceAccountingLines();
150:                List targetLines = expenseTransferDocument
151:                        .getTargetAccountingLines();
152:
153:                boolean isValid = super 
154:                        .processCustomRouteDocumentBusinessRules(document);
155:
156:                // check to ensure totals of accounting lines in source and target sections match
157:                isValid = isValid
158:                        & isAccountingLineTotalsMatch(sourceLines, targetLines);
159:
160:                // check to ensure totals of accounting lines in source and target sections match by pay FY + pay period
161:                isValid = isValid
162:                        & isAccountingLineTotalsMatchByPayFYAndPayPeriod(
163:                                sourceLines, targetLines);
164:
165:                // allow a negative amount to be moved from one account to another but do not allow a negative amount to be created when the
166:                // balance is positive
167:                Map<String, ExpenseTransferAccountingLine> accountingLineGroupMap = this 
168:                        .getAccountingLineGroupMap(sourceLines,
169:                                ExpenseTransferSourceAccountingLine.class);
170:                if (isValid) {
171:                    boolean canNegtiveAmountBeTransferred = canNegtiveAmountBeTransferred(accountingLineGroupMap);
172:                    if (!canNegtiveAmountBeTransferred) {
173:                        reportError(
174:                                KFSPropertyConstants.SOURCE_ACCOUNTING_LINES,
175:                                LaborKeyConstants.ERROR_CANNOT_TRANSFER_NEGATIVE_AMOUNT);
176:                        isValid = false;
177:                    }
178:                }
179:
180:                // target accounting lines must have the same amounts as source accounting lines for each object code
181:                if (isValid) {
182:                    isValid = isValidAmountTransferredByObjectCode(expenseTransferDocument);
183:                }
184:
185:                // only allow a transfer of benefit dollars up to the amount that already exist in labor ledger detail for a given pay
186:                // period
187:                if (isValid) {
188:                    boolean isValidTransferAmount = isValidTransferAmount(accountingLineGroupMap);
189:                    if (!isValidTransferAmount) {
190:                        reportError(
191:                                KFSPropertyConstants.SOURCE_ACCOUNTING_LINES,
192:                                LaborKeyConstants.ERROR_TRANSFER_AMOUNT_EXCEED_MAXIMUM);
193:                        isValid = false;
194:                    }
195:                }
196:
197:                return isValid;
198:            }
199:
200:            /**
201:             * Determine whether the accounts in source/target accounting lines are valid
202:             * 
203:             * @param accountingDocument the given accounting document
204:             * @return true if the accounts in source/target accounting lines are valid; otherwise, false
205:             */
206:            private boolean isValidAccount(AccountingDocument accountingDocument) {
207:                LaborExpenseTransferDocumentBase expenseTransferDocument = (LaborExpenseTransferDocumentBase) accountingDocument;
208:
209:                for (Object sourceAccountingLine : expenseTransferDocument
210:                        .getSourceAccountingLines()) {
211:                    AccountingLine line = (AccountingLine) sourceAccountingLine;
212:                    if (line.getAccount() == null) {
213:                        reportError(
214:                                KFSPropertyConstants.SOURCE_ACCOUNTING_LINES,
215:                                KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_ACCOUNT_INVALID_ACCOUNT,
216:                                new String[] { line.getChartOfAccountsCode(),
217:                                        line.getAccountNumber() });
218:                        return false;
219:                    }
220:                }
221:
222:                for (Object targetAccountingLine : expenseTransferDocument
223:                        .getTargetAccountingLines()) {
224:                    AccountingLine line = (AccountingLine) targetAccountingLine;
225:                    if (line.getAccount() == null) {
226:                        reportError(
227:                                KFSPropertyConstants.TARGET_ACCOUNTING_LINES,
228:                                KFSKeyConstants.ERROR_DOCUMENT_GLOBAL_ACCOUNT_INVALID_ACCOUNT,
229:                                new String[] { line.getChartOfAccountsCode(),
230:                                        line.getAccountNumber() });
231:                        return false;
232:                    }
233:                }
234:                return true;
235:            }
236:
237:            /**
238:             * Performs validation on emplid
239:             * 
240:             * @param emplid - id to validate
241:             * @return boolean - true if id is valid, false if invalid
242:             */
243:            public boolean isValidEmplid(String emplid) {
244:                boolean isValid = true;
245:
246:                // verify id was given
247:                if (StringUtils.isBlank(emplid)) {
248:                    reportError(LaborConstants.EMPLOYEE_LOOKUP_ERRORS,
249:                            LaborKeyConstants.MISSING_EMPLOYEE_ID, emplid);
250:                    isValid = false;
251:                }
252:
253:                return isValid;
254:            }
255:
256:            /**
257:             * This method checks if the total sum amount of the source accounting line matches the total sum amount of the target
258:             * accounting line, return true if the totals match, false otherwise.
259:             * 
260:             * @param sourceLines
261:             * @param targetLines
262:             * @return
263:             */
264:            public boolean isAccountingLineTotalsMatch(List sourceLines,
265:                    List targetLines) {
266:                boolean isValid = true;
267:
268:                AccountingLine line = null;
269:
270:                // totals for the from and to lines.
271:                KualiDecimal sourceLinesAmount = new KualiDecimal(0);
272:                KualiDecimal targetLinesAmount = new KualiDecimal(0);
273:
274:                // sum source lines
275:                for (Iterator i = sourceLines.iterator(); i.hasNext();) {
276:                    line = (ExpenseTransferAccountingLine) i.next();
277:                    sourceLinesAmount = sourceLinesAmount.add(line.getAmount());
278:                }
279:
280:                // sum target lines
281:                for (Iterator i = targetLines.iterator(); i.hasNext();) {
282:                    line = (ExpenseTransferAccountingLine) i.next();
283:                    targetLinesAmount = targetLinesAmount.add(line.getAmount());
284:                }
285:
286:                // if totals don't match, then add error message
287:                if (sourceLinesAmount.compareTo(targetLinesAmount) != 0) {
288:                    isValid = false;
289:                    reportError(
290:                            KFSPropertyConstants.SOURCE_ACCOUNTING_LINES,
291:                            LaborKeyConstants.ACCOUNTING_LINE_TOTALS_MISMATCH_ERROR);
292:                }
293:
294:                return isValid;
295:            }
296:
297:            /**
298:             * This method calls other methods to check if all source and target accounting lines match between each set by pay fiscal year
299:             * and pay period, returning true if the totals match, false otherwise.
300:             * 
301:             * @param sourceLines
302:             * @param targetLines
303:             * @return
304:             */
305:            protected boolean isAccountingLineTotalsMatchByPayFYAndPayPeriod(
306:                    List sourceLines, List targetLines) {
307:                boolean isValid = true;
308:
309:                // sum source lines by pay fy and pay period, store in map by key PayFY+PayPeriod
310:                Map sourceLinesMap = sumAccountingLineAmountsByPayFYAndPayPeriod(sourceLines);
311:
312:                // sum source lines by pay fy and pay period, store in map by key PayFY+PayPeriod
313:                Map targetLinesMap = sumAccountingLineAmountsByPayFYAndPayPeriod(targetLines);
314:
315:                // if totals don't match by PayFY+PayPeriod categories, then add error message
316:                if (compareAccountingLineTotalsByPayFYAndPayPeriod(
317:                        sourceLinesMap, targetLinesMap) == false) {
318:                    isValid = false;
319:                    reportError(
320:                            KFSPropertyConstants.SOURCE_ACCOUNTING_LINES,
321:                            LaborKeyConstants.ACCOUNTING_LINE_TOTALS_BY_PAYFY_PAYPERIOD_MISMATCH_ERROR);
322:                }
323:
324:                return isValid;
325:            }
326:
327:            /**
328:             * @see org.kuali.kfs.rules.AccountingDocumentRuleBase#isAmountValid(org.kuali.kfs.document.AccountingDocument,
329:             *      org.kuali.kfs.bo.AccountingLine)
330:             */
331:            @Override
332:            public boolean isAmountValid(AccountingDocument document,
333:                    AccountingLine accountingLine) {
334:                LOG.debug("started isAmountValid");
335:
336:                KualiDecimal amount = accountingLine.getAmount();
337:
338:                // Check for zero amount
339:                if (amount.isZero()) {
340:                    reportError(KFSPropertyConstants.AMOUNT,
341:                            KFSKeyConstants.ERROR_ZERO_AMOUNT,
342:                            "an accounting line");
343:                    return false;
344:                }
345:                return true;
346:            }
347:
348:            /**
349:             * determine whether the given accounting line has already been in the given document
350:             * 
351:             * @param accountingDocument the given document
352:             * @param accountingLine the given accounting line
353:             * @return true if the given accounting line has already been in the given document; otherwise, false
354:             */
355:            protected boolean isDuplicateSourceAccountingLine(
356:                    AccountingDocument accountingDocument,
357:                    AccountingLine accountingLine) {
358:                // only check source accounting lines
359:                if (!(accountingLine instanceof  ExpenseTransferSourceAccountingLine)) {
360:                    return false;
361:                }
362:
363:                LaborExpenseTransferDocumentBase expenseTransferDocument = (LaborExpenseTransferDocumentBase) accountingDocument;
364:                List<ExpenseTransferSourceAccountingLine> sourceAccountingLines = expenseTransferDocument
365:                        .getSourceAccountingLines();
366:                List<String> key = defaultKeyOfExpenseTransferAccountingLine();
367:
368:                int counter = 0;
369:                for (AccountingLine sourceAccountingLine : sourceAccountingLines) {
370:                    boolean isExisting = ObjectUtil.compareObject(
371:                            accountingLine, sourceAccountingLine, key);
372:                    counter = isExisting ? counter + 1 : counter;
373:
374:                    if (counter > 1) {
375:                        return true;
376:                    }
377:                }
378:                return false;
379:            }
380:
381:            /**
382:             * determine whether the amount to be tranferred is only up to the amount in ledger balance for a given pay period
383:             * 
384:             * @param accountingDocument the given accounting document
385:             * @return true if the amount to be tranferred is only up to the amount in ledger balance for a given pay period; otherwise,
386:             *         false
387:             */
388:            protected boolean isValidTransferAmount(
389:                    Map<String, ExpenseTransferAccountingLine> accountingLineGroupMap) {
390:                Set<Entry<String, ExpenseTransferAccountingLine>> entrySet = accountingLineGroupMap
391:                        .entrySet();
392:
393:                for (Entry<String, ExpenseTransferAccountingLine> entry : entrySet) {
394:                    ExpenseTransferAccountingLine accountingLine = entry
395:                            .getValue();
396:                    Map<String, Object> fieldValues = this 
397:                            .buildFieldValueMap(accountingLine);
398:
399:                    KualiDecimal balanceAmount = getBalanceAmount(fieldValues,
400:                            accountingLine.getPayrollEndDateFiscalPeriodCode());
401:                    KualiDecimal transferAmount = accountingLine.getAmount();
402:
403:                    // the tranferred amount cannot greater than the balance amount
404:                    if (balanceAmount.abs().isLessThan(transferAmount.abs())) {
405:                        return false;
406:                    }
407:
408:                    // a positive amount cannot be transferred if the balance amount is negative
409:                    if (balanceAmount.isNegative()
410:                            && transferAmount.isPositive()) {
411:                        return false;
412:                    }
413:                }
414:                return true;
415:            }
416:
417:            /**
418:             * Determine whether target accouting lines have the same amounts as source accounting lines for each object code
419:             * 
420:             * @param accountingDocument the given accounting document
421:             * @return true if target accouting lines have the same amounts as source accounting lines for each object code; otherwise,
422:             *         false
423:             */
424:            protected boolean isValidAmountTransferredByObjectCode(
425:                    AccountingDocument accountingDocument) {
426:                LaborExpenseTransferDocumentBase expenseTransferDocument = (LaborExpenseTransferDocumentBase) accountingDocument;
427:
428:                boolean isValid = true;
429:
430:                Map<String, KualiDecimal> unbalancedObjectCodes = expenseTransferDocument
431:                        .getUnbalancedObjectCodes();
432:                if (!unbalancedObjectCodes.isEmpty()) {
433:                    reportError(
434:                            KFSPropertyConstants.TARGET_ACCOUNTING_LINES,
435:                            LaborKeyConstants.ERROR_TRANSFER_AMOUNT_NOT_BALANCED_BY_OBJECT);
436:                    isValid = false;
437:                }
438:
439:                return isValid;
440:            }
441:
442:            /**
443:             * get the amount for a given period from a ledger balance that has the given values for specified fileds
444:             * 
445:             * @param fieldValues the given fields and their values
446:             * @param periodCode the given period
447:             * @return the amount for a given period from the qualified ledger balance
448:             */
449:            protected KualiDecimal getBalanceAmount(
450:                    Map<String, Object> fieldValues, String periodCode) {
451:                if (periodCode == null) {
452:                    return KualiDecimal.ZERO;
453:                }
454:
455:                fieldValues.put(
456:                        KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE,
457:                        KFSConstants.BALANCE_TYPE_ACTUAL);
458:                KualiDecimal actualBalanceAmount = this 
459:                        .getBalanceAmountOfGivenPeriod(fieldValues, periodCode);
460:
461:                fieldValues.put(
462:                        KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE,
463:                        KFSConstants.BALANCE_TYPE_A21);
464:                KualiDecimal effortBalanceAmount = this 
465:                        .getBalanceAmountOfGivenPeriod(fieldValues, periodCode);
466:
467:                return actualBalanceAmount.add(effortBalanceAmount);
468:            }
469:
470:            /**
471:             * Gets the balance amount of a given period
472:             * 
473:             * @param fieldValues
474:             * @param periodCode
475:             * @return
476:             */
477:            private KualiDecimal getBalanceAmountOfGivenPeriod(
478:                    Map<String, Object> fieldValues, String periodCode) {
479:                KualiDecimal balanceAmount = KualiDecimal.ZERO;
480:                List<LedgerBalance> ledgerBalances = (List<LedgerBalance>) SpringContext
481:                        .getBean(BusinessObjectService.class).findMatching(
482:                                LedgerBalance.class, fieldValues);
483:                if (!ledgerBalances.isEmpty()) {
484:                    balanceAmount = ledgerBalances.get(0).getAmount(periodCode);
485:                }
486:                return balanceAmount;
487:            }
488:
489:            /**
490:             * Determines whether a negtive amount can be transferred from one account to another
491:             * 
492:             * @param accountingDocument the given accounting document
493:             * @return true if a negtive amount can be transferred from one account to another; otherwise, false
494:             */
495:            protected boolean canNegtiveAmountBeTransferred(
496:                    Map<String, ExpenseTransferAccountingLine> accountingLineGroupMap) {
497:                for (String key : accountingLineGroupMap.keySet()) {
498:                    ExpenseTransferAccountingLine accountingLine = accountingLineGroupMap
499:                            .get(key);
500:                    Map<String, Object> fieldValues = this 
501:                            .buildFieldValueMap(accountingLine);
502:
503:                    KualiDecimal balanceAmount = getBalanceAmount(fieldValues,
504:                            accountingLine.getPayrollEndDateFiscalPeriodCode());
505:                    KualiDecimal transferAmount = accountingLine.getAmount();
506:
507:                    // a negtive amount cannot be transferred if the balance amount is positive
508:                    if (transferAmount.isNegative()
509:                            && balanceAmount.isPositive()) {
510:                        return false;
511:                    }
512:                }
513:                return true;
514:            }
515:
516:            /**
517:             * Groups the accounting lines by the specified key fields
518:             * 
519:             * @param accountingLines the given accounting lines that are stored in a list
520:             * @param clazz the class type of given accounting lines
521:             * @return the accounting line groups
522:             */
523:            protected Map<String, ExpenseTransferAccountingLine> getAccountingLineGroupMap(
524:                    List<ExpenseTransferAccountingLine> accountingLines,
525:                    Class clazz) {
526:                Map<String, ExpenseTransferAccountingLine> accountingLineGroupMap = new HashMap<String, ExpenseTransferAccountingLine>();
527:
528:                for (ExpenseTransferAccountingLine accountingLine : accountingLines) {
529:                    String stringKey = ObjectUtil.buildPropertyMap(
530:                            accountingLine,
531:                            defaultKeyOfExpenseTransferAccountingLine())
532:                            .toString();
533:                    ExpenseTransferAccountingLine line = null;
534:
535:                    if (accountingLineGroupMap.containsKey(stringKey)) {
536:                        line = accountingLineGroupMap.get(stringKey);
537:                        KualiDecimal amount = line.getAmount();
538:                        line.setAmount(amount.add(accountingLine.getAmount()));
539:                    } else {
540:                        try {
541:                            line = (ExpenseTransferAccountingLine) clazz
542:                                    .newInstance();
543:                            ObjectUtil.buildObject(line, accountingLine);
544:                            accountingLineGroupMap.put(stringKey, line);
545:                        } catch (Exception e) {
546:                            LOG
547:                                    .error("Cannot create a new instance of ExpenseTransferAccountingLine"
548:                                            + e);
549:                        }
550:                    }
551:                }
552:                return accountingLineGroupMap;
553:            }
554:
555:            /**
556:             * Determines whether the account in the target line accepts fringe benefits.
557:             * 
558:             * @param accountingLine the line to check
559:             * @return true if the accounts in the target accounting lines accept fringe benefits; otherwise, false
560:             */
561:            protected boolean isAccountAcceptFringeBenefit(
562:                    AccountingLine accountingLine) {
563:                boolean acceptsFringeBenefits = true;
564:
565:                Account account = accountingLine.getAccount();
566:                if (account != null
567:                        && !account.isAccountsFringesBnftIndicator()) {
568:                    String overrideCode = accountingLine.getOverrideCode();
569:                    boolean canNonFringeAccountUsed = NON_FRINGE_ACCOUNT_USED
570:                            .equals(overrideCode);
571:                    canNonFringeAccountUsed = canNonFringeAccountUsed
572:                            || EXPIRED_ACCOUNT_AND_NON_FRINGE_ACCOUNT_USED
573:                                    .equals(overrideCode);
574:
575:                    if (!canNonFringeAccountUsed) {
576:                        acceptsFringeBenefits = false;
577:                    }
578:                }
579:
580:                return acceptsFringeBenefits;
581:            }
582:
583:            /**
584:             * Gets the default key of ExpenseTransferAccountingLine
585:             * 
586:             * @return the default key of ExpenseTransferAccountingLine
587:             */
588:            protected List<String> defaultKeyOfExpenseTransferAccountingLine() {
589:                List<String> defaultKey = new ArrayList<String>();
590:
591:                defaultKey.add(KFSPropertyConstants.POSTING_YEAR);
592:                defaultKey.add(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE);
593:                defaultKey.add(KFSPropertyConstants.ACCOUNT_NUMBER);
594:                defaultKey.add(KFSPropertyConstants.SUB_ACCOUNT_NUMBER);
595:
596:                defaultKey.add(KFSPropertyConstants.BALANCE_TYPE_CODE);
597:                defaultKey.add(KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
598:                defaultKey.add(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE);
599:
600:                defaultKey.add(KFSPropertyConstants.EMPLID);
601:                defaultKey.add(KFSPropertyConstants.POSITION_NUMBER);
602:
603:                defaultKey
604:                        .add(LaborPropertyConstants.PAYROLL_END_DATE_FISCAL_YEAR);
605:                defaultKey
606:                        .add(LaborPropertyConstants.PAYROLL_END_DATE_FISCAL_PERIOD_CODE);
607:
608:                return defaultKey;
609:            }
610:
611:            /**
612:             * This method returns a String that is a concatenation of pay fiscal year and pay period code.
613:             * 
614:             * @param payFiscalYear
615:             * @param payPeriodCode
616:             * @return
617:             */
618:            private String createPayFYPeriodKey(Integer payFiscalYear,
619:                    String payPeriodCode) {
620:
621:                StringBuffer payFYPeriodKey = new StringBuffer();
622:
623:                payFYPeriodKey.append(payFiscalYear);
624:                payFYPeriodKey.append(payPeriodCode);
625:
626:                return payFYPeriodKey.toString();
627:            }
628:
629:            /**
630:             * This method sums the totals of each accounting line, making an entry in a map for each unique pay fiscal year and pay period.
631:             * 
632:             * @param accountingLines
633:             * @return
634:             */
635:            private Map sumAccountingLineAmountsByPayFYAndPayPeriod(
636:                    List accountingLines) {
637:
638:                ExpenseTransferAccountingLine line = null;
639:                KualiDecimal linesAmount = new KualiDecimal(0);
640:                Map linesMap = new HashMap();
641:                String payFYPeriodKey = null;
642:
643:                // go through source lines adding amounts to appropriate place in map
644:                for (Iterator i = accountingLines.iterator(); i.hasNext();) {
645:                    // initialize
646:                    line = (ExpenseTransferAccountingLine) i.next();
647:                    linesAmount = new KualiDecimal(0);
648:
649:                    // create hash key
650:                    payFYPeriodKey = createPayFYPeriodKey(line
651:                            .getPayrollEndDateFiscalYear(), line
652:                            .getPayrollEndDateFiscalPeriodCode());
653:
654:                    // if entry exists, pull from hash
655:                    if (linesMap.containsKey(payFYPeriodKey)) {
656:                        linesAmount = (KualiDecimal) linesMap
657:                                .get(payFYPeriodKey);
658:                    }
659:
660:                    // update and store
661:                    linesAmount = linesAmount.add(line.getAmount());
662:                    linesMap.put(payFYPeriodKey, linesAmount);
663:                }
664:
665:                return linesMap;
666:            }
667:
668:            /**
669:             * This method checks that the total amount of labor ledger accounting lines in the document's FROM section is equal to the
670:             * total amount on the labor ledger accounting lines TO section for each unique combination of pay fiscal year and pay period. A
671:             * value of true is returned if all amounts for each unique combination between source and target accounting lines match, false
672:             * otherwise.
673:             * 
674:             * @param sourceLinesMap
675:             * @param targetLinesMap
676:             * @return
677:             */
678:            private boolean compareAccountingLineTotalsByPayFYAndPayPeriod(
679:                    Map sourceLinesMap, Map targetLinesMap) {
680:
681:                boolean isValid = true;
682:                Map.Entry entry = null;
683:                String currentKey = null;
684:                KualiDecimal sourceLinesAmount = new KualiDecimal(0);
685:                KualiDecimal targetLinesAmount = new KualiDecimal(0);
686:
687:                // Loop through source lines comparing against target lines
688:                for (Iterator i = sourceLinesMap.entrySet().iterator(); i
689:                        .hasNext()
690:                        && isValid;) {
691:                    // initialize
692:                    entry = (Map.Entry) i.next();
693:                    currentKey = (String) entry.getKey();
694:                    sourceLinesAmount = (KualiDecimal) entry.getValue();
695:
696:                    if (targetLinesMap.containsKey(currentKey)) {
697:                        targetLinesAmount = (KualiDecimal) targetLinesMap
698:                                .get(currentKey);
699:
700:                        // return false if the matching key values do not total each other
701:                        if (sourceLinesAmount.compareTo(targetLinesAmount) != 0) {
702:                            isValid = false;
703:                        }
704:
705:                    } else {
706:                        isValid = false;
707:                    }
708:                }
709:
710:                /*
711:                 * Now loop through target lines comparing against source lines. This finds missing entries from either direction (source or
712:                 * target)
713:                 */
714:                for (Iterator i = targetLinesMap.entrySet().iterator(); i
715:                        .hasNext()
716:                        && isValid;) {
717:                    // initialize
718:                    entry = (Map.Entry) i.next();
719:                    currentKey = (String) entry.getKey();
720:                    targetLinesAmount = (KualiDecimal) entry.getValue();
721:
722:                    if (sourceLinesMap.containsKey(currentKey)) {
723:                        sourceLinesAmount = (KualiDecimal) sourceLinesMap
724:                                .get(currentKey);
725:
726:                        // return false if the matching key values do not total each other
727:                        if (targetLinesAmount.compareTo(sourceLinesAmount) != 0) {
728:                            isValid = false;
729:                        }
730:
731:                    } else {
732:                        isValid = false;
733:                    }
734:                }
735:                return isValid;
736:            }
737:
738:            /**
739:             * Overriding hook into generate general ledger pending entries, so no GL pending entries are created.
740:             * 
741:             * @see org.kuali.core.rule.GenerateGeneralLedgerPendingEntriesRule#processGenerateGeneralLedgerPendingEntries(org.kuali.core.document.AccountingDocument,
742:             *      org.kuali.core.bo.AccountingLine, org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper)
743:             */
744:            @Override
745:            public boolean processGenerateGeneralLedgerPendingEntries(
746:                    AccountingDocument accountingDocument,
747:                    AccountingLine accountingLine,
748:                    GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
749:                return true;
750:            }
751:
752:            /**
753:             * This method is the starting point for creating labor ledger pending entries. The logic used to create the LLPEs resides in
754:             * this method.
755:             * 
756:             * @param accountingDocument is an instance of <code>{@link LaborLedgerPostingDocument}</code>
757:             * @param accountingLine
758:             * @param sequenceHelper
759:             * @return
760:             */
761:            public boolean processGenerateLaborLedgerPendingEntries(
762:                    LaborLedgerPostingDocument accountingDocument,
763:                    AccountingLine accountingLine,
764:                    GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
765:                return true;
766:            }
767:
768:            /**
769:             * @see org.kuali.kfs.rule.AccountingLineRule#isDebit(org.kuali.kfs.document.AccountingDocument,
770:             *      org.kuali.kfs.bo.AccountingLine)
771:             */
772:            public boolean isDebit(AccountingDocument financialDocument,
773:                    AccountingLine accountingLine) {
774:                return false;
775:            }
776:
777:            /**
778:             * determine whether the expired account in the target accounting line can be used.
779:             * 
780:             * @param accountingDocument the given accounting line
781:             * @return true if the expired account in the target accounting line can be used; otherwise, false
782:             */
783:            protected boolean canExpiredAccountBeUsed(
784:                    AccountingLine accountingLine) {
785:                LOG.debug("started canExpiredAccountBeUsed(accountingLine)");
786:
787:                Account account = accountingLine.getAccount();
788:                if (account != null && account.isExpired()) {
789:                    String overrideCode = accountingLine.getOverrideCode();
790:                    boolean canExpiredAccountUsed = EXPIRED_ACCOUNT
791:                            .equals(overrideCode);
792:                    canExpiredAccountUsed = canExpiredAccountUsed
793:                            || EXPIRED_ACCOUNT_AND_NON_FRINGE_ACCOUNT_USED
794:                                    .equals(overrideCode);
795:
796:                    if (!canExpiredAccountUsed) {
797:                        return false;
798:                    }
799:                }
800:                return true;
801:            }
802:
803:            /**
804:             * build the field-value maps throught the given accouting line
805:             * 
806:             * @param accountingLine the given accounting line
807:             * @return the field-value maps built from the given accouting line
808:             */
809:            protected Map<String, Object> buildFieldValueMap(
810:                    ExpenseTransferAccountingLine accountingLine) {
811:                Map<String, Object> fieldValues = new HashMap<String, Object>();
812:
813:                fieldValues.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR,
814:                        accountingLine.getPostingYear());
815:                fieldValues.put(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE,
816:                        accountingLine.getChartOfAccountsCode());
817:                fieldValues.put(KFSPropertyConstants.ACCOUNT_NUMBER,
818:                        accountingLine.getAccountNumber());
819:
820:                String subAccountNumber = accountingLine.getSubAccountNumber();
821:                subAccountNumber = StringUtils.isBlank(subAccountNumber) ? KFSConstants
822:                        .getDashSubAccountNumber()
823:                        : subAccountNumber;
824:                fieldValues.put(KFSPropertyConstants.SUB_ACCOUNT_NUMBER,
825:                        subAccountNumber);
826:
827:                fieldValues.put(
828:                        KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE,
829:                        accountingLine.getBalanceTypeCode());
830:                fieldValues.put(KFSPropertyConstants.FINANCIAL_OBJECT_CODE,
831:                        accountingLine.getFinancialObjectCode());
832:
833:                Options options = SpringContext.getBean(OptionsService.class)
834:                        .getOptions(accountingLine.getPostingYear());
835:                fieldValues.put(
836:                        KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE,
837:                        options.getFinObjTypeExpenditureexpCd());
838:
839:                String subObjectCode = accountingLine
840:                        .getFinancialSubObjectCode();
841:                subObjectCode = StringUtils.isBlank(subObjectCode) ? KFSConstants
842:                        .getDashFinancialSubObjectCode()
843:                        : subObjectCode;
844:                fieldValues.put(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE,
845:                        subObjectCode);
846:
847:                fieldValues.put(KFSPropertyConstants.EMPLID, accountingLine
848:                        .getEmplid());
849:                fieldValues.put(KFSPropertyConstants.POSITION_NUMBER,
850:                        accountingLine.getPositionNumber());
851:
852:                return fieldValues;
853:            }
854:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.