001 /*
002 * Copyright 2011 The Kuali Foundation.
003 *
004 * Licensed under the Educational Community License, Version 2.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/ecl2.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.kfs.module.endow.batch.service.impl;
017
018 import java.text.MessageFormat;
019 import java.util.ArrayList;
020 import java.util.Collection;
021 import java.util.Date;
022 import java.util.HashMap;
023 import java.util.List;
024 import java.util.Map;
025 import java.util.Set;
026
027 import org.apache.commons.lang.StringUtils;
028 import org.kuali.kfs.module.endow.EndowConstants;
029 import org.kuali.kfs.module.endow.EndowParameterKeyConstants;
030 import org.kuali.kfs.module.endow.EndowPropertyConstants;
031 import org.kuali.kfs.module.endow.batch.CreateRecurringCashTransferTransactionsStep;
032 import org.kuali.kfs.module.endow.batch.reporter.ReportDocumentStatistics;
033 import org.kuali.kfs.module.endow.batch.service.CreateRecurringCashTransferTransactionsService;
034 import org.kuali.kfs.module.endow.businessobject.EndowmentRecurringCashTransfer;
035 import org.kuali.kfs.module.endow.businessobject.EndowmentRecurringCashTransferGLTarget;
036 import org.kuali.kfs.module.endow.businessobject.EndowmentRecurringCashTransferKEMIDTarget;
037 import org.kuali.kfs.module.endow.businessobject.EndowmentSourceTransactionLine;
038 import org.kuali.kfs.module.endow.businessobject.EndowmentTargetTransactionLine;
039 import org.kuali.kfs.module.endow.businessobject.KemidCurrentCash;
040 import org.kuali.kfs.module.endow.businessobject.RecurringCashTransferTransactionDocumentExceptionReportLine;
041 import org.kuali.kfs.module.endow.businessobject.RecurringCashTransferTransactionDocumentTotalReportLine;
042 import org.kuali.kfs.module.endow.businessobject.TargetEndowmentAccountingLine;
043 import org.kuali.kfs.module.endow.businessobject.TransactionArchive;
044 import org.kuali.kfs.module.endow.document.CashTransferDocument;
045 import org.kuali.kfs.module.endow.document.EndowmentToGLTransferOfFundsDocument;
046 import org.kuali.kfs.module.endow.document.service.HoldingTaxLotService;
047 import org.kuali.kfs.module.endow.document.service.KEMService;
048 import org.kuali.kfs.module.endow.document.service.KemidCurrentCashService;
049 import org.kuali.kfs.module.endow.document.validation.event.AddEndowmentAccountingLineEvent;
050 import org.kuali.kfs.module.endow.document.validation.event.AddTransactionLineEvent;
051 import org.kuali.kfs.sys.service.ReportWriterService;
052 import org.kuali.rice.kew.exception.WorkflowException;
053 import org.kuali.rice.kns.bo.AdHocRouteRecipient;
054 import org.kuali.rice.kns.bo.DocumentHeader;
055 import org.kuali.rice.kns.rule.event.RouteDocumentEvent;
056 import org.kuali.rice.kns.service.BusinessObjectService;
057 import org.kuali.rice.kns.service.DataDictionaryService;
058 import org.kuali.rice.kns.service.DocumentService;
059 import org.kuali.rice.kns.service.KualiConfigurationService;
060 import org.kuali.rice.kns.service.KualiRuleService;
061 import org.kuali.rice.kns.service.ParameterService;
062 import org.kuali.rice.kns.util.ErrorMessage;
063 import org.kuali.rice.kns.util.GlobalVariables;
064 import org.kuali.rice.kns.util.KualiDecimal;
065 import org.kuali.rice.kns.util.MessageMap;
066 import org.kuali.rice.kns.util.ObjectUtils;
067 import org.springframework.transaction.annotation.Transactional;
068
069 @Transactional
070 public class CreateRecurringCashTransferTransactionsServiceImpl implements CreateRecurringCashTransferTransactionsService {
071
072 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CreateCashSweepTransactionsServiceImpl.class);
073
074 private Map<String, ReportDocumentStatistics> statistics = new HashMap<String, ReportDocumentStatistics>();
075 private BusinessObjectService businessObjectService;
076 private KEMService kemService;
077 private DocumentService documentService;
078 private ParameterService parameterService;
079 private KualiRuleService kualiRuleService;
080 private KemidCurrentCashService kemidCurrentCashService;
081 private HoldingTaxLotService holdingTaxLotService;
082
083 private KualiConfigurationService configService;
084 private DataDictionaryService dataDictionaryService;
085
086 private ReportWriterService recurringCashTransferTransactionsExceptionReportWriterService;
087 private ReportWriterService recurringCashTransferTransactionsTotalReportWriterService;
088
089 private RecurringCashTransferTransactionDocumentExceptionReportLine exceptionReportLine = null;
090 private RecurringCashTransferTransactionDocumentTotalReportLine totalReportLine = null;
091
092 private RecurringCashTransferTransactionDocumentTotalReportLine subTotalReportLine = null;
093 private RecurringCashTransferTransactionDocumentTotalReportLine allTotalReportLine = null;
094
095 private boolean isFistTimeForWritingExceptionReport = true;
096 private boolean isFistTimeForWritingTotalReport = true;
097
098 /**
099 * @see org.kuali.kfs.module.endow.batch.service.CreateRecurringCashTransferTransactionsService#createCashSweepTransactions()
100 */
101 public boolean createRecurringCashTransferTransactions() {
102
103 LOG.info("Starting \"Create Recurring Cash Transfer Transactions\" batch job...");
104
105 Collection<EndowmentRecurringCashTransfer> recurringCashTransfers = getAllRecurringCashTransferTransactionsForCurrentDate();
106
107 // get lists of each case of transaction type
108 Collection<EndowmentRecurringCashTransfer> cashTransfers = new ArrayList();
109 Collection<EndowmentRecurringCashTransfer> glCashTransfers = new ArrayList();
110
111 for (EndowmentRecurringCashTransfer endowmentRecurringCashTransfer : recurringCashTransfers) {
112 String sourceTransactionType = endowmentRecurringCashTransfer.getTransactionType();
113 if (sourceTransactionType.equals(EndowConstants.ENDOWMENT_CASH_TRANSFER_TRANSACTION_TYPE)) {
114 cashTransfers.add(endowmentRecurringCashTransfer);
115 }
116 else {
117 glCashTransfers.add(endowmentRecurringCashTransfer);
118 }
119 }
120
121 // initiate total report
122 allTotalReportLine = new RecurringCashTransferTransactionDocumentTotalReportLine();
123
124 // cashTransfers (ECT) exist, then calculate
125 if (!cashTransfers.isEmpty()) {
126 subTotalReportLine = new RecurringCashTransferTransactionDocumentTotalReportLine();
127 calculateCashTransfers(cashTransfers);
128 writeSubTotalReportLine();
129 }
130
131 // cashTransfers (EGLT) exist, then calculate
132 if (!glCashTransfers.isEmpty()) {
133 subTotalReportLine = new RecurringCashTransferTransactionDocumentTotalReportLine();
134 calculateGlCashTransfers(glCashTransfers);
135 writeSubTotalReportLine();
136 }
137
138 writeGrandTotalReportLine();
139
140 writeStatistics();
141
142 LOG.info("Finished \"Create Recurring Cash Transfer Transactions\" batch job!");
143
144 return true;
145 }
146
147 // calculate when ECT
148 protected void calculateCashTransfers(Collection<EndowmentRecurringCashTransfer> cashTransfers) {
149
150 for (EndowmentRecurringCashTransfer cashTransfer : cashTransfers) {
151 String sourceKemid = cashTransfer.getSourceKemid();
152 String transferNumber = cashTransfer.getTransferNumber();
153 Date lastProcessDate = cashTransfer.getLastProcessDate();
154
155 KualiDecimal totalSourceTransaction = KualiDecimal.ZERO;
156 KualiDecimal totalTargetTransaction = KualiDecimal.ZERO;
157 KualiDecimal cashEquivalents = calculateTotalCashEquivalents(cashTransfer);
158
159 CashTransferDocument cashTransferDoc = createCashTransferDocument(sourceKemid, transferNumber);
160 List<EndowmentRecurringCashTransferKEMIDTarget> kemidTargets = cashTransfer.getKemidTarget();
161
162
163 for (EndowmentRecurringCashTransferKEMIDTarget kemidTarget : kemidTargets) {
164 KualiDecimal transactionAmount = calculateCashTransferTransactionAmount(kemidTarget, cashEquivalents, sourceKemid, lastProcessDate);
165
166 // from spec, total of source and target are same, but totalTargetTransaction will be useful for implementing
167 // total part.
168 totalSourceTransaction = totalSourceTransaction.add(transactionAmount);
169 totalTargetTransaction = totalTargetTransaction.add(transactionAmount);
170
171 // add target line
172 boolean addTransactionLine = addKemidTargetTransactionLine(kemidTarget, cashTransferDoc, transactionAmount, sourceKemid, transferNumber);
173 if (!addTransactionLine) {
174 totalTargetTransaction = totalTargetTransaction.subtract(transactionAmount);
175 totalSourceTransaction = totalSourceTransaction.subtract(transactionAmount);
176 }
177 }
178 // check ALLOW_NEGATIVE_BALANCE_IND and if it is ok then route
179 boolean allowNegativeBalanceInd = parameterService.getIndicatorParameter(CreateRecurringCashTransferTransactionsStep.class, EndowParameterKeyConstants.ALLOW_NEGATIVE_BALANCE_IND);
180 // boolean allowNegativeBalanceInd = true;
181 if (!allowNegativeBalanceInd && totalSourceTransaction.isLessEqual(cashEquivalents)) {
182 // report exception
183 // constants??
184 writeExceptionReportLine(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_TRANSFER, sourceKemid, transferNumber, "", "calculated source total is not less than the total available cash equivalents");
185
186 }
187 else {
188 // add source line
189 addSourceTransactionLineForCashTransferDoc(cashTransfer, cashTransferDoc, totalSourceTransaction);
190 if (routeCashTransferDoc(cashTransferDoc, sourceKemid, transferNumber, totalTargetTransaction)) {
191 subTotalReportLine.incrementTotalTransferAmount(totalTargetTransaction);
192 subTotalReportLine.incrementTargetLinesGenerated(cashTransferDoc.getTargetTransactionLines().size());
193
194 updatePostingStatsForCashTransferDoc(cashTransferDoc);
195 }
196 }
197 }
198 allTotalReportLine.incrementTotalTransferAmount(subTotalReportLine.getTotalTransferAmount());
199 allTotalReportLine.incrementTargetLinesGenerated(subTotalReportLine.getTargetLinesGenerated());
200 }
201
202 protected KualiDecimal calculateCashTransferTransactionAmount(EndowmentRecurringCashTransferKEMIDTarget kemidTarget, KualiDecimal cashEquivalents, String sourceKemid, Date lastProcessDate) {
203
204 // check if it is calculation scenario 1
205 if (ObjectUtils.isNotNull(kemidTarget.getTargetPercent()) && ObjectUtils.isNotNull(kemidTarget.getTargetUseEtranCode())) {
206 // retrieves transactionArchives and calculated source cash
207 KualiDecimal totalCashIncomeEtranCode = KualiDecimal.ZERO;
208
209 List<TransactionArchive> transactionArchiveList = retrieveTransactionArchives(sourceKemid, lastProcessDate, kemidTarget.getTargetUseEtranCode());
210 // if transactionArchives exist, then calculate total income and total percent of same etran code in target
211 if (transactionArchiveList.size() > 0) {
212 // need to change name...like cashIncrease..
213 totalCashIncomeEtranCode = calculateTotalIncomeTransactionArchives(transactionArchiveList);
214 }
215 return totalCashIncomeEtranCode.multiply(kemidTarget.getTargetPercent());
216 }
217 // check if it is calculation scenario 2
218 else if (ObjectUtils.isNotNull(kemidTarget.getTargetPercent())) {
219 return cashEquivalents.multiply(kemidTarget.getTargetPercent());
220 }
221 // check if it is calculation scenario 3
222 else if (ObjectUtils.isNotNull(kemidTarget.getTargetAmount())) {
223 return kemidTarget.getTargetAmount();
224 }
225 else
226 return KualiDecimal.ZERO;
227 }
228
229
230 // calculate when EGLT
231 protected void calculateGlCashTransfers(Collection<EndowmentRecurringCashTransfer> glCashTransfers) {
232 for (EndowmentRecurringCashTransfer glCashTransfer : glCashTransfers) {
233
234 String sourceTransactionType = glCashTransfer.getTransactionType();
235 String sourceKemid = glCashTransfer.getSourceKemid();
236 String transferNumber = glCashTransfer.getTransferNumber();
237 Date lastProcessDate = glCashTransfer.getLastProcessDate();
238
239 KualiDecimal totalSourceTransaction = KualiDecimal.ZERO;
240 KualiDecimal totalTargetTransaction = KualiDecimal.ZERO;
241 KualiDecimal cashEquivalents = calculateTotalCashEquivalents(glCashTransfer);
242
243 EndowmentToGLTransferOfFundsDocument gLTransferOfFundsDocument = createEndowmentToGLTransferOfFundsDocument(sourceKemid, transferNumber);
244 List<EndowmentRecurringCashTransferGLTarget> glTargets = glCashTransfer.getGlTarget();
245
246 for (EndowmentRecurringCashTransferGLTarget glTarget : glTargets) {
247 KualiDecimal transactionAmount = calculateGlCashTransferTransactionAmount(glTarget, cashEquivalents, sourceKemid, lastProcessDate);
248
249 totalSourceTransaction = totalSourceTransaction.add(transactionAmount);
250 totalTargetTransaction = totalTargetTransaction.add(transactionAmount);
251
252 // add target line
253 boolean addTransactionLine = addGlTransactionLine(glTarget, gLTransferOfFundsDocument, transactionAmount, sourceKemid, transferNumber);
254 if (!addTransactionLine) {
255 totalTargetTransaction = totalTargetTransaction.subtract(transactionAmount);
256 totalSourceTransaction = totalSourceTransaction.subtract(transactionAmount);
257 }
258 }
259
260 // check ALLOW_NEGATIVE_BALANCE_IND and if it is ok then route
261 boolean allowNegativeBalanceInd = parameterService.getIndicatorParameter(CreateRecurringCashTransferTransactionsStep.class, EndowParameterKeyConstants.ALLOW_NEGATIVE_BALANCE_IND);
262 // boolean allowNegativeBalanceInd = true;
263 if (!allowNegativeBalanceInd && totalSourceTransaction.isLessEqual(cashEquivalents)) {
264 // report exception
265 writeExceptionReportLine(EndowConstants.ENDOWMENT_GENERAL_LEDGER_CASH_TRANSFER_TRANSACTION_TYPE, sourceKemid, transferNumber, "calculated source total is less than the total available cash equivalents");
266 }
267 else {
268 // add source... line
269 addSourceTransactionLineForGLTransferOfFundsDocument(glCashTransfer, gLTransferOfFundsDocument, totalSourceTransaction);
270 // route doc
271 if (routeGLTransferOfFundsDocument(gLTransferOfFundsDocument, sourceKemid, transferNumber, totalTargetTransaction)) {
272
273 subTotalReportLine.incrementTotalTransferAmount(totalTargetTransaction);
274 subTotalReportLine.incrementTargetLinesGenerated(gLTransferOfFundsDocument.getTargetAccountingLines().size());
275
276 updatePostingStatsForGlTransferDoc(gLTransferOfFundsDocument);
277 }
278 }
279 }
280 allTotalReportLine.incrementTotalTransferAmount(subTotalReportLine.getTotalTransferAmount());
281 allTotalReportLine.incrementTargetLinesGenerated(subTotalReportLine.getTargetLinesGenerated());
282 }
283
284 protected KualiDecimal calculateGlCashTransferTransactionAmount(EndowmentRecurringCashTransferGLTarget glTarget, KualiDecimal cashEquivalents, String sourceKemid, Date lastProcessDate) {
285 // check if it is calculation scenario 1
286 if (ObjectUtils.isNotNull(glTarget.getTargetPercent()) && ObjectUtils.isNotNull(glTarget.getTargetUseEtranCode())) {
287 // retrieves transactionArchives and calculated source cash
288 KualiDecimal totalCashIncomeEtranCode = KualiDecimal.ZERO;
289
290 List<TransactionArchive> transactionArchiveList = retrieveTransactionArchives(sourceKemid, lastProcessDate, glTarget.getTargetUseEtranCode());
291 // if transactionArchives exist, then calculate total income and total percent of same etran code in target
292 if (transactionArchiveList.size() > 0) {
293 totalCashIncomeEtranCode = calculateTotalIncomeTransactionArchives(transactionArchiveList);
294 }
295 return totalCashIncomeEtranCode.multiply(glTarget.getTargetPercent());
296 }
297 // check if it is calculation scenario 2
298 else if (ObjectUtils.isNotNull(glTarget.getTargetPercent())) {
299 return cashEquivalents.multiply(glTarget.getTargetPercent());
300 }
301 // check if it is calculation scenario 3
302 else if (ObjectUtils.isNotNull(glTarget.getTargetFdocLineAmount())) {
303 return glTarget.getTargetFdocLineAmount();
304 }
305 else
306 return KualiDecimal.ZERO;
307 }
308
309 protected KualiDecimal calculateTotalCashEquivalents(EndowmentRecurringCashTransfer endowmentRecurringCashTransfer) {
310 // spec 10.2
311 KualiDecimal totalCashEquivalents = KualiDecimal.ZERO;
312 String kemid = endowmentRecurringCashTransfer.getSourceKemid();
313 KemidCurrentCash currentCash = kemidCurrentCashService.getByPrimaryKey(kemid);
314 if (endowmentRecurringCashTransfer.getSourceIncomeOrPrincipal().equals(EndowConstants.EndowmentTransactionTypeCodes.INCOME_TYPE_CODE)) {
315 totalCashEquivalents = currentCash.getCurrentIncomeCash().add(new KualiDecimal(holdingTaxLotService.getMarketValueForCashEquivalentsForAvailableIncomeCash(kemid)));
316 }
317 else {
318 totalCashEquivalents = currentCash.getCurrentPrincipalCash().add(new KualiDecimal(holdingTaxLotService.getMarketValueForCashEquivalentsForAvailablePrincipalCash(kemid)));
319 }
320 return totalCashEquivalents;
321 }
322
323 /**
324 * This method retrieves all the recurring cash transfer transactions whose frequency code matches the current date.
325 *
326 * @return List of CashSweepModel business objects
327 */
328 protected Collection<EndowmentRecurringCashTransfer> getAllRecurringCashTransferTransactionsForCurrentDate() {
329 LOG.info("Getting all EndowmentRecurringCashTransfer with Next process date = current date");
330
331 List<EndowmentRecurringCashTransfer> endowmentRecurringCashTransfer = new ArrayList<EndowmentRecurringCashTransfer>();
332 Date currentDate = kemService.getCurrentDate();
333 Map fieldValues = new HashMap();
334 fieldValues.put(EndowPropertyConstants.ENDOWMENT_RECURRING_CASH_TRANSF_NEXT_PROC_DATE, currentDate);
335 Collection<EndowmentRecurringCashTransfer> recurringCashTransfers = businessObjectService.findMatching(EndowmentRecurringCashTransfer.class, fieldValues);
336 LOG.info("Number of EndowmentRecurringCashTransfer with Next process date = current date" + recurringCashTransfers.size());
337 return recurringCashTransfers;
338 }
339
340 // protected List getSortFieldList(){
341 // List returnList = new Arraylist();
342 // returnList.add(EndowPropertyConstants.ENDOWMENT_RECURRING_CASH_TRANSF_TRANSACTION_TYPE);
343 // returnList.add(EndowPropertyConstants.ENDOWMENT_RECURRING_CASH_TRANSF_TRANSACTION_TYPE);
344 //
345 // return returnList();
346 // }
347
348 // List<EndowmentRecurringCashTransfer> recurringCashTransfers = (List)
349 // businessObjectService.findMatching(EndowmentRecurringCashTransfer.class, fieldValues);
350 // //Collection<EndowmentRecurringCashTransfer> recurringCashTransfers =
351 // businessObjectService.findMatching(EndowmentRecurringCashTransfer.class, fieldValues);
352 // List sortFieldList = new getSortFieldList();
353 // Collections.sort(recurringCashTransfers, new BeanPropertyComparator(getDefaultSortColumns(), true));
354
355
356 // spec 6.2 3.1.a
357 protected List<TransactionArchive> retrieveTransactionArchives(String sourceKemid, Date lastProcessDate, String targetEtranCode) {
358 KualiDecimal totalCashIncomeEtranCode = KualiDecimal.ZERO;
359
360 List<TransactionArchive> transactionArchiveList = null;
361 Map fieldValues = new HashMap();
362 fieldValues.put(EndowPropertyConstants.KEMID, sourceKemid);
363 fieldValues.put(EndowPropertyConstants.TRANSACTION_LINE_ENDOWMENT_TRANSACTION_CODE, targetEtranCode);
364 transactionArchiveList = (List) businessObjectService.findMatching(TransactionArchive.class, fieldValues);
365 for (TransactionArchive transactionArchive : transactionArchiveList) {
366 if (!transactionArchive.getPostedDate().after(lastProcessDate)) {
367 transactionArchiveList.remove(transactionArchive);
368 }
369 }
370 return transactionArchiveList;
371 }
372
373 // spec 6.2 3.1.a
374 protected KualiDecimal calculateTotalIncomeTransactionArchives(List<TransactionArchive> transactionArchiveList) {
375 KualiDecimal totalCashIncomeEtranCode = KualiDecimal.ZERO;
376 for (TransactionArchive transactionArchive : transactionArchiveList) {
377 if (transactionArchive.getIncomePrincipalIndicatorCode().equals(EndowConstants.EndowmentTransactionTypeCodes.INCOME_TYPE_CODE)) {
378 totalCashIncomeEtranCode = totalCashIncomeEtranCode.add(new KualiDecimal(transactionArchive.getIncomeCashAmount()));
379 }
380 else {
381 totalCashIncomeEtranCode = totalCashIncomeEtranCode.add(new KualiDecimal(transactionArchive.getPrincipalCashAmount()));
382 }
383 }
384 return totalCashIncomeEtranCode;
385 }
386
387 /**
388 * This method...
389 *
390 * @param assetIncreaseDoc
391 * @param assetSaleOffsetCode
392 * @param kemid
393 * @param cashLimit
394 * @param currentCash
395 */
396
397 protected void addSourceTransactionLineForCashTransferDoc(EndowmentRecurringCashTransfer endowmentRecurringCashTransfer, CashTransferDocument cashTransferDoc, KualiDecimal totalAmount) {
398 boolean rulesPassed = true;
399 EndowmentSourceTransactionLine transactionLine = new EndowmentSourceTransactionLine();
400 transactionLine.setTransactionLineTypeCode(EndowConstants.TRANSACTION_LINE_TYPE_SOURCE);
401 transactionLine.setKemid(endowmentRecurringCashTransfer.getSourceKemid());
402 transactionLine.setEtranCode(endowmentRecurringCashTransfer.getSourceEtranCode());
403 transactionLine.setTransactionLineDescription(endowmentRecurringCashTransfer.getSourceLineDescription());
404 transactionLine.setTransactionIPIndicatorCode(endowmentRecurringCashTransfer.getSourceIncomeOrPrincipal());
405 transactionLine.setTransactionAmount(totalAmount);
406
407 rulesPassed = kualiRuleService.applyRules(new AddTransactionLineEvent(EndowConstants.NEW_SOURCE_TRAN_LINE_PROPERTY_NAME, cashTransferDoc, transactionLine));
408
409 if (rulesPassed) {
410 cashTransferDoc.addSourceTransactionLine(transactionLine);
411 }
412 else {
413 // report to error
414 writeExceptionReportLine(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_TRANSFER, endowmentRecurringCashTransfer.getSourceKemid(), endowmentRecurringCashTransfer.getTransferNumber(), EndowConstants.EXISTING_SOURCE_TRAN_LINE_PROPERTY_NAME);
415 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(cashTransferDoc.getClass());
416 updateErrorStats(documentTypeName);
417 }
418 }
419
420 protected void addSourceTransactionLineForGLTransferOfFundsDocument(EndowmentRecurringCashTransfer endowmentRecurringCashTransfer, EndowmentToGLTransferOfFundsDocument gLTransferOfFundsDocument, KualiDecimal totalAmount) {
421 boolean rulesPassed = true;
422 EndowmentSourceTransactionLine transactionLine = new EndowmentSourceTransactionLine();
423 transactionLine.setTransactionLineTypeCode(EndowConstants.TRANSACTION_LINE_TYPE_SOURCE);
424 transactionLine.setKemid(endowmentRecurringCashTransfer.getSourceKemid());
425 transactionLine.setEtranCode(endowmentRecurringCashTransfer.getSourceEtranCode());
426 transactionLine.setTransactionLineDescription(endowmentRecurringCashTransfer.getSourceLineDescription());
427 transactionLine.setTransactionIPIndicatorCode(endowmentRecurringCashTransfer.getSourceIncomeOrPrincipal());
428 transactionLine.setTransactionAmount(totalAmount);
429
430 rulesPassed = kualiRuleService.applyRules(new AddTransactionLineEvent(EndowConstants.NEW_SOURCE_TRAN_LINE_PROPERTY_NAME, gLTransferOfFundsDocument, transactionLine));
431
432 if (rulesPassed) {
433 gLTransferOfFundsDocument.addSourceTransactionLine(transactionLine);
434 }
435 else {
436 // report to error
437 writeExceptionReportLine(EndowConstants.ENDOWMENT_GENERAL_LEDGER_CASH_TRANSFER_TRANSACTION_TYPE, endowmentRecurringCashTransfer.getSourceKemid(), endowmentRecurringCashTransfer.getTransferNumber(), EndowConstants.EXISTING_SOURCE_TRAN_LINE_PROPERTY_NAME);
438 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(gLTransferOfFundsDocument.getClass());
439 updateErrorStats(documentTypeName);
440 }
441 }
442
443 protected boolean addKemidTargetTransactionLine(EndowmentRecurringCashTransferKEMIDTarget endowmentRecurringCashTransferKEMIDTarget, CashTransferDocument cashTransferDoc, KualiDecimal totalAmount, String sourceKemid, String transferNumber) {
444 boolean rulesPassed = true;
445 EndowmentTargetTransactionLine transactionLine = new EndowmentTargetTransactionLine();
446 // set all necessary fields
447 transactionLine.setTransactionLineTypeCode(EndowConstants.TRANSACTION_LINE_TYPE_TARGET);
448 transactionLine.setKemid(endowmentRecurringCashTransferKEMIDTarget.getTargetKemid());
449 transactionLine.setEtranCode(endowmentRecurringCashTransferKEMIDTarget.getTargetEtranCode());
450 transactionLine.setTransactionLineDescription(endowmentRecurringCashTransferKEMIDTarget.getTargetLineDescription());
451 transactionLine.setTransactionIPIndicatorCode(endowmentRecurringCashTransferKEMIDTarget.getTargetIncomeOrPrincipal());
452 transactionLine.setTransactionAmount(totalAmount);
453
454 // check rules
455 rulesPassed = kualiRuleService.applyRules(new AddTransactionLineEvent(EndowConstants.NEW_TARGET_TRAN_LINE_PROPERTY_NAME, cashTransferDoc, transactionLine));
456
457 if (rulesPassed) {
458 cashTransferDoc.addTargetTransactionLine(transactionLine);
459 }
460 else {
461 // report to error
462 writeExceptionReportLine(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_TRANSFER, sourceKemid, endowmentRecurringCashTransferKEMIDTarget.getTransferNumber(), endowmentRecurringCashTransferKEMIDTarget.getTargetSequenceNumber().toString());
463 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(cashTransferDoc.getClass());
464 updateErrorStats(documentTypeName);
465 }
466
467 return rulesPassed;
468 }
469
470 protected boolean addGlTransactionLine(EndowmentRecurringCashTransferGLTarget endowmentRecurringCashTransferGLTarget, EndowmentToGLTransferOfFundsDocument endowmentToGLTransferOfFundsDocument, KualiDecimal totalAmount, String sourceKemid, String transferNumber) {
471 boolean rulesPassed = true;
472 TargetEndowmentAccountingLine endowmentAccountingLine = new TargetEndowmentAccountingLine();
473 // set all necessary fields
474 endowmentAccountingLine.setChartOfAccountsCode(endowmentRecurringCashTransferGLTarget.getTargetChartOfAccountsCode());
475 endowmentAccountingLine.setAccountNumber(endowmentRecurringCashTransferGLTarget.getTargetAccountsNumber());
476 endowmentAccountingLine.setFinancialObjectCode(endowmentRecurringCashTransferGLTarget.getTargetFinancialObjectCode());
477 endowmentAccountingLine.setAmount(totalAmount);
478 // number.setScale(digit, BigDecimal.ROUND_HALF_UP)
479
480 // check rules
481 rulesPassed = kualiRuleService.applyRules(new AddEndowmentAccountingLineEvent(EndowConstants.NEW_TARGET_ACC_LINE_PROPERTY_NAME, endowmentToGLTransferOfFundsDocument, endowmentAccountingLine));
482
483 if (rulesPassed) {
484 endowmentToGLTransferOfFundsDocument.addTargetAccountingLine(endowmentAccountingLine);
485 }
486 else {
487 // report to error
488 writeExceptionReportLine(EndowConstants.ENDOWMENT_GENERAL_LEDGER_CASH_TRANSFER_TRANSACTION_TYPE, sourceKemid, endowmentRecurringCashTransferGLTarget.getTransferNumber(), endowmentRecurringCashTransferGLTarget.getTargetSequenceNumber().toString());
489 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(endowmentToGLTransferOfFundsDocument.getClass());
490 updateErrorStats(documentTypeName);
491
492 }
493
494 return rulesPassed;
495 }
496
497 protected CashTransferDocument createCashTransferDocument(String sourceKemid, String transferNumber) {
498
499 CashTransferDocument cashTransferDoc = null;
500 try {
501 cashTransferDoc = (CashTransferDocument) documentService.getNewDocument(CashTransferDocument.class);
502
503 // Set values for doc
504 DocumentHeader docHeader = cashTransferDoc.getDocumentHeader();
505 String description = parameterService.getParameterValue(CreateRecurringCashTransferTransactionsStep.class, EndowParameterKeyConstants.DESCRIPTION);
506 docHeader.setDocumentDescription(description);
507 cashTransferDoc.setDocumentHeader(docHeader);
508 cashTransferDoc.setTransactionSourceTypeCode(EndowConstants.TransactionSourceTypeCode.RECURRING);
509 }
510 catch (WorkflowException ex) {
511 LOG.error(ex.getLocalizedMessage());
512 writeExceptionReportLine(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_TRANSFER, sourceKemid, transferNumber, "", ex.getLocalizedMessage() + " from createCashTransferDocument()");
513 }
514
515 return cashTransferDoc;
516 }
517
518 protected boolean routeCashTransferDoc(CashTransferDocument cashTransferDoc, String sourceKemid, String transferNumber, KualiDecimal totalAmount) {
519 boolean routeSuccessInd = true;
520 boolean rulesPassed = kualiRuleService.applyRules(new RouteDocumentEvent(cashTransferDoc));
521
522 if (rulesPassed) {
523 // no adhoc recipient need to add when submit doc. doc will route to the doc uploader, i.e. initiator automtically.
524 List<AdHocRouteRecipient> adHocRoutingRecipients = new ArrayList<AdHocRouteRecipient>();
525 try {
526 cashTransferDoc.setNoRouteIndicator(getNoRouteParameterAsBoolean());
527 documentService.routeDocument(cashTransferDoc, "Route CashIncreaseDocument", adHocRoutingRecipients);
528 writeTotalReportLine(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_TRANSFER, cashTransferDoc.getDocumentNumber(), transferNumber, sourceKemid, new Integer(cashTransferDoc.getTargetTransactionLines().size()), totalAmount);
529
530 }
531 catch (WorkflowException ex) {
532 LOG.error(ex.getLocalizedMessage());
533 writeExceptionReportLine(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_TRANSFER, sourceKemid, transferNumber, "", ex.getLocalizedMessage() + " from routeCashTransferDoc()");
534 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(cashTransferDoc.getClass());
535 updateErrorStats(documentTypeName);
536 routeSuccessInd = false;
537 }
538 }
539 else {
540 // report to error
541 writeExceptionReportLine(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_TRANSFER, sourceKemid, transferNumber, "");
542 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(cashTransferDoc.getClass());
543 updateErrorStats(documentTypeName);
544 routeSuccessInd = false;
545 }
546
547 return routeSuccessInd;
548 }
549
550 protected boolean routeGLTransferOfFundsDocument(EndowmentToGLTransferOfFundsDocument gLTransferOfFundsDocument, String sourceKemid, String transferNumber, KualiDecimal totalAmount) {
551 boolean routeSuccessInd = true;
552 boolean rulesPassed = kualiRuleService.applyRules(new RouteDocumentEvent(gLTransferOfFundsDocument));
553
554 if (rulesPassed) {
555 // no adhoc recipient need to add when submit doc. doc will route to the doc uploader, i.e. initiator automtically.
556 List<AdHocRouteRecipient> adHocRoutingRecipients = new ArrayList<AdHocRouteRecipient>();
557 try {
558 gLTransferOfFundsDocument.setNoRouteIndicator(getNoRouteParameterAsBoolean());
559 documentService.routeDocument(gLTransferOfFundsDocument, "Route gLTransferOfFundsDocument", adHocRoutingRecipients);
560
561 writeTotalReportLine(EndowConstants.ENDOWMENT_GENERAL_LEDGER_CASH_TRANSFER_TRANSACTION_TYPE, gLTransferOfFundsDocument.getDocumentNumber(), transferNumber, sourceKemid, new Integer(gLTransferOfFundsDocument.getTargetAccountingLines().size()), totalAmount);
562
563 }
564 catch (WorkflowException ex) {
565 LOG.error(ex.getLocalizedMessage());
566
567 writeExceptionReportLine(EndowConstants.ENDOWMENT_GENERAL_LEDGER_CASH_TRANSFER_TRANSACTION_TYPE, sourceKemid, transferNumber, "", ex.getLocalizedMessage() + " from routeGLTransferOfFundsDocument()");
568 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(gLTransferOfFundsDocument.getClass());
569 updateErrorStats(documentTypeName);
570 routeSuccessInd = false;
571 }
572 }
573 else {
574 // report to error
575 writeExceptionReportLine(EndowConstants.ENDOWMENT_GENERAL_LEDGER_CASH_TRANSFER_TRANSACTION_TYPE, sourceKemid, transferNumber, "");
576 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(gLTransferOfFundsDocument.getClass());
577 updateErrorStats(documentTypeName);
578 routeSuccessInd = false;
579 }
580
581 return routeSuccessInd;
582 }
583
584 protected EndowmentToGLTransferOfFundsDocument createEndowmentToGLTransferOfFundsDocument(String sourceKemid, String transferNumber) {
585 EndowmentToGLTransferOfFundsDocument endowmentToGLTransferOfFundsDocument = null;
586 try {
587 endowmentToGLTransferOfFundsDocument = (EndowmentToGLTransferOfFundsDocument) documentService.getNewDocument(EndowmentToGLTransferOfFundsDocument.class);
588
589 // Set values for doc
590 DocumentHeader docHeader = endowmentToGLTransferOfFundsDocument.getDocumentHeader();
591 String description = parameterService.getParameterValue(CreateRecurringCashTransferTransactionsStep.class, EndowParameterKeyConstants.DESCRIPTION);
592 docHeader.setDocumentDescription(description);
593 endowmentToGLTransferOfFundsDocument.setDocumentHeader(docHeader);
594 endowmentToGLTransferOfFundsDocument.setTransactionSourceTypeCode(EndowConstants.TransactionSourceTypeCode.RECURRING);
595 }
596 catch (WorkflowException ex) {
597 LOG.error(ex.getLocalizedMessage());
598
599 writeExceptionReportLine(EndowConstants.ENDOWMENT_GENERAL_LEDGER_CASH_TRANSFER_TRANSACTION_TYPE, sourceKemid, transferNumber, "", ex.getLocalizedMessage() + " from createEndowmentToGLTransferOfFundsDocument()");
600 }
601
602 return endowmentToGLTransferOfFundsDocument;
603
604 }
605
606 protected boolean getNoRouteParameterAsBoolean() {
607 String noRouteIndParm = parameterService.getParameterValue(CreateRecurringCashTransferTransactionsStep.class, EndowParameterKeyConstants.NO_ROUTE_IND);
608 if (noRouteIndParm.equals(EndowConstants.YES)) {
609 return true;
610 }
611 else
612 return false;
613 }
614
615 /**
616 * Extracts errors for error report writing.
617 *
618 * @return a list of error messages
619 */
620 protected List<String> extractGlobalVariableErrors() {
621 List<String> result = new ArrayList<String>();
622
623 MessageMap errorMap = GlobalVariables.getMessageMap();
624
625 Set<String> errorKeys = errorMap.keySet();
626 List<ErrorMessage> errorMessages = null;
627 Object[] messageParams;
628 String errorKeyString;
629 String errorString;
630
631 for (String errorProperty : errorKeys) {
632 errorMessages = (List<ErrorMessage>) errorMap.get(errorProperty);
633 for (ErrorMessage errorMessage : errorMessages) {
634 errorKeyString = configService.getPropertyString(errorMessage.getErrorKey());
635 messageParams = errorMessage.getMessageParameters();
636
637 // MessageFormat.format only seems to replace one
638 // per pass, so I just keep beating on it until all are gone.
639 if (StringUtils.isBlank(errorKeyString)) {
640 errorString = errorMessage.getErrorKey();
641 }
642 else {
643 errorString = errorKeyString;
644 }
645 System.out.println(errorString);
646 while (errorString.matches("^.*\\{\\d\\}.*$")) {
647 errorString = MessageFormat.format(errorString, messageParams);
648 }
649 result.add(errorString);
650 }
651 }
652
653 // clear the stuff out of globalvars, as we need to reformat it and put it back
654 GlobalVariables.getMessageMap().clear();
655 return result;
656 }
657
658 protected void writeExceptionReportLine(String documentType, String sourceKemid, String transferNumber, String targetSeqNumber) {
659 writeExceptionReportLine(documentType, sourceKemid, transferNumber, targetSeqNumber, "");
660 }
661
662 protected void writeExceptionReportLine(String documentType, String sourceKemid, String transferNumber, String targetSeqNumber, String reason) {
663 // write an exception line when a transaction line fails to pass the validation.
664 exceptionReportLine = new RecurringCashTransferTransactionDocumentExceptionReportLine(documentType, sourceKemid, transferNumber, targetSeqNumber);
665
666 if (isFistTimeForWritingExceptionReport) {
667 recurringCashTransferTransactionsExceptionReportWriterService.writeTableHeader(exceptionReportLine);
668 isFistTimeForWritingExceptionReport = false;
669 }
670 recurringCashTransferTransactionsExceptionReportWriterService.writeTableRow(exceptionReportLine);
671
672 if (StringUtils.isBlank(reason)) {
673 List<String> errorMessages = extractGlobalVariableErrors();
674 for (String errorMessage : errorMessages) {
675 recurringCashTransferTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason: %s", errorMessage);
676 recurringCashTransferTransactionsExceptionReportWriterService.writeNewLines(1);
677 }
678 }
679 else {
680 recurringCashTransferTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason: %s", reason);
681 recurringCashTransferTransactionsExceptionReportWriterService.writeNewLines(1);
682 }
683 }
684
685 protected void writeTotalReportLine(String documentType, String documentId, String transferNumber, String sourcekemid, Integer targetLinesGenerated, KualiDecimal totalTransferAmount) {
686 totalReportLine = new RecurringCashTransferTransactionDocumentTotalReportLine(documentType, documentId, transferNumber, sourcekemid, targetLinesGenerated, totalTransferAmount);
687
688 if (isFistTimeForWritingTotalReport) {
689 recurringCashTransferTransactionsTotalReportWriterService.writeTableHeader(totalReportLine);
690 isFistTimeForWritingTotalReport = false;
691 }
692
693 recurringCashTransferTransactionsTotalReportWriterService.writeTableRow(totalReportLine);
694 }
695
696 protected void writeSubTotalReportLine() {
697 writeTotalReportLine("SubTotal", "", "", "", subTotalReportLine.getTargetLinesGenerated(), subTotalReportLine.getTotalTransferAmount());
698 recurringCashTransferTransactionsTotalReportWriterService.writeNewLines(1);
699 }
700
701 protected void writeGrandTotalReportLine() {
702 writeTotalReportLine("Total", "", "", "", allTotalReportLine.getTargetLinesGenerated(), allTotalReportLine.getTotalTransferAmount());
703 }
704
705 /**
706 * Sets the businessObjectService attribute value.
707 *
708 * @param businessObjectService The businessObjectService to set.
709 */
710 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
711 this.businessObjectService = businessObjectService;
712 }
713
714 /**
715 * Sets the kemService attribute value.
716 *
717 * @param kemService The kemService to set.
718 */
719 public void setKemService(KEMService kemService) {
720 this.kemService = kemService;
721 }
722
723 /**
724 * Sets the documentService attribute value.
725 *
726 * @param documentService The documentService to set.
727 */
728 public void setDocumentService(DocumentService documentService) {
729 this.documentService = documentService;
730 }
731
732 /**
733 * Sets the parameterService attribute value.
734 *
735 * @param parameterService The parameterService to set.
736 */
737 public void setParameterService(ParameterService parameterService) {
738 this.parameterService = parameterService;
739 }
740
741 /**
742 * Sets the kualiRuleService attribute value.
743 *
744 * @param kualiRuleService The kualiRuleService to set.
745 */
746 public void setKualiRuleService(KualiRuleService kualiRuleService) {
747 this.kualiRuleService = kualiRuleService;
748 }
749
750 /**
751 * Sets the kemidCurrentCashOpenRecordsService
752 *
753 * @param kemidCurrentCashOpenRecordsService The kemidCurrentCashOpenRecordsService to set.
754 */
755 public void setKemidCurrentCashService(KemidCurrentCashService kemidCurrentCashService) {
756 this.kemidCurrentCashService = kemidCurrentCashService;
757 }
758
759 public void setHoldingTaxLotService(HoldingTaxLotService holdingTaxLotService) {
760 this.holdingTaxLotService = holdingTaxLotService;
761 }
762
763 public void setRecurringCashTransferTransactionsExceptionReportWriterService(ReportWriterService recurringCashTransferTransactionsExceptionReportWriterService) {
764 this.recurringCashTransferTransactionsExceptionReportWriterService = recurringCashTransferTransactionsExceptionReportWriterService;
765 }
766
767 public void setRecurringCashTransferTransactionsTotalReportWriterService(ReportWriterService recurringCashTransferTransactionsTotalReportWriterService) {
768 this.recurringCashTransferTransactionsTotalReportWriterService = recurringCashTransferTransactionsTotalReportWriterService;
769 }
770
771 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
772 this.dataDictionaryService = dataDictionaryService;
773 }
774
775 /**
776 * Sets the configService.
777 *
778 * @param configService
779 */
780 public void setConfigService(KualiConfigurationService configService) {
781 this.configService = configService;
782 }
783
784 private void updatePostingStatsForCashTransferDoc(CashTransferDocument cashTransferDoc) {
785
786 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(cashTransferDoc.getClass());
787 ReportDocumentStatistics stats = statistics.get(documentTypeName);
788
789 // If null that means there isn't one in the map, so create it and add
790 // it to the map.
791 if (stats == null) {
792 stats = new ReportDocumentStatistics(documentTypeName);
793 statistics.put(documentTypeName, stats);
794 }
795 stats.addNumberOfSourceTransactionLines(cashTransferDoc.getSourceTransactionLines().size());
796 stats.addNumberOfTargetTransactionLines(cashTransferDoc.getTargetTransactionLines().size());
797
798 stats.incrementNumberOfDocuments();
799 }
800
801 private void updatePostingStatsForGlTransferDoc(EndowmentToGLTransferOfFundsDocument glTransferDoc) {
802
803 String documentTypeName = dataDictionaryService.getDocumentTypeNameByClass(glTransferDoc.getClass());
804 ReportDocumentStatistics stats = statistics.get(documentTypeName);
805
806 // If null that means there isn't one in the map, so create it and add
807 // it to the map.
808 if (stats == null) {
809 stats = new ReportDocumentStatistics(documentTypeName);
810 statistics.put(documentTypeName, stats);
811 }
812 stats.addNumberOfSourceTransactionLines(glTransferDoc.getSourceTransactionLines().size());
813 stats.addNumberOfTargetTransactionLines(glTransferDoc.getTargetAccountingLines().size());
814
815 stats.incrementNumberOfDocuments();
816 }
817
818 private void updateErrorStats(String documentTypeName) {
819 ReportDocumentStatistics stats = statistics.get(documentTypeName);
820
821 // If null that means there isn't one in the map, so create it and add
822 // it to the map.
823 if (stats == null) {
824 stats = new ReportDocumentStatistics(documentTypeName);
825 statistics.put(documentTypeName, stats);
826 }
827
828 stats.incrementNumberOfErrors();
829 }
830
831 /**
832 * Write out the statistics.
833 */
834 private void writeStatistics() {
835
836 for (Map.Entry<String, ReportDocumentStatistics> entry : statistics.entrySet()) {
837
838 ReportDocumentStatistics stats = entry.getValue();
839
840 recurringCashTransferTransactionsTotalReportWriterService.writeStatisticLine("%s Documents:", stats.getDocumentTypeName());
841 recurringCashTransferTransactionsTotalReportWriterService.writeStatisticLine(" Number of Documents Generated: %d", stats.getNumberOfDocuments());
842 recurringCashTransferTransactionsTotalReportWriterService.writeStatisticLine(" Number of Transaction Lines Generated: %d", stats.getTotalNumberOfTransactionLines());
843 recurringCashTransferTransactionsTotalReportWriterService.writeStatisticLine(" Number of Error Records Written: %d", stats.getNumberOfErrors());
844 recurringCashTransferTransactionsTotalReportWriterService.writeStatisticLine("", "");
845 }
846
847 }
848
849
850 }