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.math.BigDecimal;
019    import java.sql.Date;
020    import java.util.ArrayList;
021    import java.util.Collection;
022    import java.util.HashMap;
023    import java.util.List;
024    
025    import org.kuali.kfs.module.endow.EndowConstants;
026    import org.kuali.kfs.module.endow.EndowPropertyConstants;
027    import org.kuali.kfs.module.endow.batch.service.KemidFeeService;
028    import org.kuali.kfs.module.endow.batch.service.ProcessFeeTransactionsService;
029    import org.kuali.kfs.module.endow.businessobject.EndowmentExceptionReportHeader;
030    import org.kuali.kfs.module.endow.businessobject.EndowmentSourceTransactionLine;
031    import org.kuali.kfs.module.endow.businessobject.FeeMethod;
032    import org.kuali.kfs.module.endow.businessobject.FeeProcessingTotalsProcessedDetailTotalLine;
033    import org.kuali.kfs.module.endow.businessobject.FeeProcessingTotalsProcessedGrandTotalLine;
034    import org.kuali.kfs.module.endow.businessobject.FeeProcessingTotalsProcessedReportHeader;
035    import org.kuali.kfs.module.endow.businessobject.FeeProcessingTotalsProcessedSubTotalLine;
036    import org.kuali.kfs.module.endow.businessobject.FeeProcessingWaivedAndAccruedDetailTotalLine;
037    import org.kuali.kfs.module.endow.businessobject.FeeProcessingWaivedAndAccruedGrandTotalLine;
038    import org.kuali.kfs.module.endow.businessobject.FeeProcessingWaivedAndAccruedReportHeader;
039    import org.kuali.kfs.module.endow.businessobject.FeeProcessingWaivedAndAccruedSubTotalLine;
040    import org.kuali.kfs.module.endow.businessobject.KemidFee;
041    import org.kuali.kfs.module.endow.dataaccess.CurrentTaxLotBalanceDao;
042    import org.kuali.kfs.module.endow.dataaccess.HoldingHistoryDao;
043    import org.kuali.kfs.module.endow.dataaccess.KemidFeeDao;
044    import org.kuali.kfs.module.endow.dataaccess.TransactionArchiveDao;
045    import org.kuali.kfs.module.endow.document.CashDecreaseDocument;
046    import org.kuali.kfs.module.endow.document.service.FeeMethodService;
047    import org.kuali.kfs.module.endow.document.service.KEMService;
048    import org.kuali.kfs.module.endow.document.service.TransactionArchiveService;
049    import org.kuali.kfs.module.endow.document.validation.event.AddTransactionLineEvent;
050    import org.kuali.kfs.module.endow.util.GloabalVariablesExtractHelper;
051    import org.kuali.kfs.module.endow.util.KEMCalculationRoundingHelper;
052    import org.kuali.kfs.sys.KFSConstants;
053    import org.kuali.kfs.sys.context.SpringContext;
054    import org.kuali.kfs.sys.service.ReportWriterService;
055    import org.kuali.rice.kew.exception.WorkflowException;
056    import org.kuali.rice.kim.bo.Person;
057    import org.kuali.rice.kim.service.PersonService;
058    import org.kuali.rice.kns.bo.Note;
059    import org.kuali.rice.kns.rule.event.RouteDocumentEvent;
060    import org.kuali.rice.kns.service.DocumentService;
061    import org.kuali.rice.kns.service.KNSServiceLocator;
062    import org.kuali.rice.kns.service.KualiConfigurationService;
063    import org.kuali.rice.kns.service.KualiRuleService;
064    import org.kuali.rice.kns.service.NoteService;
065    import org.kuali.rice.kns.service.TransactionalDocumentDictionaryService;
066    import org.kuali.rice.kns.util.KualiDecimal;
067    import org.kuali.rice.kns.util.ObjectUtils;
068    import org.springframework.transaction.annotation.Transactional;
069    
070    /**
071     * This class implements the ProcessFeeTransactionsService.
072     */
073    @Transactional
074    public class ProcessFeeTransactionsServiceImpl implements ProcessFeeTransactionsService {
075        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ProcessFeeTransactionsServiceImpl.class);
076        
077        protected KemidFeeService kemidFeeService;
078        protected FeeMethodService feeMethodService;
079        protected KEMService kemService;
080        protected TransactionArchiveDao transactionArchiveDao;
081        protected HoldingHistoryDao holdingHistoryDao;
082        protected CurrentTaxLotBalanceDao currentTaxLotBalanceDao;
083        protected KemidFeeDao kemidFeeDao;
084        protected DocumentService documentService;
085        protected KualiRuleService kualiRuleService;
086        protected NoteService noteService;
087        protected PersonService personService;
088        protected KualiConfigurationService configService;
089        
090        protected ReportWriterService processFeeTransactionsExceptionReportsWriterService;
091        protected ReportWriterService processFeeTransactionsTotalProcessedReportsWriterService;
092        protected ReportWriterService processFeeTransactionsWaivedAndAccruedFeesReportsWriterService;
093        
094        protected EndowmentExceptionReportHeader processFeeTransactionsExceptionReportHeader;
095        protected FeeProcessingTotalsProcessedReportHeader processFeeTransactionsTotalProcessedReportHeader;
096        protected FeeProcessingWaivedAndAccruedReportHeader processFeeTransactionsWaivedAndAccruedFeesReportHeader;    
097        
098        protected EndowmentExceptionReportHeader processFeeTransactionsRowValues;
099        protected EndowmentExceptionReportHeader processFeeTransactionsExceptionRowReason;    
100        
101        protected FeeProcessingWaivedAndAccruedDetailTotalLine feeProcessingWaivedAndAccruedDetailTotalLine;
102        protected FeeProcessingWaivedAndAccruedSubTotalLine feeProcessingWaivedAndAccruedSubTotalLine;
103        protected FeeProcessingWaivedAndAccruedGrandTotalLine feeProcessingWaivedAndAccruedGrandTotalLine;
104    
105        protected FeeProcessingTotalsProcessedDetailTotalLine feeProcessingTotalsProcessedDetailTotalLine;
106        protected FeeProcessingTotalsProcessedSubTotalLine feeProcessingTotalsProcessedSubTotalLine;
107        protected FeeProcessingTotalsProcessedGrandTotalLine feeProcessingTotalsProcessedGrandTotalLine;
108        
109        //the properties to hold count, total amounts and fee etc.
110        protected long totalNumberOfRecords = 0;
111        protected BigDecimal totalAmountCalculated = BigDecimal.ZERO;
112        protected BigDecimal feeToBeCharged = BigDecimal.ZERO;    
113        protected BigDecimal transactionIncomeAmount = BigDecimal.ZERO;
114        protected BigDecimal transacationPrincipalAmount = BigDecimal.ZERO;
115        protected BigDecimal totalHoldingUnits = BigDecimal.ZERO;
116        
117        //properties to help in writing subtotals and grand totals lines.
118        //lines generated
119        protected int totalProcessedLinesGeneratedSubTotal = 0;
120        protected int totalProcessedLinesGeneratedGrandTotal = 0;
121        
122        //income, principal subtotals at the eDoc level
123        protected BigDecimal totalProcessedIncomeAmountSubTotalEDoc = BigDecimal.ZERO; 
124        protected BigDecimal totalProcessedPrincipalAmountSubTotalEDoc = BigDecimal.ZERO; 
125        
126        //income, principal subtotals at the fee method level
127        protected BigDecimal totalProcessedIncomeAmountSubTotal = BigDecimal.ZERO; 
128        protected BigDecimal totalProcessedPrincipalAmountSubTotal = BigDecimal.ZERO; 
129        
130        //income, principal subtotals at the grand total level
131        protected BigDecimal totalProcessedIncomeAmountGrandTotal = BigDecimal.ZERO; 
132        protected BigDecimal totalProcessedPrincipalAmountGrandTotal = BigDecimal.ZERO; 
133        
134        /**
135         * Constructs a HoldingHistoryMarketValuesUpdateServiceImpl instance
136         */
137        public ProcessFeeTransactionsServiceImpl() {
138            //report writer headers
139            processFeeTransactionsExceptionReportHeader = new EndowmentExceptionReportHeader();
140            processFeeTransactionsTotalProcessedReportHeader = new FeeProcessingTotalsProcessedReportHeader();
141            processFeeTransactionsWaivedAndAccruedFeesReportHeader = new FeeProcessingWaivedAndAccruedReportHeader();
142            
143            processFeeTransactionsRowValues = new EndowmentExceptionReportHeader();
144            processFeeTransactionsExceptionRowReason = new EndowmentExceptionReportHeader();  
145            
146            //waiver and accrual report....
147            feeProcessingWaivedAndAccruedDetailTotalLine = new FeeProcessingWaivedAndAccruedDetailTotalLine();
148            feeProcessingWaivedAndAccruedSubTotalLine = new FeeProcessingWaivedAndAccruedSubTotalLine();
149            feeProcessingWaivedAndAccruedGrandTotalLine = new FeeProcessingWaivedAndAccruedGrandTotalLine();
150            
151            //Totals processed report....
152            feeProcessingTotalsProcessedDetailTotalLine = new FeeProcessingTotalsProcessedDetailTotalLine();
153            feeProcessingTotalsProcessedSubTotalLine = new FeeProcessingTotalsProcessedSubTotalLine();
154            feeProcessingTotalsProcessedGrandTotalLine = new FeeProcessingTotalsProcessedGrandTotalLine();
155        }
156    
157        /**
158         * The fee process is intended to provide as much flexibility to the institution as possible when 
159         * designing the charges to be assessed against a KEMID.  The fees can be based on either balances 
160         * or activity and can be charged, accrued or waived at the KEMID level.
161         * @see oorg.kuali.kfs.module.endow.batch.service.ProcessFeeTransactionsService#processFeeTransactions()\
162         * return boolean true if successful else false
163         */
164        public boolean processFeeTransactions() {
165            LOG.info("processFeeTransactions() started");
166            
167            boolean success = true;
168            
169            writeReportHeaders();
170            
171            if (!updateKemidFeeWaivedYearToDateAmount()) {
172                writeTableRowAndTableReason("Reason: unable to update update Waiver Fee Year To Date column to Zero.");
173                return false;
174            }
175            
176            //Update the fee transactions.
177            success &= processUpdateFeeTransactions();
178            
179            //generate the waived and accrued report...
180            success &= generateWaivedAndAccruedReport();
181            
182            return success;
183        }
184        
185        /**
186         * Updates waived fee year to date column to zero in WAIVED_FEE_YTD
187         * @return true if updated successfully else return false
188         */
189        protected boolean updateKemidFeeWaivedYearToDateAmount() {
190            LOG.info("updateKemidFeeWaivedFeeYearToDateToZero() started"); 
191            
192            // 6.2.1 Basic Process - Step 1:
193            boolean updated = true;
194            
195            if (!kemidFeeDao.updateKemidFeeWaivedFeeYearToDateToZero()) {
196                writeTableRowAndTableReason("Batch Process Fee Transactions job is aborted.  Unable to update KEMID Year-To-Date Waiver Fee amounts");
197                return false;
198            }
199            
200            LOG.info("updateKemidFeeWaivedFeeYearToDateToZero() ended."); 
201            return updated;
202        }
203        
204        /**
205         * Writes the reports headers for totals processed, waived and accrued fee, and exceptions reports.
206         */
207        protected void writeReportHeaders() {
208            //writes the exception report header
209            processFeeTransactionsExceptionReportsWriterService.writeNewLines(1);
210            processFeeTransactionsExceptionReportsWriterService.writeTableHeader(processFeeTransactionsExceptionReportHeader);
211    
212            //writes the Waived and Accrued Fees report header....
213            processFeeTransactionsWaivedAndAccruedFeesReportsWriterService.writeNewLines(1);
214            processFeeTransactionsWaivedAndAccruedFeesReportsWriterService.writeTableHeader(processFeeTransactionsWaivedAndAccruedFeesReportHeader);
215            
216            //writes the Totals Processed report header....
217            processFeeTransactionsTotalProcessedReportsWriterService.writeNewLines(1);
218            processFeeTransactionsTotalProcessedReportsWriterService.writeTableHeader(processFeeTransactionsTotalProcessedReportHeader);
219        }
220        
221        /**
222         * Processes update Fee Transactions
223         */
224        protected boolean processUpdateFeeTransactions() {
225            LOG.info("processUpdateFeeTransactions() started"); 
226            
227            boolean success = true;
228            
229            java.util.Date currentDate = kemService.getCurrentDate();
230            int maxNumberOfTransactionLinesPerDocument = kemService.getMaxNumberOfTransactionLinesPerDocument();
231            
232            Collection<FeeMethod> feeMethods = feeMethodService.getFeeMethodsByNextProcessingDate(currentDate);
233            for (FeeMethod feeMethod : feeMethods) {
234                String feeTypeCode = feeMethod.getFeeTypeCode();
235                
236               //1. IF the END_FEE_MTHD_T:  FEE_TYP_CD is equal to T (Transactions)
237                if (feeTypeCode.equals(EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_TRANSACTIONS)) {
238                    processTransactionArchivesCountForTransactionsFeeType(feeMethod);
239                }
240                
241                //2. IF the END_FEE_MTHD_T:  FEE_TYP_CD is equal to B (Balance)
242                if (feeTypeCode.equals(EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_BALANCES)) {
243                    processBalanceFeeType(feeMethod);
244                }
245                
246                if (feeTypeCode.equals(EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_TRANSACTIONS) ||
247                    feeTypeCode.equals(EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_BALANCES)) {    
248                    performCalculationsForKemId(feeMethod);
249                    success &= generateCashDecreaseDocument(feeMethod, maxNumberOfTransactionLinesPerDocument);
250                }
251            }
252            
253            if (feeMethods.size() > 0) { //REMOVE
254                // write out the grand totals line for Totals processed report...
255                writeTotalsProcessedGrandTotalsLine();
256            }
257            
258            LOG.info("processUpdateFeeTransactions() ended."); 
259            
260            return success;
261        }
262        
263        /**
264         * Generates the fee waived and fee accrued report
265         */
266        protected boolean generateWaivedAndAccruedReport() {
267            LOG.info("generateWaivedAndAccruedReport() started"); 
268            
269            boolean success = true;
270            KualiDecimal accruedFeeGrandTotal = KualiDecimal.ZERO;
271            KualiDecimal waivedFeeGrandTotal = KualiDecimal.ZERO;
272            
273            Date currentDate = kemService.getCurrentDate();
274            
275            Collection<FeeMethod> feeMethods = feeMethodService.getFeeMethodsByNextProcessingDate(currentDate);
276    
277            for (FeeMethod feeMethod : feeMethods) {
278                KualiDecimal accruedFeeSubTotal = KualiDecimal.ZERO;
279                KualiDecimal waivedFeeSubTotal = KualiDecimal.ZERO;
280                
281                Collection<KemidFee> kemidFeeRecords = kemidFeeService.getAllKemidForFeeMethodCode(feeMethod.getCode());
282                
283                for (KemidFee kemidFee : kemidFeeRecords) {
284                    feeProcessingWaivedAndAccruedDetailTotalLine.setTotal(feeMethod.getCode());
285                    feeProcessingWaivedAndAccruedDetailTotalLine.setKemid(kemidFee.getKemid());
286                    feeProcessingWaivedAndAccruedDetailTotalLine.setTotalAccruedFees(kemidFee.getTotalAccruedFees());
287                    feeProcessingWaivedAndAccruedDetailTotalLine.setTotalWaivedFees(kemidFee.getTotalWaivedFees());
288    
289                    processFeeTransactionsWaivedAndAccruedFeesReportsWriterService.writeTableRow(feeProcessingWaivedAndAccruedDetailTotalLine);
290                    
291                    accruedFeeSubTotal = accruedFeeSubTotal.add(kemidFee.getTotalAccruedFees());
292                    waivedFeeSubTotal = waivedFeeSubTotal.add(kemidFee.getTotalWaivedFees());
293                }
294                
295                feeProcessingWaivedAndAccruedSubTotalLine.setTotalAccruedFees(accruedFeeSubTotal);
296                feeProcessingWaivedAndAccruedSubTotalLine.setTotalWaivedFees(waivedFeeSubTotal);
297                
298                if (kemidFeeRecords.size() > 0) {
299                    processFeeTransactionsWaivedAndAccruedFeesReportsWriterService.writeTableRow(feeProcessingWaivedAndAccruedSubTotalLine);
300                    processFeeTransactionsWaivedAndAccruedFeesReportsWriterService.writeNewLines(1);
301                }
302                accruedFeeGrandTotal = accruedFeeGrandTotal.add(accruedFeeSubTotal);
303                waivedFeeGrandTotal = waivedFeeGrandTotal.add(waivedFeeSubTotal);
304            }
305            
306            feeProcessingWaivedAndAccruedGrandTotalLine.setTotalAccruedFees(accruedFeeGrandTotal);
307            feeProcessingWaivedAndAccruedGrandTotalLine.setTotalWaivedFees(waivedFeeGrandTotal);
308            processFeeTransactionsWaivedAndAccruedFeesReportsWriterService.writeTableRow(feeProcessingWaivedAndAccruedGrandTotalLine);
309            
310            LOG.info("generateWaivedAndAccruedReport() ended."); 
311            
312            return success;
313        }
314        
315        /**
316         * IF the END_FEE_MTHD_T:  FEE_TYP_CD is equal to T (Transactions), then the fee 
317         * will use the transaction records from END_TRAN_ARCHV_T to calculate the fee.
318         * IF the END_FEE_MTHD_T:  FEE_RT_DEF_CD is equal to C (Count), then the process will total 
319         * the number of the records that fit the selection criteria (6.2.2.1) where the 
320         * END_TRAN_ARCHV_T:TRAN_PSTD_DT is greater than the END_KEMID_FEE_TFEE_MTHD_T: FEE_LST_PROC_DT.
321         * IF the END_FEE_MTHD_T: FEE_RT_DEF_CD is equal to V (Value), then the process will total 
322         * the TRAN_INC_CSH_AMT, and/or TRAN_PRIN_CSH_AMT of the records that fit the selection 
323         * criteria (6.2.2.1) where the END_TRAN_ARCHV_T:  TRAN_PSTD_DT is greater than the 
324         * END_KEMID_FEE_TFEE_MTHD_T: FEE_LST_PROC_DT.
325         */
326        protected void processTransactionArchivesCountForTransactionsFeeType(FeeMethod feeMethod) {
327            // case: FEE_RT_DEF_CD = C for count
328            if (feeMethod.getFeeRateDefinitionCode().equalsIgnoreCase(EndowConstants.FeeMethod.FEE_RATE_DEFINITION_CODE_FOR_COUNT)) {
329                totalNumberOfRecords = transactionArchiveDao.getTransactionArchivesCountForTransactions(feeMethod);
330                totalAmountCalculated = KEMCalculationRoundingHelper.multiply(feeMethod.getFirstFeeRate(), BigDecimal.valueOf(totalNumberOfRecords), EndowConstants.Scale.SECURITY_INCOME_RATE);
331            }
332                
333            // case: FEE_RT_DEF_CD = V for value...
334            if (feeMethod.getFeeRateDefinitionCode().equalsIgnoreCase(EndowConstants.FeeMethod.FEE_RATE_DEFINITION_CODE_FOR_VALUE)) {
335                HashMap<String, BigDecimal> incomeAndPrincipalValues = transactionArchiveDao.getTransactionArchivesIncomeAndPrincipalCashAmountForTransactions(feeMethod);
336                transactionIncomeAmount = incomeAndPrincipalValues.get(EndowPropertyConstants.TRANSACTION_ARCHIVE_INCOME_CASH_AMOUNT);
337                transacationPrincipalAmount = incomeAndPrincipalValues.get(EndowPropertyConstants.TRANSACTION_ARCHIVE_PRINCIPAL_CASH_AMOUNT);
338            }
339        }
340        
341        /**
342         * IF fee rate code is equal to C (Count), then process will examine the number of units held and
343         *      If fee balance type code is equal to AU (Average Units) the process will total the holding units
344         *         where month end date is greater than last process date divided by number of records selected.
345         *      If fee balance type code is equal to MU (Month End Units) the process will total holding units
346         *         for all records where the END_ME_DT_T: ME_DT is the most recent date.
347         *      If the fee balance type code is equal to CU (Current Units) the process will total the holding units
348         *
349         *  IF rate def code is equal to V (Value), then the process will examine the Market Value of the records.
350         *      If fee balance type code is equal to AMV (Average Market Value) the process will total holding market value
351         *         where month end date is greater last process date and divide the result by the number of records selected.
352         *      If fee balance type code is equal to MMV (Month End market Value) the process will 
353         *         total holding market value for all records where month end date is the most recent date.
354         *      If fee balance type code is equal to CMV (Current Market Value) the process will 
355         *         total holding market value for all selected records.
356         */
357        protected void processBalanceFeeType(FeeMethod feeMethod) {
358            if (feeMethod.getFeeRateDefinitionCode().equalsIgnoreCase(EndowConstants.FeeMethod.FEE_RATE_DEFINITION_CODE_FOR_COUNT)) {
359                //when FEE_BAL_TYP_CD = AU OR CU then total END_HLDG_HIST_T:HLDG_UNITS column
360                performFeeRateDefintionForCountCalculations(feeMethod);
361            }
362            
363            //if FEE_RATE_DEFINITION_CODE = "V"
364            if (feeMethod.getFeeRateDefinitionCode().equalsIgnoreCase(EndowConstants.FeeMethod.FEE_RATE_DEFINITION_CODE_FOR_VALUE)) {
365                performFeeRateDefintionForValueCalculations(feeMethod);
366            }
367        }
368        
369        /**
370         * performs calculations when Fee Rate Definition Code is C
371         */
372        protected void performFeeRateDefintionForCountCalculations(FeeMethod feeMethod) {
373            String feeBalanceTypeCode = feeMethod.getFeeBalanceTypeCode();
374            
375            //when FEE_BAL_TYP_CD = AU OR MU then total END_HLDG_HIST_T:HLDG_UNITS column
376            if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_AVERAGE_UNITS) || 
377                feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_MONTH_END_UNITS)) { 
378                totalHoldingUnits = holdingHistoryDao.getHoldingHistoryTotalHoldingUnits(feeMethod);
379            }
380            
381            if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_CURRENT_UNITS)) {
382                totalHoldingUnits = currentTaxLotBalanceDao.getCurrentTaxLotBalanceTotalHoldingUnits(feeMethod);
383            }
384            
385            totalAmountCalculated = KEMCalculationRoundingHelper.multiply(feeMethod.getFirstFeeRate(), totalHoldingUnits, EndowConstants.Scale.SECURITY_MARKET_VALUE);
386        }
387        
388        /**
389         * performs calculations when Fee Rate Definition Code is V
390         */
391        protected void performFeeRateDefintionForValueCalculations(FeeMethod feeMethod) {
392            String feeBalanceTypeCode = feeMethod.getFeeBalanceTypeCode();
393            
394            //when FEE_BAL_TYP_CD = AMV OR MMV then total END_HLDG_HIST_T:HLDG_UNITS column
395            if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_AVERAGE_MARKET_VALUE) || 
396                feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_MONTH_END_MARKET_VALUE)) { 
397                totalHoldingUnits = holdingHistoryDao.getHoldingHistoryTotalHoldingMarketValue(feeMethod);
398            }
399            
400            if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_CURRENT_MARKET_VALUE)) {
401                totalHoldingUnits = currentTaxLotBalanceDao.getCurrentTaxLotBalanceTotalHoldingMarketValue(feeMethod);
402            }
403            
404            totalAmountCalculated = KEMCalculationRoundingHelper.multiply(feeMethod.getFirstFeeRate(), totalHoldingUnits, EndowConstants.Scale.SECURITY_MARKET_VALUE);
405        }
406    
407        /**
408         * Performs the calculations to get the fee amount to be charged against the selected kemids
409         * @param feeMethod 
410         */
411        protected void performCalculationsForKemId(FeeMethod feeMethod) {
412            LOG.info("performCalculationsForKemId() started"); 
413            
414            Collection<KemidFee> kemidFeeRecords = new ArrayList();
415            
416            kemidFeeRecords = kemidFeeService.getAllKemidForFeeMethodCode(feeMethod.getCode());
417            
418            for (KemidFee kemidFee : kemidFeeRecords) {
419                if (kemidFeeService.chargeFeeToKemid(feeMethod, kemidFee)) {
420                    performCalculationsAgainstTotalAmountCalculated(feeMethod);
421                    calculateMinumumFeeAmount(feeMethod);
422                    if (checkForMinimumThresholdAmount(feeMethod, kemidFee)) {
423                        if (kemidFee.isAccrueFees()) {
424                            processFeeAccrual(feeMethod, kemidFee);
425                        }
426                        if (kemidFee.isWaiveFees()) {
427                            processFeeWaiver(feeMethod, kemidFee);
428                        }
429                    }
430                }
431            }
432            
433            LOG.info("performCalculationsForKemId() ended."); 
434        }
435        
436        /**
437         * Perform the calculations against the total amount calculated for each KEMID following the process outlined in step three above and calculate the fee amount by adding together the results of the following calculations:
438         *  1.  Multiply the value of the total amount calculated that is less than or equal to the 
439         *      END_KEMID_FEE_TFEE_MTHD_T: FEE_BRK_1 by END_KEMID_FEE_TFEE_MTHD_T: FEE_RT_1
440         *  2.  Multiply the value of the total amount calculated that is greater than the 
441         *      END_KEMID_FEE_TFEE_MTHD_T: FEE_BRK_1 and less than or equal to the END_KEMID_FEE_TFEE_MTHD_T: FEE_BRK_2 by END_KEMID_FEE_TFEE_MTHD_T: FEE_RT_2
442         *  3.  Multiply the value of the total amount calculated that is greater than the 
443         *      END_KEMID_FEE_TFEE_MTHD_T: FEE_BRK_2 by END_KEMID_FEE_TFEE_MTHD_T: FEE_RT_3.
444         * @param feeMethod
445         */
446        protected void performCalculationsAgainstTotalAmountCalculated(FeeMethod feeMethod) {
447            BigDecimal firstFeeBreakpoint = feeMethod.getFirstFeeBreakpoint().bigDecimalValue();
448            BigDecimal secondFeeBreakpoint = feeMethod.getSecondFeeBreakpoint().bigDecimalValue();
449            
450            if (totalAmountCalculated.compareTo(firstFeeBreakpoint) <= 0) {
451                feeToBeCharged = feeToBeCharged.add(KEMCalculationRoundingHelper.multiply(totalAmountCalculated, feeMethod.getFirstFeeRate(), EndowConstants.Scale.SECURITY_MARKET_VALUE));
452            }
453            
454            if (totalAmountCalculated.compareTo(firstFeeBreakpoint) > 0 &&
455                totalAmountCalculated.compareTo(secondFeeBreakpoint) <= 0){
456                feeToBeCharged = feeToBeCharged.add(KEMCalculationRoundingHelper.multiply(totalAmountCalculated, feeMethod.getSecondFeeRate(), EndowConstants.Scale.SECURITY_MARKET_VALUE));
457            }
458            
459            if (totalAmountCalculated.compareTo(secondFeeBreakpoint) > 0){
460                feeToBeCharged = feeToBeCharged.add(KEMCalculationRoundingHelper.multiply(totalAmountCalculated, feeMethod.getThirdFeeRate(), EndowConstants.Scale.SECURITY_MARKET_VALUE));
461            }
462        }
463        
464        /**
465         * IF the calculated fee is less than the amount in END_FEE_MTHD_T:  FEE_MIN_AMT, then 
466         * the feee to be charged is the minimum fee amount..
467         * @param feeMethod
468         */
469        protected void calculateMinumumFeeAmount(FeeMethod feeMethod) {
470            if (totalAmountCalculated.compareTo(feeMethod.getMinimumFeeToCharge().bigDecimalValue()) < 0) {
471                feeToBeCharged = feeMethod.getMinimumFeeToCharge().bigDecimalValue();
472            }
473        }
474        
475        /**
476         * IF the calculated fee amount is LESS  than the value in END_FEE_MTHD_T: FEE_MIN_THRSHLD, 
477         * then do not charge the fee (no transaction generated.  The information should be reported as an 
478         * exception on the exception report.
479         * @param feeMethod
480         * @param kemidFee
481         * @return true calculated fee amount is greater than 0
482         */
483        protected boolean checkForMinimumThresholdAmount(FeeMethod feeMethod, KemidFee kemidFee) {
484            boolean shouldNotCharge = true;
485            
486            if (feeToBeCharged.compareTo(feeMethod.getMinimumFeeThreshold().bigDecimalValue()) < 0) {
487                writeExceptionReportLine(feeMethod.getCode(), kemidFee.getKemid(), "Reason: Fee is not charged as the fee is less than the minimum threshold");
488                return false;
489            }
490            
491            return shouldNotCharge;
492        }
493        
494        /**
495         * IF the field ACR_FEE is equal to Y (Yes), then add the calculated fee amount to the value in 
496         * END_KEMID_FEE_MTHD_T: ACRD_FEE_TO_DT.
497         * @param feeMethod, kemidFee
498         * @return feeAcrrued true if fee amount is added to total accrued fees else return false
499         */
500        protected boolean processFeeAccrual(FeeMethod feeMethod, KemidFee kemidFee) {
501            boolean feeAcrrued = true;
502            
503            KualiDecimal accruelFee = new KualiDecimal(feeToBeCharged.toString());
504            kemidFee.setTotalAccruedFees(kemidFee.getTotalAccruedFees().add(accruelFee));
505                
506            //unable to save. write to exception...
507            if (!kemidFeeService.saveKemidFee(kemidFee)) {
508                writeExceptionReportLine(feeMethod.getCode(), kemidFee.getKemid(), "Reason: Unable to add Calculated Fee to Total Accrued Fees in END_KEMID_FEE_T table.");
509                return false;
510            }
511            
512            return feeAcrrued;
513        }
514        
515        /**
516         * IF the field WAIVE_FEE is equal to Y (Yes), then add the calculated fee amount to the value 
517         * in END_KEMID_FEE_MTHD_T: WAIVED_FEE_TO_DT and add the calculated fee amount to the value in 
518         * END_KEMID_FEE_MTHD_T: WAIVED_FEE_YDT
519         * @param feeMethod, kemidFee
520         * @return feeWaived - true if fee amount is added to total waived fees else return false
521         */
522        protected boolean processFeeWaiver(FeeMethod feeMethod, KemidFee kemidFee) {
523            boolean feeWaived = true;
524            
525            KualiDecimal accruelFee = new KualiDecimal(feeToBeCharged.toString());
526            kemidFee.setTotalWaivedFeesThisFiscalYear(kemidFee.getTotalWaivedFeesThisFiscalYear().add(accruelFee));
527            kemidFee.setTotalWaivedFees(kemidFee.getTotalWaivedFees().add(accruelFee));
528                
529            //save kemidFee record.
530            if (!kemidFeeService.saveKemidFee(kemidFee)) {
531                writeExceptionReportLine(feeMethod.getCode(), kemidFee.getKemid(), "Reason: Unable to add Calculated Fee to Total Waived Fees in END_KEMID_FEE_T table.");
532                return false;
533            }
534            
535            return feeWaived;
536        }
537        
538        /**
539         * Generate a CashDecreaseDocument (ECDD) and processes the document by submitting/routing it.
540         * @param feeMethod, kemidFee
541         */
542        protected boolean generateCashDecreaseDocument(FeeMethod feeMethod, int maxNumberOfTransacationLines) {
543            LOG.info("generateCashDecreaseDocument() entered.");  
544            
545            String feeMethodCode = feeMethod.getCode();
546            int lineNumber = 0;
547            
548            Collection<KemidFee> kemidFeeRecords = kemidFeeService.getAllKemidForFeeMethodCode(feeMethodCode);
549            
550            if (kemidFeeRecords.size() <= 0) {
551                return true;
552            }
553            
554            // initialize CashDecreaseDocument...
555            CashDecreaseDocument cashDecreaseDocument = (CashDecreaseDocument) createNewCashDecreaseDocument(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_DECREASE);
556            if (ObjectUtils.isNull(cashDecreaseDocument)) {
557                writeExceptionReportLine(feeMethodCode, null, "Reason: Unable to create a new CashDecreaseDocument.");
558                return false;
559            }
560            
561            //sets document description and source type code and subtype code
562            setDocumentOverviewAndDetails(cashDecreaseDocument, feeMethod.getName());
563            
564            for (KemidFee kemidFee : kemidFeeRecords) {
565                if (lineNumber <= maxNumberOfTransacationLines) {
566                    if (!createTransactionLines(cashDecreaseDocument, feeMethod, kemidFee, ++lineNumber, maxNumberOfTransacationLines)) {
567                        //did not add the line so reduce the number of lines generated....
568                        --lineNumber;
569                    }
570                }
571                else {
572                    // reached max transactions.  submit and then create a new document....
573                    if (kualiRuleService.applyRules(new RouteDocumentEvent(cashDecreaseDocument))) {
574                        if (submitDocumentForApprovalProcess(cashDecreaseDocument, feeMethod)) {
575                            // write the detail line for eDoc level...
576                            writeTotalsProcessedDetailTotalsLine(cashDecreaseDocument.getDocumentNumber(), feeMethodCode, lineNumber);
577                            
578                            // initialize CashDecreaseDocument...
579                            cashDecreaseDocument = (CashDecreaseDocument) createNewCashDecreaseDocument(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_DECREASE);
580                            if (ObjectUtils.isNull(cashDecreaseDocument)) {
581                                writeExceptionReportLine(feeMethodCode, kemidFee.getKemid(), "Reason: Unable to create a new CashDecreaseDocument.");
582                                return false;
583                            }
584    
585                            setDocumentOverviewAndDetails(cashDecreaseDocument, feeMethod.getName());
586                            lineNumber = 0;
587                        }
588                        else {
589                            //write out exception since can not submit the document....
590                            writeExceptionReportLine(feeMethodCode, kemidFee.getKemid(), "Reason: Unable to submit or route the document.");
591                            writeExceptionReportLine(feeMethodCode, kemidFee.getKemid(), "Reason: The document did not pass the rule validations during routing.");
592                        }
593                    }
594                    else {
595                        // document rules did not pass the validations.  so write exception report....
596                        writeExceptionReportLine(feeMethodCode, kemidFee.getKemid(), "Reason: The document did not pass the rule validations during routing.");
597                        wrtieExceptionMessagaeFromGlobalVariables(feeMethodCode, kemidFee.getKemid());
598                    }
599                }
600            }
601            
602            //submit the document as all the transactional lines have been added..
603            if (kualiRuleService.applyRules(new RouteDocumentEvent(cashDecreaseDocument))) {
604                if (submitDocumentForApprovalProcess(cashDecreaseDocument, feeMethod)) {
605                    // write the detail line for eDoc level...
606                    writeTotalsProcessedDetailTotalsLine(cashDecreaseDocument.getDocumentNumber(), feeMethodCode, lineNumber);
607                }
608                else {
609                    //write out exception since can not submit the document....
610                    writeExceptionReportLine(feeMethodCode, null, "Reason: Unable to submit or route the document.");
611                    wrtieExceptionMessagaeFromGlobalVariables(feeMethodCode, null);
612                }
613                    
614            }
615            else {
616                // document rules did not pass the validations.  so write exception report....
617                writeExceptionReportLine(feeMethodCode, null, "Reason: The document did not pass the rule validations during routing.");
618                wrtieExceptionMessagaeFromGlobalVariables(feeMethodCode, null);
619            }
620            
621            writeTotalsProcessedSubTotalsLine(feeMethodCode);
622            LOG.info("generateCashDecreaseDocument() ended.");
623            
624            return true;
625        }
626        
627        protected void writeTotalsProcessedDetailTotalsLine(String documentNumber, String feeMethodCode, int totalLinesGenerated) {
628            feeProcessingTotalsProcessedDetailTotalLine.setFeeMethodCode(feeMethodCode);
629            feeProcessingTotalsProcessedDetailTotalLine.setEDocNumber(documentNumber);
630            feeProcessingTotalsProcessedDetailTotalLine.setLinesGenerated(totalLinesGenerated);
631            feeProcessingTotalsProcessedDetailTotalLine.setTotalIncomeAmount(new KualiDecimal(totalProcessedIncomeAmountSubTotalEDoc.toString()));        
632            feeProcessingTotalsProcessedDetailTotalLine.setTotalPrincipalAmount(new KualiDecimal(totalProcessedPrincipalAmountSubTotalEDoc.toString()));        
633    
634            processFeeTransactionsTotalProcessedReportsWriterService.writeTableRow(feeProcessingTotalsProcessedDetailTotalLine);
635        //    processFeeTransactionsTotalProcessedReportsWriterService.writeNewLines(1);
636    
637            // add the edoc subtotals to fee method subtotal...
638            totalProcessedLinesGeneratedSubTotal += totalLinesGenerated;
639            totalProcessedIncomeAmountSubTotal = totalProcessedIncomeAmountSubTotal.add(totalProcessedIncomeAmountSubTotalEDoc); 
640            totalProcessedPrincipalAmountSubTotal = totalProcessedPrincipalAmountSubTotal.add(totalProcessedPrincipalAmountSubTotalEDoc); 
641        }
642        
643        protected void writeTotalsProcessedSubTotalsLine(String feeMethodCode) {
644            feeProcessingTotalsProcessedSubTotalLine.setEDocNumber("");
645            feeProcessingTotalsProcessedSubTotalLine.setLinesGenerated(totalProcessedLinesGeneratedSubTotal);
646            feeProcessingTotalsProcessedSubTotalLine.setTotalIncomeAmount(new KualiDecimal(totalProcessedIncomeAmountSubTotal.toString()));
647            feeProcessingTotalsProcessedSubTotalLine.setTotalPrincipalAmount(new KualiDecimal(totalProcessedPrincipalAmountSubTotal.toString()));
648    
649            processFeeTransactionsTotalProcessedReportsWriterService.writeTableRow(feeProcessingTotalsProcessedSubTotalLine);
650            processFeeTransactionsTotalProcessedReportsWriterService.writeNewLines(1);
651            
652            totalProcessedIncomeAmountGrandTotal = totalProcessedIncomeAmountGrandTotal.add(totalProcessedIncomeAmountSubTotal);
653            totalProcessedPrincipalAmountGrandTotal = totalProcessedPrincipalAmountGrandTotal.add(totalProcessedPrincipalAmountSubTotal); 
654            totalProcessedLinesGeneratedGrandTotal += totalProcessedLinesGeneratedSubTotal;
655        }
656        
657        protected void writeTotalsProcessedGrandTotalsLine() {
658            feeProcessingTotalsProcessedGrandTotalLine.setEDocNumber("");
659            feeProcessingTotalsProcessedGrandTotalLine.setLinesGenerated(totalProcessedLinesGeneratedGrandTotal);
660            feeProcessingTotalsProcessedGrandTotalLine.setTotalIncomeAmount(new KualiDecimal(totalProcessedIncomeAmountGrandTotal.toString()));
661            feeProcessingTotalsProcessedGrandTotalLine.setTotalPrincipalAmount(new KualiDecimal(totalProcessedPrincipalAmountGrandTotal.toString()));
662    
663            processFeeTransactionsTotalProcessedReportsWriterService.writeTableRow(feeProcessingTotalsProcessedGrandTotalLine);
664        }
665        
666        /**
667         * Sets document description, source type code to A (automated), and subtype code to C (cash) 
668         * @param cashDecreaseDocument newly generated document.
669         * @param documentDescription  fee method description to be used as document description
670         */
671        protected void setDocumentOverviewAndDetails(CashDecreaseDocument cashDecreaseDocument, String documentDescription) {
672            cashDecreaseDocument.getDocumentHeader().setDocumentDescription(documentDescription);
673            cashDecreaseDocument.setTransactionSourceTypeCode(EndowConstants.TransactionSourceTypeCode.AUTOMATED);
674            cashDecreaseDocument.setTransactionSubTypeCode(EndowConstants.TransactionSubTypeCode.CASH);
675        }
676        
677        /**
678         * After the last transaction line allowed in the eDoc (based on the institutional parameter) or 
679         * the last KEMID fee calculated for the fee method, IF the END_FEE_MTHD_T: FEE_POST_PEND_IND is 
680         * equal to Y submit the document as a blanket approved 'No Route' document.
681         * Otherwise, submit the document for routing and approval.
682         * @param cashDecreaseDocument
683         * @param feeMethod
684         * @return true if successful in submitting or routing the document.
685         */
686        protected boolean submitDocumentForApprovalProcess(CashDecreaseDocument cashDecreaseDocument, FeeMethod feeMethod) {
687            LOG.info("submitDocumentForApprovalProcess() entered.");
688            
689            boolean success = true;
690            
691            if (feeMethod.getFeePostPendingIndicator()) {
692                cashDecreaseDocument.setNoRouteIndicator(false);            
693                success = submitCashDecreaseDocument(cashDecreaseDocument, feeMethod.getCode());
694            }
695            else {
696                cashDecreaseDocument.setNoRouteIndicator(true);            
697                success = routeCashDecreaseDocument(cashDecreaseDocument, feeMethod.getCode());
698            }
699            
700            LOG.info("submitDocumentForApprovalProcess() ended.");
701            
702            return success;
703        }
704        
705        /**
706         * Gets a new document of the document type from the workflow using document service.
707         * @param documentType
708         * @return newCashDecreaseDocument if successfully created a new document else return null
709         */
710        protected CashDecreaseDocument createNewCashDecreaseDocument(String documentType) {
711            CashDecreaseDocument newCashDecreaseDocument = null;
712            
713            try {
714                newCashDecreaseDocument = (CashDecreaseDocument) documentService.getNewDocument(SpringContext.getBean(TransactionalDocumentDictionaryService.class).getDocumentClassByName(documentType));     
715            } catch (WorkflowException wfe) {
716                LOG.info("Failed to initialize CashDecreaseDocument");            
717                return null;
718            }
719            
720            return newCashDecreaseDocument;
721        }
722        
723        /**
724         * 
725         * IF the END_KEMID_FEE_T:  PCT_CHRG_FEE_TO_INC is equal to 100%, then generate the 
726         * transaction line(s) for the eDoc
727         * @param cashDecreaseDocument
728         * @param feeMethod
729         * @param kemidFee
730         * @param lineNumber current transaction line number
731         * @param maxNumberOfTransacationLines The system parameter specifying the max number of lines
732         * @return true if transaction lines created.
733         */
734        protected boolean createTransactionLines(CashDecreaseDocument cashDecreaseDocument, FeeMethod feeMethod, KemidFee kemidFee, int lineNumber, int maxNumberOfTransacationLines) {
735            // logic as in 9.3.b
736            if (kemidFee.getPercentOfFeeChargedToIncome().equals(new KualiDecimal("1"))) {
737                EndowmentSourceTransactionLine endowmentSourceTransactionLine = createEndowmentSourceTransactionLine(lineNumber, feeMethod, kemidFee, EndowConstants.IncomePrincipalIndicator.INCOME, feeToBeCharged);
738                if (addTransactionLineToDocument(cashDecreaseDocument, endowmentSourceTransactionLine, lineNumber, feeMethod.getCode())) {
739                    totalProcessedIncomeAmountSubTotalEDoc = totalProcessedIncomeAmountSubTotalEDoc.add(feeToBeCharged);
740                    return true;
741                }
742                else {
743                    return false;
744                }
745            }
746            
747            // logic to charge according to logic in 9.3.c
748            BigDecimal feeAmountForIncome = KEMCalculationRoundingHelper.multiply(feeToBeCharged, new BigDecimal(kemidFee.getPercentOfFeeChargedToIncome().toString()), EndowConstants.Scale.SECURITY_MARKET_VALUE);
749            EndowmentSourceTransactionLine endowmentSourceTransactionLine = createEndowmentSourceTransactionLine(lineNumber, feeMethod, kemidFee, EndowConstants.IncomePrincipalIndicator.INCOME, feeAmountForIncome);
750    
751            if (addTransactionLineToDocument(cashDecreaseDocument, endowmentSourceTransactionLine, ++lineNumber, feeMethod.getCode())) {
752                totalProcessedIncomeAmountSubTotalEDoc = totalProcessedIncomeAmountSubTotalEDoc.add(feeAmountForIncome);
753            }
754            else {
755                return false;
756            }
757            
758            BigDecimal feeAmountForPrincipal = KEMCalculationRoundingHelper.multiply(feeToBeCharged, new BigDecimal(kemidFee.getPercentOfFeeChargedToPrincipal().toString()), EndowConstants.Scale.SECURITY_MARKET_VALUE);
759            
760            if (lineNumber <= maxNumberOfTransacationLines) {
761                endowmentSourceTransactionLine = createEndowmentSourceTransactionLine(lineNumber, feeMethod, kemidFee, EndowConstants.IncomePrincipalIndicator.PRINCIPAL, feeAmountForPrincipal);
762                if (addTransactionLineToDocument(cashDecreaseDocument, endowmentSourceTransactionLine, ++lineNumber, feeMethod.getCode())) {
763                    totalProcessedPrincipalAmountSubTotalEDoc = totalProcessedPrincipalAmountSubTotalEDoc.add(feeAmountForPrincipal);
764                    return true;                
765                }
766                else {
767                    return false;
768                }
769            }
770            else {
771                boolean submitted = submitDocumentForApprovalProcess(cashDecreaseDocument, feeMethod);
772                //write sub totals at eDoc leve....
773                writeTotalsProcessedDetailTotalsLine(cashDecreaseDocument.getDocumentNumber(), feeMethod.getCode(), lineNumber);
774                
775                // initialize CashDecreaseDocument...
776                cashDecreaseDocument = (CashDecreaseDocument) createNewCashDecreaseDocument(EndowConstants.DocumentTypeNames.ENDOWMENT_CASH_DECREASE);
777                if (ObjectUtils.isNull(cashDecreaseDocument)) {
778                    writeExceptionReportLine(feeMethod.getCode(), null, "Reason: Unable to create a new CashDecreaseDocument.");
779                    return false;
780                }
781    
782                setDocumentOverviewAndDetails(cashDecreaseDocument, feeMethod.getName());
783                
784                lineNumber = 0;
785                endowmentSourceTransactionLine = createEndowmentSourceTransactionLine(lineNumber, feeMethod, kemidFee, EndowConstants.IncomePrincipalIndicator.PRINCIPAL, feeAmountForPrincipal);
786                return addTransactionLineToDocument(cashDecreaseDocument, endowmentSourceTransactionLine, ++lineNumber, feeMethod.getCode());
787            }
788        }
789        
790        /**
791         * 
792         * Add the new transaction line after applying the validation rules to the line.
793         * @param cashDecreaseDocument
794         * @param endowmentSourceTransactionLine
795         * @param lineNumber
796         * @return true if the line passed the business rules and added successfully else false.
797         */
798        protected boolean addTransactionLineToDocument(CashDecreaseDocument cashDecreaseDocument, EndowmentSourceTransactionLine endowmentSourceTransactionLine, int lineNumber, String feeMethodCode) {
799            boolean added = true;
800            
801            if (kualiRuleService.applyRules(new AddTransactionLineEvent(EndowConstants.NEW_SOURCE_TRAN_LINE_PROPERTY_NAME, cashDecreaseDocument, endowmentSourceTransactionLine))) {
802                cashDecreaseDocument.getSourceTransactionLines().add(endowmentSourceTransactionLine);
803                cashDecreaseDocument.setNextSourceLineNumber(lineNumber);
804            }
805            else {
806                LOG.info("CashDecreaseDocument Rules Failed.  The transaction line is not added for Kemid: " + endowmentSourceTransactionLine.getKemid());
807                wrtieExceptionMessagaeFromGlobalVariables(feeMethodCode, endowmentSourceTransactionLine.getKemid());
808                --lineNumber;
809                
810                return false;
811            }
812            
813            return added;
814        }
815        
816        /**
817         * extracts the error messages in the global variables for this session id and writes as exception report
818         */
819        protected void wrtieExceptionMessagaeFromGlobalVariables(String feeMethodCode, String kemid) {
820            processFeeTransactionsRowValues.setColumnHeading1(feeMethodCode);
821            processFeeTransactionsRowValues.setColumnHeading2(kemid);
822            processFeeTransactionsRowValues.setColumnHeading3(feeToBeCharged.toString());
823            processFeeTransactionsExceptionReportsWriterService.writeTableRow(processFeeTransactionsRowValues);
824            
825         //   List<String> errorMessages = extractGlobalVariableErrors();
826            List<String> errorMessages =  GloabalVariablesExtractHelper.extractGlobalVariableErrors();
827            
828            for (String errorMessage : errorMessages) {
829                processFeeTransactionsExceptionReportsWriterService.writeFormattedMessageLine("Reason:  %s", errorMessage);
830            }
831    
832            processFeeTransactionsExceptionReportsWriterService.writeNewLines(1);
833        }
834        
835        /**
836         * Creates a source transaction line
837         * @param lineNumber the current transaction line number
838         * @param feeMethod
839         * @param kemidFee
840         * @param iPIndicator Income or principal indicator for this line
841         * @param feeAmount the calculate fee amount for the transaction amount field
842         * @return endowmentSourceTransactionLine the new source transaction line
843         */
844        protected EndowmentSourceTransactionLine createEndowmentSourceTransactionLine(int lineNumber, FeeMethod feeMethod, KemidFee kemidFee, String iPIndicator, BigDecimal feeAmount) {
845            EndowmentSourceTransactionLine endowmentSourceTransactionLine = new EndowmentSourceTransactionLine();
846            endowmentSourceTransactionLine.setTransactionLineNumber(lineNumber);
847            endowmentSourceTransactionLine.setKemid(kemidFee.getChargeFeeToKemid());
848            endowmentSourceTransactionLine.setEtranCode(feeMethod.getFeeExpenseETranCode());
849            endowmentSourceTransactionLine.setTransactionIPIndicatorCode(iPIndicator);
850            endowmentSourceTransactionLine.setTransactionAmount(new KualiDecimal(feeToBeCharged.toString()));
851     
852           return endowmentSourceTransactionLine;
853        }
854        
855        /**
856         * 
857         * submits the document.  It sets the no route indicator to true and creates a note and sets its text and
858         * adds the note to the document.  The document is saved and put into workflow
859         * @param cashDecreaseDocument
860         * @return true if document submitted else false
861         */
862        protected boolean submitCashDecreaseDocument(CashDecreaseDocument cashDecreaseDocument, String feeMethodCode) {
863            boolean saved = true;
864            
865            try {
866                documentService.saveDocument(cashDecreaseDocument);
867            }
868            catch (WorkflowException wfe) {
869                LOG.info("CashDecreaseDocument Rules Failed.  The transaction line is not added for Document: " + cashDecreaseDocument.getDocumentNumber());
870                wrtieExceptionMessagaeFromGlobalVariables(feeMethodCode, null);
871                return false;
872            }
873            catch (Exception ex) {
874                return false;            
875            }
876            
877            return saved;
878        }
879        
880        /**
881         * Routes the document
882         * @param cashDecreaseDocument
883         * @return true if successful else return false
884         */
885        protected boolean routeCashDecreaseDocument(CashDecreaseDocument cashDecreaseDocument, String feeMethodCode) {
886            boolean routed = true;
887            
888            try {
889                documentService.routeDocument(cashDecreaseDocument, "Created by Fee Transactions Batch Job and routed.", null);
890            }
891            catch (WorkflowException wfe) {
892                try {
893                    // write errors messages and clear them befor saving.....
894                    LOG.info("CashDecreaseDocument Rules Failed.  The transaction line is not added for Document: " + cashDecreaseDocument.getDocumentNumber());
895                    wrtieExceptionMessagaeFromGlobalVariables(feeMethodCode, null);
896                    
897                    documentService.saveDocument(cashDecreaseDocument);
898                }
899                catch (WorkflowException wfesave) {
900                    return false;
901                }
902                catch (Exception ex) {
903                    return false;            
904                }
905                
906                return false;
907            }
908            
909            return routed;
910        }
911        
912        /**
913         * Writes the exception report line after setting fee method code and kemid and the reason
914         * @param feeMethodCode
915         * @param kemid
916         * @param reason the reason written on the reason line.
917         */
918        protected void writeExceptionReportLine(String feeMethodCode, String kemid, String reason) {
919            processFeeTransactionsRowValues.setColumnHeading1(feeMethodCode);
920            processFeeTransactionsRowValues.setColumnHeading2(kemid);
921            processFeeTransactionsRowValues.setColumnHeading3(feeToBeCharged.toString());
922            writeTableRowAndTableReason(reason);
923        }
924        
925        /**
926         * writes out the table row values then writes the reason row and inserts a blank line
927         * @param reasonMessage the reason message
928         */
929        protected void writeTableRowAndTableReason(String reasonMessage) {
930            processFeeTransactionsExceptionReportsWriterService.writeTableRow(processFeeTransactionsRowValues);            
931            setExceptionReportTableRowReason(reasonMessage);
932            processFeeTransactionsExceptionReportsWriterService.writeTableRow(processFeeTransactionsExceptionRowReason);            
933            processFeeTransactionsExceptionReportsWriterService.writeNewLines(1);
934        }
935        
936        /**
937         * sets the exception message with the passed in value.
938         * @param reasonForException The reason that will be set in the exception report
939         */
940        protected void setExceptionReportTableRowReason(String reasonForException) {
941            
942            processFeeTransactionsExceptionRowReason.setColumnHeading1("Reason: " + reasonForException);
943            processFeeTransactionsExceptionRowReason.setColumnHeading2("");
944            processFeeTransactionsExceptionRowReason.setColumnHeading3("");
945        }
946    
947        
948        /**
949         * Gets the processFeeTransactionsExceptionReportsWriterService attribute. 
950         * @return Returns the processFeeTransactionsExceptionReportsWriterService.
951         */
952        protected ReportWriterService getProcessFeeTransactionsExceptionReportsWriterService() {
953            return processFeeTransactionsExceptionReportsWriterService;
954        }
955        
956        /**
957         * Sets the processFeeTransactionsExceptionReportsWriterService attribute value.
958         * @param processFeeTransactionsExceptionReportsWriterService The processFeeTransactionsExceptionReportsWriterService to set.
959         */
960        public void setProcessFeeTransactionsExceptionReportsWriterService(ReportWriterService processFeeTransactionsExceptionReportsWriterService) {
961            this.processFeeTransactionsExceptionReportsWriterService = processFeeTransactionsExceptionReportsWriterService;
962        }
963    
964        /**
965         * Gets the processFeeTransactionsTotalProcessedReportsWriterService attribute. 
966         * @return Returns the processFeeTransactionsTotalProcessedReportsWriterService.
967         */
968        public ReportWriterService getProcessFeeTransactionsTotalProcessedReportsWriterService() {
969            return processFeeTransactionsTotalProcessedReportsWriterService;
970        }
971    
972        /**
973         * Sets the processFeeTransactionsTotalProcessedReportsWriterService attribute value.
974         * @param processFeeTransactionsTotalProcessedReportsWriterService The processFeeTransactionsTotalProcessedReportsWriterService to set.
975         */
976        public void setProcessFeeTransactionsTotalProcessedReportsWriterService(ReportWriterService processFeeTransactionsTotalProcessedReportsWriterService) {
977            this.processFeeTransactionsTotalProcessedReportsWriterService = processFeeTransactionsTotalProcessedReportsWriterService;
978        }
979        
980        /**
981         * Gets the processFeeTransactionsWaivedAndAccruedFeesReportsWriterService attribute. 
982         * @return Returns the processFeeTransactionsWaivedAndAccruedFeesReportsWriterService.
983         */
984        public ReportWriterService getProcessFeeTransactionsWaivedAndAccruedFeesReportsWriterService() {
985            return processFeeTransactionsWaivedAndAccruedFeesReportsWriterService;
986        }
987    
988        /**
989         * Sets the processFeeTransactionsWaivedAndAccruedFeesReportsWriterService attribute value.
990         * @param processFeeTransactionsWaivedAndAccruedFeesReportsWriterService The processFeeTransactionsWaivedAndAccruedFeesReportsWriterService to set.
991         */
992        public void setProcessFeeTransactionsWaivedAndAccruedFeesReportsWriterService(ReportWriterService processFeeTransactionsWaivedAndAccruedFeesReportsWriterService) {
993            this.processFeeTransactionsWaivedAndAccruedFeesReportsWriterService = processFeeTransactionsWaivedAndAccruedFeesReportsWriterService;
994        }
995        
996        /**
997         * Gets the holdingHistoryService attribute. 
998         * @return Returns the holdingHistoryService.
999         */
1000        protected KemidFeeService getKemidFeeService() {
1001            return kemidFeeService;
1002        }
1003    
1004        /**
1005         * Sets the kKemidFeeService attribute value.
1006         * @param kemidFeeService The kemidFeeService to set.
1007         */
1008        public void setKemidFeeService(KemidFeeService kemidFeeService) {
1009            this.kemidFeeService = kemidFeeService;
1010        }
1011        
1012        /**
1013         * Gets the feeMethodService attribute. 
1014         * @return Returns the feeMethodService.
1015         */
1016        protected FeeMethodService getFeeMethodService() {
1017            return feeMethodService;
1018        }
1019    
1020        /**
1021         * Sets the feeMethodService attribute value.
1022         * @param feeMethodService The feeMethodService to set.
1023         */
1024        public void setFeeMethodService(FeeMethodService feeMethodService) {
1025            this.feeMethodService = feeMethodService;
1026        }
1027        
1028        /**
1029         * Gets the kemService.
1030         * @return kemService
1031         */
1032        protected KEMService getKemService() {
1033            return kemService;
1034        }
1035    
1036        /**
1037         * Sets the kemService.
1038         * @param kemService
1039         */
1040        public void setKemService(KEMService kemService) {
1041            this.kemService = kemService;
1042        }
1043    
1044        /**
1045         * Gets the processFeeTransactionsExceptionReportHeader attribute. 
1046         * @return Returns the processFeeTransactionsExceptionReportHeader.
1047         */
1048        public EndowmentExceptionReportHeader getProcessFeeTransactionsExceptionReportHeader() {
1049            return processFeeTransactionsExceptionReportHeader;
1050        }
1051    
1052        /**
1053         * Sets the processFeeTransactionsExceptionReportHeader attribute value.
1054         * @param processFeeTransactionsExceptionReportHeader The processFeeTransactionsExceptionReportHeader to set.
1055         */
1056        public void setProcessFeeTransactionsExceptionReportHeader(EndowmentExceptionReportHeader processFeeTransactionsExceptionReportHeader) {
1057            this.processFeeTransactionsExceptionReportHeader = processFeeTransactionsExceptionReportHeader;
1058        }
1059    
1060        /**
1061         * Gets the processFeeTransactionsTotalProcessedReportHeader attribute. 
1062         * @return Returns the processFeeTransactionsTotalProcessedReportHeader.
1063         */
1064        public FeeProcessingTotalsProcessedReportHeader getProcessFeeTransactionsTotalProcessedReportHeader() {
1065            return processFeeTransactionsTotalProcessedReportHeader;
1066        }
1067    
1068        /**
1069         * Sets the processFeeTransactionsTotalProcessedReportHeader attribute value.
1070         * @param processFeeTransactionsTotalProcessedReportHeader The processFeeTransactionsTotalProcessedReportHeader to set.
1071         */
1072        public void setProcessFeeTransactionsTotalProcessedReportHeader(FeeProcessingTotalsProcessedReportHeader processFeeTransactionsTotalProcessedReportHeader) {
1073            this.processFeeTransactionsTotalProcessedReportHeader = processFeeTransactionsTotalProcessedReportHeader;
1074        }
1075    
1076        /**
1077         * Gets the processFeeTransactionsWaivedAndAccruedFeesReportHeader attribute. 
1078         * @return Returns the processFeeTransactionsWaivedAndAccruedFeesReportHeader.
1079         */
1080        public FeeProcessingWaivedAndAccruedReportHeader getProcessFeeTransactionsWaivedAndAccruedFeesReportHeader() {
1081            return processFeeTransactionsWaivedAndAccruedFeesReportHeader;
1082        }
1083    
1084        /**
1085         * Sets the processFeeTransactionsWaivedAndAccruedFeesReportHeader attribute value.
1086         * @param processFeeTransactionsWaivedAndAccruedFeesReportHeader The processFeeTransactionsWaivedAndAccruedFeesReportHeader to set.
1087         */
1088        public void setProcessFeeTransactionsWaivedAndAccruedFeesReportHeader(FeeProcessingWaivedAndAccruedReportHeader processFeeTransactionsWaivedAndAccruedFeesReportHeader) {
1089            this.processFeeTransactionsWaivedAndAccruedFeesReportHeader = processFeeTransactionsWaivedAndAccruedFeesReportHeader;
1090        }
1091    
1092        /**
1093         * Gets the processFeeTransactionsRowValues attribute. 
1094         * @return Returns the processFeeTransactionsRowValues.
1095         */
1096        public EndowmentExceptionReportHeader getProcessFeeTransactionsRowValues() {
1097            return processFeeTransactionsRowValues;
1098        }
1099    
1100        /**
1101         * Sets the processFeeTransactionsRowValues attribute value.
1102         * @param processFeeTransactionsRowValues The processFeeTransactionsRowValues to set.
1103         */
1104        public void setProcessFeeTransactionsRowValues(EndowmentExceptionReportHeader processFeeTransactionsRowValues) {
1105            this.processFeeTransactionsRowValues = processFeeTransactionsRowValues;
1106        }
1107    
1108        /**
1109         * Gets the processFeeTransactionsExceptionRowReason attribute. 
1110         * @return Returns the processFeeTransactionsExceptionRowReason.
1111         */
1112        public EndowmentExceptionReportHeader getProcessFeeTransactionsExceptionRowReason() {
1113            return processFeeTransactionsExceptionRowReason;
1114        }
1115    
1116        /**
1117         * Sets the processFeeTransactionsExceptionRowReason attribute value.
1118         * @param processFeeTransactionsExceptionRowReason The processFeeTransactionsExceptionRowReason to set.
1119         */
1120        public void setProcessFeeTransactionsExceptionRowReason(EndowmentExceptionReportHeader processFeeTransactionsExceptionRowReason) {
1121            this.processFeeTransactionsExceptionRowReason = processFeeTransactionsExceptionRowReason;
1122        }
1123        
1124        /**
1125         * Gets the transactionArchiveDao attribute. 
1126         * @return Returns the transactionArchiveDao.
1127         */
1128        protected TransactionArchiveDao getTransactionArchiveDao() {
1129            return transactionArchiveDao;
1130        }
1131    
1132        /**
1133         * Sets the transactionArchiveDao attribute value.
1134         * @param transactionArchiveDao The transactionArchiveDao to set.
1135         */
1136        public void setTransactionArchiveDao(TransactionArchiveDao transactionArchiveDao) {
1137            this.transactionArchiveDao = transactionArchiveDao;
1138        }
1139        /**
1140         * Gets the holdingHistoryDao attribute. 
1141         * @return Returns the holdingHistoryDao.
1142         */
1143        protected HoldingHistoryDao getHoldingHistoryDao() {
1144            return holdingHistoryDao;
1145        }
1146    
1147        /**
1148         * Sets the holdingHistoryDao attribute value.
1149         * @param holdingHistoryDao The holdingHistoryDao to set.
1150         */
1151        public void setHoldingHistoryDao(HoldingHistoryDao holdingHistoryDao) {
1152            this.holdingHistoryDao = holdingHistoryDao;
1153        }
1154        
1155        /**
1156         * Gets the currentTaxLotBalanceDao attribute. 
1157         * @return Returns the currentTaxLotBalanceDao.
1158         */
1159        protected CurrentTaxLotBalanceDao getCurrentTaxLotBalanceDao() {
1160            return currentTaxLotBalanceDao;
1161        }
1162    
1163        /**
1164         * Sets the currentTaxLotBalanceDao attribute value.
1165         * @param currentTaxLotBalanceDao The currentTaxLotBalanceDao to set.
1166         */
1167        public void setCurrentTaxLotBalanceDao(CurrentTaxLotBalanceDao currentTaxLotBalanceDao) {
1168            this.currentTaxLotBalanceDao = currentTaxLotBalanceDao;
1169        }
1170    
1171        /**
1172         * Gets the kemidFeeDao attribute. 
1173         * @return Returns the kemidFeeDao.
1174         */
1175        protected KemidFeeDao getKemidFeeDao() {
1176            return kemidFeeDao;
1177        }
1178    
1179        /**
1180         * Sets the kemidFeeDao attribute value.
1181         * @param kemidFeeDao The kemidFeeDao to set.
1182         */
1183        public void setKemidFeeDao(KemidFeeDao kemidFeeDao) {
1184            this.kemidFeeDao = kemidFeeDao;
1185        }
1186        /**
1187         * Sets the documentService attribute value.
1188         * @param documentService The documentService to set.
1189         */
1190        public void setDocumentService(DocumentService documentService) {
1191            this.documentService = documentService;
1192        }
1193        /**
1194         * Gets the documentService attribute value.
1195         */
1196        protected DocumentService getDocumentService() {
1197            return documentService;
1198        }
1199        
1200        /**
1201         * Gets the kualiRuleService attribute. 
1202         * @return Returns the kualiRuleService.
1203         */
1204        protected KualiRuleService getKualiRuleService() {
1205            return kualiRuleService;
1206        }
1207    
1208        /**
1209         * Sets the kualiRuleService attribute value.
1210         * @param kualiRuleService The kualiRuleService to set.
1211         */
1212        public void setKualiRuleService(KualiRuleService kualiRuleService) {
1213            this.kualiRuleService = kualiRuleService;
1214        }
1215      
1216        /**
1217         * Gets the NoteService, lazily initializing if necessary
1218         * @return the NoteService
1219         */
1220        protected synchronized NoteService getNoteService() {
1221            if (this.noteService == null) {
1222                this.noteService = KNSServiceLocator.getNoteService();
1223            }
1224            return this.noteService;
1225        }
1226        
1227        /**
1228         * Sets the noteService attribute value.
1229         * 
1230         * @param noteService The noteService to set.
1231         */
1232        public void setNoteService(NoteService noteService) {
1233            this.noteService = noteService;
1234        }
1235        
1236        /**
1237         * @return Returns the personService.
1238         */
1239        protected PersonService<Person> getPersonService() {
1240            if(personService==null)
1241                personService = SpringContext.getBean(PersonService.class);
1242            return personService;
1243        }
1244        
1245        /**
1246         * Gets the feeProcessingWaivedAndAccruedDetailTotalLine attribute. 
1247         * @return Returns the feeProcessingWaivedAndAccruedDetailTotalLine.
1248         */
1249        protected FeeProcessingWaivedAndAccruedDetailTotalLine getFeeProcessingWaivedAndAccruedDetailTotalLine() {
1250            return feeProcessingWaivedAndAccruedDetailTotalLine;
1251        }
1252    
1253        /**
1254         * Sets the feeProcessingWaivedAndAccruedDetailTotalLine attribute value.
1255         * @param feeProcessingWaivedAndAccruedDetailTotalLine The feeProcessingWaivedAndAccruedDetailTotalLine to set.
1256         */
1257        public void setFeeProcessingWaivedAndAccruedDetailTotalLine(FeeProcessingWaivedAndAccruedDetailTotalLine feeProcessingWaivedAndAccruedDetailTotalLine) {
1258            this.feeProcessingWaivedAndAccruedDetailTotalLine = feeProcessingWaivedAndAccruedDetailTotalLine;
1259        }
1260    
1261        /**
1262         * Gets the feeProcessingWaivedAndAccruedSubTotalLine attribute. 
1263         * @return Returns the feeProcessingWaivedAndAccruedSubTotalLine.
1264         */
1265        protected FeeProcessingWaivedAndAccruedSubTotalLine getFeeProcessingWaivedAndAccruedSubTotalLine() {
1266            return feeProcessingWaivedAndAccruedSubTotalLine;
1267        }
1268    
1269        /**
1270         * Sets the feeProcessingWaivedAndAccruedSubTotalLine attribute value.
1271         * @param feeProcessingWaivedAndAccruedSubTotalLine The feeProcessingWaivedAndAccruedSubTotalLine to set.
1272         */
1273        public void setFeeProcessingWaivedAndAccruedSubTotalLine(FeeProcessingWaivedAndAccruedSubTotalLine feeProcessingWaivedAndAccruedSubTotalLine) {
1274            this.feeProcessingWaivedAndAccruedSubTotalLine = feeProcessingWaivedAndAccruedSubTotalLine;
1275        }
1276    
1277        /**
1278         * Gets the feeProcessingWaivedAndAccruedGrandTotalLine attribute. 
1279         * @return Returns the feeProcessingWaivedAndAccruedGrandTotalLine.
1280         */
1281        protected FeeProcessingWaivedAndAccruedGrandTotalLine getFeeProcessingWaivedAndAccruedGrandTotalLine() {
1282            return feeProcessingWaivedAndAccruedGrandTotalLine;
1283        }
1284    
1285        /**
1286         * Sets the feeProcessingWaivedAndAccruedGrandTotalLine attribute value.
1287         * @param feeProcessingWaivedAndAccruedGrandTotalLine The feeProcessingWaivedAndAccruedGrandTotalLine to set.
1288         */
1289        public void setFeeProcessingWaivedAndAccruedGrandTotalLine(FeeProcessingWaivedAndAccruedGrandTotalLine feeProcessingWaivedAndAccruedGrandTotalLine) {
1290            this.feeProcessingWaivedAndAccruedGrandTotalLine = feeProcessingWaivedAndAccruedGrandTotalLine;
1291        }
1292        
1293        /**
1294         * Gets the feeProcessingTotalsProcessedDetailTotalLine attribute. 
1295         * @return Returns the feeProcessingTotalsProcessedDetailTotalLine.
1296         */
1297        protected FeeProcessingTotalsProcessedDetailTotalLine getFeeProcessingTotalsProcessedDetailTotalLine() {
1298            return feeProcessingTotalsProcessedDetailTotalLine;
1299        }
1300    
1301        /**
1302         * Sets the feeProcessingTotalsProcessedDetailTotalLine attribute value.
1303         * @param feeProcessingTotalsProcessedDetailTotalLine The feeProcessingTotalsProcessedDetailTotalLine to set.
1304         */
1305        public void setFeeProcessingTotalsProcessedDetailTotalLine(FeeProcessingTotalsProcessedDetailTotalLine feeProcessingTotalsProcessedDetailTotalLine) {
1306            this.feeProcessingTotalsProcessedDetailTotalLine = feeProcessingTotalsProcessedDetailTotalLine;
1307        }
1308    
1309        /**
1310         * Gets the feeProcessingTotalsProcessedSubTotalLine attribute. 
1311         * @return Returns the feeProcessingTotalsProcessedSubTotalLine.
1312         */
1313        protected FeeProcessingTotalsProcessedSubTotalLine getFeeProcessingTotalsProcessedSubTotalLine() {
1314            return feeProcessingTotalsProcessedSubTotalLine;
1315        }
1316    
1317        /**
1318         * Sets the feeProcessingTotalsProcessedSubTotalLine attribute value.
1319         * @param feeProcessingTotalsProcessedSubTotalLine The feeProcessingTotalsProcessedSubTotalLine to set.
1320         */
1321        public void setFeeProcessingTotalsProcessedSubTotalLine(FeeProcessingTotalsProcessedSubTotalLine feeProcessingTotalsProcessedSubTotalLine) {
1322            this.feeProcessingTotalsProcessedSubTotalLine = feeProcessingTotalsProcessedSubTotalLine;
1323        }
1324    
1325        /**
1326         * Gets the feeProcessingTotalsProcessedGrandTotalLine attribute. 
1327         * @return Returns the feeProcessingTotalsProcessedGrandTotalLine.
1328         */
1329        protected FeeProcessingTotalsProcessedGrandTotalLine getFeeProcessingTotalsProcessedGrandTotalLine() {
1330            return feeProcessingTotalsProcessedGrandTotalLine;
1331        }
1332    
1333        /**
1334         * Sets the feeProcessingTotalsProcessedGrandTotalLine attribute value.
1335         * @param feeProcessingTotalsProcessedGrandTotalLine The feeProcessingTotalsProcessedGrandTotalLine to set.
1336         */
1337        public void setFeeProcessingTotalsProcessedGrandTotalLine(FeeProcessingTotalsProcessedGrandTotalLine feeProcessingTotalsProcessedGrandTotalLine) {
1338            this.feeProcessingTotalsProcessedGrandTotalLine = feeProcessingTotalsProcessedGrandTotalLine;
1339        }
1340        
1341        /**
1342         * Gets the configService attribute. 
1343         * @return Returns the configService.
1344         */
1345        protected KualiConfigurationService getConfigService() {
1346            return configService;
1347        }
1348    
1349        /**
1350         * Sets the configService.
1351         * @param configService
1352         */
1353        public void setConfigService(KualiConfigurationService configService) {
1354            this.configService = configService;
1355        }
1356        
1357    }
1358