1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.fp.document;
17
18 import static org.kuali.ole.fp.document.validation.impl.AuxiliaryVoucherDocumentRuleConstants.AUXILIARY_VOUCHER_ACCOUNTING_PERIOD_GRACE_PERIOD;
19 import static org.kuali.ole.fp.document.validation.impl.AuxiliaryVoucherDocumentRuleConstants.GENERAL_LEDGER_PENDING_ENTRY_OFFSET_CODE;
20 import static org.kuali.ole.sys.OLEConstants.GL_CREDIT_CODE;
21 import static org.kuali.ole.sys.OLEConstants.GL_DEBIT_CODE;
22 import static org.kuali.ole.sys.OLEConstants.AuxiliaryVoucher.ACCRUAL_DOC_TYPE;
23 import static org.kuali.ole.sys.OLEConstants.AuxiliaryVoucher.ADJUSTMENT_DOC_TYPE;
24 import static org.kuali.ole.sys.OLEConstants.AuxiliaryVoucher.RECODE_DOC_TYPE;
25
26 import java.sql.Date;
27 import java.util.Iterator;
28 import java.util.List;
29
30 import org.apache.commons.lang.StringUtils;
31 import org.kuali.ole.coa.businessobject.AccountingPeriod;
32 import org.kuali.ole.coa.service.AccountingPeriodService;
33 import org.kuali.ole.gl.service.SufficientFundsService;
34 import org.kuali.ole.sys.OLEConstants;
35 import org.kuali.ole.sys.businessobject.AccountingLine;
36 import org.kuali.ole.sys.businessobject.AccountingLineBase;
37 import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntry;
38 import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
39 import org.kuali.ole.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
40 import org.kuali.ole.sys.businessobject.SourceAccountingLine;
41 import org.kuali.ole.sys.businessobject.SystemOptions;
42 import org.kuali.ole.sys.context.SpringContext;
43 import org.kuali.ole.sys.document.AccountingDocumentBase;
44 import org.kuali.ole.sys.document.AmountTotaling;
45 import org.kuali.ole.sys.document.Correctable;
46 import org.kuali.ole.sys.document.service.DebitDeterminerService;
47 import org.kuali.ole.sys.service.OptionsService;
48 import org.kuali.ole.sys.service.UniversityDateService;
49 import org.kuali.rice.core.api.datetime.DateTimeService;
50 import org.kuali.rice.core.api.util.type.KualiDecimal;
51 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
52 import org.kuali.rice.kew.api.exception.WorkflowException;
53 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
54 import org.kuali.rice.krad.document.Copyable;
55
56
57
58
59
60
61 public class AuxiliaryVoucherDocument extends AccountingDocumentBase implements VoucherDocument, Copyable, Correctable, AmountTotaling {
62 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AuxiliaryVoucherDocument.class);
63
64 protected String typeCode = ADJUSTMENT_DOC_TYPE;
65 protected java.sql.Date reversalDate;
66
67
68
69
70 @Override
71 public boolean documentPerformsSufficientFundsCheck() {
72 if (isRecodeType()) {
73 return super.documentPerformsSufficientFundsCheck();
74 }
75 else {
76 return false;
77 }
78 }
79
80
81
82
83 public AuxiliaryVoucherDocument() {
84 super();
85 }
86
87
88
89
90
91
92 public java.sql.Date getReversalDate() {
93 return reversalDate;
94 }
95
96
97
98
99
100
101 public void setReversalDate(java.sql.Date reversalDate) {
102 this.reversalDate = reversalDate;
103 }
104
105
106
107
108
109
110 public String getTypeCode() {
111 return typeCode;
112 }
113
114
115
116
117
118
119 public void setTypeCode(String typeCode) {
120 this.typeCode = typeCode;
121 }
122
123
124
125
126
127
128 public boolean isAdjustmentType() {
129 return ADJUSTMENT_DOC_TYPE.equals(typeCode);
130 }
131
132
133
134
135
136
137 public boolean isRecodeType() {
138 return RECODE_DOC_TYPE.equals(typeCode);
139 }
140
141
142
143
144
145
146 public boolean isAccrualType() {
147 return ACCRUAL_DOC_TYPE.equals(typeCode);
148 }
149
150
151
152
153
154
155
156 public KualiDecimal getDebitTotal() {
157 KualiDecimal debitTotal = KualiDecimal.ZERO;
158 AccountingLineBase al = null;
159 Iterator<?> iter = sourceAccountingLines.iterator();
160 while (iter.hasNext()) {
161 al = (AccountingLineBase) iter.next();
162 if (StringUtils.isNotBlank(al.getDebitCreditCode()) && al.getDebitCreditCode().equals(OLEConstants.GL_DEBIT_CODE)) {
163 debitTotal = debitTotal.add(al.getAmount());
164 }
165 }
166 return debitTotal;
167 }
168
169
170
171
172
173
174
175 public KualiDecimal getCreditTotal() {
176 KualiDecimal creditTotal = KualiDecimal.ZERO;
177 AccountingLineBase al = null;
178 Iterator<?> iter = sourceAccountingLines.iterator();
179 while (iter.hasNext()) {
180 al = (AccountingLineBase) iter.next();
181 if (StringUtils.isNotBlank(al.getDebitCreditCode()) && al.getDebitCreditCode().equals(OLEConstants.GL_CREDIT_CODE)) {
182 creditTotal = creditTotal.add(al.getAmount());
183 }
184 }
185 return creditTotal;
186 }
187
188
189
190
191
192
193
194 @Override
195 public KualiDecimal getTotalDollarAmount() {
196 return getCreditTotal().equals(KualiDecimal.ZERO) ? getDebitTotal() : getCreditTotal();
197 }
198
199
200
201
202 @Override
203 public void toCopy() throws WorkflowException {
204 super.toCopy();
205 refreshReversalDate();
206 }
207
208
209
210
211
212 @Override
213 public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
214 LOG.debug("In doRouteStatusChange() for AV documents");
215 super.doRouteStatusChange(statusChangeEvent);
216
217 if (this.getDocumentHeader().getWorkflowDocument().isProcessed()) {
218
219
220 updateReversalDate();
221 }
222 }
223
224
225
226
227
228 protected void updateReversalDate() {
229 if (refreshReversalDate()) {
230
231 List<GeneralLedgerPendingEntry> glpes = getGeneralLedgerPendingEntries();
232 for (GeneralLedgerPendingEntry entry : glpes) {
233 entry.setFinancialDocumentReversalDate(getReversalDate());
234 }
235 }
236 }
237
238
239
240
241
242 protected boolean refreshReversalDate() {
243 boolean refreshed = false;
244 if ((isAccrualType() || isRecodeType()) && getReversalDate() != null) {
245 java.sql.Date today = SpringContext.getBean(DateTimeService.class).getCurrentSqlDateMidnight();
246 if (getReversalDate().before(today)) {
247
248 setReversalDate(today);
249 refreshed = true;
250 }
251 }
252 return refreshed;
253 }
254
255
256
257
258 @Override
259 public void toErrorCorrection() throws WorkflowException {
260 super.toErrorCorrection();
261 processAuxiliaryVoucherErrorCorrections();
262 }
263
264
265
266
267
268 protected void processAuxiliaryVoucherErrorCorrections() {
269 Iterator<?> i = getSourceAccountingLines().iterator();
270
271 int index = 0;
272 while (i.hasNext()) {
273 SourceAccountingLine sLine = (SourceAccountingLine) i.next();
274
275 String debitCreditCode = sLine.getDebitCreditCode();
276
277 if (StringUtils.isNotBlank(debitCreditCode)) {
278
279 sLine.setAmount(sLine.getAmount().negated());
280
281
282 if (GL_DEBIT_CODE.equals(debitCreditCode)) {
283 sLine.setDebitCreditCode(GL_CREDIT_CODE);
284 }
285 else if (GL_CREDIT_CODE.equals(debitCreditCode)) {
286 sLine.setDebitCreditCode(GL_DEBIT_CODE);
287 }
288 else {
289 throw new IllegalStateException("SourceAccountingLine at index " + index + " does not have a debit/credit " + "code associated with it. This should never have occured. Please contact your system administrator.");
290
291 }
292 index++;
293 }
294 }
295 }
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316 public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) throws IllegalStateException {
317 String debitCreditCode = ((AccountingLine)postable).getDebitCreditCode();
318 DebitDeterminerService isDebitUtils = SpringContext.getBean(DebitDeterminerService.class);
319 if (StringUtils.isBlank(debitCreditCode)) {
320 throw new IllegalStateException(isDebitUtils.getDebitCalculationIllegalStateExceptionMessage());
321 }
322 return isDebitUtils.isDebitCode(debitCreditCode);
323 }
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338 @Override
339 public void customizeExplicitGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySourceDetail postable, GeneralLedgerPendingEntry explicitEntry) {
340
341 java.sql.Date reversalDate = getReversalDate();
342 if (reversalDate != null) {
343 explicitEntry.setFinancialDocumentReversalDate(reversalDate);
344 }
345 else {
346 explicitEntry.setFinancialDocumentReversalDate(null);
347 }
348 explicitEntry.setFinancialDocumentTypeCode(getTypeCode());
349
350 explicitEntry.setFinancialObjectTypeCode(getObjectTypeCode(postable));
351 explicitEntry.setUniversityFiscalPeriodCode(getPostingPeriodCode());
352 explicitEntry.setUniversityFiscalYear(getPostingYear());
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368 @Override
369 public boolean customizeOffsetGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySourceDetail postable, GeneralLedgerPendingEntry explicitEntry, GeneralLedgerPendingEntry offsetEntry) {
370
371 if (isRecodeType()) {
372 offsetEntry.setFinancialDocumentTypeCode(OLEConstants.FinancialDocumentTypeCodes.DISTRIBUTION_OF_INCOME_AND_EXPENSE);
373
374
375 java.sql.Date today = SpringContext.getBean(DateTimeService.class).getCurrentSqlDateMidnight();
376 offsetEntry.setUniversityFiscalPeriodCode(SpringContext.getBean(AccountingPeriodService.class).getByDate(today).getUniversityFiscalPeriodCode());
377 }
378
379
380
381 if (isAccrualType() || isAdjustmentType()) {
382 String glpeOffsetObjectCode = SpringContext.getBean(ParameterService.class).getParameterValueAsString(this.getClass(), getGeneralLedgerPendingEntryOffsetObjectCode());
383 offsetEntry.setFinancialObjectCode(glpeOffsetObjectCode);
384
385
386 offsetEntry.setUniversityFiscalPeriodCode(getPostingPeriodCode());
387 }
388
389
390 offsetEntry.setFinancialDocumentReversalDate(null);
391
392
393 offsetEntry.setUniversityFiscalYear(getPostingYear());
394
395
396 offsetEntry.setTransactionEntryOffsetIndicator(false);
397
398
399
400 offsetEntry.refreshNonUpdateableReferences();
401 offsetEntry.setAcctSufficientFundsFinObjCd(SpringContext.getBean(SufficientFundsService.class).getSufficientFundsObjectCode(offsetEntry.getFinancialObject(), offsetEntry.getAccount().getAccountSufficientFundsCode()));
402
403 return true;
404 }
405
406
407
408
409
410
411
412
413
414 protected String getObjectTypeCode(GeneralLedgerPendingEntrySourceDetail line) {
415 SystemOptions options = SpringContext.getBean(OptionsService.class).getCurrentYearOptions();
416 String objectTypeCode = line.getObjectCode().getFinancialObjectTypeCode();
417
418 if (options.getFinObjTypeExpenditureexpCd().equals(objectTypeCode) || options.getFinObjTypeExpendNotExpCode().equals(objectTypeCode)) {
419 objectTypeCode = options.getFinObjTypeExpNotExpendCode();
420 }
421 else if (options.getFinObjectTypeIncomecashCode().equals(objectTypeCode) || options.getFinObjTypeExpendNotExpCode().equals(objectTypeCode)) {
422 objectTypeCode = options.getFinObjTypeIncomeNotCashCd();
423 }
424
425 return objectTypeCode;
426 }
427
428
429
430
431
432
433 protected String getGeneralLedgerPendingEntryOffsetObjectCode() {
434 return GENERAL_LEDGER_PENDING_ENTRY_OFFSET_CODE;
435 }
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451 @Override
452 public boolean processOffsetGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntry explicitEntry, GeneralLedgerPendingEntry offsetEntry) {
453 AccountingLine accountingLineCopy = (AccountingLine)glpeSourceDetail;
454 boolean success = true;
455
456
457 if (isAccrualType() || isAdjustmentType()) {
458 success &= processOffsetGeneralLedgerPendingEntryForAccrualsAndAdjustments(sequenceHelper, accountingLineCopy, explicitEntry, offsetEntry);
459 }
460 else if (isRecodeType()) {
461 success &= processOffsetGeneralLedgerPendingEntryForRecodes(sequenceHelper, accountingLineCopy, explicitEntry, offsetEntry);
462 }
463 else {
464 throw new IllegalStateException("Illegal auxiliary voucher type: " + getTypeCode());
465 }
466 return success;
467 }
468
469
470
471
472
473
474
475
476
477
478
479 protected boolean processOffsetGeneralLedgerPendingEntryForRecodes(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, AccountingLine accountingLineCopy, GeneralLedgerPendingEntry explicitEntry, GeneralLedgerPendingEntry offsetEntry) {
480
481
482
483
484
485 GeneralLedgerPendingEntry explicitEntryDeepCopy = new GeneralLedgerPendingEntry(explicitEntry);
486 explicitEntryDeepCopy.setFinancialDocumentTypeCode(OLEConstants.FinancialDocumentTypeCodes.DISTRIBUTION_OF_INCOME_AND_EXPENSE);
487
488
489 java.sql.Date today = SpringContext.getBean(DateTimeService.class).getCurrentSqlDateMidnight();
490 explicitEntryDeepCopy.setUniversityFiscalPeriodCode(SpringContext.getBean(AccountingPeriodService.class).getByDate(today).getUniversityFiscalPeriodCode());
491
492
493
494 boolean success = super.processOffsetGeneralLedgerPendingEntry(sequenceHelper, accountingLineCopy, explicitEntryDeepCopy, offsetEntry);
495
496
497 sequenceHelper.increment();
498
499
500
501 processAuxiliaryVoucherRecodeDistributionOfIncomeAndExpenseGeneralLedgerPendingEntry( sequenceHelper, explicitEntryDeepCopy);
502 return success;
503 }
504
505
506
507
508
509
510
511
512
513
514
515 protected boolean processOffsetGeneralLedgerPendingEntryForAccrualsAndAdjustments(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, AccountingLine accountingLineCopy, GeneralLedgerPendingEntry explicitEntry, GeneralLedgerPendingEntry offsetEntry) {
516 boolean success = true;
517 if (this.isDocumentForMultipleAccounts()) {
518 success = super.processOffsetGeneralLedgerPendingEntry(sequenceHelper, accountingLineCopy, explicitEntry, offsetEntry);
519 }
520 else {
521 sequenceHelper.decrement();
522
523 }
524 return success;
525 }
526
527
528
529
530
531
532
533
534
535 protected boolean isDocumentForMultipleAccounts() {
536 String baseAccountNumber = "";
537
538 int index = 0;
539 List<AccountingLine> lines = this.getSourceAccountingLines();
540 for (AccountingLine line : lines) {
541 if (index == 0) {
542 baseAccountNumber = line.getAccountNumber();
543 }
544 else if (!baseAccountNumber.equals(line.getAccountNumber())) {
545 return true;
546 }
547 index++;
548 }
549
550 return false;
551 }
552
553
554
555
556
557
558
559
560
561
562 protected void processAuxiliaryVoucherRecodeDistributionOfIncomeAndExpenseGeneralLedgerPendingEntry(GeneralLedgerPendingEntrySequenceHelper sequenceHelper, GeneralLedgerPendingEntry explicitEntry) {
563
564 GeneralLedgerPendingEntry recodeGlpe = new GeneralLedgerPendingEntry(explicitEntry);
565
566
567 recodeGlpe.setTransactionLedgerEntrySequenceNumber(new Integer(sequenceHelper.getSequenceCounter()));
568
569
570 recodeGlpe.setFinancialDocumentTypeCode(OLEConstants.FinancialDocumentTypeCodes.DISTRIBUTION_OF_INCOME_AND_EXPENSE);
571
572
573 recodeGlpe.setFinancialObjectTypeCode(getObjectTypeCodeForRecodeDistributionOfIncomeAndExpenseEntry(explicitEntry));
574
575
576 recodeGlpe.setFinancialDocumentReversalDate(null);
577
578
579 recodeGlpe.setTransactionEntryOffsetIndicator(false);
580
581
582 addPendingEntry(recodeGlpe);
583 }
584
585
586
587
588
589
590
591
592
593 protected String getObjectTypeCodeForRecodeDistributionOfIncomeAndExpenseEntry(GeneralLedgerPendingEntry explicitEntry) {
594 SystemOptions options = SpringContext.getBean(OptionsService.class).getCurrentYearOptions();
595 String objectTypeCode = explicitEntry.getFinancialObjectTypeCode();
596
597 if (options.getFinObjTypeExpNotExpendCode().equals(objectTypeCode)) {
598 objectTypeCode = options.getFinObjTypeExpenditureexpCd();
599 }
600 else if (options.getFinObjTypeIncomeNotCashCd().equals(objectTypeCode)) {
601 objectTypeCode = options.getFinObjectTypeIncomecashCode();
602 }
603
604 return objectTypeCode;
605 }
606
607
608
609
610
611
612
613
614 public boolean calculateIfWithinGracePeriod(Date today, AccountingPeriod periodToCheck) {
615 boolean result = false;
616 final int todayAsComparableDate = comparableDateForm(today);
617 final int periodClose = new Integer(comparableDateForm(periodToCheck.getUniversityFiscalPeriodEndDate()));
618 final int periodBegin = comparableDateForm(calculateFirstDayOfMonth(periodToCheck.getUniversityFiscalPeriodEndDate()));
619 final int gracePeriodClose = periodClose + new Integer(SpringContext.getBean(ParameterService.class).getParameterValueAsString(getClass(), AUXILIARY_VOUCHER_ACCOUNTING_PERIOD_GRACE_PERIOD)).intValue();
620 return (todayAsComparableDate >= periodBegin && todayAsComparableDate <= gracePeriodClose);
621 }
622
623
624
625
626
627
628
629 public int comparableDateForm(Date d) {
630 java.util.Calendar cal = new java.util.GregorianCalendar();
631 cal.setTime(d);
632 return cal.get(java.util.Calendar.YEAR) * 365 + cal.get(java.util.Calendar.DAY_OF_YEAR);
633 }
634
635
636
637
638
639
640
641 public Date calculateFirstDayOfMonth(Date d) {
642 java.util.Calendar cal = new java.util.GregorianCalendar();
643 cal.setTime(d);
644 int dayOfMonth = cal.get(java.util.Calendar.DAY_OF_MONTH) - 1;
645 cal.add(java.util.Calendar.DAY_OF_YEAR, -1 * dayOfMonth);
646 return new Date(cal.getTimeInMillis());
647 }
648
649
650
651
652
653
654
655 public boolean isEndOfPreviousFiscalYear(AccountingPeriod acctPeriod) {
656 final UniversityDateService universityDateService = SpringContext.getBean(UniversityDateService.class);
657 final Date firstDayOfCurrFiscalYear = new Date(universityDateService.getFirstDateOfFiscalYear(universityDateService.getCurrentFiscalYear()).getTime());
658 final Date periodClose = acctPeriod.getUniversityFiscalPeriodEndDate();
659 java.util.Calendar cal = new java.util.GregorianCalendar();
660 cal.setTime(periodClose);
661 cal.add(java.util.Calendar.DATE, 1);
662 return (firstDayOfCurrFiscalYear.equals(new Date(cal.getTimeInMillis())));
663 }
664
665 }