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