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.dataaccess.impl;
017    
018    import java.math.BigDecimal;
019    import java.sql.Date;
020    import java.util.ArrayList;
021    import java.util.Collection;
022    import java.util.HashMap;
023    import java.util.Iterator;
024    import java.util.List;
025    import java.util.Map;
026    
027    import org.apache.commons.lang.StringUtils;
028    import org.apache.ojb.broker.query.Criteria;
029    import org.apache.ojb.broker.query.QueryByCriteria;
030    import org.apache.ojb.broker.query.QueryFactory;
031    import org.apache.ojb.broker.query.ReportQueryByCriteria;
032    import org.kuali.kfs.module.endow.EndowConstants;
033    import org.kuali.kfs.module.endow.EndowPropertyConstants;
034    import org.kuali.kfs.module.endow.EndowConstants.IncomePrincipalIndicator;
035    import org.kuali.kfs.module.endow.businessobject.FeeClassCode;
036    import org.kuali.kfs.module.endow.businessobject.FeeMethod;
037    import org.kuali.kfs.module.endow.businessobject.FeeSecurity;
038    import org.kuali.kfs.module.endow.businessobject.HoldingHistory;
039    import org.kuali.kfs.module.endow.businessobject.KEMID;
040    import org.kuali.kfs.module.endow.businessobject.PooledFundValue;
041    import org.kuali.kfs.module.endow.businessobject.Security;
042    import org.kuali.kfs.module.endow.dataaccess.HoldingHistoryDao;
043    import org.kuali.kfs.module.endow.dataaccess.SecurityDao;
044    import org.kuali.kfs.module.endow.document.service.MonthEndDateService;
045    import org.kuali.kfs.module.endow.util.KEMCalculationRoundingHelper;
046    import org.kuali.kfs.sys.context.SpringContext;
047    import org.kuali.rice.kns.dao.impl.PlatformAwareDaoBaseOjb;
048    import org.kuali.rice.kns.service.DataDictionaryService;
049    import org.kuali.rice.kns.util.KualiInteger;
050    
051    public class HoldingHistoryDaoOjb extends PlatformAwareDaoBaseOjb implements HoldingHistoryDao {
052        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(HoldingHistoryDaoOjb.class);
053        
054        protected MonthEndDateService monthEndDateService;
055        protected SecurityDao securityDao;
056        
057        /**
058         * Prepares the criteria and selects the records from END_HLDG_HIST_T table
059         */
060        protected Collection<HoldingHistory> getHoldingHistoryForBlance(FeeMethod feeMethod) {
061            Collection<HoldingHistory> holdingHistory = new ArrayList(); 
062            
063            Collection incomePrincipalValues = new ArrayList();
064            incomePrincipalValues.add(EndowConstants.FeeMethod.FEE_BASE_CODE_VALUE_FOR_INCOME);
065            incomePrincipalValues.add(EndowConstants.FeeMethod.FEE_BASE_CODE_VALUE_FOR_PRINCIPAL);
066            
067            Criteria criteria = new Criteria();
068            
069            if (feeMethod.getFeeBaseCode().equalsIgnoreCase(EndowConstants.FeeMethod.FEE_BASE_CODE_VALUE_FOR_INCOME_AND_PRINCIPAL)) {
070                criteria.addIn(EndowPropertyConstants.HOLDING_HISTORY_INCOME_PRINCIPAL_INDICATOR, incomePrincipalValues);
071            }
072            else {
073                if (feeMethod.getFeeBaseCode().equalsIgnoreCase(EndowConstants.FeeMethod.FEE_BASE_CODE_VALUE_FOR_INCOME)) {
074                    criteria.addEqualTo(EndowPropertyConstants.HOLDING_HISTORY_INCOME_PRINCIPAL_INDICATOR, EndowConstants.FeeMethod.FEE_BASE_CODE_VALUE_FOR_INCOME);
075                }
076                
077                if (feeMethod.getFeeBaseCode().equalsIgnoreCase(EndowConstants.FeeMethod.FEE_BASE_CODE_VALUE_FOR_PRINCIPAL)) {
078                    criteria.addEqualTo(EndowPropertyConstants.HOLDING_HISTORY_INCOME_PRINCIPAL_INDICATOR, EndowConstants.FeeMethod.FEE_BASE_CODE_VALUE_FOR_PRINCIPAL);
079                }
080            }
081    
082            Collection securityClassCodes =  new ArrayList();
083            Collection securityIds = new ArrayList();
084            
085            if (feeMethod.getFeeByClassCode() && feeMethod.getFeeBySecurityCode()) {
086                securityClassCodes = getSecurityClassCodes(feeMethod.getCode());
087                securityIds = getSecurityIds(feeMethod.getCode());
088                
089                securityIds.addAll(securityClassCodes);
090                if (securityIds.size() > 0) {
091                   criteria.addIn(EndowPropertyConstants.HOLDING_HISTORY_SECURITY_ID, securityIds);
092                }
093            }
094            else {
095                if (feeMethod.getFeeByClassCode()) {
096                    securityClassCodes = getSecurityClassCodes(feeMethod.getCode());
097                    if (securityClassCodes.size() > 0) {
098                       criteria.addIn(EndowPropertyConstants.HOLDING_HISTORY_SECURITY_ID, securityClassCodes);
099                    }
100                }
101                
102                if (feeMethod.getFeeBySecurityCode()) {
103                    securityIds = getSecurityIds(feeMethod.getCode());                
104                    if (securityIds.size() > 0) {
105                        criteria.addIn(EndowPropertyConstants.HOLDING_HISTORY_SECURITY_ID, securityIds);
106                    }
107                }
108            }
109            
110            QueryByCriteria query = QueryFactory.newQuery(HoldingHistory.class, criteria);
111                
112            holdingHistory = getPersistenceBrokerTemplate().getCollectionByQuery(query);
113            
114            return holdingHistory;
115        }
116           
117        /**
118         * Gets the security codes for a given securityClassCode in END_FEE_CLS_CD_T table
119         * @feeMethodCode FEE_MTH
120         * @return securityCodes
121         */
122        protected Collection getSecurityClassCodes(String feeMethodCode) {
123            Collection securityClassCodes = new ArrayList();
124            Collection<FeeClassCode> feeClassCodes = new ArrayList();        
125    
126            if (StringUtils.isNotBlank(feeMethodCode)) {        
127                Map<String, String>  crit = new HashMap<String, String>();
128                
129                if (SpringContext.getBean(DataDictionaryService.class).getAttributeForceUppercase(FeeClassCode.class, EndowPropertyConstants.FEE_METHOD_CODE)) {
130                    feeMethodCode = feeMethodCode.toUpperCase();
131                }
132                
133                Criteria criteria = new Criteria();
134                criteria.addEqualTo(EndowPropertyConstants.FEE_METHOD_CODE, feeMethodCode);
135                criteria.addEqualTo(EndowPropertyConstants.FEE_CLASS_CODE_INCLUDE, EndowConstants.YES);
136                
137                QueryByCriteria query = QueryFactory.newQuery(FeeClassCode.class, criteria);
138                
139                feeClassCodes = getPersistenceBrokerTemplate().getCollectionByQuery(query);
140                for (FeeClassCode feeClassCode : feeClassCodes) {
141                    Collection <Security> securities = securityDao.getSecuritiesBySecurityClassCode(feeClassCode.getFeeClassCode());
142                    for (Security security : securities) {
143                        securityClassCodes.add(security.getId());
144                    }
145                }
146            }
147            
148            return securityClassCodes;
149        }
150        
151        /**
152         * Gets the security ids for a given securityClassCode in END_FEE_SEC_T table
153         * @feeMethodCode FEE_MTH
154         * @return securityIds
155         */
156        protected Collection getSecurityIds(String feeMethodCode) {
157            Collection securityIds = new ArrayList();
158            Collection<FeeSecurity> feeSecuritys = new ArrayList();        
159    
160            if (StringUtils.isNotBlank(feeMethodCode)) {        
161                Map<String, String>  crit = new HashMap<String, String>();
162                
163                if (SpringContext.getBean(DataDictionaryService.class).getAttributeForceUppercase(FeeSecurity.class, EndowPropertyConstants.FEE_METHOD_CODE)) {
164                    feeMethodCode = feeMethodCode.toUpperCase();
165                }
166                
167                Criteria criteria = new Criteria();
168                criteria.addEqualTo(EndowPropertyConstants.FEE_METHOD_CODE, feeMethodCode);
169                criteria.addEqualTo(EndowPropertyConstants.FEE_SECURITY_INCLUDE, EndowConstants.YES);
170                
171                QueryByCriteria query = QueryFactory.newQuery(FeeSecurity.class, criteria);
172                
173                feeSecuritys = getPersistenceBrokerTemplate().getCollectionByQuery(query);
174                for (FeeSecurity feeSecurity : feeSecuritys) {
175                    securityIds.add(feeSecurity.getSecurityCode());
176                }
177            }
178            
179            return securityIds;
180        }
181        
182        /**
183         * @see org.kuali.kfs.module.endow.dataaccess.HoldingHistoryDao#getHoldingHistoryTotalHoldingUnits(FeeMethod)
184         */
185        public BigDecimal getHoldingHistoryTotalHoldingUnits(FeeMethod feeMethod) {
186            BigDecimal totalHoldingUnits = BigDecimal.ZERO;
187            
188            Date lastProcessDate = feeMethod.getFeeLastProcessDate();
189            Date mostRecentDate = monthEndDateService.getMostRecentDate();
190            
191            String feeBalanceTypeCode = feeMethod.getFeeBalanceTypeCode();
192            
193            Collection <HoldingHistory> holdingHistoryRecords = getHoldingHistoryForBlance(feeMethod);
194            for (HoldingHistory holdingHistory : holdingHistoryRecords) {
195                Date monthEndDate = monthEndDateService.getByPrimaryKey(holdingHistory.getMonthEndDateId());
196    
197                if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_AVERAGE_UNITS) && (monthEndDate.compareTo(lastProcessDate) > 0)) {
198                    totalHoldingUnits = totalHoldingUnits.add(holdingHistory.getUnits());    
199                }
200                if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_MONTH_END_UNITS) && (mostRecentDate.compareTo(lastProcessDate) > 0)) {
201                    totalHoldingUnits = totalHoldingUnits.add(holdingHistory.getUnits());    
202                }
203            }
204            
205            if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_AVERAGE_UNITS)) {
206                totalHoldingUnits = KEMCalculationRoundingHelper.divide(totalHoldingUnits, BigDecimal.valueOf(holdingHistoryRecords.size()), EndowConstants.Scale.SECURITY_UNIT_VALUE);
207            }
208            
209            return totalHoldingUnits;
210        }
211        
212        /**
213         * @see org.kuali.kfs.module.endow.dataaccess.HoldingHistoryDao#getHoldingHistoryTotalHoldingMarketValue(FeeMethod)
214         */
215        public BigDecimal getHoldingHistoryTotalHoldingMarketValue(FeeMethod feeMethod) {
216            BigDecimal totalHoldingMarkteValue = BigDecimal.ZERO;
217            
218            Date lastProcessDate = feeMethod.getFeeLastProcessDate();
219            Date mostRecentDate = monthEndDateService.getMostRecentDate();
220            
221            String feeBalanceTypeCode = feeMethod.getFeeBalanceTypeCode();
222            
223            Collection <HoldingHistory> holdingHistoryRecords = getHoldingHistoryForBlance(feeMethod);
224            for (HoldingHistory holdingHistory : holdingHistoryRecords) {
225                Date monthEndDate = monthEndDateService.getByPrimaryKey(holdingHistory.getMonthEndDateId());
226                if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_AVERAGE_MARKET_VALUE) && (monthEndDate.compareTo(lastProcessDate) > 0)) {
227                    totalHoldingMarkteValue = totalHoldingMarkteValue.add(holdingHistory.getMarketValue());    
228                }
229                if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_MONTH_END_MARKET_VALUE) && (monthEndDate.compareTo(mostRecentDate) > 0)) {
230                    totalHoldingMarkteValue = totalHoldingMarkteValue.add(holdingHistory.getMarketValue());    
231                }
232            }
233            
234            if (feeBalanceTypeCode.equals(EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_AVERAGE_MARKET_VALUE)) {
235                totalHoldingMarkteValue = KEMCalculationRoundingHelper.divide(totalHoldingMarkteValue, BigDecimal.valueOf(holdingHistoryRecords.size()), EndowConstants.Scale.SECURITY_UNIT_VALUE);
236            }
237            
238            return totalHoldingMarkteValue;
239        }
240    
241        /**
242         * 
243         * @see org.kuali.kfs.module.endow.dataaccess.HoldingHistoryDao#getHoldingHistory(java.lang.String, java.lang.String)
244         */
245        public List<HoldingHistory> getHoldingHistory(String kemid, KualiInteger medId) {
246           
247            Criteria criteria = new Criteria();
248            criteria.addEqualTo(EndowPropertyConstants.HOLDING_TAX_LOT_KEMID, kemid);
249            criteria.addEqualTo(EndowPropertyConstants.HOLDING_HISTORY_MONTH_END_DATE_ID, medId);
250            QueryByCriteria qbc = QueryFactory.newQuery(HoldingHistory.class, criteria);
251            qbc.addOrderByAscending(EndowPropertyConstants.HOLDING_TAX_LOT_KEMID);
252            
253            return (List<HoldingHistory>) getPersistenceBrokerTemplate().getCollectionByQuery(qbc);
254        }
255    
256        /**
257         * 
258         * @see org.kuali.kfs.module.endow.dataaccess.HoldingHistoryDao#getHoldingHistoryByKemid(java.lang.String)
259         */
260        public List<HoldingHistory> getHoldingHistoryByKemid(String kemid) {
261           
262            Criteria criteria = new Criteria();
263            criteria.addEqualTo(EndowPropertyConstants.HOLDING_TAX_LOT_KEMID, kemid);
264            QueryByCriteria qbc = QueryFactory.newQuery(HoldingHistory.class, criteria);
265            qbc.addOrderByAscending(EndowPropertyConstants.HOLDING_TAX_LOT_KEMID);
266            
267            return (List<HoldingHistory>) getPersistenceBrokerTemplate().getCollectionByQuery(qbc);
268        }
269        
270        public List<HoldingHistory> getHoldingHistoryByKemidIdAndMonthEndIdAndIpInd(String kemid, KualiInteger monthEndId, String ipInd) {
271    
272            Criteria criteria = new Criteria();
273            criteria.addEqualTo(EndowPropertyConstants.HOLDING_HISTORY_KEMID, kemid);
274            criteria.addEqualTo(EndowPropertyConstants.HOLDING_HISTORY_MONTH_END_DATE_ID, monthEndId);
275            criteria.addGreaterThan(EndowPropertyConstants.HOLDING_TAX_LOT_UNITS, BigDecimal.ZERO);
276            if (ipInd.equalsIgnoreCase(IncomePrincipalIndicator.INCOME) || ipInd.equalsIgnoreCase(IncomePrincipalIndicator.PRINCIPAL)) {
277                criteria.addEqualTo(EndowPropertyConstants.HOLDING_HISTORY_INCOME_PRINCIPAL_INDICATOR, ipInd);
278            }
279            
280            QueryByCriteria qbc = QueryFactory.newQuery(HoldingHistory.class, criteria);
281            qbc.addOrderByAscending(EndowPropertyConstants.KEMID);
282            
283            return (List<HoldingHistory>) getPersistenceBrokerTemplate().getCollectionByQuery(qbc);
284            
285        }
286        
287        /**
288         * Gets the sum of the specified attribute values
289         * 
290         * @param kemid
291         * @param medId
292         * @param securityId
293         * @param ipInd
294         * @param attributeName
295         * @return
296         */
297        public BigDecimal getSumOfHoldginHistoryAttribute(String attributeName, String kemid, KualiInteger medId, String securityId, String ipInd) {
298            
299            BigDecimal total = BigDecimal.ZERO;
300            
301            Criteria criteria = new Criteria();
302            criteria.addEqualTo(EndowPropertyConstants.HOLDING_TAX_LOT_KEMID, kemid);
303            criteria.addEqualTo(EndowPropertyConstants.HOLDING_HISTORY_MONTH_END_DATE_ID, medId);
304            criteria.addEqualTo(EndowPropertyConstants.HOLDING_HISTORY_SECURITY_ID, securityId);
305            criteria.addGreaterThan(EndowPropertyConstants.HOLDING_TAX_LOT_UNITS, BigDecimal.ZERO);
306            if (ipInd.equalsIgnoreCase(IncomePrincipalIndicator.INCOME) || ipInd.equalsIgnoreCase(IncomePrincipalIndicator.PRINCIPAL)) {
307                criteria.addEqualTo(EndowPropertyConstants.HOLDING_HISTORY_INCOME_PRINCIPAL_INDICATOR, ipInd);
308            }
309                    
310            ReportQueryByCriteria rqbc = QueryFactory.newReportQuery(HoldingHistory.class, criteria);        
311            rqbc.setAttributes(new String[] {"sum(" + attributeName + ")"});
312            rqbc.addGroupBy(attributeName);      
313            Iterator<?> result = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(rqbc);        
314    
315            while (result.hasNext()) {
316                Object[] data = (Object[]) result.next();
317                total = total.add((BigDecimal)data[0]);
318            }
319            
320            return total;
321        }
322        
323        /**
324         * Gets the monthEndDateService attribute. 
325         * @return Returns the monthEndDateService.
326         */
327        protected MonthEndDateService getMonthEndDateService() {
328            return monthEndDateService;
329        }
330    
331        /**
332         * Sets the monthEndDateService attribute value.
333         * @param monthEndDateService The monthEndDateService to set.
334         */
335        public void setMonthEndDateService(MonthEndDateService monthEndDateService) {
336            this.monthEndDateService = monthEndDateService;
337        }
338        
339        /**
340         * Gets the securityDao attribute. 
341         * @return Returns the securityDao.
342         */
343        protected SecurityDao getSecurityDao() {
344            return securityDao;
345        }
346    
347        /**
348         * Sets the securityDao attribute value.
349         * @param securityDao The securityDao to set.
350         */
351        public void setSecurityDao(SecurityDao securityDao) {
352            this.securityDao = securityDao;
353        }
354    }