View Javadoc

1   /**
2    * Copyright 2004-2012 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 org.apache.commons.lang.StringUtils;
19  import org.apache.log4j.Logger;
20  import org.kuali.hr.time.accrual.AccrualCategory;
21  import org.kuali.hr.time.accrual.TimeOffAccrual;
22  import org.kuali.hr.time.accrual.dao.TimeOffAccrualDao;
23  import org.kuali.hr.time.earncode.EarnCode;
24  import org.kuali.hr.time.service.base.TkServiceLocator;
25  import org.kuali.hr.time.timeblock.TimeBlock;
26  import org.kuali.hr.time.timesheet.TimesheetDocument;
27  import org.kuali.hr.time.util.TKUtils;
28  import org.kuali.hr.time.util.TkConstants;
29  
30  import java.math.BigDecimal;
31  import java.sql.Date;
32  import java.util.*;
33  
34  public class TimeOffAccrualServiceImpl implements TimeOffAccrualService {
35  
36  	private static final Logger LOG = Logger.getLogger(TimeOffAccrualServiceImpl.class);
37  	public static final String ACCRUAL_CATEGORY_KEY = "accrualCategory";
38  	public static final String ACCRUAL_NAME_KEY = "accrualName";
39  	public static final String YEARLY_CARRYOVER_KEY = "yearlyCarryover";
40  	public static final String HOURS_ACCRUED_KEY = "hoursAccrued";
41  	public static final String HOURS_TAKEN_KEY = "hoursTaken";
42  	public static final String HOURS_ADJUST_KEY = "hoursAdjust";
43  	public static final String TOTAL_HOURS_KEY = "totalHours";
44  	public static final String EFF_DATE_KEY = "effdt";
45  
46  	private TimeOffAccrualDao timeOffAccrualDao;
47  
48  	public void setTimeOffAccrualDao(TimeOffAccrualDao timeOffAccrualDao) {
49  		this.timeOffAccrualDao = timeOffAccrualDao;
50  	}
51  
52  	@Override
53  	public List<TimeOffAccrual> getTimeOffAccruals(String principalId, Date asOfDate) {
54  		java.sql.Date currentDate = TKUtils.getTimelessDate(null);
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  	@SuppressWarnings("unchecked")
92  	public List<String> validateAccrualHoursLimit(TimesheetDocument timesheetDocument) {
93      	 String pId = "";
94           if (timesheetDocument != null) {
95               pId = timesheetDocument.getPrincipalId();
96           }
97           
98       	return validateAccrualHoursLimit(pId, timesheetDocument.getTimeBlocks(),  timesheetDocument.getAsOfDate());
99          
100     }
101 	
102 	@SuppressWarnings("unchecked")
103 	public List<String> validateAccrualHoursLimit(String pId, List<TimeBlock> tbList, Date asOfDate) {
104 		 List<String> warningMessages = new ArrayList<String>();
105 
106          List<Map<String, Object>> calcList = this.getTimeOffAccrualsCalc(pId, asOfDate);
107          
108            if (tbList.isEmpty()) {
109              return warningMessages;
110          }
111          List<String> accruals = new ArrayList<String>();
112          for (Map<String, Object> aMap : calcList) {
113     		accruals.add((String) aMap.get(ACCRUAL_CATEGORY_KEY));
114     	 }
115          for (Map<String, Object> aMap : calcList) {
116              String accrualCategory = (String) aMap.get(ACCRUAL_NAME_KEY);
117              List<TimeBlock> warningTbs = new ArrayList<TimeBlock>();
118              BigDecimal totalForAccrCate = this.totalForAccrCate(accrualCategory, tbList, warningTbs);
119              //if there is no timeblocks for this category no warning is necessary 
120              if(totalForAccrCate.compareTo(BigDecimal.ZERO)==0){
121             	 continue;
122              }
123              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)));
124              
125              if (totalForAccrCate.compareTo(balanceHrs) == 1) {
126              	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/>";
127              	for(TimeBlock tb : warningTbs) {
128              		msg += "Earn code: " + tb.getEarnCode()+ " Hours: " + tb.getHours().toString() + " on Date " + (tb.getBeginTimeDisplay() != null ? tb.getBeginTimeDisplay().toString(TkConstants.DT_BASIC_DATE_FORMAT) : "") + "<br/>";
129              	}
130                 warningMessages.add(msg);
131 
132              }
133          }
134          return warningMessages;
135     }
136 	public List<String> validateAccrualHoursLimitByEarnCode(TimesheetDocument timesheetDocument, String earnCode) {
137 		 List<String> warningMessages = new ArrayList<String>();
138    	 String pId = "";
139         if (timesheetDocument != null) {
140             pId = timesheetDocument.getPrincipalId();
141         }
142         List<Map<String, Object>> calcList = this.getTimeOffAccrualsCalc(pId, timesheetDocument.getAsOfDate());
143 
144         List<TimeBlock> tbList = timesheetDocument.getTimeBlocks();
145         if (tbList.isEmpty()) {
146             return warningMessages;
147         }
148         List<String> accruals = new ArrayList<String>();
149         for (Map<String, Object> aMap : calcList) {
150    		accruals.add((String) aMap.get(ACCRUAL_CATEGORY_KEY));
151    	 }
152         
153         List<AccrualCategory> accrualCategories = TkServiceLocator.getAccrualCategoryService().getActiveAccrualCategories(timesheetDocument.getAsOfDate());
154     
155         for(AccrualCategory accrualCategory : accrualCategories){
156        	 if(!accruals.contains(accrualCategory.getAccrualCategory()) && !StringUtils.equals(TkConstants.HOLIDAY_EARN_CODE, accrualCategory.getAccrualCategory())){
157        		Map<String, Object> accrualData = new LinkedHashMap<String, Object>();
158     			accrualData.put(ACCRUAL_CATEGORY_KEY, accrualCategory.getAccrualCategory());
159     			accrualData.put(YEARLY_CARRYOVER_KEY, new BigDecimal(0.00));
160     			accrualData.put(HOURS_ACCRUED_KEY, new BigDecimal(0.00));
161     			accrualData.put(HOURS_TAKEN_KEY, new BigDecimal(0.00));
162     			accrualData.put(HOURS_ADJUST_KEY, new BigDecimal(0.00));
163     			calcList.add(accrualData);
164        	 }
165         }
166         for (Map<String, Object> aMap : calcList) {
167             String accrualCategory = (String) aMap.get(ACCRUAL_CATEGORY_KEY);
168             List<TimeBlock> warningTbs = new ArrayList<TimeBlock>();
169             BigDecimal totalForAccrCate = this.totalForAccrCate(accrualCategory, tbList, warningTbs);
170             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)));
171             
172             if (totalForAccrCate.compareTo(balanceHrs) == 1) {
173             	if (accrualCategory.equals(earnCode)) {
174 	            	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: ";
175 	            	for(TimeBlock tb : warningTbs) {
176 	            		msg += "Earn code: " + tb.getEarnCode()+ " Hours: " + tb.getHours().toString() + " on Date " + (tb.getBeginTimeDisplay() != null ? tb.getBeginTimeDisplay().toString(TkConstants.DT_BASIC_DATE_FORMAT) : "") + " ";
177 	            	}
178 	            	
179 	               warningMessages.add(msg);
180             	}
181 
182             }
183         }
184         return warningMessages;
185    }
186 
187     public BigDecimal totalForAccrCate(String accrualCategory, List<TimeBlock> tbList, List<TimeBlock> warningTbs) {
188         BigDecimal total = BigDecimal.ZERO;
189         for (TimeBlock tb : tbList) {
190             String earnCode = tb.getEarnCode();
191             Date asOfDate = new java.sql.Date(tb.getBeginTimestamp().getTime());
192             EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(earnCode, asOfDate);
193             String accrCate = "";
194             if (ec != null) {
195                 accrCate = ec.getAccrualCategory();
196                 if (accrCate != null) {
197                     if (accrCate.equals(accrualCategory)) {
198                         total = total.add(tb.getHours());
199                         warningTbs.add(tb);
200                     }
201                 }
202             }
203         }
204         return total;
205     }
206 
207 	@Override
208 	public TimeOffAccrual getTimeOffAccrual(Long laTimeOffAccrualId) {
209 		return timeOffAccrualDao.getTimeOffAccrual(laTimeOffAccrualId);
210 	}
211 	
212 	@Override
213 	public int getTimeOffAccrualCount(String accrualCategory, Date effectiveDate, String principalId, String lmAccrualId) {
214 		return timeOffAccrualDao.getTimeOffAccrualCount(accrualCategory, effectiveDate, principalId, lmAccrualId);
215 	}
216 }