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 static org.kuali.kfs.module.endow.EndowConstants.NEW_TARGET_TRAN_LINE_PROPERTY_NAME;
019    
020    import java.math.BigDecimal;
021    import java.util.ArrayList;
022    import java.util.HashMap;
023    import java.util.List;
024    import java.util.Map;
025    
026    import org.kuali.kfs.module.endow.EndowConstants;
027    import org.kuali.kfs.module.endow.EndowParameterKeyConstants;
028    import org.kuali.kfs.module.endow.batch.CreateAccrualTransactionsStep;
029    import org.kuali.kfs.module.endow.batch.service.CreateAccrualTransactionsService;
030    import org.kuali.kfs.module.endow.businessobject.EndowmentTargetTransactionLine;
031    import org.kuali.kfs.module.endow.businessobject.EndowmentTargetTransactionSecurity;
032    import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLine;
033    import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionSecurity;
034    import org.kuali.kfs.module.endow.businessobject.HoldingTaxLot;
035    import org.kuali.kfs.module.endow.businessobject.Security;
036    import org.kuali.kfs.module.endow.businessobject.TransactionDocumentExceptionReportLine;
037    import org.kuali.kfs.module.endow.businessobject.TransactionDocumentTotalReportLine;
038    import org.kuali.kfs.module.endow.dataaccess.SecurityDao;
039    import org.kuali.kfs.module.endow.document.CashIncreaseDocument;
040    import org.kuali.kfs.module.endow.document.service.HoldingTaxLotService;
041    import org.kuali.kfs.module.endow.document.service.KEMService;
042    import org.kuali.kfs.module.endow.document.validation.event.AddTransactionLineEvent;
043    import org.kuali.kfs.module.endow.util.GloabalVariablesExtractHelper;
044    import org.kuali.kfs.sys.service.ReportWriterService;
045    import org.kuali.rice.kew.exception.WorkflowException;
046    import org.kuali.rice.kns.rule.event.RouteDocumentEvent;
047    import org.kuali.rice.kns.service.BusinessObjectService;
048    import org.kuali.rice.kns.service.DocumentService;
049    import org.kuali.rice.kns.service.KualiConfigurationService;
050    import org.kuali.rice.kns.service.KualiRuleService;
051    import org.kuali.rice.kns.service.ParameterService;
052    import org.kuali.rice.kns.util.KualiDecimal;
053    import org.springframework.transaction.annotation.Transactional;
054    
055    /**
056     * This class...
057     */
058    @Transactional
059    public class CreateAccrualTransactionsServiceImpl implements CreateAccrualTransactionsService {
060        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CreateAccrualTransactionsServiceImpl.class);
061    
062        private BusinessObjectService businessObjectService;
063        private KEMService kemService;
064        private HoldingTaxLotService holdingTaxLotService;
065        private SecurityDao securityDao;
066        private DocumentService documentService;
067        private KualiConfigurationService configService;
068        private KualiRuleService kualiRuleService;
069        protected ParameterService parameterService;
070    
071        protected ReportWriterService accrualTransactionsExceptionReportWriterService;
072        protected ReportWriterService accrualTransactionsTotalReportWriterService;
073    
074        protected TransactionDocumentExceptionReportLine exceptionReportLine = null;
075        protected TransactionDocumentTotalReportLine totalReportLine = null;
076    
077        protected boolean isFistTimeForWritingTotalReport = true;
078        protected boolean isFistTimeForWritingExceptionReport = true;
079    
080        /**
081         * Constructs a CreateAccrualTransactionsServiceImpl.java.
082         */
083        public CreateAccrualTransactionsServiceImpl() {
084            
085        }
086    
087        /**
088         * @see org.kuali.kfs.module.endow.batch.service.CreateAccrualTransactionsService#createAccrualTransactions()
089         */
090        public boolean createAccrualTransactions() {
091            boolean success = true;
092    
093            LOG.debug("createAccrualTransactions() started");
094    
095            int maxNumberOfTranLines = kemService.getMaxNumberOfTransactionLinesPerDocument();
096    
097            // get all securities with next income pay date equal to current date
098            List<Security> securities = getAllSecuritiesWithNextPayDateEqualCurrentDate();
099    
100            for (Security security : securities) {
101    
102                // get all tax lots that have an accrued income greater than zero
103                List<HoldingTaxLot> taxLots = holdingTaxLotService.getAllTaxLotsWithAccruedIncomeGreaterThanZeroPerSecurity(security.getId());
104    
105                // build a map that groups tax lots based on registration code ( a map from registration code to taxlots)
106                Map<String, List<HoldingTaxLot>> regCodeMap = groupTaxLotsBasedOnRegistrationCode(taxLots);
107    
108                // create Cash Increase documents for each security and registration code
109                for (String registrationCode : regCodeMap.keySet()) {
110    
111                    // 4. create new CashIncreaseDocument
112                    CashIncreaseDocument cashIncreaseDocument = createNewCashIncreaseDocument(security.getId(), registrationCode);
113    
114                    if (cashIncreaseDocument != null) {
115    
116                        // create a new totalReportLine and exceptionReportLine for a new CashIncreaseDocument
117                        initializeTotalAndExceptionReportLines(cashIncreaseDocument.getDocumentNumber(), security.getId());
118    
119                        // group tax lots by kemid and ip indicator; for each kemid and ip indicator we create a new transaction line
120                        Map<String, List<HoldingTaxLot>> kemidIpMap = groupTaxLotsBasedOnKemidAndIPIndicator(regCodeMap.get(registrationCode));
121    
122                        // keep track of the tax lots to be updated
123                        List<HoldingTaxLot> taxLotsForUpdate = new ArrayList<HoldingTaxLot>();
124                        // keep a counter to create a new document if there are more that maximum number of allowed transaction lines
125                        // per
126                        // document
127                        int counter = 0;
128    
129                        // create a new transaction line for each kemid and ip indicator
130                        for (String kemidIp : kemidIpMap.keySet()) {
131    
132                            // compute the total amount for the transaction line
133                            KualiDecimal totalAmount = KualiDecimal.ZERO;
134                            String kemid = null;
135    
136                            for (HoldingTaxLot lot : kemidIpMap.get(kemidIp)) {
137                                totalAmount = totalAmount.add(new KualiDecimal(lot.getCurrentAccrual()));
138    
139                                // initialize kemid
140                                if (kemid == null) {
141                                    kemid = lot.getKemid();
142                                }
143                            }
144    
145                            // collect tax lots for update: when the document is submitted the tax lots accrual is copied to prior
146                            // accrual
147                            // and the current accrual is reset to zero
148                            taxLotsForUpdate.addAll(kemidIpMap.get(kemidIp));
149    
150                            // if we have already reached the maximum number of transaction lines on the current document then create a
151                            // new
152                            // document
153                            if (counter == maxNumberOfTranLines) {
154                                // submit the current ECI doc and update the values in the tax lots used already
155                                submitCashIncreaseDocumentAndUpdateTaxLots(cashIncreaseDocument, taxLotsForUpdate);
156                                
157                                // clear tax lots for update and create a new Cash Increase document
158                                taxLotsForUpdate.clear();
159                                cashIncreaseDocument = createNewCashIncreaseDocument(security.getId(), registrationCode);
160    
161                                if (cashIncreaseDocument != null) {
162                                    // create a new totalReportLine and exceptionReportLine for a new CashIncreaseDocument
163                                    initializeTotalAndExceptionReportLines(cashIncreaseDocument.getDocumentNumber(), security.getId());
164    
165                                    counter = 0;
166                                }
167                            }
168    
169                            if (cashIncreaseDocument != null) {
170                                // add a new transaction line
171                                if (addTransactionLine(cashIncreaseDocument, security, kemid, totalAmount)) {
172                                    counter++;
173                                }
174                                else {
175                                    // if unable to add a new transaction line then remove the tax lots from the tax lots to update list
176                                    taxLotsForUpdate.remove(kemidIp);
177                                }
178                            }
179                        }
180    
181                        // submit the current ECI doc and update the values in the tax lots used already
182                        submitCashIncreaseDocumentAndUpdateTaxLots(cashIncreaseDocument, taxLotsForUpdate);
183                    }
184    
185                }
186    
187                LOG.debug("createAccrualTransactions() done");
188            }
189    
190            return success;
191        }
192    
193        /**
194         * Builds a map that groups tax lots based on registration code ( a map from registration code to taxlots)
195         * 
196         * @param taxLots
197         * @return a map from registration code to taxlots
198         */
199        protected Map<String, List<HoldingTaxLot>> groupTaxLotsBasedOnRegistrationCode(List<HoldingTaxLot> taxLots) {
200            // build a map that groups tax lots based on registration code ( a map from registration code to taxlots)
201            Map<String, List<HoldingTaxLot>> regCodeMap = new HashMap<String, List<HoldingTaxLot>>();
202    
203            for (HoldingTaxLot holdingTaxLot : taxLots) {
204                String registrationCode = holdingTaxLot.getRegistrationCode();
205                if (regCodeMap.containsKey(registrationCode)) {
206                    regCodeMap.get(registrationCode).add(holdingTaxLot);
207                }
208                else {
209                    List<HoldingTaxLot> tmpTaxLots = new ArrayList<HoldingTaxLot>();
210                    tmpTaxLots.add(holdingTaxLot);
211                    regCodeMap.put(registrationCode, tmpTaxLots);
212                }
213            }
214    
215            return regCodeMap;
216        }
217    
218        /**
219         * Builds a map that groups tax lots based on kemid and income principal indicator ( a map from kemid and IP to taxlots).
220         * 
221         * @param taxLots
222         * @return a map from kemid and IP to taxlots
223         */
224        protected Map<String, List<HoldingTaxLot>> groupTaxLotsBasedOnKemidAndIPIndicator(List<HoldingTaxLot> taxLots) {
225            // group tax lots by kemid and ip indicator
226            Map<String, List<HoldingTaxLot>> kemidIpMap = new HashMap<String, List<HoldingTaxLot>>();
227    
228            for (HoldingTaxLot holdingTaxLot : taxLots) {
229                String kemidAndIp = holdingTaxLot.getKemid() + holdingTaxLot.getIncomePrincipalIndicator();
230                if (kemidIpMap.containsKey(kemidAndIp)) {
231                    kemidIpMap.get(kemidAndIp).add(holdingTaxLot);
232                }
233                else {
234                    List<HoldingTaxLot> tmpTaxLots = new ArrayList<HoldingTaxLot>();
235                    tmpTaxLots.add(holdingTaxLot);
236                    kemidIpMap.put(kemidAndIp, tmpTaxLots);
237                }
238            }
239    
240            return kemidIpMap;
241        }
242    
243        /**
244         * Creates and adds a new transaction line to the cash increase document.
245         * 
246         * @param cashIncreaseDocument
247         * @param security
248         * @param kemid
249         * @param totalAmount
250         * @return true if transaction line successfully added, false otherwise
251         */
252        protected boolean addTransactionLine(CashIncreaseDocument cashIncreaseDocument, Security security, String kemid, KualiDecimal totalAmount) {
253            boolean success = true;
254    
255            // Create a new transaction line
256            EndowmentTransactionLine endowmentTransactionLine = new EndowmentTargetTransactionLine();
257            endowmentTransactionLine.setDocumentNumber(cashIncreaseDocument.getDocumentNumber());
258            endowmentTransactionLine.setKemid(kemid);
259            endowmentTransactionLine.setEtranCode(security.getClassCode().getSecurityIncomeEndowmentTransactionPostCode());
260            endowmentTransactionLine.setTransactionIPIndicatorCode(EndowConstants.IncomePrincipalIndicator.INCOME);
261            endowmentTransactionLine.setTransactionAmount(totalAmount);
262    
263            boolean rulesPassed = kualiRuleService.applyRules(new AddTransactionLineEvent(NEW_TARGET_TRAN_LINE_PROPERTY_NAME, cashIncreaseDocument, endowmentTransactionLine));
264    
265            if (rulesPassed) {
266                cashIncreaseDocument.addTargetTransactionLine((EndowmentTargetTransactionLine) endowmentTransactionLine);
267                totalReportLine.addIncomeAmount(totalAmount);
268            }
269            else {
270                success = false;
271    
272                // write an exception line when a transaction line fails to pass the validation.
273                exceptionReportLine.setKemid(kemid);
274                exceptionReportLine.setIncomeAmount(totalAmount);
275                if (isFistTimeForWritingExceptionReport) {
276                    accrualTransactionsExceptionReportWriterService.writeTableHeader(exceptionReportLine);
277                    isFistTimeForWritingExceptionReport = false;
278                }
279                accrualTransactionsExceptionReportWriterService.writeTableRow(exceptionReportLine);
280                List<String> errorMessages = GloabalVariablesExtractHelper.extractGlobalVariableErrors();
281                for (String errorMessage : errorMessages) {
282                    accrualTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", errorMessage);
283                    accrualTransactionsExceptionReportWriterService.writeNewLines(1);
284                }
285            }
286            return success;
287        }
288    
289        /**
290         * Creates a new CashIncreaseDocument with source type Automated, transaction sub-type Cash, target security id set to the input
291         * security id.
292         * 
293         * @param securityId
294         * @return a new CashIncreaseDocument
295         */
296        protected CashIncreaseDocument createNewCashIncreaseDocument(String securityId, String registrationCode) {
297            CashIncreaseDocument cashIncreaseDocument = null;
298            try {
299    
300                cashIncreaseDocument = (CashIncreaseDocument) documentService.getNewDocument(getCashIncreaseDocumentType());
301                String documentDescription = parameterService.getParameterValue(CreateAccrualTransactionsStep.class, EndowParameterKeyConstants.DESCRIPTION);
302                cashIncreaseDocument.getDocumentHeader().setDocumentDescription(documentDescription);
303                cashIncreaseDocument.setTransactionSourceTypeCode(EndowConstants.TransactionSourceTypeCode.AUTOMATED);
304                cashIncreaseDocument.setTransactionSubTypeCode(EndowConstants.TransactionSubTypeCode.CASH);
305    
306                // set security details
307                EndowmentTransactionSecurity targetTransactionSecurity = new EndowmentTargetTransactionSecurity();
308                targetTransactionSecurity.setSecurityID(securityId);
309                targetTransactionSecurity.setRegistrationCode(registrationCode);
310                cashIncreaseDocument.setTargetTransactionSecurity(targetTransactionSecurity);
311    
312            }
313            catch (WorkflowException ex) {
314                if (isFistTimeForWritingExceptionReport) {
315                    if (exceptionReportLine == null) {
316                        exceptionReportLine = new TransactionDocumentExceptionReportLine(getCashIncreaseDocumentType(), "", securityId);
317                    }
318                    accrualTransactionsExceptionReportWriterService.writeTableHeader(exceptionReportLine);
319                    isFistTimeForWritingExceptionReport = false;
320                }
321                accrualTransactionsExceptionReportWriterService.writeTableRow(exceptionReportLine);
322                accrualTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", "WorkflowException while creating a CashIncreaseDocument for Accrual Transactions: " + ex.toString());
323                accrualTransactionsExceptionReportWriterService.writeNewLines(1);
324            }
325    
326            return cashIncreaseDocument;
327        }
328    
329        /**
330         * Submits the ECI doc and updates the values in the tax lots list.
331         * 
332         * @param cashIncreaseDocument
333         * @param taxLotsForUpdate
334         */
335        protected void submitCashIncreaseDocumentAndUpdateTaxLots(CashIncreaseDocument cashIncreaseDocument, List<HoldingTaxLot> taxLotsForUpdate) {
336    
337            boolean rulesPassed = kualiRuleService.applyRules(new RouteDocumentEvent(cashIncreaseDocument));
338    
339            if (rulesPassed) {
340    
341                String noRouteIndVal = parameterService.getParameterValue(CreateAccrualTransactionsStep.class, EndowParameterKeyConstants.NO_ROUTE_IND);
342                boolean noRouteIndicator = EndowConstants.YES.equalsIgnoreCase(noRouteIndVal) ? true : false;
343    
344                try {
345                    cashIncreaseDocument.setNoRouteIndicator(noRouteIndicator);
346                    // TODO figure out if/how we use the ad hoc recipients list
347                    documentService.routeDocument(cashIncreaseDocument, "Created by Accrual Transactions Batch process.", null);
348    
349                    // write a total report line for a CashIncreaseDocument
350                    if (isFistTimeForWritingTotalReport) {
351                        accrualTransactionsTotalReportWriterService.writeTableHeader(totalReportLine);
352                        isFistTimeForWritingTotalReport = false;
353                    }
354    
355                    accrualTransactionsTotalReportWriterService.writeTableRow(totalReportLine);
356    
357                    // set accrued income to zero and copy current value in prior accrued income
358                    for (HoldingTaxLot taxLotForUpdate : taxLotsForUpdate) {
359                        taxLotForUpdate.setPriorAccrual(taxLotForUpdate.getCurrentAccrual());
360                        taxLotForUpdate.setCurrentAccrual(BigDecimal.ZERO);
361                    }
362    
363                    // save changes
364                    businessObjectService.save(taxLotsForUpdate);
365                }
366                catch (WorkflowException ex) {
367                    // save document if it can not be routed....
368                    try {
369                        documentService.saveDocument(cashIncreaseDocument);
370                    } catch (WorkflowException savewfe) {
371                        
372                    }
373                    
374                    if (isFistTimeForWritingExceptionReport) {
375                        accrualTransactionsExceptionReportWriterService.writeTableHeader(exceptionReportLine);
376                        isFistTimeForWritingExceptionReport = false;
377                    }
378    
379                    accrualTransactionsExceptionReportWriterService.writeTableRow(exceptionReportLine);
380                    accrualTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", "WorkflowException while routing a CashIncreaseDocument for Accrual Transactions batch process: " + ex.toString());
381                    accrualTransactionsExceptionReportWriterService.writeNewLines(1);
382                }
383            }
384            else {
385                try {
386                    exceptionReportLine.setSecurityId(cashIncreaseDocument.getTargetTransactionSecurity().getSecurityID());
387                    exceptionReportLine.setIncomeAmount(cashIncreaseDocument.getTargetIncomeTotal());
388                    accrualTransactionsExceptionReportWriterService.writeTableRow(exceptionReportLine);
389                    List<String> errorMessages = GloabalVariablesExtractHelper.extractGlobalVariableErrors();
390                    for (String errorMessage : errorMessages) {
391                        accrualTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", errorMessage);
392                        accrualTransactionsExceptionReportWriterService.writeNewLines(1);
393                    }
394    
395                    // try to save the document
396                    documentService.saveDocument(cashIncreaseDocument);
397    
398                }
399                catch (WorkflowException ex) {
400                    // have to write a table header before write the table row.
401                    if (isFistTimeForWritingExceptionReport) {
402                        accrualTransactionsExceptionReportWriterService.writeTableHeader(exceptionReportLine);
403                        isFistTimeForWritingExceptionReport = false;
404                    }
405                    accrualTransactionsExceptionReportWriterService.writeTableRow(exceptionReportLine);
406                    // Write reason as a formatted message in a second line
407                    accrualTransactionsExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", "WorkflowException while saving a CashIncreaseDocument for Accrual Transactions batch process: " + ex.toString());
408                    accrualTransactionsExceptionReportWriterService.writeNewLines(1);
409    
410                }
411    
412            }
413        }
414    
415        /**
416         * Gets the CashIncreaseDocument type.
417         * 
418         * @return the CashIncreaseDocument type
419         */
420        private String getCashIncreaseDocumentType() {
421            return "ECI";
422        }
423    
424        /**
425         * Locates all Security records for which the next income pay date is equal to the current date.
426         * 
427         * @return
428         */
429        protected List<Security> getAllSecuritiesWithNextPayDateEqualCurrentDate() {
430            List<Security> result = new ArrayList<Security>();
431    
432            result = securityDao.getAllSecuritiesWithNextPayDateEqualCurrentDate();
433    
434            return result;
435        }
436    
437        /**
438         * Initializes the total report line and the exception report line.
439         * 
440         * @param theDocumentId
441         * @param theSecurityId
442         */
443        protected void initializeTotalAndExceptionReportLines(String theDocumentId, String theSecurityId) {
444            // create a new totalReportLine for each new CashIncreaseDocument
445            this.totalReportLine = new TransactionDocumentTotalReportLine(getCashIncreaseDocumentType(), theDocumentId, theSecurityId);
446    
447            // create an exceptionReportLine instance that can be reused for reporting multiple errors for a CashIncreaseDocument
448            this.exceptionReportLine = new TransactionDocumentExceptionReportLine(getCashIncreaseDocumentType(), theDocumentId, theSecurityId);
449    
450        }
451    
452        /**
453         * Sets the businessObjectService.
454         * 
455         * @param businessObjectService
456         */
457        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
458            this.businessObjectService = businessObjectService;
459        }
460    
461        /**
462         * Sets the kemService.
463         * 
464         * @param kemService
465         */
466        public void setKemService(KEMService kemService) {
467            this.kemService = kemService;
468        }
469    
470        /**
471         * Sets the holdingTaxLotService.
472         * 
473         * @param holdingTaxLotService
474         */
475        public void setHoldingTaxLotService(HoldingTaxLotService holdingTaxLotService) {
476            this.holdingTaxLotService = holdingTaxLotService;
477        }
478    
479        /**
480         * Sets the securityDao.
481         * 
482         * @param securityDao
483         */
484        public void setSecurityDao(SecurityDao securityDao) {
485            this.securityDao = securityDao;
486        }
487    
488        /**
489         * Sets the documenyService.
490         * 
491         * @param documentService
492         */
493        public void setDocumentService(DocumentService documentService) {
494            this.documentService = documentService;
495        }
496    
497        /**
498         * Sets the configService.
499         * 
500         * @param configService
501         */
502        public void setConfigService(KualiConfigurationService configService) {
503            this.configService = configService;
504        }
505    
506        /**
507         * Sets the kualiRuleService.
508         * 
509         * @param kualiRuleService
510         */
511        public void setKualiRuleService(KualiRuleService kualiRuleService) {
512            this.kualiRuleService = kualiRuleService;
513        }
514    
515        /**
516         * Sets the parameterService.
517         * 
518         * @param parameterService
519         */
520        public void setParameterService(ParameterService parameterService) {
521            this.parameterService = parameterService;
522        }
523    
524        /**
525         * Gets the accrualTransactionsExceptionReportWriterService.
526         * 
527         * @return accrualTransactionsExceptionReportWriterService
528         */
529        public ReportWriterService getAccrualTransactionsExceptionReportWriterService() {
530            return accrualTransactionsExceptionReportWriterService;
531        }
532    
533        /**
534         * Sets the accrualTransactionsExceptionReportWriterService.
535         * 
536         * @param accrualTransactionsExceptionReportWriterService
537         */
538        public void setAccrualTransactionsExceptionReportWriterService(ReportWriterService accrualTransactionsExceptionReportWriterService) {
539            this.accrualTransactionsExceptionReportWriterService = accrualTransactionsExceptionReportWriterService;
540        }
541    
542        /**
543         * Gets the accrualTransactionsTotalReportWriterService.
544         * 
545         * @return accrualTransactionsTotalReportWriterService
546         */
547        public ReportWriterService getAccrualTransactionsTotalReportWriterService() {
548            return accrualTransactionsTotalReportWriterService;
549        }
550    
551        /**
552         * Sets the accrualTransactionsTotalReportWriterService.
553         * 
554         * @param accrualTransactionsTotalReportWriterService
555         */
556        public void setAccrualTransactionsTotalReportWriterService(ReportWriterService accrualTransactionsTotalReportWriterService) {
557            this.accrualTransactionsTotalReportWriterService = accrualTransactionsTotalReportWriterService;
558        }
559    }