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_SOURCE_TRAN_LINE_PROPERTY_NAME;
019    import static org.kuali.kfs.module.endow.EndowConstants.NEW_TARGET_TRAN_LINE_PROPERTY_NAME;
020    
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.CreateGainLossDistributionTransactionsStep;
029    import org.kuali.kfs.module.endow.batch.service.CreateGainLossDistributionTransactionsService;
030    import org.kuali.kfs.module.endow.businessobject.EndowmentExceptionReportHeader;
031    import org.kuali.kfs.module.endow.businessobject.EndowmentSourceTransactionLine;
032    import org.kuali.kfs.module.endow.businessobject.EndowmentSourceTransactionSecurity;
033    import org.kuali.kfs.module.endow.businessobject.EndowmentTargetTransactionLine;
034    import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLine;
035    import org.kuali.kfs.module.endow.businessobject.GainLossDistributionTotalReportLine;
036    import org.kuali.kfs.module.endow.businessobject.HoldingTaxLot;
037    import org.kuali.kfs.module.endow.businessobject.PooledFundValue;
038    import org.kuali.kfs.module.endow.businessobject.TransactionDocumentExceptionReportLine;
039    import org.kuali.kfs.module.endow.document.HoldingAdjustmentDocument;
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.service.PooledFundValueService;
043    import org.kuali.kfs.module.endow.document.service.UpdateHoldingAdjustmentDocumentTaxLotsService;
044    import org.kuali.kfs.module.endow.document.validation.event.AddTransactionLineEvent;
045    import org.kuali.kfs.module.endow.util.GloabalVariablesExtractHelper;
046    import org.kuali.kfs.sys.KFSConstants;
047    import org.kuali.kfs.sys.service.ReportWriterService;
048    import org.kuali.rice.kew.exception.WorkflowException;
049    import org.kuali.rice.kns.rule.event.RouteDocumentEvent;
050    import org.kuali.rice.kns.service.BusinessObjectService;
051    import org.kuali.rice.kns.service.DocumentService;
052    import org.kuali.rice.kns.service.KualiConfigurationService;
053    import org.kuali.rice.kns.service.KualiRuleService;
054    import org.kuali.rice.kns.service.ParameterService;
055    import org.kuali.rice.kns.util.ObjectUtils;
056    import org.springframework.transaction.annotation.Transactional;
057    
058    @Transactional
059    public class CreateGainLossDistributionTransactionsServiceImpl implements CreateGainLossDistributionTransactionsService {
060    
061        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CreateGainLossDistributionTransactionsServiceImpl.class);
062    
063        private PooledFundValueService pooledFundValueService;
064        private HoldingTaxLotService holdingTaxLotService;
065        private DocumentService documentService;
066        private ParameterService parameterService;
067        private KualiConfigurationService configService;
068        private KualiRuleService kualiRuleService;
069        private BusinessObjectService businessObjectService;
070        private UpdateHoldingAdjustmentDocumentTaxLotsService updateHoldingAdjustmentDocumentTaxLotsService;
071        private KEMService kemService;
072    
073        private ReportWriterService gainLossDistributionExceptionReportWriterService;
074        private ReportWriterService gainLossDistributionTotalsReportWriterService;
075    
076        private EndowmentExceptionReportHeader gainLossDistributionExceptionRowReason;
077        private GainLossDistributionTotalReportLine distributionTotalReportLine;
078        private TransactionDocumentExceptionReportLine exceptionReportLine;
079    
080        private boolean isFistTimeForWritingTotalReport = true;
081        private boolean isFistTimeForWritingExceptionReport = true;
082    
083        /**
084         * Constructs a CreateGainLossDistributionTransactionsServiceImpl.java.
085         */
086        public CreateGainLossDistributionTransactionsServiceImpl() {
087            gainLossDistributionExceptionRowReason = new EndowmentExceptionReportHeader();
088        }
089    
090        /**
091         * @see org.kuali.kfs.module.endow.batch.service.CreateGainLossDistributionTransactionsService#processGainLossDistribution()
092         */
093        public boolean processGainLossDistribution() {
094            boolean result = true;
095    
096            LOG.debug("processGainLossDistribution() started");
097    
098            // process short term gain/loss
099            result &= processShortTermGainLossDistribution();
100    
101            // process long term gain/loss
102            result &= processLongTermGainLossDistribution();
103    
104            return result;
105        }
106    
107        /**
108         * Processes Short Term Gains and Losses.
109         * 
110         * @return true if successful, false otherwise
111         */
112        protected boolean processShortTermGainLossDistribution() {
113            return processGainLossDistribution(true);
114        }
115    
116        /**
117         * Processes Long Term Gains and Losses.
118         * 
119         * @return true if successful, false otherwise
120         */
121        protected boolean processLongTermGainLossDistribution() {
122            return processGainLossDistribution(false);
123        }
124    
125    
126        /**
127         * Processes Short/Long Term Gains and Losses.
128         * 
129         * @return true if successful, false otherwise
130         */
131        protected boolean processGainLossDistribution(boolean isShortTerm) {
132            boolean result = true;
133            List<PooledFundValue> pooledFundValues = null;
134            int maxNumberOfTranLines = kemService.getMaxNumberOfTransactionLinesPerDocument();
135    
136            // process gain/loss
137    
138            if (isShortTerm) {
139                // 1. collect all PooledFundValue entries with ST_PROC_ON_DT equal to current date
140                pooledFundValues = pooledFundValueService.getPooledFundValueWhereSTProcessOnDateIsCurrentDate();
141            }
142            else {
143                // 1. collect all PooledFundValue entries with LT_PROC_ON_DT equal to current date
144                pooledFundValues = pooledFundValueService.getPooledFundValueWhereLTProcessOnDateIsCurrentDate();
145            }
146    
147            for (PooledFundValue pooledFundValue : pooledFundValues) {
148                // 3. get all tax lots with security ID equal to pooledSecurityId
149                List<HoldingTaxLot> holdingTaxLots = holdingTaxLotService.getTaxLotsPerSecurityIDWithUnitsGreaterThanZero(pooledFundValue.getPooledSecurityID());
150    
151                // group by registration code
152                if (holdingTaxLots != null) {
153                    // a map from registration code to taxlots
154                    Map<String, List<HoldingTaxLot>> regCodeMap = groupTaxLotsByRegistrationCode(holdingTaxLots);
155    
156                    // for each security and registration code generate a new HoldingAdjustmentDocument
157    
158                    for (String registrationCode : regCodeMap.keySet()) {
159    
160                        List<HoldingTaxLot> taxLots = regCodeMap.get(registrationCode);
161                        // 4. generate Holding Adjustment document
162                        HoldingAdjustmentDocument holdingAdjustmentDocument = generateHoldingAdjustmentDocument(isShortTerm, pooledFundValue.getPooledSecurityID());
163    
164                        if (holdingAdjustmentDocument != null) {
165                            // add security details
166                            addSecurityDetails(holdingAdjustmentDocument, pooledFundValue.getPooledSecurityID(), registrationCode);
167    
168                            initializeReportLines(holdingAdjustmentDocument.getDocumentNumber(), pooledFundValue.getPooledSecurityID());
169    
170                            int counter = 0;
171                            // add transaction lines
172                            if (taxLots != null) {
173    
174                                for (HoldingTaxLot holdingTaxLot : taxLots) {
175    
176                                    // check if we reached the maximum number of transaction lines
177                                    if (counter == maxNumberOfTranLines) {
178                                        counter = 0;
179    
180                                        // route document
181                                        validateAndRouteHoldingAdjustmentDocument(holdingAdjustmentDocument, pooledFundValue, isShortTerm);
182    
183                                        // generate a new Holding Adjustment document
184                                        holdingAdjustmentDocument = generateHoldingAdjustmentDocument(isShortTerm, pooledFundValue.getPooledSecurityID());
185    
186                                        if (holdingAdjustmentDocument != null) {
187                                            // add security details
188                                            addSecurityDetails(holdingAdjustmentDocument, pooledFundValue.getPooledSecurityID(), registrationCode);
189    
190                                            initializeReportLines(holdingAdjustmentDocument.getDocumentNumber(), pooledFundValue.getPooledSecurityID());
191                                        }
192                                    }
193    
194                                    if (holdingAdjustmentDocument != null) {
195                                        if (addTransactionLine(isShortTerm, holdingAdjustmentDocument, holdingTaxLot, pooledFundValue))
196                                            counter++;
197                                    }
198    
199                                }
200                            }
201    
202                            if (holdingAdjustmentDocument != null) {
203                                // route document
204                                validateAndRouteHoldingAdjustmentDocument(holdingAdjustmentDocument, pooledFundValue, isShortTerm);
205                            }
206                        }
207                    }
208                }
209            }
210    
211            return result;
212        }
213    
214        /**
215         * Groups tax lots by registration code.
216         * 
217         * @param holdingTaxLots
218         * @return a map from registration code to taxlots
219         */
220        protected Map<String, List<HoldingTaxLot>> groupTaxLotsByRegistrationCode(List<HoldingTaxLot> holdingTaxLots) {
221            Map<String, List<HoldingTaxLot>> regCodeMap = new HashMap<String, List<HoldingTaxLot>>();
222    
223            for (HoldingTaxLot holdingTaxLot : holdingTaxLots) {
224                String registrationCode = holdingTaxLot.getRegistrationCode();
225                if (regCodeMap.containsKey(registrationCode)) {
226                    regCodeMap.get(registrationCode).add(holdingTaxLot);
227                }
228                else {
229                    List<HoldingTaxLot> tmpTaxLots = new ArrayList<HoldingTaxLot>();
230                    tmpTaxLots.add(holdingTaxLot);
231                    regCodeMap.put(registrationCode, tmpTaxLots);
232                }
233            }
234    
235            return regCodeMap;
236        }
237    
238    
239        /**
240         * Generates a HoldingAdjustmentDocument.
241         * 
242         * @return the HoldingAdjustmentDocument
243         */
244        protected HoldingAdjustmentDocument generateHoldingAdjustmentDocument(boolean isShortTerm, String securityId) {
245            HoldingAdjustmentDocument holdingAdjustmentDocument = null;
246    
247            String documentDescription = "";
248    
249            if (isShortTerm) {
250                documentDescription = parameterService.getParameterValue(CreateGainLossDistributionTransactionsStep.class, EndowParameterKeyConstants.SHORT_TERM_GAIN_LOSS_DESCRIPTION);
251            }
252            else {
253                documentDescription = parameterService.getParameterValue(CreateGainLossDistributionTransactionsStep.class, EndowParameterKeyConstants.LONG_TERM_GAIN_LOSS_DESCRIPTION);
254            }
255    
256            try {
257                holdingAdjustmentDocument = (HoldingAdjustmentDocument) documentService.getNewDocument(getHoldingAdjustmentDocumentTypeName());
258                holdingAdjustmentDocument.getDocumentHeader().setDocumentDescription(documentDescription);
259                holdingAdjustmentDocument.setTransactionSourceTypeCode(EndowConstants.TransactionSourceTypeCode.AUTOMATED);
260                holdingAdjustmentDocument.setTransactionSubTypeCode(EndowConstants.TransactionSubTypeCode.NON_CASH);
261            }
262            catch (WorkflowException ex) {
263    
264                if (isFistTimeForWritingExceptionReport) {
265                    if (exceptionReportLine == null) {
266                        exceptionReportLine = new TransactionDocumentExceptionReportLine(getHoldingAdjustmentDocumentTypeName(), "", securityId);
267                    }
268                    gainLossDistributionExceptionReportWriterService.writeTableHeader(exceptionReportLine);
269                    isFistTimeForWritingExceptionReport = false;
270                }
271                gainLossDistributionExceptionReportWriterService.writeTableRow(exceptionReportLine);
272                gainLossDistributionExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", "WorkflowException while creating a HoldingAdjustmentDocument for Distribution of Gains and Losses Batch process: " + ex.toString());
273                gainLossDistributionExceptionReportWriterService.writeNewLines(1);
274            }
275    
276            return holdingAdjustmentDocument;
277        }
278    
279        /**
280         * Creates and add a source security details to the holding adjustment document.
281         * 
282         * @param holdingAdjustmentDocument
283         * @param securityId
284         * @param registrationCode
285         */
286        protected void addSecurityDetails(HoldingAdjustmentDocument holdingAdjustmentDocument, String securityId, String registrationCode) {
287    
288            // create new source security details
289            EndowmentSourceTransactionSecurity endowmentSourceTransactionSecurity = new EndowmentSourceTransactionSecurity();
290            endowmentSourceTransactionSecurity.setDocumentNumber(holdingAdjustmentDocument.getDocumentNumber());
291            endowmentSourceTransactionSecurity.setSecurityID(securityId);
292            endowmentSourceTransactionSecurity.setRegistrationCode(registrationCode);
293    
294            // add it to the document
295            holdingAdjustmentDocument.setSourceTransactionSecurity(endowmentSourceTransactionSecurity);
296        }
297        
298        /**
299         * creates a transaction line and setups the data based on isLoss
300         * if isLoss = true then creates source line else creates target line.
301         */
302        protected EndowmentTransactionLine createEndowmentTransactionLine(boolean isLoss, boolean isShortTerm, HoldingAdjustmentDocument holdingAdjustmentDocument, HoldingTaxLot holdingTaxLot, PooledFundValue pooledFundValue) {
303            EndowmentTransactionLine endowmentTransactionLine = null;
304            
305            if (isLoss) {
306                // loss
307                endowmentTransactionLine = new EndowmentSourceTransactionLine();
308            }
309            else {
310                //gain
311                endowmentTransactionLine = new EndowmentTargetTransactionLine();
312            }
313            
314            if (isShortTerm) {
315                if (isLoss) {
316                    endowmentTransactionLine.setUnitAdjustmentAmount(pooledFundValue.getShortTermGainLossDistributionPerUnit().negate());
317                }
318                else {
319                    endowmentTransactionLine.setUnitAdjustmentAmount(pooledFundValue.getShortTermGainLossDistributionPerUnit());
320                }
321            }
322            else {
323                if (isLoss) {
324                    endowmentTransactionLine.setUnitAdjustmentAmount(pooledFundValue.getLongTermGainLossDistributionPerUnit().negate());
325                }
326                else {
327                    endowmentTransactionLine.setUnitAdjustmentAmount(pooledFundValue.getLongTermGainLossDistributionPerUnit());
328                }
329            }
330    
331            // populate transaction line
332            endowmentTransactionLine.setDocumentNumber(holdingAdjustmentDocument.getDocumentNumber());
333            endowmentTransactionLine.setKemid(holdingTaxLot.getKemid());
334            endowmentTransactionLine.setEtranCode(pooledFundValue.getPooledFundControl().getFundSaleGainLossOffsetTranCode());
335            endowmentTransactionLine.setTransactionIPIndicatorCode(holdingTaxLot.getIncomePrincipalIndicator());
336            
337            return endowmentTransactionLine; 
338        }
339    
340    
341        /**
342         * Creates and adds a transaction line to the holding adjustment document.
343         * 
344         * @param isShortTerm
345         * @param holdingAdjustmentDocument
346         * @param holdingTaxLot
347         * @param gainloss
348         */
349        protected boolean addTransactionLine(boolean isShortTerm, HoldingAdjustmentDocument holdingAdjustmentDocument, HoldingTaxLot holdingTaxLot, PooledFundValue pooledFundValue) {
350            boolean result = false;
351            boolean isLoss = false;
352            
353            if (isShortTerm) {
354                if (pooledFundValue.getShortTermGainLossDistributionPerUnit().signum() == 0) {
355                    return false;    
356                }
357                if (pooledFundValue.getShortTermGainLossDistributionPerUnit().signum() == -1) {
358                    isLoss = true; 
359                }
360            }
361            else {
362                if (pooledFundValue.getLongTermGainLossDistributionPerUnit().signum() == 0) {
363                    return false;    
364                }
365                if (pooledFundValue.getLongTermGainLossDistributionPerUnit().signum() == -1) {
366                    isLoss = true; 
367                }
368            }
369    
370            EndowmentTransactionLine endowmentTransactionLine = createEndowmentTransactionLine(isLoss, isShortTerm, holdingAdjustmentDocument, holdingTaxLot, pooledFundValue);
371            
372            if (ObjectUtils.isNull(endowmentTransactionLine)) {
373                exceptionReportLine.setKemid(holdingTaxLot.getKemid());
374                exceptionReportLine.setSecurityId(pooledFundValue.getPooledSecurityID());
375                if (isFistTimeForWritingExceptionReport) {
376                    gainLossDistributionExceptionReportWriterService.writeTableHeader(exceptionReportLine);
377                    isFistTimeForWritingExceptionReport = false;
378                }
379                gainLossDistributionExceptionReportWriterService.writeTableRow(exceptionReportLine);
380                gainLossDistributionExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", "Unable to create the transaction line to add to the document.");
381                gainLossDistributionExceptionReportWriterService.writeNewLines(1);
382                
383                return false;
384            }
385            
386       //     if (isShortTerm) {
387       //         if (pooledFundValue.getShortTermGainLossDistributionPerUnit().signum() == -1) {
388       //             // loss
389       //             isLoss = true;
390       //             endowmentTransactionLine = new EndowmentSourceTransactionLine();
391       //             endowmentTransactionLine.setUnitAdjustmentAmount(pooledFundValue.getShortTermGainLossDistributionPerUnit().negate());
392    //
393       //         }
394       //         if (pooledFundValue.getShortTermGainLossDistributionPerUnit().signum() >= 0) {
395        //            // gain
396        //            isLoss = false;
397        //            endowmentTransactionLine = new EndowmentTargetTransactionLine();
398        //            endowmentTransactionLine.setUnitAdjustmentAmount(pooledFundValue.getShortTermGainLossDistributionPerUnit());
399        //        }
400        //    }
401       //     else {
402       //         if (pooledFundValue.getLongTermGainLossDistributionPerUnit().signum() == -1) {
403       //             // loss
404       //             isLoss = true;
405       //             endowmentTransactionLine = new EndowmentSourceTransactionLine();
406       //             endowmentTransactionLine.setUnitAdjustmentAmount(pooledFundValue.getLongTermGainLossDistributionPerUnit().negate());
407    //
408        //        }
409        //        if (pooledFundValue.getLongTermGainLossDistributionPerUnit().signum() >= 0) {
410        //            // gain
411        //            isLoss = false;
412         //           endowmentTransactionLine = new EndowmentTargetTransactionLine();
413         //           endowmentTransactionLine.setUnitAdjustmentAmount(pooledFundValue.getLongTermGainLossDistributionPerUnit());
414         //       }
415         //   }
416    
417        //    // populate transaction line
418        //    endowmentTransactionLine.setDocumentNumber(holdingAdjustmentDocument.getDocumentNumber());
419        //    endowmentTransactionLine.setKemid(holdingTaxLot.getKemid());
420       //     endowmentTransactionLine.setEtranCode(pooledFundValue.getPooledFundControl().getFundSaleGainLossOffsetTranCode());
421        //    endowmentTransactionLine.setTransactionIPIndicatorCode(holdingTaxLot.getIncomePrincipalIndicator());
422    
423            // add transaction line
424            String errorPrefix = KFSConstants.EMPTY_STRING;
425            if (endowmentTransactionLine instanceof EndowmentTargetTransactionLine) {
426                errorPrefix = NEW_TARGET_TRAN_LINE_PROPERTY_NAME;
427            }
428            else {
429                errorPrefix = NEW_SOURCE_TRAN_LINE_PROPERTY_NAME;
430            }
431    
432            boolean rulesPassed = kualiRuleService.applyRules(new AddTransactionLineEvent(errorPrefix, holdingAdjustmentDocument, endowmentTransactionLine));
433    
434            if (rulesPassed) {
435                if (isLoss) {
436                    holdingAdjustmentDocument.addSourceTransactionLine((EndowmentSourceTransactionLine) endowmentTransactionLine);
437                }
438                else {
439                    holdingAdjustmentDocument.addTargetTransactionLine((EndowmentTargetTransactionLine) endowmentTransactionLine);
440                }
441    
442                // Generate the tax lots for the transaction line
443                updateHoldingAdjustmentDocumentTaxLotsService.updateTransactionLineTaxLotsByUnitAdjustmentAmount(false, holdingAdjustmentDocument, endowmentTransactionLine, isLoss);
444    
445                distributionTotalReportLine.addUnitAdjustmentAmount(endowmentTransactionLine.getUnitAdjustmentAmount());
446                distributionTotalReportLine.addTotalHoldingAdjustmentAmount(endowmentTransactionLine);
447    
448                result = true;
449            }
450            else {
451                exceptionReportLine.setKemid(holdingTaxLot.getKemid());
452                exceptionReportLine.setSecurityId(pooledFundValue.getPooledSecurityID());
453                if (isFistTimeForWritingExceptionReport) {
454                    gainLossDistributionExceptionReportWriterService.writeTableHeader(exceptionReportLine);
455                    isFistTimeForWritingExceptionReport = false;
456                }
457                gainLossDistributionExceptionReportWriterService.writeTableRow(exceptionReportLine);
458                List<String> errorMessages = GloabalVariablesExtractHelper.extractGlobalVariableErrors();
459                for (String errorMessage : errorMessages) {
460                    gainLossDistributionExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", errorMessage);
461                    gainLossDistributionExceptionReportWriterService.writeNewLines(1);
462                }
463    
464            }
465    
466            return result;
467        }
468    
469        /**
470         * Validates and Routes the HoldingAdjustmentDocument. If document successfully routed set short/long term process complete to
471         * Yes.
472         * 
473         * @param holdingAdjustmentDocument
474         * @param pooledFundValue
475         */
476        protected void validateAndRouteHoldingAdjustmentDocument(HoldingAdjustmentDocument holdingAdjustmentDocument, PooledFundValue pooledFundValue, boolean isShortTerm) {
477            boolean rulesPassed = kualiRuleService.applyRules(new RouteDocumentEvent(holdingAdjustmentDocument));
478    
479            if (rulesPassed) {
480    
481                String noRouteIndVal = parameterService.getParameterValue(CreateGainLossDistributionTransactionsStep.class, EndowParameterKeyConstants.GAIN_LOSS_NO_ROUTE_IND);
482                boolean noRouteIndicator = EndowConstants.YES.equalsIgnoreCase(noRouteIndVal) ? true : false;
483    
484                try {
485                    holdingAdjustmentDocument.setNoRouteIndicator(noRouteIndicator);
486                    // TODO figure out if/how we use the ad hoc recipients list
487                    documentService.routeDocument(holdingAdjustmentDocument, "Created by Distribution of Gains and Losses Batch process.", null);
488    
489                    // write a total report line for a HoldingAdjustmentDocument
490                    if (isFistTimeForWritingTotalReport) {
491                        gainLossDistributionTotalsReportWriterService.writeTableHeader(distributionTotalReportLine);
492                        isFistTimeForWritingTotalReport = false;
493                    }
494    
495                    gainLossDistributionTotalsReportWriterService.writeTableRow(distributionTotalReportLine);
496    
497                    // set short/long term process complete to Yes
498                    if (isShortTerm) {
499                        pooledFundValue.setShortTermGainLossDistributionComplete(true);
500                    }
501                    else {
502                        pooledFundValue.setLongTermGainLossDistributionComplete(true);
503                    }
504    
505                    // save changes
506                    businessObjectService.save(pooledFundValue);
507                }
508                catch (WorkflowException ex) {
509                    if (isFistTimeForWritingExceptionReport) {
510                        if (exceptionReportLine == null) {
511                            exceptionReportLine = new TransactionDocumentExceptionReportLine(getHoldingAdjustmentDocumentTypeName(), "", holdingAdjustmentDocument.getSourceTransactionSecurity().getSecurityID());
512                        }
513                        gainLossDistributionExceptionReportWriterService.writeTableHeader(exceptionReportLine);
514                        isFistTimeForWritingExceptionReport = false;
515                    }
516                    gainLossDistributionExceptionReportWriterService.writeTableRow(exceptionReportLine);
517                    gainLossDistributionExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", "WorkflowException while routing a HoldingAdjustmentDocument for Distribution of Gains and Losses Batch process: " + ex.toString());
518                    gainLossDistributionExceptionReportWriterService.writeNewLines(1);
519                }
520            }
521            else {
522    
523                try {
524                    // try to save the document
525                    documentService.saveDocument(holdingAdjustmentDocument);
526                    exceptionReportLine.setSecurityId(holdingAdjustmentDocument.getSourceTransactionSecurity().getSecurityID());
527                    gainLossDistributionExceptionReportWriterService.writeTableRow(exceptionReportLine);
528                    List<String> errorMessages = GloabalVariablesExtractHelper.extractGlobalVariableErrors();
529                    for (String errorMessage : errorMessages) {
530                        gainLossDistributionExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", errorMessage);
531                        gainLossDistributionExceptionReportWriterService.writeNewLines(1);
532                    }
533                }
534                catch (WorkflowException ex) {
535                    // have to write a table header before write the table row.
536                    if (isFistTimeForWritingExceptionReport) {
537                        gainLossDistributionExceptionReportWriterService.writeTableHeader(exceptionReportLine);
538                        isFistTimeForWritingExceptionReport = false;
539                    }
540                    gainLossDistributionExceptionReportWriterService.writeTableRow(exceptionReportLine);
541                    // Write reason as a formatted message in a second line
542                    gainLossDistributionExceptionReportWriterService.writeFormattedMessageLine("Reason:  %s", "WorkflowException while saving a HoldingAdjustmentDocument for Gain Loss Distribution batch process: " + ex.toString());
543                    gainLossDistributionExceptionReportWriterService.writeNewLines(1);
544                }
545            }
546        }
547    
548    
549        /**
550         * Gets the HoldingAdjustmentDocument type.
551         * 
552         * @return the HoldingAdjustmentDocument type
553         */
554        protected String getHoldingAdjustmentDocumentTypeName() {
555            return "EHA";
556        }
557    
558        /**
559         * Sets the pooledFundValueService.
560         * 
561         * @param pooledFundValueService
562         */
563        public void setPooledFundValueService(PooledFundValueService pooledFundValueService) {
564            this.pooledFundValueService = pooledFundValueService;
565        }
566    
567        /**
568         * Sets the holdingTaxLotService.
569         * 
570         * @param holdingTaxLotService
571         */
572        public void setHoldingTaxLotService(HoldingTaxLotService holdingTaxLotService) {
573            this.holdingTaxLotService = holdingTaxLotService;
574        }
575    
576        /**
577         * Sets the parameterService.
578         * 
579         * @param parameterService
580         */
581        public void setParameterService(ParameterService parameterService) {
582            this.parameterService = parameterService;
583        }
584    
585        /**
586         * Sets the configService.
587         * 
588         * @param configService
589         */
590        public void setConfigService(KualiConfigurationService configService) {
591            this.configService = configService;
592        }
593    
594        /**
595         * Sets the kualiRuleService.
596         * 
597         * @param kualiRuleService
598         */
599        public void setKualiRuleService(KualiRuleService kualiRuleService) {
600            this.kualiRuleService = kualiRuleService;
601        }
602    
603        /**
604         * Sets the businessObjectService.
605         * 
606         * @param businessObjectService
607         */
608        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
609            this.businessObjectService = businessObjectService;
610        }
611    
612        /**
613         * Sets the documentService.
614         * 
615         * @param documentService
616         */
617        public void setDocumentService(DocumentService documentService) {
618            this.documentService = documentService;
619        }
620    
621        /**
622         * Sets the gainLossDistributionExceptionReportWriterService.
623         * 
624         * @param gainLossDistributionExceptionReportWriterService
625         */
626        public void setGainLossDistributionExceptionReportWriterService(ReportWriterService gainLossDistributionExceptionReportWriterService) {
627            this.gainLossDistributionExceptionReportWriterService = gainLossDistributionExceptionReportWriterService;
628        }
629    
630        /**
631         * Gets the gainLossDistributionExceptionReportWriterService.
632         * 
633         * @return gainLossDistributionExceptionReportWriterService
634         */
635        public ReportWriterService getGainLossDistributionExceptionReportWriterService() {
636            return gainLossDistributionExceptionReportWriterService;
637        }
638    
639        /**
640         * Sets the updateHoldingAdjustmentDocumentTaxLotsService.
641         * 
642         * @param updateHoldingAdjustmentDocumentTaxLotsService
643         */
644        public void setUpdateHoldingAdjustmentDocumentTaxLotsService(UpdateHoldingAdjustmentDocumentTaxLotsService updateHoldingAdjustmentDocumentTaxLotsService) {
645            this.updateHoldingAdjustmentDocumentTaxLotsService = updateHoldingAdjustmentDocumentTaxLotsService;
646        }
647    
648        /**
649         * Sets the kemService.
650         * 
651         * @param kemService
652         */
653        public void setKemService(KEMService kemService) {
654            this.kemService = kemService;
655        }
656    
657        /**
658         * Initializes the distributionTotalReportLine and exceptionReportLine for further use.
659         * 
660         * @param theDocumentId
661         * @param theSecurityId
662         */
663        protected void initializeReportLines(String theDocumentId, String theSecurityId) {
664            // create a new distributionTotalReportLine for each new HoldingAdjustmentDocument
665            this.distributionTotalReportLine = new GainLossDistributionTotalReportLine(getHoldingAdjustmentDocumentTypeName(), theDocumentId, theSecurityId);
666    
667            // create an exceptionReportLine instance that can be reused for reporting multiple errors for a HoldingAdjustmentDocument
668            this.exceptionReportLine = new TransactionDocumentExceptionReportLine(getHoldingAdjustmentDocumentTypeName(), theDocumentId, theSecurityId);
669    
670        }
671    
672        /**
673         * Gets the gainLossDistributionTotalsReportWriterService.
674         * 
675         * @return gainLossDistributionTotalsReportWriterService
676         */
677        public ReportWriterService getGainLossDistributionTotalsReportWriterService() {
678            return gainLossDistributionTotalsReportWriterService;
679        }
680    
681        /**
682         * Sets the gainLossDistributionTotalsReportWriterService.
683         * 
684         * @param gainLossDistributionTotalsReportWriterService
685         */
686        public void setGainLossDistributionTotalsReportWriterService(ReportWriterService gainLossDistributionTotalsReportWriterService) {
687            this.gainLossDistributionTotalsReportWriterService = gainLossDistributionTotalsReportWriterService;
688        }
689    }