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.lm.leaveblock.service;
17  
18  import java.math.BigDecimal;
19  import java.sql.Timestamp;
20  import java.util.*;
21  
22  import org.apache.commons.collections.CollectionUtils;
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.commons.lang.time.DateUtils;
25  import org.apache.log4j.Logger;
26  import org.joda.time.DateTime;
27  import org.joda.time.DateTimeConstants;
28  import org.joda.time.DateTimeZone;
29  import org.joda.time.Interval;
30  import org.kuali.hr.lm.LMConstants;
31  import org.kuali.hr.lm.leaveblock.LeaveBlock;
32  import org.kuali.hr.lm.leaveblock.LeaveBlockHistory;
33  import org.kuali.hr.lm.leaveblock.dao.LeaveBlockDao;
34  import org.kuali.hr.lm.workflow.LeaveCalendarDocumentHeader;
35  import org.kuali.hr.time.assignment.Assignment;
36  import org.kuali.hr.time.calendar.CalendarEntries;
37  import org.kuali.hr.time.earncode.EarnCode;
38  import org.kuali.hr.time.service.base.TkServiceLocator;
39  import org.kuali.hr.time.util.TKContext;
40  import org.kuali.hr.time.util.TKUtils;
41  import org.kuali.hr.time.util.TkConstants;
42  import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
43  import org.kuali.rice.krad.service.KRADServiceLocator;
44  
45  public class LeaveBlockServiceImpl implements LeaveBlockService {
46  
47      private static final Logger LOG = Logger.getLogger(LeaveBlockServiceImpl.class);
48  
49      private LeaveBlockDao leaveBlockDao;
50  
51      @Override
52      public LeaveBlock getLeaveBlock(String leaveBlockId) {
53          return leaveBlockDao.getLeaveBlock(leaveBlockId);
54      }
55  
56      public LeaveBlockDao getLeaveBlockDao() {
57          return leaveBlockDao;
58      }
59  
60      public void setLeaveBlockDao(LeaveBlockDao leaveBlockDao) {
61          this.leaveBlockDao = leaveBlockDao;
62      }
63  
64      public List<LeaveBlock> getLeaveBlocksForDocumentId(String documentId) {
65          return leaveBlockDao.getLeaveBlocksForDocumentId(documentId);
66      }
67  
68  
69      @Override
70      public List<LeaveBlock> getLeaveBlocks(String principalId, Date beginDate,
71                                     Date endDate) {
72          return leaveBlockDao.getLeaveBlocks(principalId, beginDate, endDate);
73      }
74  
75      @Override
76      public List<LeaveBlock> getLeaveBlocksWithAccrualCategory(String principalId, Date beginDate,
77                                             Date endDate, String accrualCategory) {
78          return leaveBlockDao.getLeaveBlocksWithAccrualCategory(principalId, beginDate, endDate, accrualCategory);
79      }
80  
81      @Override
82      public List<LeaveBlock> getLeaveBlocksWithType(String principalId, Date beginDate,
83                                             Date endDate, String leaveBlockType) {
84          return leaveBlockDao.getLeaveBlocksWithType(principalId, beginDate, endDate, leaveBlockType);
85      }
86  
87      @Override
88      public List<LeaveBlock> getLeaveBlocksSinceCarryOver(String principalId, Map<String, LeaveBlock> carryOver, DateTime endDate, boolean includeAllAccrualCategories) {
89          return leaveBlockDao.getLeaveBlocksSinceCarryOver(principalId, carryOver, endDate, includeAllAccrualCategories);
90      }
91  
92      @Override
93      public Map<String, LeaveBlock> getLastCarryOverBlocks(String principalId, Date asOfDate) {
94          if (StringUtils.isEmpty(principalId)) {
95              return Collections.emptyMap();
96          }
97          return leaveBlockDao.getLastCarryOverBlocks(principalId, LMConstants.LEAVE_BLOCK_TYPE.CARRY_OVER, asOfDate);
98      }
99  
100     @Override
101     public void saveLeaveBlocks(List<LeaveBlock> leaveBlocks) {
102     	KRADServiceLocator.getBusinessObjectService().save(leaveBlocks);
103     	
104     	List<LeaveBlockHistory> leaveBlockHistories = new ArrayList<LeaveBlockHistory>();
105         for (LeaveBlock leaveBlock : leaveBlocks) {
106         	LeaveBlockHistory lbh = new LeaveBlockHistory(leaveBlock);
107         	lbh.setAction(LMConstants.ACTION.ADD);
108         	leaveBlockHistories.add(lbh);
109         }
110         
111         KRADServiceLocator.getBusinessObjectService().save(leaveBlockHistories);
112     }
113 
114     @Override
115     public void deleteLeaveBlock(String leaveBlockId, String principalId) {
116         LeaveBlock leaveBlock = getLeaveBlock(leaveBlockId);
117         
118 //        leaveBlock.setPrincipalIdModified(TKContext.getTargetPrincipalId());
119 //        leaveBlock.setTimestamp(TKUtils.getCurrentTimestamp());
120         
121         // Make entry into LeaveBlockHistory table
122         LeaveBlockHistory leaveBlockHistory = new LeaveBlockHistory(leaveBlock);
123         leaveBlockHistory.setPrincipalIdDeleted(principalId);
124         leaveBlockHistory.setTimestampDeleted(new Timestamp(System.currentTimeMillis()));
125         leaveBlockHistory.setAction(LMConstants.ACTION.DELETE);
126 
127         // deleting leaveblock
128         KRADServiceLocator.getBusinessObjectService().delete(leaveBlock);
129         
130         // creating history
131         KRADServiceLocator.getBusinessObjectService().save(leaveBlockHistory);
132         
133         
134     }
135 
136     @Override
137     public void saveLeaveBlock(LeaveBlock leaveBlock, String principalId) {
138 
139     	// first delete and create new entry in the database
140     	KRADServiceLocator.getBusinessObjectService().delete(leaveBlock);
141     	
142     	// create new 
143         leaveBlock.setLmLeaveBlockId(null);
144     	leaveBlock.setTimestamp(new Timestamp(System.currentTimeMillis()));
145     	leaveBlock.setPrincipalIdModified(principalId);
146     	KRADServiceLocator.getBusinessObjectService().save(leaveBlock);
147 
148         // save history
149         LeaveBlockHistory lbh = new LeaveBlockHistory(leaveBlock);
150         lbh.setAction(LMConstants.ACTION.MODIFIED);
151         TkServiceLocator.getLeaveBlockHistoryService().saveLeaveBlockHistory(lbh);
152         
153     }
154 
155     @Override
156     public void addLeaveBlocks(DateTime beginDate, DateTime endDate, CalendarEntries ce, String selectedEarnCode, 
157     		BigDecimal hours, String description, Assignment selectedAssignment, String spanningWeeks, String leaveBlockType, String principalId) {
158         DateTime calBeginDateTime = beginDate;
159     	DateTime calEndDateTime = endDate;
160         if(ce != null) {
161         	calBeginDateTime = ce.getBeginLocalDateTime().toDateTime();
162         	calEndDateTime = ce.getEndLocalDateTime().toDateTime();
163         } else {
164             throw new RuntimeException("Calendar Entry parameter is null.");
165         }
166         Interval calendarInterval = new Interval(calBeginDateTime, calEndDateTime);
167        
168         // To create the correct interval by the given begin and end dates,
169         // we need to plus one day on the end date to include that date
170         List<Interval> leaveBlockIntervals = TKUtils.createDaySpan(beginDate.toDateMidnight().toDateTime(), endDate.plusDays(1).toDateMidnight().toDateTime(), TKUtils.getSystemDateTimeZone());
171         // need to use beginDate and endDate of the calendar to find all leaveBlocks since LeaveCalendarDocument Id is not always available
172         List<LeaveBlock> currentLeaveBlocks = getLeaveBlocks(principalId, calBeginDateTime.toDate(), calEndDateTime.toDate());
173     
174         // use the current calendar's begin and end date to figure out if this pay period has a leaveDocument
175         LeaveCalendarDocumentHeader lcdh = TkServiceLocator.getLeaveCalendarDocumentHeaderService()
176         		.getDocumentHeader(principalId, ce.getBeginLocalDateTime().toDateTime().toDate(), ce.getEndLocalDateTime().toDateTime().toDate());
177         String docId = lcdh == null ? null : lcdh.getDocumentId();
178         
179         // TODO: need to integrate with the scheduled timeoff.
180         for (Interval leaveBlockInt : leaveBlockIntervals) {
181             if (calendarInterval.contains(leaveBlockInt)) {
182             	// KPME-1446 if "Include weekends" check box is checked, don't add Sat and Sun to the leaveblock list
183             	if (StringUtils.isEmpty(spanningWeeks) && 
184                 	(leaveBlockInt.getStart().getDayOfWeek() == DateTimeConstants.SATURDAY ||leaveBlockInt.getStart().getDayOfWeek() == DateTimeConstants.SUNDAY)) {
185             		
186             		// do nothing
187             	} else {
188             		 // Currently, we store the accrual category value in the leave code table, but store accrual category id in the leaveBlock.
189                     // That's why there is a two step server call to get the id. This might be changed in the future.
190 
191                     java.sql.Date sqlDate = new java.sql.Date(ce.getEndLocalDateTime().toDateTime().toDate().getTime());
192                     if ((leaveBlockType.equals(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR)
193                                 || leaveBlockType.equals((LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR)))
194                             && BigDecimal.ZERO.compareTo(hours) < 0) {
195                         hours = hours.negate();
196                     }
197 
198                     CalendarEntries calendarEntry = TkServiceLocator.getCalendarEntriesService().getCurrentCalendarEntriesByCalendarId(ce.getHrCalendarId(), TKUtils.getCurrentDate());
199                     Date leaveBlockDate = new DateTime(leaveBlockInt.getStartMillis()).toDate();
200                     
201                     String requestStatus = LMConstants.REQUEST_STATUS.USAGE;
202                     if (TkServiceLocator.getLeaveApprovalService().isActiveAssignmentFoundOnJobFlsaStatus(principalId, TkConstants.FLSA_STATUS_NON_EXEMPT, true)) {
203                     	TimesheetDocumentHeader tdh = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeaderForDate(principalId, leaveBlockDate);
204                     	if (tdh != null) {
205      	            	   if (DateUtils.isSameDay(leaveBlockDate, tdh.getEndDate()) || leaveBlockDate.after(tdh.getEndDate())) {
206      	            		  requestStatus = LMConstants.REQUEST_STATUS.PLANNED;
207      	            	   }
208      	               } else {
209      	            	  requestStatus = LMConstants.REQUEST_STATUS.PLANNED;
210      	               }
211                     } else {
212                     	if (DateUtils.isSameDay(leaveBlockDate, calendarEntry.getEndPeriodDateTime()) || leaveBlockDate.after(calendarEntry.getEndPeriodDateTime())) {
213                     		requestStatus = LMConstants.REQUEST_STATUS.PLANNED;
214                     	}
215                     }
216                     
217                     EarnCode earnCodeObj = TkServiceLocator.getEarnCodeService().getEarnCode(selectedEarnCode, sqlDate);
218 	                LeaveBlock leaveBlock = new LeaveBlock.Builder(new DateTime(leaveBlockInt.getStartMillis()), docId, principalId, selectedEarnCode, hours)
219 	                        .description(description)
220 	                        .principalIdModified(principalId)
221 	                        .timestamp(TKUtils.getCurrentTimestamp())
222 	                        .scheduleTimeOffId("0")
223 	                        .accrualCategory(earnCodeObj.getAccrualCategory())
224 	                        .workArea(selectedAssignment.getWorkArea())
225 	                        .jobNumber(selectedAssignment.getJobNumber())
226 	                        .task(selectedAssignment.getTask())
227                             .requestStatus(requestStatus)
228 	                        .leaveBlockType(leaveBlockType)
229 	                        .build();
230                     if (!currentLeaveBlocks.contains(leaveBlock)) {
231                         currentLeaveBlocks.add(leaveBlock);
232                     }
233             	}
234             }
235         }
236 
237         saveLeaveBlocks(currentLeaveBlocks);
238     }
239     
240     // KPME-1447
241     @Override
242     public void updateLeaveBlock(LeaveBlock leaveBlock, String principalId) {
243     	//verify that if leave block is usage, leave amount is negative
244         if ((LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR.equals(leaveBlock.getLeaveBlockType())
245                     || LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR.equals(leaveBlock.getLeaveBlockType()))
246                 && BigDecimal.ZERO.compareTo(leaveBlock.getLeaveAmount()) < 0) {
247             leaveBlock.setLeaveAmount(leaveBlock.getLeaveAmount().negate());
248         }
249 
250         // Make entry into LeaveBlockHistory table
251         LeaveBlockHistory leaveBlockHistory = new LeaveBlockHistory(leaveBlock);
252         leaveBlockHistory.setPrincipalIdDeleted(principalId);
253         leaveBlockHistory.setTimestampDeleted(new Timestamp(System.currentTimeMillis()));
254         leaveBlockHistory.setAction(LMConstants.ACTION.MODIFIED);
255 
256         KRADServiceLocator.getBusinessObjectService().save(leaveBlock);
257         
258         // creating history
259         KRADServiceLocator.getBusinessObjectService().save(leaveBlockHistory); 
260     }    
261 
262     public static List<Interval> createDaySpan(DateTime beginDateTime, DateTime endDateTime, DateTimeZone zone) {
263         beginDateTime = beginDateTime.toDateTime(zone);
264         endDateTime = endDateTime.toDateTime(zone);
265         List<Interval> dayIntervals = new ArrayList<Interval>();
266 
267         DateTime currDateTime = beginDateTime;
268         while (currDateTime.isBefore(endDateTime)) {
269             DateTime prevDateTime = currDateTime;
270             currDateTime = currDateTime.plusDays(1);
271             Interval daySpan = new Interval(prevDateTime, currDateTime);
272             dayIntervals.add(daySpan);
273         }
274 
275         return dayIntervals;
276     }
277 
278 	@Override
279 	public List<LeaveBlock> getLeaveBlocks(String principalId, String leaveBlockType, String requestStatus, Date currentDate) {
280 		return leaveBlockDao.getLeaveBlocks(principalId, leaveBlockType, requestStatus, currentDate);
281 	}
282 	
283 	@Override
284 	public List<LeaveBlock> getLeaveBlocksForDate(String principalId, Date leaveDate) {
285 		return leaveBlockDao.getLeaveBlocksForDate(principalId, leaveDate);
286 	}
287 
288 	@Override
289 	public List<LeaveBlock> getNotAccrualGeneratedLeaveBlocksForDate(String principalId, Date leaveDate) {
290 		return leaveBlockDao.getNotAccrualGeneratedLeaveBlocksForDate(principalId, leaveDate);
291 	}
292 
293 	public List<LeaveBlock> getLeaveBlocksForTimeCalendar(String principalId, Date beginDate, Date endDate, List<String> assignmentKeys) {
294 		List<LeaveBlock> col = leaveBlockDao.getCalendarLeaveBlocks(principalId, beginDate, endDate);
295 		List<LeaveBlock> leaveBlocks = filterLeaveBlocksForTimeCalendar(col, assignmentKeys);
296 		return leaveBlocks;
297 	}
298 	
299 	public List<LeaveBlock> getLeaveBlocksForLeaveCalendar(String principalId, Date beginDate, Date endDate, List<String> assignmentKeys) {
300 		List<LeaveBlock> col = leaveBlockDao.getLeaveBlocks(principalId, beginDate, endDate);
301 		List<LeaveBlock> leaveBlocks = filterLeaveBlocksForLeaveCalendar(col, assignmentKeys);
302 		return leaveBlocks;
303 	}
304 	
305 	public List<LeaveBlock> filterLeaveBlocksForTimeCalendar(List<LeaveBlock> lbs, List<String> assignmentKeys) {
306 		if(CollectionUtils.isEmpty(assignmentKeys)) {
307 			return lbs;
308 		}
309     	List<LeaveBlock> results = new ArrayList<LeaveBlock> ();
310     	for(LeaveBlock lb : lbs) {
311     		if(lb != null) {
312 	    		if (StringUtils.equals(lb.getLeaveBlockType(), LMConstants.LEAVE_BLOCK_TYPE.ACCRUAL_SERVICE)
313 	    				&& StringUtils.isNotEmpty(lb.getScheduleTimeOffId()) 
314 	    				&& lb.getLeaveAmount().compareTo(BigDecimal.ZERO) < 0) {
315 					// display usage leave blocks generated by system scheduled time off
316 					results.add(lb);
317 				} else if(StringUtils.isNotEmpty(lb.getAssignmentKey()) && assignmentKeys.contains(lb.getAssignmentKey())) {
318 	    			if (StringUtils.equals(lb.getLeaveBlockType(), LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR)) {
319 	    				// only add approved leave blocks that are created from leave calendar
320 	    				if (StringUtils.equals(lb.getRequestStatus(), LMConstants.REQUEST_STATUS.APPROVED)) {	
321 	    					results.add(lb);
322 	    				}
323 	    			} else if(StringUtils.equals(lb.getLeaveBlockType(), LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR)) {
324 	    				results.add(lb);
325 	    			}
326 	    		}
327     		}
328     	}
329     	return results;
330     }
331 	
332 	public List<LeaveBlock> filterLeaveBlocksForLeaveCalendar(List<LeaveBlock> lbs, List<String> assignmentKeys) {
333 		if(CollectionUtils.isEmpty(assignmentKeys)) {
334 			return lbs;
335 		}
336 		List<LeaveBlock> leaveBlocks = new ArrayList<LeaveBlock>();
337 		for(LeaveBlock lb : lbs) {
338   		   if(lb != null) {
339   			   if(lb.getLeaveBlockType().equals(LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR)) {
340   				  if(StringUtils.isNotEmpty(lb.getAssignmentKey()) && assignmentKeys.contains(lb.getAssignmentKey())) {
341   					  leaveBlocks.add(lb);
342   				  }
343   			   } else {
344   				   leaveBlocks.add(lb);
345   			   }
346   		   }
347   	   	}
348     	return leaveBlocks;
349     }
350 
351     @Override
352     public void deleteLeaveBlocksForDocumentId(String documentId){
353         leaveBlockDao.deleteLeaveBlocksForDocumentId(documentId);
354     }
355     
356     
357     @Override
358     public List<LeaveBlock> getAccrualGeneratedLeaveBlocks(String principalId, Date beginDate, Date endDate) {
359     	return leaveBlockDao.getAccrualGeneratedLeaveBlocks(principalId, beginDate, endDate);
360     }
361     
362     @Override
363     public List<LeaveBlock> getSSTOLeaveBlocks(String principalId, String sstoId, Date accruledDate) {
364     	return leaveBlockDao.getSSTOLeaveBlocks(principalId, sstoId, accruledDate);
365     }
366     
367     @Override
368     public List<LeaveBlock> getABELeaveBlocksSinceTime(String principalId, Timestamp lastRanTime) {
369     	return leaveBlockDao.getABELeaveBlocksSinceTime(principalId, lastRanTime);
370     }
371 }