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.util.ArrayList;
019    import java.util.List;
020    
021    import org.kuali.kfs.module.endow.EndowConstants;
022    import org.kuali.kfs.module.endow.EndowParameterKeyConstants;
023    import org.kuali.kfs.module.endow.batch.PooledFundControlTransactionsStep;
024    import org.kuali.kfs.module.endow.batch.service.PooledFundControlTransactionsService;
025    import org.kuali.kfs.module.endow.businessobject.EndowmentSourceTransactionLine;
026    import org.kuali.kfs.module.endow.businessobject.EndowmentTargetTransactionLine;
027    import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLineBase;
028    import org.kuali.kfs.module.endow.businessobject.PooledFundControl;
029    import org.kuali.kfs.module.endow.businessobject.TransactionArchive;
030    import org.kuali.kfs.module.endow.businessobject.TransactionArchiveSecurity;
031    import org.kuali.kfs.module.endow.businessobject.TransactionDocumentExceptionReportLine;
032    import org.kuali.kfs.module.endow.businessobject.TransactionDocumentTotalReportLine;
033    import org.kuali.kfs.module.endow.dataaccess.PooledFundControlTransactionsDao;
034    import org.kuali.kfs.module.endow.document.CashDecreaseDocument;
035    import org.kuali.kfs.module.endow.document.CashIncreaseDocument;
036    import org.kuali.kfs.module.endow.document.EndowmentSecurityDetailsDocumentBase;
037    import org.kuali.kfs.module.endow.document.service.KEMService;
038    import org.kuali.kfs.module.endow.document.validation.event.AddTransactionLineEvent;
039    import org.kuali.kfs.module.endow.util.GloabalVariablesExtractHelper;
040    import org.kuali.kfs.sys.context.SpringContext;
041    import org.kuali.kfs.sys.service.ReportWriterService;
042    import org.kuali.rice.kew.exception.WorkflowException;
043    import org.kuali.rice.kns.rule.event.RouteDocumentEvent;
044    import org.kuali.rice.kns.service.BusinessObjectService;
045    import org.kuali.rice.kns.service.DocumentService;
046    import org.kuali.rice.kns.service.KualiRuleService;
047    import org.kuali.rice.kns.service.ParameterService;
048    import org.kuali.rice.kns.service.TransactionalDocumentDictionaryService;
049    import org.kuali.rice.kns.util.GlobalVariables;
050    import org.kuali.rice.kns.util.KualiDecimal;
051    import org.kuali.rice.kns.util.ObjectUtils;
052    import org.springframework.transaction.annotation.Transactional;
053    
054    /*
055     * This class is the implementation of the Bach Generate Pooled fund Control Transactions 
056     */
057    @Transactional
058    public class PooledFundControlTransactionsServiceImpl implements PooledFundControlTransactionsService {
059        
060        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PooledFundControlTransactionsServiceImpl.class);
061        
062        protected BusinessObjectService businessObjectService;
063        protected DocumentService documentService;
064        protected ParameterService parameterService;
065        protected KualiRuleService kualiRuleService;
066        
067        protected KEMService kemService;
068        
069        protected PooledFundControlTransactionsDao pooledFundControlTransactionsDao;
070        
071        protected ReportWriterService pooledFundControlTransactionsExceptionReportWriterService;
072        protected ReportWriterService pooledFundControlTransactionsTotalReportWriterService;
073        
074        private TransactionDocumentTotalReportLine totalReportLine = null;    
075        private TransactionDocumentExceptionReportLine exceptionReportLine = null;
076        
077        /*
078         * @see org.kuali.kfs.module.endow.batch.service.PooledFundControlTransactionsService#generatePooledFundControlTransactions()
079         */
080        public boolean generatePooledFundControlTransactions() {
081            
082            LOG.info("Begin the batch Generate Pooled Fund Control Transactions ..."); 
083            
084            // prepare for reports
085            initializeReports();
086            
087            // All the jobs below should be attempted regardless of the status of another.
088            // In fact, all jobs in the process could be run concurrently.
089            // The job, itself, does not fail but completes with exceptions.
090            createCashDocumentForPurchase();   
091            createCashDocumentForSale();
092            createCashDocumentForSaleGainLoss();
093            createCashDocumentForIncomeDistribution();
094    
095            LOG.info("The batch Generate Pooled Fund Control Transactions was finished"); 
096            
097            return true;        
098        }
099        
100        /**
101         * Creates an ECI or an ECDD eDoc according to the total amount of holding cost for EAI
102         */
103        protected boolean createCashDocumentForPurchase() {
104            return createCashDocumentBasedOnHoldingCost(EndowConstants.DocumentTypeNames.ENDOWMENT_ASSET_INCREASE, EndowParameterKeyConstants.PURCHASE_DESCRIPTION, EndowConstants.TRANSACTION_SECURITY_TYPE_TARGET, EndowParameterKeyConstants.PURCHASE_NO_ROUTE_IND, EndowConstants.IncomePrincipalIndicator.PRINCIPAL);       
105        }
106    
107        /**
108         * Creates an ECI or an ECDD eDoc according to the total amount of holding cost for EAD
109         */
110        protected boolean createCashDocumentForSale() {        
111            return createCashDocumentBasedOnHoldingCost(EndowConstants.DocumentTypeNames.ENDOWMENT_ASSET_DECREASE, EndowParameterKeyConstants.SALE_DESCRIPTION, EndowConstants.TRANSACTION_SECURITY_TYPE_SOURCE, EndowParameterKeyConstants.SALE_NO_ROUTE_IND, EndowConstants.IncomePrincipalIndicator.PRINCIPAL);          
112        }
113        
114        /**
115         * Creates an ECI or an ECDD eDoc according to the total amount of holding cost 
116         * @param documentName
117         * @param DocDescription
118         * @param noRouteInd
119         * @param ipInd
120         */
121        protected boolean createCashDocumentBasedOnHoldingCost(String documentName, String DocDescription, String securityLineType, String noRouteInd, String ipInd) {
122            
123            List<String> documentTypeNames = new ArrayList<String>();
124            documentTypeNames.add(documentName);
125            List<PooledFundControl> pooledFundControlRecords = (List<PooledFundControl>) pooledFundControlTransactionsDao.getAllPooledFundControlTransaction();        
126            //if (pooledFundControlRecords == null) return;
127            
128            // generate a cash document per each PooledFundControl
129            // If one should fail, that would be an exception to report and the remainder that does not fail should continue.
130            for (PooledFundControl pooledFundControl : pooledFundControlRecords) {
131                KualiDecimal totalAmount = KualiDecimal.ZERO;
132                // get the list of TransactionArchiveSecurity that has the same security id and document name
133                List<TransactionArchiveSecurity> transactionArchiveSecurityRecords = pooledFundControlTransactionsDao.getTransactionArchiveSecurityWithSecurityId(pooledFundControl, documentTypeNames, kemService.getCurrentDate());
134                if (transactionArchiveSecurityRecords != null) {
135                    // get the total of security cost
136                    for (TransactionArchiveSecurity transactionArchiveSecurity : transactionArchiveSecurityRecords) {
137                        totalAmount = totalAmount.add(new KualiDecimal(transactionArchiveSecurity.getHoldingCost()));
138                    }               
139                }
140                
141                // create a cash document per security id of pooled fund control
142                if (totalAmount.isPositive()) {
143                    createECI(pooledFundControl, totalAmount, DocDescription, securityLineType, noRouteInd, ipInd);
144                } else if (totalAmount.isNegative()) {
145                    totalAmount = totalAmount.negated();
146                    createECDD(pooledFundControl, totalAmount, DocDescription, securityLineType, noRouteInd, ipInd);
147                }
148            }   
149            
150            return true;
151        }
152        
153        /**
154         * Creates an ECI or an ECDD eDoc according to the total amount of gain/loss for transaction type EAD
155         */
156        protected boolean createCashDocumentForSaleGainLoss() {
157            
158            List<String> documentTypeNames = new ArrayList<String>();
159            documentTypeNames.add(EndowConstants.DocumentTypeNames.ENDOWMENT_ASSET_DECREASE);
160            List<PooledFundControl> pooledFundControlRecords = (List<PooledFundControl>) pooledFundControlTransactionsDao.getAllPooledFundControlTransaction();        
161            //if (pooledFundControlRecords == null) return;
162            
163            // generate a cash document per each PooledFundControl
164            // If one should fail, that would be an exception to report and the remainder that does not fail should continue.
165            for (PooledFundControl pooledFundControl : pooledFundControlRecords) {
166                KualiDecimal totalAmount = KualiDecimal.ZERO;
167                // get the list of TransactionArchiveSecurity that has the same security id and document name
168                List<TransactionArchiveSecurity> transactionArchiveSecurityRecords = pooledFundControlTransactionsDao.getTransactionArchiveSecurityWithSecurityId(pooledFundControl, documentTypeNames, kemService.getCurrentDate());
169                // get the total of security long term and short term gain and loss
170                if (transactionArchiveSecurityRecords != null) {
171                    for (TransactionArchiveSecurity transactionArchiveSecurity : transactionArchiveSecurityRecords) {                         
172                        totalAmount = totalAmount.add(new KualiDecimal(transactionArchiveSecurity.getLongTermGainLoss()).add(new KualiDecimal(transactionArchiveSecurity.getShortTermGainLoss())));
173                    }
174                }
175                // create a cash document per security id of pooled fund control
176                // If the pool is paying out gains, the net value of the pool must be reduced (ECDD). 
177                // If it is 'recovering' (paying out) Losses, we must increase the value of the pool (ECI).
178                if (totalAmount.isPositive()) {
179                    createECDD(pooledFundControl, totalAmount, EndowParameterKeyConstants.GAIN_LOSS_DESCRIPTION, EndowConstants.TRANSACTION_SECURITY_TYPE_SOURCE, EndowParameterKeyConstants.GAIN_LOSS_NO_ROUTE_IND, EndowConstants.IncomePrincipalIndicator.PRINCIPAL);
180                } else if (totalAmount.isNegative()) {
181                    totalAmount = totalAmount.negated();
182                    createECI(pooledFundControl, totalAmount, EndowParameterKeyConstants.GAIN_LOSS_DESCRIPTION, EndowConstants.TRANSACTION_SECURITY_TYPE_SOURCE, EndowParameterKeyConstants.GAIN_LOSS_NO_ROUTE_IND, EndowConstants.IncomePrincipalIndicator.PRINCIPAL);
183                }
184            }    
185            
186            return true;
187        }
188        
189        /**
190         * Creates an ECI or an ECDD eDoc according to the total amount of income/principle cash for transaction type ECI and ECDD
191         */
192        protected boolean createCashDocumentForIncomeDistribution() {
193            
194            List<String> documentTypeNames = new ArrayList<String>();
195            documentTypeNames.add(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_INCREASE);
196            documentTypeNames.add(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_DECREASE);
197            List<PooledFundControl> pooledFundControlRecords = (List<PooledFundControl>) pooledFundControlTransactionsDao.getAllPooledFundControlTransaction();
198            //if (pooledFundControlRecords == null) return;
199            
200            // If one should fail, that would be an exception to report and the remainder that does not fail should continue.
201            for (PooledFundControl pooledFundControl : pooledFundControlRecords) {
202                KualiDecimal totalAmount = KualiDecimal.ZERO;
203                List<TransactionArchive> transactionArchiveRecords = pooledFundControlTransactionsDao.getTransactionArchiveWithSecurityAndDocNames(pooledFundControl, documentTypeNames, kemService.getCurrentDate());
204                if (transactionArchiveRecords != null) {
205                    for (TransactionArchive transactionArchive : transactionArchiveRecords) {
206                        totalAmount = totalAmount.add(new KualiDecimal(transactionArchive.getIncomeCashAmount())).add(new KualiDecimal(transactionArchive.getPrincipalCashAmount()));
207                    }
208                }
209                
210                // create a cash document per security id of pooled fund control
211                if (totalAmount.isPositive()) {
212                    createECDD(pooledFundControl, totalAmount, EndowParameterKeyConstants.INCOME_DESCRIPTION, EndowConstants.TRANSACTION_SECURITY_TYPE_SOURCE, EndowParameterKeyConstants.INCOME_NO_ROUTE_IND, EndowConstants.IncomePrincipalIndicator.INCOME); 
213                } else if (totalAmount.isNegative()) {
214                    totalAmount = totalAmount.negated();
215                    createECI(pooledFundControl, totalAmount, EndowParameterKeyConstants.INCOME_DESCRIPTION, EndowConstants.TRANSACTION_SECURITY_TYPE_SOURCE, EndowParameterKeyConstants.INCOME_NO_ROUTE_IND, EndowConstants.IncomePrincipalIndicator.INCOME);
216                }
217            }
218            
219            return true;
220        }
221        
222        /**
223         * Creates ECI
224         * @param pooledFundControl
225         * @param totalAmount
226         * @param paramDescriptionName
227         * @param securityLineType
228         * @param paramNoRouteInd
229         * @param incomePrincipalIndicator
230         * @return
231         */
232        protected boolean createECI(PooledFundControl pooledFundControl, KualiDecimal totalAmount, String paramDescriptionName, String securityLineTypeCode, String paramNoRouteInd, String incomePrincipalIndicator) {
233    
234            LOG.info("Creating ECI ..."); 
235    
236            boolean success = true;
237            CashIncreaseDocument cashIncreaseDocument = null; 
238            
239            // initialize CashIncreaseDocument
240            cashIncreaseDocument = initializeCashDocument(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_INCREASE, EndowConstants.MAXMUM_NUMBER_OF_EDOC_INITIALIZATION_TRY);
241            if (ObjectUtils.isNull(cashIncreaseDocument)) {
242                return false;
243            }        
244            cashIncreaseDocument.getDocumentHeader().setDocumentDescription(parameterService.getParameterValue(PooledFundControlTransactionsStep.class, paramDescriptionName));
245            cashIncreaseDocument.setTransactionSourceTypeCode(EndowConstants.TransactionSourceTypeCode.AUTOMATED);
246    
247            // set security and add a transaction line 
248            String etranTypeCode = getEtranTypeCode(pooledFundControl, paramDescriptionName);
249            populateECI(cashIncreaseDocument, pooledFundControl, totalAmount, securityLineTypeCode, incomePrincipalIndicator, etranTypeCode);
250    
251            // if there are transaction lines, proceed.   
252            if (cashIncreaseDocument.getNextTargetLineNumber() > 1) {            
253                // validate and submit it. Since we have only one transaction line for each ECI, we do not need to validate the transaction line separately
254                GlobalVariables.clear();
255                if (validateECI(cashIncreaseDocument)) {
256                    success = submitCashDocument(cashIncreaseDocument, EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_INCREASE, paramNoRouteInd);
257                    if (success) {
258                        writeTotalReport(cashIncreaseDocument, EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_INCREASE, incomePrincipalIndicator);
259                        LOG.info("Submitted an ECI successfully: document# " + cashIncreaseDocument.getDocumentNumber());
260                    }
261                } else {
262                    success = false;
263                    writeDocumentValdiationErrorReport(cashIncreaseDocument, EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_INCREASE);
264                    LOG.error("createECI() Validation Error: Document# " + cashIncreaseDocument.getDocumentHeader().getDocumentNumber()); 
265                    try {
266                        documentService.saveDocument(cashIncreaseDocument);
267                    } catch (WorkflowException wfe) {
268                        LOG.error("createECI() Saving Error: Document# " + cashIncreaseDocument.getDocumentHeader().getDocumentNumber() + " : " + wfe.getMessage());
269                    } 
270                }
271            } else {
272                LOG.error("ECI was not sumitted because no transaction lines are found in document# " + cashIncreaseDocument.getDocumentNumber());
273            }
274            
275            return success;
276        }
277       
278        /**
279         * Creates ECDD
280         * @param pooledFundControl
281         * @param totalAmount
282         * @param paramDescriptionName
283         * @param securityLineType
284         * @param paramNoRouteInd
285         * @param incomePrincipalIndicator
286         * @return
287         */
288        protected boolean createECDD(PooledFundControl pooledFundControl, KualiDecimal totalAmount, String paramDescriptionName, String securityLineType, String paramNoRouteInd, String incomePrincipalIndicator) {
289    
290            LOG.info("Creating ECDD ...");
291            
292            boolean success = true;
293            CashDecreaseDocument cashDecreaseDocument = null; 
294        
295            // initialize CashDecreaseDocument        
296            cashDecreaseDocument = initializeCashDocument(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_DECREASE, EndowConstants.MAXMUM_NUMBER_OF_EDOC_INITIALIZATION_TRY);
297            if (ObjectUtils.isNull(cashDecreaseDocument)) {
298                return false;
299            }        
300            cashDecreaseDocument.getDocumentHeader().setDocumentDescription(parameterService.getParameterValue(PooledFundControlTransactionsStep.class, paramDescriptionName));
301            cashDecreaseDocument.setTransactionSourceTypeCode(EndowConstants.TransactionSourceTypeCode.AUTOMATED);
302        
303            // set security and a transaction line
304            String etranTypeCode = getEtranTypeCode(pooledFundControl, paramDescriptionName);        
305            populateECDD(cashDecreaseDocument, pooledFundControl, totalAmount, securityLineType, incomePrincipalIndicator, etranTypeCode);
306    
307            // if there are transaction lines, proceed.   
308            if (cashDecreaseDocument.getNextSourceLineNumber() > 1) {
309                // validate and submit it. Since we have only one transaction line for each ECDD, we do not need to validate the transaction line separately
310                GlobalVariables.clear();
311                if (validateECDD(cashDecreaseDocument)) {
312                    success = submitCashDocument(cashDecreaseDocument, EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_DECREASE, paramNoRouteInd);
313                    if (success) {
314                        writeTotalReport(cashDecreaseDocument, EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_DECREASE, incomePrincipalIndicator);
315                        LOG.info("Submitted an ECDD successfully: document# " + cashDecreaseDocument.getDocumentNumber());
316                    }
317                } else {
318                    success = false;
319                    writeDocumentValdiationErrorReport(cashDecreaseDocument, EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_DECREASE);
320                    LOG.error("createECDD() Validation Error: Document# " + cashDecreaseDocument.getDocumentHeader().getDocumentNumber());
321                    try {
322                        documentService.saveDocument(cashDecreaseDocument);
323                    } catch (WorkflowException wfe) {
324                        LOG.error("createECDD() Saving Error: Document# " + cashDecreaseDocument.getDocumentHeader().getDocumentNumber() + " : " + wfe.getMessage());                    
325                    } 
326                }
327            } else {
328                LOG.error("ECDD was not sumitted because no transaction lines are found in document# " + cashDecreaseDocument.getDocumentNumber());
329            }
330    
331            return success;
332        } 
333        
334        /**
335         * Populates security and transaction lines 
336         * @param cashIncreaseDocument
337         * @param pooledFundControl
338         * @param totalAmount
339         * @param securityLineTypeCode
340         * @param transactionIPIndicatorCode
341         */
342        protected void populateECI(CashIncreaseDocument cashIncreaseDocument, PooledFundControl pooledFundControl, KualiDecimal totalAmount, String securityLineTypeCode, String transactionIPIndicatorCode, String etranTypeCode) {
343            
344            // create a transaction line - needs only one for this batch job
345            EndowmentTargetTransactionLine endowmentTargetTransactionLine = new EndowmentTargetTransactionLine();
346            endowmentTargetTransactionLine.setTransactionLineNumber(new Integer(1));
347            endowmentTargetTransactionLine.setKemid(pooledFundControl.getFundKEMID());
348            endowmentTargetTransactionLine.setEtranCode(etranTypeCode);
349            endowmentTargetTransactionLine.setTransactionIPIndicatorCode(transactionIPIndicatorCode);
350            endowmentTargetTransactionLine.setTransactionAmount(totalAmount);
351            
352            GlobalVariables.clear();        
353            if (validateTransactionLine(cashIncreaseDocument, endowmentTargetTransactionLine, EndowConstants.NEW_TARGET_TRAN_LINE_PROPERTY_NAME)) {
354                // add a transaction line -  only one for this batch            
355                cashIncreaseDocument.addTargetTransactionLine(endowmentTargetTransactionLine);
356                // set security
357                cashIncreaseDocument.getTargetTransactionSecurity().setSecurityLineTypeCode(securityLineTypeCode);
358                cashIncreaseDocument.getTargetTransactionSecurity().setSecurityID(pooledFundControl.getPooledSecurityID());   
359                cashIncreaseDocument.getTargetTransactionSecurity().setRegistrationCode(pooledFundControl.getFundRegistrationCode());  // 
360    
361            } else {
362                writeTransactionLineValidationErrorReport(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_INCREASE, cashIncreaseDocument.getDocumentNumber(), cashIncreaseDocument.getTargetTransactionSecurity().getSecurityID(), pooledFundControl.getFundKEMID(), totalAmount); 
363            }
364        }
365        
366        /**
367         * Populates security and transaction lines
368         * @param cashDecreaseDocument
369         * @param pooledFundControl
370         * @param totalAmount
371         * @param securityLineTypeCode
372         * @param transactionIPIndicatorCode
373         */
374        protected void populateECDD(CashDecreaseDocument cashDecreaseDocument, PooledFundControl pooledFundControl, KualiDecimal totalAmount, String securityLineTypeCode, String transactionIPIndicatorCode, String etranTypeCode) {
375            
376            // create a transaction line - needs only one for this batch job
377            EndowmentSourceTransactionLine endowmentSourceTransactionLine = new EndowmentSourceTransactionLine();
378            endowmentSourceTransactionLine.setTransactionLineNumber(new Integer(1));
379            endowmentSourceTransactionLine.setKemid(pooledFundControl.getFundKEMID());
380            endowmentSourceTransactionLine.setEtranCode(etranTypeCode);
381            endowmentSourceTransactionLine.setTransactionIPIndicatorCode(transactionIPIndicatorCode);
382            //endowmentSourceTransactionLine.setTransactionLineTypeCode(securityLineTypeCode);
383            endowmentSourceTransactionLine.setTransactionAmount(totalAmount);
384            
385            GlobalVariables.clear();
386            if (validateTransactionLine(cashDecreaseDocument, endowmentSourceTransactionLine, EndowConstants.NEW_SOURCE_TRAN_LINE_PROPERTY_NAME)) {
387                // add transaction line
388                cashDecreaseDocument.addSourceTransactionLine(endowmentSourceTransactionLine);
389                // set security
390                cashDecreaseDocument.getSourceTransactionSecurity().setSecurityLineTypeCode(securityLineTypeCode);
391                cashDecreaseDocument.getSourceTransactionSecurity().setSecurityID(pooledFundControl.getPooledSecurityID());
392                cashDecreaseDocument.getSourceTransactionSecurity().setRegistrationCode(pooledFundControl.getFundRegistrationCode());
393            } else {
394                writeTransactionLineValidationErrorReport(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_DECREASE, cashDecreaseDocument.getDocumentNumber(), cashDecreaseDocument.getSourceTransactionSecurity().getSecurityID(), pooledFundControl.getFundKEMID(), totalAmount);
395            }
396        }
397        
398        /**
399         * Initialize a cash document. If fails, try as many times as EndowConstants.MAXMUM_NUMBER_OF_EDOC_INITILIZATION_TRY.
400         * @param <C>
401         * @param documentType
402         * @param counter
403         * @return
404         */
405        protected <C extends EndowmentSecurityDetailsDocumentBase> C initializeCashDocument(String documentType, int counter) {
406            
407            C cashDocument = null;
408            
409            if (counter > 0) {
410                try {
411                    cashDocument = (C) getDocumentService().getNewDocument(SpringContext.getBean(TransactionalDocumentDictionaryService.class).getDocumentClassByName(documentType));
412                } catch (WorkflowException e) {
413                    LOG.error( (EndowConstants.MAXMUM_NUMBER_OF_EDOC_INITIALIZATION_TRY - counter + 1) + ": The creation of " + documentType + " failed. Tyring it again ...");
414                    cashDocument = (C) initializeCashDocument(documentType, --counter);
415                }
416            } 
417            
418            return cashDocument;
419        }
420        
421        /**
422         * Submits the document
423         * @param <T>
424         * @param cashDocument
425         * @param documentType
426         * @param paramNoRouteInd
427         * @return
428         */
429        protected <T extends EndowmentSecurityDetailsDocumentBase> boolean submitCashDocument(T cashDocument, String documentType, String paramNoRouteInd) {
430    
431            boolean success = false;
432            
433            try {
434                cashDocument.setNoRouteIndicator(isNoRoute(paramNoRouteInd));
435                documentService.routeDocument(cashDocument, "Submitted by the batch job", null);
436                success = true;
437            } catch (WorkflowException wfe) {
438                writeSubmissionErrorReport(cashDocument, documentType, wfe.getMessage());
439                LOG.error("submitCashDocument() Routing Error: Document# " + cashDocument.getDocumentHeader().getDocumentNumber() + " : " + wfe.getMessage());
440                try {
441                    documentService.saveDocument(cashDocument);
442                } catch (WorkflowException wfe2) {
443                    LOG.error("submitCashDocument() Saving Error: Document# " + cashDocument.getDocumentHeader().getDocumentNumber() + " : " + wfe2.getMessage());
444                } 
445            } catch (Exception e) {  // in case
446                writeSubmissionErrorReport(cashDocument, documentType, e.getMessage());
447                LOG.error("submitCashDocument() Runtime Error: Document# " + cashDocument.getDocumentHeader().getDocumentNumber() + " : " + e.getMessage());
448                try {
449                    documentService.saveDocument(cashDocument);
450                } catch (WorkflowException wfe3) {
451                    LOG.error("submitCashDocument() Saving Error: Document# " + cashDocument.getDocumentHeader().getDocumentNumber() + " : " + wfe3.getMessage());
452                }                          
453            }
454            
455            return success;
456        }       
457            
458        /**
459         * Validate Cash Transaction line
460         * @param <C>
461         * @param <T>
462         * @param cashDocument
463         * @param endowmentTransactionLine
464         * @param trnsactionPropertyName
465         * @return
466         */
467        protected <C extends EndowmentSecurityDetailsDocumentBase, T extends EndowmentTransactionLineBase> boolean validateTransactionLine(C cashDocument, T endowmentTransactionLine, String trnsactionPropertyName) {
468            return kualiRuleService.applyRules(new AddTransactionLineEvent(trnsactionPropertyName, cashDocument, endowmentTransactionLine));
469        }
470        
471        /**
472         * validate the ECI business rules 
473         * @param cashIncreaseDocument
474         * @return boolean
475         */
476        protected boolean validateECI(CashIncreaseDocument cashIncreaseDocument) {        
477            return kualiRuleService.applyRules(new RouteDocumentEvent(cashIncreaseDocument));
478        }
479        
480        /**
481         * validate the ECDD business rules
482         * @param cashDecreaseDocument
483         * @return boolean
484         */
485        protected boolean validateECDD(CashDecreaseDocument cashDecreaseDocument) {
486            return kualiRuleService.applyRules(new RouteDocumentEvent(cashDecreaseDocument));
487        }
488        
489        /**
490         * Gets the transaction type code based on the document component type
491         * @param pooledFundControl
492         * @param docComponentType
493         * @return
494         */
495        protected String getEtranTypeCode(PooledFundControl pooledFundControl, String docComponentType) {
496            String etranTypeCode = "";
497            if (docComponentType.equalsIgnoreCase(EndowParameterKeyConstants.PURCHASE_DESCRIPTION)) {
498                etranTypeCode = pooledFundControl.getFundAssetPurchaseOffsetTranCode();
499            } else if (docComponentType.equalsIgnoreCase(EndowParameterKeyConstants.SALE_DESCRIPTION)) {
500                etranTypeCode = pooledFundControl.getFundAssetSaleOffsetTranCode();
501            } else if (docComponentType.equalsIgnoreCase(EndowParameterKeyConstants.GAIN_LOSS_DESCRIPTION)) {
502                etranTypeCode = pooledFundControl.getFundSaleGainLossOffsetTranCode();
503            } else if (docComponentType.equalsIgnoreCase(EndowParameterKeyConstants.INCOME_DESCRIPTION)) {
504                etranTypeCode = pooledFundControl.getFundCashDepositOffsetTranCode();
505            }
506            
507            return etranTypeCode;
508        }
509        
510        /**
511         * check if it is no route 
512         * @return boolean
513         */
514        public boolean isNoRoute(String paramNoRouteInd) {        
515            return parameterService.getIndicatorParameter(PooledFundControlTransactionsStep.class, paramNoRouteInd);
516        }
517        
518        /**
519         * Writes the total report
520         * @param <C>
521         * @param cashDocument
522         * @param documentType
523         */
524        protected <C extends EndowmentSecurityDetailsDocumentBase> void writeTotalReport(C cashDocument, String documentType, String incomePrincipalIndicator) {
525            totalReportLine.setDocumentType(documentType);
526            totalReportLine.setDocumentId(cashDocument.getDocumentNumber());
527            totalReportLine.setSecurityId(cashDocument.getTargetTransactionSecurity().getSecurityID());
528            if (incomePrincipalIndicator.equalsIgnoreCase(EndowConstants.IncomePrincipalIndicator.PRINCIPAL)) {
529                totalReportLine.setPrincipalAmount(cashDocument.getTargetPrincipalTotal().add(cashDocument.getSourcePrincipalTotal()));
530                totalReportLine.setPrincipalUnits(cashDocument.getTargetPrincipalTotalUnits().add(cashDocument.getSourcePrincipalTotalUnits()));
531            } else if (incomePrincipalIndicator.equalsIgnoreCase(EndowConstants.IncomePrincipalIndicator.INCOME)) {
532                totalReportLine.setIncomeAmount(cashDocument.getTargetIncomeTotal().add(cashDocument.getSourceIncomeTotal()));
533                totalReportLine.setIncomeUnits(cashDocument.getTargetIncomeTotalUnits().add(cashDocument.getSourceIncomeTotalUnits()));
534            }
535            if (cashDocument.getNextTargetLineNumber() > 1) {
536                totalReportLine.setTotalNumberOfTransactionLines(cashDocument.getNextTargetLineNumber() - 1);
537            } else {
538                totalReportLine.setTotalNumberOfTransactionLines(cashDocument.getNextSourceLineNumber() - 1);
539            }
540            pooledFundControlTransactionsTotalReportWriterService.writeTableRow(totalReportLine);
541            
542            // reset for the next total report
543            totalReportLine.setTotalNumberOfTransactionLines(0);
544            totalReportLine.setPrincipalAmount(KualiDecimal.ZERO);
545            totalReportLine.setPrincipalUnits(KualiDecimal.ZERO);
546            totalReportLine.setIncomeAmount(KualiDecimal.ZERO);
547            totalReportLine.setIncomeUnits(KualiDecimal.ZERO);
548        }
549            
550        /**
551         * Writes transaction line validation errors per each
552         * @param documentType
553         * @param kemid
554         * @param transactionAmount
555         */
556        protected void writeTransactionLineValidationErrorReport(String documentType, String documentId, String securityId, String kemid, KualiDecimal transactionAmount) {
557            exceptionReportLine.setDocumentType(documentType);
558            exceptionReportLine.setDocumentId(documentId);
559            exceptionReportLine.setSecurityId(securityId);
560            exceptionReportLine.setKemid(kemid);
561            exceptionReportLine.setIncomeAmount(transactionAmount);
562            pooledFundControlTransactionsExceptionReportWriterService.writeTableRow(exceptionReportLine);
563            
564            List<String> errorMessages = GloabalVariablesExtractHelper.extractGlobalVariableErrors();
565            for (String errorMessage : errorMessages) {
566                pooledFundControlTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", errorMessage);
567            }
568            pooledFundControlTransactionsExceptionReportWriterService.writeNewLines(1);
569        }
570        
571        /**
572         * Writes document validation errors
573         * @param <T>
574         * @param cashDocument
575         * @param documentType
576         */
577        protected <T extends EndowmentSecurityDetailsDocumentBase> void writeDocumentValdiationErrorReport(T cashDocument, String documentType) {
578            exceptionReportLine.setDocumentType(documentType);
579            exceptionReportLine.setDocumentId(cashDocument.getDocumentNumber());
580            exceptionReportLine.setSecurityId(cashDocument.getTargetTransactionSecurity().getSecurityID());
581            exceptionReportLine.setIncomeAmount(cashDocument.getTargetIncomeTotal());
582            pooledFundControlTransactionsExceptionReportWriterService.writeTableRow(exceptionReportLine);
583            
584            List<String> errorMessages = GloabalVariablesExtractHelper.extractGlobalVariableErrors();
585            for (String errorMessage : errorMessages) {
586                pooledFundControlTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", errorMessage);
587            }
588            pooledFundControlTransactionsExceptionReportWriterService.writeNewLines(1);
589        }
590        
591        /** 
592         * Writes the submission errors
593         * @param <T>
594         * @param cashDocument
595         * @param documentType
596         */
597        protected <T extends EndowmentSecurityDetailsDocumentBase> void writeSubmissionErrorReport(T cashDocument, String documentType, String errorMessage) {
598            exceptionReportLine.setDocumentType(documentType);
599            exceptionReportLine.setDocumentId(cashDocument.getDocumentNumber());
600            exceptionReportLine.setSecurityId(cashDocument.getTargetTransactionSecurity().getSecurityID());
601            exceptionReportLine.setIncomeAmount(cashDocument.getTargetIncomeTotal());
602            pooledFundControlTransactionsExceptionReportWriterService.writeTableRow(exceptionReportLine);
603            pooledFundControlTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", errorMessage);
604            pooledFundControlTransactionsExceptionReportWriterService.writeNewLines(1);
605        }
606        
607        /**
608         * Initializes reports
609         */
610        protected void initializeReports() {
611    
612            // initialize totalReportLine  
613            this.totalReportLine = new TransactionDocumentTotalReportLine();
614            pooledFundControlTransactionsTotalReportWriterService.writeSubTitle("<pooledFundControlTransactionsJob> Totals Processed");
615            pooledFundControlTransactionsTotalReportWriterService.writeNewLines(1);
616            pooledFundControlTransactionsTotalReportWriterService.writeTableHeader(totalReportLine);
617    
618            // initialize exceptionReportLine 
619            this.exceptionReportLine = new TransactionDocumentExceptionReportLine();
620            pooledFundControlTransactionsExceptionReportWriterService.writeSubTitle("<pooledFundControlTransactionsJob> Exception Report");
621            pooledFundControlTransactionsExceptionReportWriterService.writeNewLines(1);
622            pooledFundControlTransactionsExceptionReportWriterService.writeTableHeader(exceptionReportLine); 
623        }
624            
625        /**
626         * Sets the businessObjectService attribute value.
627         * @param businessObjectService The businessObjectService to set.
628         */
629        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
630            this.businessObjectService = businessObjectService;
631        }
632        
633        /**
634         * Sets the pooledFundControlTransactionsDaoOjb attribute value.
635         * @param pooledFundControlTransactionsDaoOjb The pooledFundControlTransactionsDaoOjb to set.
636         */
637        public void setPooledFundControlTransactionsDao(PooledFundControlTransactionsDao pooledFundControlTransactionsDao) {
638            this.pooledFundControlTransactionsDao = pooledFundControlTransactionsDao;
639        }
640    
641        /**
642         * Gets the documentService attribute. 
643         * @return Returns the documentService.
644         */
645        public DocumentService getDocumentService() {
646            return documentService;
647        }
648    
649        /**
650         * Sets the documentService attribute value.
651         * @param documentService The documentService to set.
652         */
653        public void setDocumentService(DocumentService documentService) {
654            this.documentService = documentService;
655        }
656    
657        /**
658         * Sets the kualiRuleService attribute value.
659         * @param kualiRuleService The kualiRuleService to set.
660         */
661        public void setKualiRuleService(KualiRuleService kualiRuleService) {
662            this.kualiRuleService = kualiRuleService;
663        }
664        
665        /**
666         * Sets the parameterService attribute value.
667         * @param parameterService The parameterService to set.
668         */
669        public void setParameterService(ParameterService parameterService) {
670            this.parameterService = parameterService;
671        }
672    
673        /**
674         * Sets the pooledFundControlTransactionsExceptionReportWriterService attribute value.
675         * @param pooledFundControlTransactionsExceptionReportWriterService The pooledFundControlTransactionsExceptionReportWriterService to set.
676         */
677        public void setPooledFundControlTransactionsExceptionReportWriterService(ReportWriterService pooledFundControlTransactionsExceptionReportWriterService) {
678            this.pooledFundControlTransactionsExceptionReportWriterService = pooledFundControlTransactionsExceptionReportWriterService;
679        }
680    
681        /**
682         * Sets the pooledFundControlTransactionsTotalReportWriterService attribute value.
683         * @param pooledFundControlTransactionsTotalReportWriterService The pooledFundControlTransactionsTotalReportWriterService to set.
684         */
685        public void setPooledFundControlTransactionsTotalReportWriterService(ReportWriterService pooledFundControlTransactionsTotalReportWriterService) {
686            this.pooledFundControlTransactionsTotalReportWriterService = pooledFundControlTransactionsTotalReportWriterService;
687        }
688    
689        /**
690         * Sets the kemService attribute value.
691         * @param kemService The kemService to set.
692         */
693        public void setKemService(KEMService kemService) {
694            this.kemService = kemService;
695        }
696        
697    }