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.document.service.impl;
017    
018    import java.math.BigDecimal;
019    import java.util.ArrayList;
020    import java.util.Calendar;
021    import java.util.Collection;
022    import java.util.Date;
023    import java.util.HashMap;
024    import java.util.List;
025    import java.util.Map;
026    
027    import org.apache.commons.lang.StringUtils;
028    import org.kuali.kfs.module.endow.EndowConstants;
029    import org.kuali.kfs.module.endow.EndowPropertyConstants;
030    import org.kuali.kfs.module.endow.batch.service.impl.CurrentTaxLotBalanceUpdateServiceImpl;
031    import org.kuali.kfs.module.endow.businessobject.CurrentTaxLotBalance;
032    import org.kuali.kfs.module.endow.businessobject.HoldingHistory;
033    import org.kuali.kfs.module.endow.businessobject.HoldingTaxLot;
034    import org.kuali.kfs.module.endow.businessobject.Security;
035    import org.kuali.kfs.module.endow.dataaccess.CurrentTaxLotBalanceDao;
036    import org.kuali.kfs.module.endow.dataaccess.TransactionArchiveDao;
037    import org.kuali.kfs.module.endow.document.service.CurrentTaxLotService;
038    import org.kuali.kfs.module.endow.document.service.KEMService;
039    import org.kuali.kfs.module.endow.document.service.SecurityService;
040    import org.kuali.kfs.module.endow.util.KEMCalculationRoundingHelper;
041    import org.kuali.kfs.sys.context.SpringContext;
042    import org.kuali.rice.kns.service.BusinessObjectService;
043    import org.kuali.rice.kns.service.DataDictionaryService;
044    import org.kuali.rice.kns.util.KualiInteger;
045    import org.kuali.rice.kns.util.ObjectUtils;
046    import org.springframework.transaction.annotation.Transactional;
047    
048    /**
049     * Implementation to provide services for CurrentTaxLotBalance business object.
050     */
051    @Transactional
052    public class CurrentTaxLotServiceImpl implements CurrentTaxLotService {
053        protected BusinessObjectService businessObjectService;
054        protected SecurityService securityService;
055        protected KEMService kEMService;
056        protected CurrentTaxLotBalanceDao currentTaxLotBalanceDao;
057        protected TransactionArchiveDao transactionArchiveDao;
058    
059        /**
060         * @see org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getByPrimaryKey(java.lang.String, java.lang.String,
061         *      java.lang.String, int, java.lang.String)
062         */
063        public CurrentTaxLotBalance getByPrimaryKey(String kemid, String securityId, String registrationCode, KualiInteger lotNumber, String ipIndicator) {
064            Map<String, String> primaryKeys = new HashMap<String, String>();
065    
066            primaryKeys.put(EndowPropertyConstants.CURRENT_TAX_LOT_KEMID, kemid);
067            primaryKeys.put(EndowPropertyConstants.CURRENT_TAX_LOT_SECURITY_ID, securityId);
068            primaryKeys.put(EndowPropertyConstants.CURRENT_TAX_LOT_REGIS_CD, registrationCode);
069            primaryKeys.put(EndowPropertyConstants.CURRENT_TAX_LOT_LOT_NBR, String.valueOf(lotNumber));
070            primaryKeys.put(EndowPropertyConstants.CURRENT_TAX_LOT_IP_IND, ipIndicator);
071    
072            return (CurrentTaxLotBalance) businessObjectService.findByPrimaryKey(CurrentTaxLotBalance.class, primaryKeys);
073    
074        }
075        
076        /**
077         * @org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getCurrentTaxLotBalancesForMatchingSecurityClassCode(String)
078         */
079        public Collection<CurrentTaxLotBalance>getCurrentTaxLotBalancesForMatchingSecurityClassCode(String securityClassCode) {
080            Collection<CurrentTaxLotBalance> currentTaxLotBalances = new ArrayList();
081            
082            Collection<Security> securities = new ArrayList();
083            
084            if (StringUtils.isNotBlank(securityClassCode)) {
085                Map criteria = new HashMap();
086                
087                if (SpringContext.getBean(DataDictionaryService.class).getAttributeForceUppercase(Security.class, EndowPropertyConstants.SECURITY_CLASS_CODE)) {
088                    securityClassCode = securityClassCode.toUpperCase();
089                }
090                criteria.put(EndowPropertyConstants.SECURITY_CLASS_CODE, securityClassCode);
091    
092                securities = businessObjectService.findMatching(Security.class, criteria);
093                
094                for (Security security : securities) {
095                    criteria.clear();
096                    criteria.put(EndowPropertyConstants.CURRENT_TAX_LOT_BALANCE_SECURITY_ID, security.getId());
097                    
098                    currentTaxLotBalances.addAll(businessObjectService.findMatching(HoldingHistory.class, criteria)); 
099                }
100            }
101            
102            return currentTaxLotBalances;
103        }
104        
105        /**
106         * @org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getCurrentTaxLotBalancesForMatchingSecurityClassCodeAndSecurityId(String, String)
107         */
108        public Collection<CurrentTaxLotBalance>getCurrentTaxLotBalancesForMatchingSecurityClassCodeAndSecurityId(String securityClassCode, String securityId) {
109            Collection<CurrentTaxLotBalance> currentTaxLotBalances = new ArrayList();
110            
111            currentTaxLotBalances = getCurrentTaxLotBalancesForMatchingSecurityClassCode(securityClassCode);
112            currentTaxLotBalances.addAll(getCurrentTaxLotBalancesBySecurityId(securityId));
113            
114            return currentTaxLotBalances;
115        }
116    
117        
118        /**
119         * @org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getCurrentTaxLotBalancesBySecurityId(String)
120         */
121        public Collection<CurrentTaxLotBalance>getCurrentTaxLotBalancesBySecurityId(String securityId) {
122            Collection<CurrentTaxLotBalance> currentTaxLotBalances = new ArrayList();
123            
124            if (StringUtils.isNotBlank(securityId)) {
125                Map criteria = new HashMap();
126                
127                if (SpringContext.getBean(DataDictionaryService.class).getAttributeForceUppercase(CurrentTaxLotBalance.class, EndowPropertyConstants.CURRENT_TAX_LOT_BALANCE_SECURITY_ID)) {
128                    securityId = securityId.toUpperCase();
129                }
130                
131                criteria.put(EndowPropertyConstants.CURRENT_TAX_LOT_BALANCE_SECURITY_ID, securityId);
132    
133                currentTaxLotBalances = businessObjectService.findMatching(CurrentTaxLotBalance.class, criteria);
134            }
135            
136            return currentTaxLotBalances;
137        }
138        
139        /**
140         * @org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getCurrentTaxLotBalancesBySecurityId(String)
141         */
142        public Collection<CurrentTaxLotBalance>getCurrentTaxLotBalancesByIncomePrincipalIndicator(String incomePrincipalIndicator) {
143            Collection<CurrentTaxLotBalance> currentTaxLotBalances = new ArrayList();
144            
145            if (StringUtils.isNotBlank(incomePrincipalIndicator)) {
146                Map criteria = new HashMap();
147                
148                if (SpringContext.getBean(DataDictionaryService.class).getAttributeForceUppercase(CurrentTaxLotBalance.class, EndowPropertyConstants.CURRENT_TAX_LOT_BALANCE_INCOME_PRINCIPAL_INDICATOR)) {
149                    incomePrincipalIndicator = incomePrincipalIndicator.toUpperCase();
150                }
151                
152                criteria.put(EndowPropertyConstants.CURRENT_TAX_LOT_BALANCE_INCOME_PRINCIPAL_INDICATOR, incomePrincipalIndicator);
153                
154                currentTaxLotBalances = businessObjectService.findMatching(CurrentTaxLotBalance.class, criteria);
155            }
156            
157            return currentTaxLotBalances;
158        }
159    
160        /**
161         * @org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getAllCurrentTaxLotBalance()
162         */
163        public Collection<CurrentTaxLotBalance> getAllCurrentTaxLotBalance() {
164            Collection<CurrentTaxLotBalance> currentTaxLotBalances = new ArrayList();
165            
166            currentTaxLotBalances = businessObjectService.findAll(CurrentTaxLotBalance.class);
167            
168            return currentTaxLotBalances;
169        }
170        
171        /**
172         * Service Method to create a new current tax lot balance record and copy HoldingTaxLot record to it
173         * 
174         * @param holdingTaxLot
175         * @return currentTaxLotBalance
176         */
177        public CurrentTaxLotBalance copyHoldingTaxLotToCurrentTaxLotBalance(HoldingTaxLot holdingTaxLot) {
178            CurrentTaxLotBalance currentTaxLotBalance = new CurrentTaxLotBalance();
179    
180            currentTaxLotBalance.setKemid(holdingTaxLot.getKemid());
181            currentTaxLotBalance.setSecurityId(holdingTaxLot.getSecurityId());
182            currentTaxLotBalance.setRegistrationCode(holdingTaxLot.getRegistrationCode());
183            currentTaxLotBalance.setLotNumber(holdingTaxLot.getLotNumber());
184            currentTaxLotBalance.setIncomePrincipalIndicator(holdingTaxLot.getIncomePrincipalIndicator());
185    
186            currentTaxLotBalance.setUnits(holdingTaxLot.getUnits());
187            currentTaxLotBalance.setCost(holdingTaxLot.getCost());
188            currentTaxLotBalance.setAcquiredDate(holdingTaxLot.getAcquiredDate());
189            currentTaxLotBalance.setPriorAccrual(holdingTaxLot.getPriorAccrual());
190            currentTaxLotBalance.setCurrentAccrual(holdingTaxLot.getCurrentAccrual());
191            currentTaxLotBalance.setLastTransactionDate(holdingTaxLot.getLastTransactionDate());
192    
193            return currentTaxLotBalance;
194        }
195    
196        /**
197         * @see org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getByPrimaryKey(java.lang.String, java.lang.String,
198         *      java.lang.String, int, java.lang.String)
199         */
200        public void updateCurrentTaxLotBalance(CurrentTaxLotBalance currentTaxLotBalance) {
201            if (currentTaxLotBalance == null) {
202                throw new IllegalArgumentException("invalid (null) currentTaxLotBalance");
203            }
204    
205            businessObjectService.save(currentTaxLotBalance);
206        }
207    
208        /**
209         * @see org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#clearAllCurrentTaxLotRecords() clears all the records
210         *      from the CurrentTaxLotBalance table.
211         */
212        public void clearAllCurrentTaxLotRecords() {
213            Collection<CurrentTaxLotBalance> currentTaxLotBalances = businessObjectService.findAll(CurrentTaxLotBalance.class);
214    
215            for (CurrentTaxLotBalance currentTaxLotBalance : currentTaxLotBalances) {
216                businessObjectService.delete(currentTaxLotBalance);
217            }
218        }
219    
220        /**
221         * @see org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getCurrentTaxLotBalanceSecurityUnitValue(String) Method
222         *      to get the security unit value for the current balance tax lot record
223         * @param securityId
224         * @return securityUnitValue
225         */
226        public BigDecimal getCurrentTaxLotBalanceSecurityUnitValue(String securityId) {
227            BigDecimal securityUnitValue = BigDecimal.ZERO;
228    
229            Security security = securityService.getByPrimaryKey(securityId);
230    
231            return security.getUnitValue();
232        }
233    
234        /**
235         * @see org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getNextTwelveMonthsEstimatedValue(String) Method to
236         *      calculate Next Twelve Months Estimated value
237         * @param securityId
238         * @return nextTwelveMonthsEstimatedValue
239         */
240        public BigDecimal getNextTwelveMonthsEstimatedValue(HoldingTaxLot holdingTaxLot, String securityId) {
241            BigDecimal nextTweleveMonthsEstimatedValue = BigDecimal.ZERO;
242    
243            Security security = securityService.getByPrimaryKey(securityId);
244    
245            return KEMCalculationRoundingHelper.multiply(holdingTaxLot.getUnits(), security.getIncomeRate(), EndowConstants.Scale.SECURITY_MARKET_VALUE);
246        }
247    
248        /**
249         * @see org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getRemainderOfFiscalYearEstimatedIncome(HoldingTaxLot,
250         *      String) Method to calculate remainder of fiscal year estimated income
251         * @param securityId
252         * @return remainderOfFiscalYearEstimatedIncome
253         */
254        public BigDecimal getRemainderOfFiscalYearEstimatedIncome(HoldingTaxLot holdingTaxLot, String securityId) {
255            BigDecimal incomeAmount = BigDecimal.ZERO;
256    
257            Security security = securityService.getByPrimaryKey(securityId);
258    
259            String classCodeType = security.getClassCode().getClassCodeType();
260    
261            if (EndowConstants.ClassCodeTypes.ALTERNATIVE_INVESTMENT.equalsIgnoreCase(classCodeType)) {
262                return BigDecimal.ZERO;
263            }
264            // calculations for BONDS
265            if (EndowConstants.ClassCodeTypes.BOND.equalsIgnoreCase(classCodeType)) {
266                return getRemainderOfFiscalYearEstimatedIncomeForBonds(security, holdingTaxLot);
267            }
268    
269            // calculations for CASH
270            if (EndowConstants.ClassCodeTypes.CASH_EQUIVALENTS.equalsIgnoreCase(classCodeType)) {
271                return getRemainderOfFiscalYearEstimatedIncomeForCash(security, holdingTaxLot);
272            }
273    
274            // calculations for LIABILITIES
275            if (EndowConstants.ClassCodeTypes.LIABILITY.equalsIgnoreCase(classCodeType)) {
276                return BigDecimal.ZERO;
277            }
278    
279            // calculations for OTHER
280            if (EndowConstants.ClassCodeTypes.OTHER.equalsIgnoreCase(classCodeType)) {
281                return BigDecimal.ZERO;
282            }
283    
284            // calculations for POOLED FUNDS
285            if (EndowConstants.ClassCodeTypes.POOLED_INVESTMENT.equalsIgnoreCase(classCodeType)) {
286                return getRemainderOfFiscalYearEstimatedIncomeForPooledFunds(security, holdingTaxLot);
287            }
288    
289            // calculations for STOCKS
290            if (EndowConstants.ClassCodeTypes.STOCKS.equalsIgnoreCase(classCodeType)) {
291                return getRemainderOfFiscalYearEstimatedIncomeForStocks(security, holdingTaxLot);
292            }
293    
294            return incomeAmount;
295    
296        }
297    
298        /**
299         * @see org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getNextFiscalYearInvestmentIncome(HoldingTaxLot,
300         *      String) Method to calculate next fiscal year investment income
301         * @param securityId
302         * @return nextFiscalyearInvestmentIncome
303         */
304        public BigDecimal getNextFiscalYearInvestmentIncome(HoldingTaxLot holdingTaxLot, String securityId) {
305            BigDecimal nextFiscalyearInvestmentIncome = BigDecimal.ZERO;
306    
307            Security security = securityService.getByPrimaryKey(securityId);
308            nextFiscalyearInvestmentIncome = KEMCalculationRoundingHelper.multiply(security.getNextFiscalYearDistributionAmount(), holdingTaxLot.getUnits(), EndowConstants.Scale.SECURITY_MARKET_VALUE);
309    
310            return nextFiscalyearInvestmentIncome;
311        }
312    
313        /**
314         * calculates the remainder of fiscal year estimated income for bonds
315         * 
316         * @param security
317         * @param holdingTaxLot
318         * @return amount
319         */
320        protected BigDecimal getRemainderOfFiscalYearEstimatedIncomeForBonds(Security security, HoldingTaxLot holdingTaxLot) {
321            BigDecimal amount = BigDecimal.ZERO;
322    
323            if (ObjectUtils.isNull(security.getIncomeRate()) || security.getIncomeRate().compareTo(BigDecimal.ZERO) == 0) {
324                return amount;
325            }
326            
327            Date nextIncomeDueDate = security.getIncomeNextPayDate();
328            if (ObjectUtils.isNull(nextIncomeDueDate)) {
329                return amount;
330            }
331            
332            Date fiscalYearEndDate = getFiscalYearEndDate();
333    
334            // BONDS - rule 2.a
335            if (nextIncomeDueDate.after(fiscalYearEndDate)) {
336                return BigDecimal.ZERO;
337            }
338    
339            int numberOfMonthsRemaining = getNumberOfMonthsRemaining(fiscalYearEndDate, nextIncomeDueDate);
340            // rule 2.b
341            if (nextIncomeDueDate.before(fiscalYearEndDate) && numberOfMonthsRemaining < EndowConstants.NUMBER_OF_MONTHS_REMAINING) {
342                amount = KEMCalculationRoundingHelper.multiply(holdingTaxLot.getUnits(), security.getIncomeRate(), EndowConstants.Scale.SECURITY_MARKET_VALUE);
343                amount = KEMCalculationRoundingHelper.divide(amount, BigDecimal.valueOf(2), EndowConstants.Scale.SECURITY_MARKET_VALUE);
344            }
345            else {
346                amount = KEMCalculationRoundingHelper.multiply(holdingTaxLot.getUnits(), security.getIncomeRate(), EndowConstants.Scale.SECURITY_MARKET_VALUE);
347            }
348    
349            return amount;
350        }
351    
352        /**
353         * Helper method to calculate the number of months
354         * 
355         * @param fiscalYearEndDate
356         * @param nextIncomeDueDate
357         * @return numberOfMonths
358         */
359        protected int getNumberOfMonthsRemaining(Date fiscalYearEndDate, Date nextIncomeDueDate) {
360            int numberOfMonths = 0;
361    
362            Calendar calendar = Calendar.getInstance();
363    
364            calendar.setTime(fiscalYearEndDate);
365            int fiscalMonths = calendar.get(Calendar.MONTH) + 1;
366            int fiscalYear = calendar.get(Calendar.YEAR);
367            
368            calendar.setTime(nextIncomeDueDate);
369            int nextIncomeMonths = calendar.get(Calendar.MONTH) + 1;
370            int nextIncomeYear = calendar.get(Calendar.YEAR);
371            
372            numberOfMonths = ((fiscalYear-nextIncomeYear) * 12);
373            numberOfMonths += fiscalMonths - nextIncomeMonths;
374            
375            return numberOfMonths;
376        }
377    
378        /**
379         * Helper method to get the system parameter FISCAL_YEAR_END_DAY_AND_MONTH and convert the value into a date value
380         */
381        protected Date getFiscalYearEndDate() {
382            Date fiscalYearEndDate = null;
383    
384            fiscalYearEndDate = kEMService.getFiscalYearEndDayAndMonth();
385    
386            if (fiscalYearEndDate == null) {
387                throw new RuntimeException("ParseException: CurrentTaxLotBalanceUpdateStep job stopped because System Parameter FISCAL_YEAR_END_DAY_AND_MONTH is invalid");
388            }
389    
390            return fiscalYearEndDate;
391        }
392    
393        /**
394         * calculates the remainder of fiscal year estimated income for cash
395         * 
396         * @param security
397         * @param holdingTaxLot
398         * @return amount
399         */
400        protected BigDecimal getRemainderOfFiscalYearEstimatedIncomeForCash(Security security, HoldingTaxLot holdingTaxLot) {
401            BigDecimal amount = BigDecimal.ZERO;
402    
403            if (ObjectUtils.isNull(security.getIncomeRate()) || security.getIncomeRate().compareTo(BigDecimal.ZERO) == 0) {
404                return amount;
405            }
406            
407            Date nextIncomeDueDate = security.getIncomeNextPayDate();
408            Date fiscalYearEndDate = getFiscalYearEndDate();
409            String incomePayFrequency = security.getIncomePayFrequency();
410    
411            if (ObjectUtils.isNull(nextIncomeDueDate) || ObjectUtils.isNull(incomePayFrequency)) {
412                return amount;            
413            }
414    
415            // BONDS - rule 3.a
416            if (nextIncomeDueDate.after(fiscalYearEndDate)) {
417                return BigDecimal.ZERO;
418            }
419    
420            // rule 3.b
421            if (nextIncomeDueDate.before(fiscalYearEndDate)) {
422                Date lastPaymentDate = getLastPaymentDate(incomePayFrequency, fiscalYearEndDate);
423                long daysToLastPayment = getTotalDaysToLastPayment(lastPaymentDate, nextIncomeDueDate);
424    
425                amount = KEMCalculationRoundingHelper.multiply(holdingTaxLot.getUnits(), security.getIncomeRate(), EndowConstants.Scale.SECURITY_MARKET_VALUE);
426                amount = amount.multiply(BigDecimal.valueOf(daysToLastPayment));
427                amount = KEMCalculationRoundingHelper.divide(amount, BigDecimal.valueOf(EndowConstants.NUMBER_OF_DAYS_IN_YEAR), EndowConstants.Scale.SECURITY_MARKET_VALUE);
428                amount = amount.add(holdingTaxLot.getCurrentAccrual());
429            }
430    
431            return amount;
432        }
433    
434        /**
435         * Helper method to calculate the number of days to the last payment
436         */
437        protected long getTotalDaysToLastPayment(Date lastPaymentDate, Date nextIncomeDueDate) {
438            long totalDays = 0;
439            long MILLISECS_PER_DAY = (1000*60*60*24) ; // total milliseconds in a day
440            
441            Calendar currentDateCalendar = Calendar.getInstance();
442            currentDateCalendar.setTime(kEMService.getCurrentDate());
443            currentDateCalendar.set(Calendar.HOUR, 0);
444            currentDateCalendar.set(Calendar.MINUTE, 0);
445            currentDateCalendar.set(Calendar.SECOND, 0);
446            
447            Calendar lastPaymentDateCalendar = Calendar.getInstance();
448            lastPaymentDateCalendar.setTime(lastPaymentDate);
449            lastPaymentDateCalendar.set(Calendar.HOUR, 0);
450            lastPaymentDateCalendar.set(Calendar.MINUTE, 0);
451            lastPaymentDateCalendar.set(Calendar.SECOND, 0);
452            
453            //to take care of leap year and day light savings time.
454            long endL = lastPaymentDateCalendar.getTimeInMillis() + lastPaymentDateCalendar.getTimeZone().getOffset(lastPaymentDateCalendar.getTimeInMillis());
455            long startL = currentDateCalendar.getTimeInMillis() + currentDateCalendar.getTimeZone().getOffset(currentDateCalendar.getTimeInMillis());
456            
457            return (endL - startL) / MILLISECS_PER_DAY ;
458        }
459    
460        /**
461         * Helper method to examine the SEC_INC_PAY_FREQ and determine the date of the last payment to be made in the fiscal year.
462         */
463        protected Date getLastPaymentDate(String incomePayFrequency, Date fiscalYearEndDate) {
464            Date lastPaymentDate = null;
465    
466            String frequencyType = incomePayFrequency.substring(0, 1);
467            
468            Date currentDate = kEMService.getCurrentDate();
469            
470            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.DAILY)) {
471                return fiscalYearEndDate;
472            }
473            
474            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.WEEKLY)) {
475                return calculateLastPaymentWeekDate(currentDate, fiscalYearEndDate);
476            }
477            
478            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.SEMI_MONTHLY)) {
479                String dayOfSemiMonthly =  incomePayFrequency.substring(1, 3);
480                return calculateLastPaymentSemiMonthlyDate(currentDate, fiscalYearEndDate, dayOfSemiMonthly);
481            }
482            
483            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.MONTHLY)) {
484                String dayOfMonth =  incomePayFrequency.substring(1, 3);
485                return calculateLastPaymentMonthlyDate(currentDate, fiscalYearEndDate, dayOfMonth);
486            }
487            
488            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.QUARTERLY)) {
489                String month = incomePayFrequency.substring(1, 2);
490                String dayOfMonth =  incomePayFrequency.substring(2, 4);
491                
492                return calculateLastPaymentQuarterlyDate(currentDate, fiscalYearEndDate, dayOfMonth, month);
493            }
494    
495            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.SEMI_ANNUALLY)) {
496                String month = incomePayFrequency.substring(1, 2);
497                String dayOfMonth =  incomePayFrequency.substring(2, 4);
498                
499                return calculateLastPaymentSemiAnnuallyDate(currentDate, fiscalYearEndDate, dayOfMonth, month);
500            }
501    
502            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.ANNUALLY)) {
503                String month = incomePayFrequency.substring(1, 2);
504                String dayOfMonth =  incomePayFrequency.substring(2, 4);
505                
506                return calculateLastPaymentAnnuallyDate(currentDate, fiscalYearEndDate, dayOfMonth, month);
507            }
508            
509            return lastPaymentDate;
510        }
511    
512        /**
513         * Method to calculate the last payment date for WEEKLY frequency code
514         * @param currentDate, fiscalYearEndDate
515         * @return lastPaymentDate
516         */
517        protected Date calculateLastPaymentWeekDate(Date currentDate, Date fiscalYearEndDate) {
518            Calendar calendar = Calendar.getInstance();
519            calendar.setTime(currentDate);
520            
521            while (calendar.getTime().before(fiscalYearEndDate)) {
522                calendar.add(Calendar.DAY_OF_MONTH, 7);            
523            }
524            
525            if (calendar.getTime().after(fiscalYearEndDate)) {
526                calendar.add(Calendar.DAY_OF_MONTH, -7);
527            }
528            
529            return new java.sql.Date(calendar.getTimeInMillis());
530        }
531        
532        /**
533         * Method to calculate the last payment date for semimonthly frequency code
534         * @param currentDate, fiscalYearEndDate, dayOfSemiMonthly
535         * @return lastPaymentDate
536         */
537        protected Date calculateLastPaymentSemiMonthlyDate(Date currentDate, Date fiscalYearEndDate, String dayOfSemiMonthly) {
538            Calendar calendar = Calendar.getInstance();
539            calendar.setTime(currentDate);
540            
541            int dayOfMonthToSet = Integer.parseInt(dayOfSemiMonthly);
542            calendar.set(Calendar.DAY_OF_MONTH, dayOfMonthToSet);
543            
544            while (calendar.getTime().before(fiscalYearEndDate)) {
545                calendar.add(Calendar.DAY_OF_MONTH, 15);            
546            }
547            
548            if (calendar.getTime().after(fiscalYearEndDate)) {
549                calendar.add(Calendar.DAY_OF_MONTH, -15);
550            }
551            
552            return new java.sql.Date(calendar.getTimeInMillis());
553        }
554        
555        /**
556         * Method to calculate the last payment date for semimonthly frequency code
557         * @param currentDate, fiscalYearEndDate, dayOfMonth
558         * @return lastPaymentDate
559         */
560        protected Date calculateLastPaymentMonthlyDate(Date currentDate, Date fiscalYearEndDate, String dayOfMonth) {
561            Calendar calendar = Calendar.getInstance();
562            calendar.setTime(currentDate);
563            
564            int dayOfMonthToSet = Integer.parseInt(dayOfMonth);
565            calendar.set(Calendar.DAY_OF_MONTH, dayOfMonthToSet);
566            
567            while (calendar.getTime().before(fiscalYearEndDate)) {
568                calendar.add(Calendar.MONTH, 1);            
569            }
570            
571            if (calendar.getTime().after(fiscalYearEndDate)) {
572                calendar.add(Calendar.MONTH, -1);
573            }
574            
575            return new java.sql.Date(calendar.getTimeInMillis());
576        }
577    
578        /**
579         * Method to calculate the last payment date for quarterly frequency code
580         * @param currentDate, fiscalYearEndDate, dayOfMonth
581         * @return lastPaymentDate
582         */
583        protected Date calculateLastPaymentQuarterlyDate(Date currentDate, Date fiscalYearEndDate, String dayOfMonth, String month) {
584            Calendar calendar = setCaledarWithMonth(month, currentDate);
585            setCalendarWithDays(calendar, dayOfMonth);
586            
587            while (calendar.getTime().before(fiscalYearEndDate)) {
588                calendar.add(Calendar.MONTH, 3);            
589            }
590            
591            if (calendar.getTime().after(fiscalYearEndDate)) {
592                calendar.add(Calendar.MONTH, -3);
593            }
594            
595            return new java.sql.Date(calendar.getTimeInMillis());
596        }
597    
598        /**
599         * Method to calculate the last payment date for SemiAnnually frequency code
600         * @param currentDate, fiscalYearEndDate, dayOfMonth
601         * @return lastPaymentDate
602         */
603        protected Date calculateLastPaymentSemiAnnuallyDate(Date currentDate, Date fiscalYearEndDate, String dayOfMonth, String month) {
604            Calendar calendar = setCaledarWithMonth(month, currentDate);
605            setCalendarWithDays(calendar, dayOfMonth);
606            
607            while (calendar.getTime().before(fiscalYearEndDate)) {
608                calendar.add(Calendar.MONTH, 6);            
609            }
610            
611            if (calendar.getTime().after(fiscalYearEndDate)) {
612                calendar.add(Calendar.MONTH, -6);
613            }
614            
615            return new java.sql.Date(calendar.getTimeInMillis());
616        }
617    
618        /**
619         * Method to calculate the last payment date for Annually frequency code
620         * @param currentDate, fiscalYearEndDate, dayOfMonth
621         * @return lastPaymentDate
622         */
623        protected Date calculateLastPaymentAnnuallyDate(Date currentDate, Date fiscalYearEndDate, String dayOfMonth, String month) {
624            Calendar calendar = setCaledarWithMonth(month, currentDate);
625            setCalendarWithDays(calendar, dayOfMonth);
626            
627            while (calendar.getTime().before(fiscalYearEndDate)) {
628                calendar.add(Calendar.YEAR, 1);            
629            }
630            
631            if (calendar.getTime().after(fiscalYearEndDate)) {
632                calendar.add(Calendar.YEAR, -1);
633            }
634            
635            return new java.sql.Date(calendar.getTimeInMillis());
636        }
637    
638        /**
639         * This method will check the current month and set the calendar to that month
640         * @param month month to set the calendar, currentDate currentDate
641         * @return calendar calendar is set to the month selected
642         */
643        protected Calendar setCaledarWithMonth(String month, Date lastPaymentDate) {
644            Calendar calendar = Calendar.getInstance();
645            calendar.setTime(lastPaymentDate);
646            
647            int calendarMonth = 1;
648            
649            if (EndowConstants.FrequencyMonths.JANUARY.equalsIgnoreCase(month)) {
650                calendarMonth = Calendar.JANUARY;
651            } else if (EndowConstants.FrequencyMonths.FEBRUARY.equalsIgnoreCase(month)) {
652                calendarMonth = Calendar.FEBRUARY;
653              } else if (EndowConstants.FrequencyMonths.MARCH.equalsIgnoreCase(month)) {
654                  calendarMonth = Calendar.MARCH;
655                } else if (EndowConstants.FrequencyMonths.APRIL.equalsIgnoreCase(month)) {
656                    calendarMonth = Calendar.APRIL;
657                  } else if (EndowConstants.FrequencyMonths.MAY.equalsIgnoreCase(month)) {
658                      calendarMonth = Calendar.MAY;
659                    } else if (EndowConstants.FrequencyMonths.JUNE.equalsIgnoreCase(month)) {
660                        calendarMonth = Calendar.JUNE;
661                      } else if (EndowConstants.FrequencyMonths.JULY.equalsIgnoreCase(month)) {
662                          calendarMonth = Calendar.JULY;
663                        } else if (EndowConstants.FrequencyMonths.AUGUST.equalsIgnoreCase(month)) {
664                            calendarMonth = Calendar.AUGUST;
665                          } else if (EndowConstants.FrequencyMonths.SEPTEMBER.equalsIgnoreCase(month)) {
666                              calendarMonth = Calendar.SEPTEMBER;
667                            } else if (EndowConstants.FrequencyMonths.OCTOBER.equalsIgnoreCase(month)) {
668                                calendarMonth = Calendar.OCTOBER;
669                              } else if (EndowConstants.FrequencyMonths.NOVEMBER.equalsIgnoreCase(month)) {
670                                  calendarMonth = Calendar.NOVEMBER;
671                                } else if (EndowConstants.FrequencyMonths.DECEMBER.equalsIgnoreCase(month)) {
672                                    calendarMonth = Calendar.DECEMBER;
673                                  }
674            
675            calendar.set(Calendar.MONTH, calendarMonth);
676            
677            return calendar;
678        }
679        
680        /**
681         * This method will check the current month and set the calendar to that month
682         * @param month, dayOfMonth month to set the calendar, dayOfMonth day of the month to set to
683         * @return calendar calendar is set to the month selected
684         */
685        protected void setCalendarWithDays(Calendar calendar, String dayOfMonth) {
686            int dayInMonthToSet;
687            int calendarMonth = calendar.get(Calendar.MONTH);
688            
689            if (StringUtils.equalsIgnoreCase(dayOfMonth, EndowConstants.FrequencyMonthly.MONTH_END)) { // month end for the month so need to get max days...
690                dayInMonthToSet = checkMaximumDaysInMonth(calendar.get(Calendar.MONTH));
691            } else {
692                dayInMonthToSet = Integer.parseInt(dayOfMonth);
693                
694                if (dayInMonthToSet > 29 && calendarMonth == Calendar.FEBRUARY) {
695                    dayInMonthToSet = checkMaximumDaysInFebruary();
696                } else if (dayInMonthToSet > 30 && (calendarMonth == Calendar.APRIL || calendarMonth == Calendar.JUNE ||
697                           calendarMonth == Calendar.SEPTEMBER || calendarMonth == Calendar.NOVEMBER)) {
698                           dayInMonthToSet = 30;
699                           dayInMonthToSet = checkMaximumDaysInMonth(calendarMonth);                       
700                  }
701              }
702                
703            calendar.set(Calendar.DAY_OF_MONTH, dayInMonthToSet);
704        }
705        
706        /**
707         * This method will check and return either maximum days in the month as 28 or 29 for leap year.
708         * It first sets the month to February and then checks the maximum days..
709         * @return maxDays Maximum number of days in the month of February for calendar.
710         */
711        protected int checkMaximumDaysInFebruary() {
712            int maxDays;      
713            Calendar februaryMonthlyDateCalendar = Calendar.getInstance();
714            februaryMonthlyDateCalendar.set(Calendar.MONTH, Calendar.FEBRUARY);
715            maxDays = februaryMonthlyDateCalendar.getActualMaximum(Calendar.DAY_OF_MONTH);
716            
717            return maxDays;
718        }
719        
720        /**
721         * This method will check and return maximum days in a month.
722         * @param monthNumber The number of the month to test for maximum days..
723         * @return maxDays Maximum number of days in the month of February for calendar.
724         */
725        protected int checkMaximumDaysInMonth(int monthNumber) {
726            int maxDays;   
727            
728            Calendar calendar = Calendar.getInstance();
729            calendar.set(Calendar.MONTH, monthNumber);
730            maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
731            
732            return maxDays;
733        }
734        
735        /**
736         * calculates the remainder of fiscal year estimated income for pooled funds
737         * 
738         * @param security
739         * @param holdingTaxLot
740         * @return amount
741         */
742        protected BigDecimal getRemainderOfFiscalYearEstimatedIncomeForPooledFunds(Security security, HoldingTaxLot holdingTaxLot) {
743            BigDecimal amount = BigDecimal.ZERO;
744    
745            if (ObjectUtils.isNull(security.getIncomeNextPayDate()) || ObjectUtils.isNull(security.getFrequencyCode())) {
746                return amount;
747            }
748    
749            Date nextIncomeDueDate = security.getIncomeNextPayDate();
750            if (ObjectUtils.isNull(nextIncomeDueDate)) {
751                return amount;
752            }
753            
754            Date fiscalYearEndDate = getFiscalYearEndDate();
755    
756            // BONDS - rule 4.a
757            if (nextIncomeDueDate.after(fiscalYearEndDate)) {
758                return BigDecimal.ZERO;
759            }
760    
761            // rule 4.b
762            if (nextIncomeDueDate.before(fiscalYearEndDate)) {
763                String incomePayFrequency = security.getIncomePayFrequency();
764                if (ObjectUtils.isNull(incomePayFrequency)) {
765                    return amount;
766                }
767                
768                Date lastPaymentDate = getLastPaymentDate(incomePayFrequency, fiscalYearEndDate);
769    
770                long paymentsRemaining = getTotalPaymentsRemaining(lastPaymentDate, fiscalYearEndDate, incomePayFrequency, nextIncomeDueDate);
771                
772                long totalNumberOfPayments = kEMService.getTotalNumberOfPaymentsForFiscalYear();
773    
774                amount = KEMCalculationRoundingHelper.multiply(holdingTaxLot.getUnits(), security.getIncomeRate(), EndowConstants.Scale.SECURITY_MARKET_VALUE);
775                amount = amount.multiply(BigDecimal.valueOf(paymentsRemaining));
776                amount = KEMCalculationRoundingHelper.divide(amount, BigDecimal.valueOf(totalNumberOfPayments), EndowConstants.Scale.SECURITY_MARKET_VALUE);
777                amount = amount.add(holdingTaxLot.getCurrentAccrual());
778            }
779    
780            return amount;
781        }
782    
783        /**
784         * Helper method to calculate the remaining payments till the last payment date for the fiscal year
785         * @param lastPaymentDate, fiscalYearEndDate, incomePayFrequency
786         * @return totalPaymentsRemaining
787         */
788        protected long getTotalPaymentsRemaining(Date lastPaymentDate, Date fiscalYearEndDate, String incomePayFrequency, Date nextIncomeDueDate) {
789            long totalPaymentsRemaining = 0;
790            long totalDaysToLastPayment = getTotalDaysToLastPayment(lastPaymentDate, nextIncomeDueDate);
791            
792            String frequencyType = incomePayFrequency.substring(0, 1);
793            
794            Date currentDate = kEMService.getCurrentDate();
795            
796            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.DAILY)) {
797                return totalDaysToLastPayment;
798            }
799            
800            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.WEEKLY)) {
801                return (totalDaysToLastPayment / 7);
802            }
803            
804            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.SEMI_MONTHLY)) {
805                return (totalDaysToLastPayment / 15);
806            }
807            
808            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.MONTHLY)) {
809                String dayOfMonth =  incomePayFrequency.substring(1, 3);
810                return getNumberOfPaymentsRemainingForMonthlyFrequency(nextIncomeDueDate, lastPaymentDate, dayOfMonth);
811            }
812            
813            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.QUARTERLY)) {
814                String month = incomePayFrequency.substring(1, 2);
815                String dayOfMonth =  incomePayFrequency.substring(2, 4);
816                
817                return getNumberOfPaymentsRemainingForQuarterlyFrequency(nextIncomeDueDate, lastPaymentDate, dayOfMonth, month);
818            }
819    
820            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.SEMI_ANNUALLY)) {
821                String month = incomePayFrequency.substring(1, 2);
822                String dayOfMonth =  incomePayFrequency.substring(2, 4);
823                
824                return getNumberOfPaymentsRemainingForSemiAnnuallyDate(nextIncomeDueDate, lastPaymentDate, dayOfMonth, month);
825            }
826    
827            if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.ANNUALLY)) {
828                String month = incomePayFrequency.substring(1, 2);
829                String dayOfMonth =  incomePayFrequency.substring(2, 4);
830                
831                return getNumberOfPaymentsRemainingForAnnuallyDate(nextIncomeDueDate, lastPaymentDate, dayOfMonth, month);
832            }
833            
834            return totalPaymentsRemaining;
835        }
836    
837        /**
838         * Method to calculate the last payment date for monthly frequency code
839         * @param currentDate, fiscalYearEndDate, dayOfMonth
840         * @return totalPayments
841         */
842        protected long getNumberOfPaymentsRemainingForMonthlyFrequency(Date nextIncomeDueDate, Date lastPaymentDate, String dayOfMonth) {
843            long totalPayments = 0;
844            
845            Calendar calendar = Calendar.getInstance();
846            calendar.setTime(nextIncomeDueDate);
847            
848            int dayOfMonthToSet = Integer.parseInt(dayOfMonth);
849            calendar.set(Calendar.DAY_OF_MONTH, dayOfMonthToSet);
850            
851            if (calendar.getTime().before(lastPaymentDate)) {
852                totalPayments = totalPayments + 1; 
853            }
854            else {
855                return totalPayments;
856            }
857            
858            while (calendar.getTime().before(lastPaymentDate)) {
859                calendar.add(Calendar.MONTH, 1);
860                totalPayments = totalPayments + 1;
861            }
862            
863            return totalPayments;
864        }
865        
866        /**
867         * Method to calculate the last payment date for quarterly frequency code
868         * @param currentDate, fiscalYearEndDate, dayOfMonth
869         * @return lastPaymentDate
870         */
871        protected long getNumberOfPaymentsRemainingForQuarterlyFrequency(Date nextIncomeDueDate, Date lastPaymentDate, String dayOfMonth, String month) {
872            long totalPayments = 0;
873    
874            Calendar calendar = setCaledarWithMonth(month, nextIncomeDueDate);
875            setCalendarWithDays(calendar, dayOfMonth);
876            
877            if (calendar.getTime().before(lastPaymentDate)) {
878                totalPayments = totalPayments + 1; 
879            }
880            else {
881                return totalPayments;
882            }
883            
884            while (calendar.getTime().before(lastPaymentDate)) {
885                calendar.add(Calendar.MONTH, 3); 
886                totalPayments = totalPayments + 1;            
887            }
888            
889            return totalPayments;
890        }
891        
892        /**
893         * Method to calculate the last payment date for SemiAnnually frequency code
894         * @param currentDate, fiscalYearEndDate, dayOfMonth
895         * @return lastPaymentDate
896         */
897        protected long getNumberOfPaymentsRemainingForSemiAnnuallyDate(Date nextIncomeDueDate, Date lastPaymentDate, String dayOfMonth, String month) {
898            long totalPayments = 0;
899    
900            Calendar calendar = setCaledarWithMonth(month, nextIncomeDueDate);
901            setCalendarWithDays(calendar, dayOfMonth);
902            
903            if (calendar.getTime().before(lastPaymentDate)) {
904                totalPayments = totalPayments + 1; 
905            }
906            else {
907                return totalPayments;
908            }
909            
910            while (calendar.getTime().before(lastPaymentDate)) {
911                calendar.add(Calendar.MONTH, 6);    
912                totalPayments = totalPayments + 1;            
913            }
914            
915            return totalPayments;
916        }
917        
918        /**
919         * Method to calculate the last payment date for Annually frequency code
920         * @param currentDate, fiscalYearEndDate, dayOfMonth
921         * @return lastPaymentDate
922         */
923        protected long getNumberOfPaymentsRemainingForAnnuallyDate(Date nextIncomeDueDate, Date lastPaymentDate, String dayOfMonth, String month) {
924            long totalPayments = 0;
925    
926            Calendar calendar = setCaledarWithMonth(month, nextIncomeDueDate);
927            setCalendarWithDays(calendar, dayOfMonth);
928            
929            if (calendar.getTime().before(lastPaymentDate)) {
930                totalPayments = totalPayments + 1; 
931            }
932            else {
933                return totalPayments;
934            }
935            
936            while (calendar.getTime().before(lastPaymentDate)) {
937                calendar.add(Calendar.YEAR, 1);  
938                totalPayments = totalPayments + 1;
939            }
940            
941            return totalPayments;
942        }
943        
944        /**
945         * calculates the remainder of fiscal year estimated income for stocks
946         * 
947         * @param security
948         * @param holdingTaxLot
949         * @return amount
950         */
951        protected BigDecimal getRemainderOfFiscalYearEstimatedIncomeForStocks(Security security, HoldingTaxLot holdingTaxLot) {
952            BigDecimal amount = BigDecimal.ZERO;
953    
954            if (ObjectUtils.isNull(security.getIncomeRate()) || security.getIncomeRate().compareTo(BigDecimal.ZERO) == 0) {
955                return amount;
956            }
957            
958            String incomePayFrequency = security.getIncomePayFrequency();
959            Date nextIncomeDueDate = security.getIncomeNextPayDate();
960            
961            if (ObjectUtils.isNull(nextIncomeDueDate)) {
962                return amount;
963            }
964                    
965            Date fiscalYearEndDate = getFiscalYearEndDate();
966    
967            // BONDS - rule 4.a
968            if (nextIncomeDueDate.after(fiscalYearEndDate)) {
969                return BigDecimal.ZERO;
970            }
971    
972            int numberOfMonthsRemaing = getNumberOfMonthsRemaining(fiscalYearEndDate, nextIncomeDueDate);
973    
974            if (nextIncomeDueDate.before(fiscalYearEndDate) && numberOfMonthsRemaing < 4) {
975                return BigDecimal.ZERO;
976            }
977            
978            long quartersLeftToFiscalYear = getQuartersLeftToFiscalYear(fiscalYearEndDate);
979            
980            //calculate holding units times security rate....
981            amount = KEMCalculationRoundingHelper.multiply(holdingTaxLot.getUnits(), security.getIncomeRate(), EndowConstants.Scale.SECURITY_MARKET_VALUE);
982            
983            // now multiply the above amount by 4 to get amount for 4 quarters or for the year...
984            amount = KEMCalculationRoundingHelper.divide(amount, BigDecimal.valueOf(4), EndowConstants.Scale.SECURITY_MARKET_VALUE);
985            
986            //now compute the amount for the quarters remaining in the fiscal year....
987            amount = KEMCalculationRoundingHelper.multiply(amount, BigDecimal.valueOf(quartersLeftToFiscalYear), EndowConstants.Scale.SECURITY_MARKET_VALUE);
988    
989            return amount;
990        }
991    
992        /**
993         * Helper method to calculate the quarter number of the fiscal year.
994         * 
995         * @param nextIncomeDueDate
996         * @return quarterOfFiscalYear
997         */
998        protected int getQuartersLeftToFiscalYear(Date fiscalYearEndDate) {
999            int numberOfMonthsRemaing = getNumberOfMonthsRemaining(fiscalYearEndDate, kEMService.getCurrentDate());
1000            return Math.round(numberOfMonthsRemaing / 3); 
1001        }
1002    
1003        /**
1004         * @see org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getHoldingMarketValueSumForSecurity(java.lang.String)
1005         */
1006        public BigDecimal getHoldingMarketValueSumForSecurity(String securityId) {
1007            BigDecimal sum = BigDecimal.ZERO;
1008    
1009            List<CurrentTaxLotBalance> currentTaxLotBalances = (List<CurrentTaxLotBalance>) currentTaxLotBalanceDao.getAllCurrentTaxLotBalanceEntriesForSecurity(securityId);
1010    
1011            if (currentTaxLotBalances != null) {
1012                for (CurrentTaxLotBalance currentTaxLotBalance : currentTaxLotBalances) {
1013                    if (currentTaxLotBalance.getHoldingMarketValue() != null) {
1014                        sum = sum.add(currentTaxLotBalance.getHoldingMarketValue());
1015                    }
1016                }
1017            }
1018            
1019            return sum;
1020        }
1021    
1022        /**
1023         * @see org.kuali.kfs.module.endow.document.service.CurrentTaxLotService#getHoldingMarketValue(HoldingTaxLot, String)
1024         */
1025        public BigDecimal getHoldingMarketValue(HoldingTaxLot holdingTaxLot, String securityId) {
1026            BigDecimal holdingMarketValue = BigDecimal.ZERO;
1027    
1028            Security security = securityService.getByPrimaryKey(securityId);
1029    
1030            String classCodeType = security.getClassCode().getClassCodeType();
1031    
1032            if (EndowConstants.ClassCodeTypes.ALTERNATIVE_INVESTMENT.equalsIgnoreCase(classCodeType)) {
1033                BigDecimal totalCashActivity = transactionArchiveDao.getTransactionArchivesTotalCashActivity(holdingTaxLot.getKemid(), securityId);
1034                return (security.getSecurityValueByMarket().subtract(totalCashActivity));
1035            }
1036            // calculations for BONDS
1037            if (EndowConstants.ClassCodeTypes.BOND.equalsIgnoreCase(classCodeType)) {
1038                holdingMarketValue = KEMCalculationRoundingHelper.multiply(holdingTaxLot.getUnits(), security.getUnitValue(), EndowConstants.Scale.SECURITY_MARKET_VALUE);
1039                holdingMarketValue = KEMCalculationRoundingHelper.divide(holdingMarketValue, BigDecimal.valueOf(100), EndowConstants.Scale.SECURITY_MARKET_VALUE);
1040                return holdingMarketValue;
1041            }
1042            
1043            //other cases...
1044            holdingMarketValue =  KEMCalculationRoundingHelper.multiply(holdingTaxLot.getUnits(), security.getUnitValue(), EndowConstants.Scale.SECURITY_MARKET_VALUE);
1045            
1046            return holdingMarketValue;
1047        }
1048        
1049        /**
1050         * Gets the businessObjectService.
1051         * 
1052         * @return businessObjectService
1053         */
1054        protected BusinessObjectService getBusinessObjectService() {
1055            return businessObjectService;
1056        }
1057    
1058        /**
1059         * Sets the businessObjectService.
1060         * 
1061         * @param businessObjectService
1062         */
1063        public void setBusinessObjectService(BusinessObjectService businessObjectService) {
1064            this.businessObjectService = businessObjectService;
1065        }
1066    
1067        /**
1068         * Gets the securityService.
1069         * 
1070         * @return securityService
1071         */
1072        protected SecurityService getSecurityService() {
1073            return securityService;
1074        }
1075    
1076        /**
1077         * Sets the securityService.
1078         * 
1079         * @param securityService
1080         */
1081        public void setSecurityService(SecurityService securityService) {
1082            this.securityService = securityService;
1083        }
1084    
1085        /**
1086         * gets the kEMService.
1087         * 
1088         * @param kEMService
1089         */
1090        protected KEMService getkEMService() {
1091            return kEMService;
1092        }
1093    
1094        /**
1095         * Sets the kEMService.
1096         * 
1097         * @param kEMService
1098         */
1099        public void setkEMService(KEMService kEMService) {
1100            this.kEMService = kEMService;
1101        }
1102    
1103        public void setCurrentTaxLotBalanceDao(CurrentTaxLotBalanceDao currentTaxLotBalanceDao) {
1104            this.currentTaxLotBalanceDao = currentTaxLotBalanceDao;
1105        }
1106    
1107        
1108        /**
1109         * Gets the transactionArchiveDao attribute. 
1110         * @return Returns the transactionArchiveDao.
1111         */
1112        protected TransactionArchiveDao getTransactionArchiveDao() {
1113            return transactionArchiveDao;
1114        }
1115    
1116        /**
1117         * Sets the transactionArchiveDao attribute value.
1118         * @param transactionArchiveDao The transactionArchiveDao to set.
1119         */
1120        public void setTransactionArchiveDao(TransactionArchiveDao transactionArchiveDao) {
1121            this.transactionArchiveDao = transactionArchiveDao;
1122        }
1123    }