View Javadoc

1   /**
2    * Copyright 2004-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.hr.time.accrual.service;
17  
18  import java.math.BigDecimal;
19  import java.sql.Date;
20  import java.util.ArrayList;
21  import java.util.HashMap;
22  import java.util.LinkedHashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.commons.lang.StringUtils;
27  import org.kuali.hr.time.accrual.AccrualCategory;
28  import org.kuali.hr.time.accrual.TimeOffAccrual;
29  import org.kuali.hr.time.accrual.dao.TimeOffAccrualDao;
30  import org.kuali.hr.time.earncode.EarnCode;
31  import org.kuali.hr.time.service.base.TkServiceLocator;
32  import org.kuali.hr.time.timeblock.TimeBlock;
33  import org.kuali.hr.time.timesheet.TimesheetDocument;
34  import org.kuali.hr.time.util.TkConstants;
35  
36  public class TimeOffAccrualServiceImpl implements TimeOffAccrualService {
37  
38  	public static final String ACCRUAL_CATEGORY_KEY = "accrualCategory";
39  	public static final String ACCRUAL_NAME_KEY = "accrualName";
40  	public static final String YEARLY_CARRYOVER_KEY = "yearlyCarryover";
41  	public static final String HOURS_ACCRUED_KEY = "hoursAccrued";
42  	public static final String HOURS_TAKEN_KEY = "hoursTaken";
43  	public static final String HOURS_ADJUST_KEY = "hoursAdjust";
44  	public static final String TOTAL_HOURS_KEY = "totalHours";
45  	public static final String EFF_DATE_KEY = "effdt";
46  
47  	private TimeOffAccrualDao timeOffAccrualDao;
48  
49  	public void setTimeOffAccrualDao(TimeOffAccrualDao timeOffAccrualDao) {
50  		this.timeOffAccrualDao = timeOffAccrualDao;
51  	}
52  
53  	@Override
54  	public List<TimeOffAccrual> getTimeOffAccruals(String principalId, Date asOfDate) {
55  		return timeOffAccrualDao.getActiveTimeOffAccruals(principalId, asOfDate);
56  	}
57  
58  	@Override
59  	public List<Map<String, Object>> getTimeOffAccrualsCalc(String principalId, Date asOfDate) {
60  
61  		List<Map<String, Object>> timeOffAccrualsCalc = new ArrayList<Map<String, Object>>();
62  		Map<String,String> accrualCatToDescr = new HashMap<String, String>();
63  
64  		for (TimeOffAccrual timeOffAccrual : getTimeOffAccruals(principalId, asOfDate)) {
65  			String accrualCatDescr = accrualCatToDescr.get(timeOffAccrual.getAccrualCategory());
66  			//if no accrual cat description found look up accrual category and find one
67  			if (StringUtils.isBlank(accrualCatDescr)){
68  				AccrualCategory accrualCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(timeOffAccrual.getAccrualCategory(), asOfDate);
69  				if (accrualCat != null) {
70  					accrualCatDescr = accrualCat.getDescr();
71  					accrualCatToDescr.put(accrualCat.getAccrualCategory(), accrualCatDescr);
72  				}
73  			}
74  			Map<String, Object> output = new LinkedHashMap<String, Object>();
75  			output.put(ACCRUAL_CATEGORY_KEY, accrualCatDescr + "("+timeOffAccrual.getAccrualCategory()+")");
76  			output.put(ACCRUAL_NAME_KEY, timeOffAccrual.getAccrualCategory());
77  			output.put(YEARLY_CARRYOVER_KEY, timeOffAccrual.getYearlyCarryover());
78  			output.put(HOURS_ACCRUED_KEY, timeOffAccrual.getHoursAccrued());
79  			output.put(HOURS_TAKEN_KEY, timeOffAccrual.getHoursTaken());
80  			output.put(HOURS_ADJUST_KEY, timeOffAccrual.getHoursAdjust());
81  			BigDecimal totalHours = timeOffAccrual.getYearlyCarryover().add(timeOffAccrual.getHoursAccrued().subtract(timeOffAccrual.getHoursTaken()).add(timeOffAccrual.getHoursAdjust()));
82  			output.put(TOTAL_HOURS_KEY, totalHours);
83  			output.put(EFF_DATE_KEY, timeOffAccrual.getEffectiveDate());
84  
85  			timeOffAccrualsCalc.add(output);
86  		}
87  
88  		return timeOffAccrualsCalc;
89  	}
90  
91  	public List<String> validateAccrualHoursLimit(TimesheetDocument timesheetDocument) {
92      	 String pId = "";
93           if (timesheetDocument != null) {
94               pId = timesheetDocument.getPrincipalId();
95           }
96           
97       	return validateAccrualHoursLimit(pId, timesheetDocument.getTimeBlocks(),  timesheetDocument.getAsOfDate());
98          
99      }
100 	
101 	public List<String> validateAccrualHoursLimit(String pId, List<TimeBlock> tbList, Date asOfDate) {
102 		 List<String> warningMessages = new ArrayList<String>();
103 
104          List<Map<String, Object>> calcList = this.getTimeOffAccrualsCalc(pId, asOfDate);
105          
106            if (tbList.isEmpty()) {
107              return warningMessages;
108          }
109          List<String> accruals = new ArrayList<String>();
110          for (Map<String, Object> aMap : calcList) {
111     		accruals.add((String) aMap.get(ACCRUAL_CATEGORY_KEY));
112     	 }
113          for (Map<String, Object> aMap : calcList) {
114              String accrualCategory = (String) aMap.get(ACCRUAL_NAME_KEY);
115              List<TimeBlock> warningTbs = new ArrayList<TimeBlock>();
116              BigDecimal totalForAccrCate = this.totalForAccrCate(accrualCategory, tbList, warningTbs);
117              //if there is no timeblocks for this category no warning is necessary 
118              if(totalForAccrCate.compareTo(BigDecimal.ZERO)==0){
119             	 continue;
120              }
121              BigDecimal balanceHrs = (((BigDecimal)aMap.get(YEARLY_CARRYOVER_KEY)).add((BigDecimal)aMap.get(HOURS_ACCRUED_KEY)).subtract((BigDecimal)aMap.get(HOURS_TAKEN_KEY)).add((BigDecimal)aMap.get(HOURS_ADJUST_KEY)));
122              
123              if (totalForAccrCate.compareTo(balanceHrs) == 1) {
124              	String msg = "Warning: Total hours entered (" + totalForAccrCate.toString() + ") for Accrual Category \"" + (String) aMap.get(ACCRUAL_CATEGORY_KEY) + "\" has exceeded balance (" + balanceHrs.toString() + "). Problem Time Blocks are:<br/>";
125              	for(TimeBlock tb : warningTbs) {
126              		msg += "Earn code: " + tb.getEarnCode()+ " Hours: " + tb.getHours().toString() + " on Date " + (tb.getBeginTimeDisplay() != null ? tb.getBeginTimeDisplay().toString(TkConstants.DT_BASIC_DATE_FORMAT) : "") + "<br/>";
127              	}
128                 warningMessages.add(msg);
129 
130              }
131          }
132          return warningMessages;
133     }
134 	public List<String> validateAccrualHoursLimitByEarnCode(TimesheetDocument timesheetDocument, String earnCode) {
135 		 List<String> warningMessages = new ArrayList<String>();
136    	 String pId = "";
137         if (timesheetDocument != null) {
138             pId = timesheetDocument.getPrincipalId();
139         }
140         List<Map<String, Object>> calcList = this.getTimeOffAccrualsCalc(pId, timesheetDocument.getAsOfDate());
141 
142         List<TimeBlock> tbList = timesheetDocument.getTimeBlocks();
143         if (tbList.isEmpty()) {
144             return warningMessages;
145         }
146         List<String> accruals = new ArrayList<String>();
147         for (Map<String, Object> aMap : calcList) {
148    		accruals.add((String) aMap.get(ACCRUAL_CATEGORY_KEY));
149    	 }
150         
151         List<AccrualCategory> accrualCategories = TkServiceLocator.getAccrualCategoryService().getActiveAccrualCategories(timesheetDocument.getAsOfDate());
152     
153         for(AccrualCategory accrualCategory : accrualCategories){
154        	 if(!accruals.contains(accrualCategory.getAccrualCategory()) && !StringUtils.equals(TkConstants.HOLIDAY_EARN_CODE, accrualCategory.getAccrualCategory())){
155        		Map<String, Object> accrualData = new LinkedHashMap<String, Object>();
156     			accrualData.put(ACCRUAL_CATEGORY_KEY, accrualCategory.getAccrualCategory());
157     			accrualData.put(YEARLY_CARRYOVER_KEY, new BigDecimal(0.00));
158     			accrualData.put(HOURS_ACCRUED_KEY, new BigDecimal(0.00));
159     			accrualData.put(HOURS_TAKEN_KEY, new BigDecimal(0.00));
160     			accrualData.put(HOURS_ADJUST_KEY, new BigDecimal(0.00));
161     			calcList.add(accrualData);
162        	 }
163         }
164         for (Map<String, Object> aMap : calcList) {
165             String accrualCategory = (String) aMap.get(ACCRUAL_CATEGORY_KEY);
166             List<TimeBlock> warningTbs = new ArrayList<TimeBlock>();
167             BigDecimal totalForAccrCate = this.totalForAccrCate(accrualCategory, tbList, warningTbs);
168             BigDecimal balanceHrs = (((BigDecimal)aMap.get(YEARLY_CARRYOVER_KEY)).add((BigDecimal)aMap.get(HOURS_ACCRUED_KEY)).subtract((BigDecimal)aMap.get(HOURS_TAKEN_KEY)).add((BigDecimal)aMap.get(HOURS_ADJUST_KEY)));
169             
170             if (totalForAccrCate.compareTo(balanceHrs) == 1) {
171             	if (accrualCategory.equals(earnCode)) {
172 	            	String msg = "Warning: Total hours entered (" + totalForAccrCate.toString() + ") for Accrual Category \"" + (String) aMap.get(ACCRUAL_CATEGORY_KEY) + "\" has exceeded balance (" + balanceHrs.toString() + "). Problem Time Blocks are: ";
173 	            	for(TimeBlock tb : warningTbs) {
174 	            		msg += "Earn code: " + tb.getEarnCode()+ " Hours: " + tb.getHours().toString() + " on Date " + (tb.getBeginTimeDisplay() != null ? tb.getBeginTimeDisplay().toString(TkConstants.DT_BASIC_DATE_FORMAT) : "") + " ";
175 	            	}
176 	            	
177 	               warningMessages.add(msg);
178             	}
179 
180             }
181         }
182         return warningMessages;
183    }
184 
185     public BigDecimal totalForAccrCate(String accrualCategory, List<TimeBlock> tbList, List<TimeBlock> warningTbs) {
186         BigDecimal total = BigDecimal.ZERO;
187         for (TimeBlock tb : tbList) {
188             String earnCode = tb.getEarnCode();
189             Date asOfDate = new java.sql.Date(tb.getBeginTimestamp().getTime());
190             EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(earnCode, asOfDate);
191             String accrCate = "";
192             if (ec != null) {
193                 accrCate = ec.getAccrualCategory();
194                 if (accrCate != null) {
195                     if (accrCate.equals(accrualCategory)) {
196                         total = total.add(tb.getHours());
197                         warningTbs.add(tb);
198                     }
199                 }
200             }
201         }
202         return total;
203     }
204 
205 	@Override
206 	public TimeOffAccrual getTimeOffAccrual(Long laTimeOffAccrualId) {
207 		return timeOffAccrualDao.getTimeOffAccrual(laTimeOffAccrualId);
208 	}
209 	
210 	@Override
211 	public int getTimeOffAccrualCount(String accrualCategory, Date effectiveDate, String principalId, String lmAccrualId) {
212 		return timeOffAccrualDao.getTimeOffAccrualCount(accrualCategory, effectiveDate, principalId, lmAccrualId);
213 	}
214 
215     @Override
216     public  List<TimeOffAccrual> getTimeOffAccruals(String principalId, String accrualCategory){
217         return timeOffAccrualDao.getTimeOffAccruals(principalId, accrualCategory);
218     }
219 }