1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.hr.time.util;
17  
18  import java.math.BigDecimal;
19  import java.sql.Time;
20  import java.sql.Timestamp;
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.Comparator;
24  import java.util.List;
25  import java.util.ListIterator;
26  
27  import org.apache.commons.collections.CollectionUtils;
28  import org.joda.time.DateTime;
29  import org.joda.time.DateTimeZone;
30  import org.joda.time.Interval;
31  import org.joda.time.LocalDateTime;
32  import org.joda.time.LocalTime;
33  import org.kuali.hr.lm.leaveblock.LeaveBlock;
34  import org.kuali.hr.lm.util.LeaveBlockAggregate;
35  import org.kuali.hr.time.assignment.Assignment;
36  import org.kuali.hr.time.calendar.Calendar;
37  import org.kuali.hr.time.calendar.CalendarEntries;
38  import org.kuali.hr.time.flsa.FlsaDay;
39  import org.kuali.hr.time.flsa.FlsaWeek;
40  import org.kuali.hr.time.service.base.TkServiceLocator;
41  import org.kuali.hr.time.timeblock.TimeBlock;
42  import org.kuali.hr.time.timeblock.TimeHourDetail;
43  import org.kuali.hr.time.timesheet.TimesheetDocument;
44  import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
45  
46  public class TkTimeBlockAggregate {
47  	private List<List<TimeBlock>> dayTimeBlockList = new ArrayList<List<TimeBlock>>();
48  	private List<List<LeaveBlock>> dayLeaveBlockList = new ArrayList<List<LeaveBlock>>();
49  	private CalendarEntries payCalendarEntry;
50  	private Calendar payCalendar;
51  
52      
53  
54  
55  
56  
57  
58  	public TkTimeBlockAggregate(List<TimeBlock> timeBlocks, CalendarEntries payCalendarEntry){
59  		this(timeBlocks, payCalendarEntry, TkServiceLocator.getCalendarService().getCalendar(payCalendarEntry.getHrCalendarId()));
60  	}
61  
62      
63  
64  
65  
66  
67  
68  
69  	public TkTimeBlockAggregate(List<TimeBlock> timeBlocks, CalendarEntries payCalendarEntry, Calendar payCalendar) {
70          this(timeBlocks, payCalendarEntry, payCalendar, false);
71      }
72  
73      
74  
75  
76  
77  
78  
79  
80  
81      public TkTimeBlockAggregate(List<TimeBlock> timeBlocks, CalendarEntries payCalendarEntry, Calendar payCalendar, boolean useUserTimeZone) {
82          this(timeBlocks, payCalendarEntry, payCalendar, useUserTimeZone, 
83          		useUserTimeZone ? TKUtils.getDaySpanForCalendarEntry(payCalendarEntry) : TKUtils.getDaySpanForCalendarEntry(payCalendarEntry, TKUtils.getSystemDateTimeZone()));
84  	}
85  
86      public TkTimeBlockAggregate(List<TimeBlock> timeBlocks, CalendarEntries payCalendarEntry, Calendar payCalendar, boolean useUserTimeZone, List<Interval> dayIntervals) {
87      	this.payCalendarEntry = payCalendarEntry;
88  		this.payCalendar = payCalendar;
89  		
90  		for(Interval dayInt : dayIntervals){
91  			List<TimeBlock> dayTimeBlocks = new ArrayList<TimeBlock>();
92  			for(TimeBlock timeBlock : timeBlocks){
93  
94                  
95                  
96                  
97                  
98  
99  				DateTime beginTime = useUserTimeZone ? timeBlock.getBeginTimeDisplay() : new DateTime(timeBlock.getBeginTimestamp(), TKUtils.getSystemDateTimeZone());
100 				DateTime endTime = useUserTimeZone ? timeBlock.getEndTimeDisplay() :  new DateTime(timeBlock.getEndTimestamp(), TKUtils.getSystemDateTimeZone());
101 				if(dayInt.contains(beginTime)){
102 					if(dayInt.contains(endTime) || endTime.compareTo(dayInt.getEnd()) == 0){
103 						
104 						if(beginTime.getHourOfDay() < dayInt.getStart().getHourOfDay()) {
105 							timeBlock.setPushBackward(true);
106 						}
107 
108 						dayTimeBlocks.add(timeBlock);
109 					}
110 				}
111 			}
112 			dayTimeBlockList.add(dayTimeBlocks);
113 		}
114 		
115     }
116     
117     
118 
119 
120 
121 
122 
123 
124 	public TkTimeBlockAggregate(List<TimeBlock> timeBlocks, List<LeaveBlock> leaveBlocks, CalendarEntries payCalendarEntry){
125 		this(timeBlocks, leaveBlocks, payCalendarEntry, TkServiceLocator.getCalendarService().getCalendar(payCalendarEntry.getHrCalendarId()));
126 	}
127 
128     
129 
130 
131 
132 
133 
134 
135 
136 	public TkTimeBlockAggregate(List<TimeBlock> timeBlocks, List<LeaveBlock> leaveBlocks, CalendarEntries payCalendarEntry, Calendar payCalendar) {
137         this(timeBlocks, leaveBlocks, payCalendarEntry, payCalendar, false);
138     }
139 
140     
141 
142 
143 
144 
145 
146 
147 
148     public TkTimeBlockAggregate(List<TimeBlock> timeBlocks, List<LeaveBlock> leaveBlocks, CalendarEntries payCalendarEntry, Calendar payCalendar, boolean useUserTimeZone) {
149         this(timeBlocks, leaveBlocks, payCalendarEntry, payCalendar, useUserTimeZone, 
150         		useUserTimeZone ? TKUtils.getDaySpanForCalendarEntry(payCalendarEntry) : TKUtils.getDaySpanForCalendarEntry(payCalendarEntry, TKUtils.getSystemDateTimeZone()));
151 	}
152 
153     public TkTimeBlockAggregate(List<TimeBlock> timeBlocks, List<LeaveBlock> leaveBlocks, CalendarEntries payCalendarEntry, Calendar payCalendar, boolean useUserTimeZone, List<Interval> dayIntervals) {
154     	this.payCalendarEntry = payCalendarEntry;
155 		this.payCalendar = payCalendar;
156 		
157 		for(Interval dayInt : dayIntervals){
158 			List<TimeBlock> dayTimeBlocks = new ArrayList<TimeBlock>();
159 			for(TimeBlock timeBlock : timeBlocks){
160 
161                 
162                 
163                 
164                 
165 
166 				DateTime beginTime = useUserTimeZone ? timeBlock.getBeginTimeDisplay() : new DateTime(timeBlock.getBeginTimestamp(), TKUtils.getSystemDateTimeZone());
167 				DateTime endTime = useUserTimeZone ? timeBlock.getEndTimeDisplay() :  new DateTime(timeBlock.getEndTimestamp(), TKUtils.getSystemDateTimeZone());
168 				if(dayInt.contains(beginTime)){
169 					if(dayInt.contains(endTime) || endTime.compareTo(dayInt.getEnd()) == 0){
170 						
171 						if(beginTime.getHourOfDay() < dayInt.getStart().getHourOfDay()) {
172 							timeBlock.setPushBackward(true);
173 						}
174 
175 						dayTimeBlocks.add(timeBlock);
176 					}
177 				}
178 			}
179 			dayTimeBlockList.add(dayTimeBlocks);
180 			
181 			List<LeaveBlock> dayLeaveBlocks = new ArrayList<LeaveBlock>();
182 			for(LeaveBlock leaveBlock : leaveBlocks){
183 
184                 
185                 
186                 
187                 
188 				
189 				DateTimeZone dateTimeZone = TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
190 				DateTime beginTime = new DateTime(leaveBlock.getLeaveDate(), useUserTimeZone ? dateTimeZone : TKUtils.getSystemDateTimeZone());
191 				DateTime endTime = new DateTime(leaveBlock.getLeaveDate(), useUserTimeZone ? dateTimeZone : TKUtils.getSystemDateTimeZone());
192 				if(dayInt.contains(beginTime)){
193 					if(dayInt.contains(endTime) || endTime.compareTo(dayInt.getEnd()) == 0){
194 						dayLeaveBlocks.add(leaveBlock);
195 					}
196 				}
197 			}
198 			dayLeaveBlockList.add(dayLeaveBlocks);
199 		}
200     }
201     
202 	public List<TimeBlock> getFlattenedTimeBlockList(){
203 		List<TimeBlock> lstTimeBlocks = new ArrayList<TimeBlock>();
204 		for(List<TimeBlock> timeBlocks : dayTimeBlockList){
205 			lstTimeBlocks.addAll(timeBlocks);
206 		}
207 
208 		Collections.sort(lstTimeBlocks, new Comparator<TimeBlock>() { 
209 			public int compare(TimeBlock tb1, TimeBlock tb2) {
210 				if (tb1 != null && tb2 != null)
211 					return tb1.getBeginTimestamp().compareTo(tb2.getBeginTimestamp());
212 				return 0;
213 			}
214 		});
215 
216 		return lstTimeBlocks;
217 	}
218 	
219 	public List<LeaveBlock> getFlattenedLeaveBlockList(){
220 		List<LeaveBlock> lstLeaveBlocks = new ArrayList<LeaveBlock>();
221 		for(List<LeaveBlock> leaveBlocks : dayLeaveBlockList){
222 			lstLeaveBlocks.addAll(leaveBlocks);
223 		}
224 
225 		Collections.sort(lstLeaveBlocks, new Comparator<LeaveBlock>() { 
226 			public int compare(LeaveBlock lb1, LeaveBlock lb2) {
227 				if (lb1 != null && lb2 != null)
228 					return lb1.getLeaveDate().compareTo(lb2.getLeaveDate());
229 				return 0;
230 			}
231 		});
232 
233 		return lstLeaveBlocks;
234 	}
235 
236 	
237 
238 
239 
240 
241 
242 
243 
244 
245 
246 
247 
248 
249 
250 	public List<List<TimeBlock>> getWeekTimeBlocks(int week){
251 		int startIndex = week*7;
252 		int endIndex = (week*7)+7;
253 		endIndex = endIndex > dayTimeBlockList.size() ? dayTimeBlockList.size() : endIndex;
254 
255         
256         List<List<TimeBlock>> wList = dayTimeBlockList.subList(startIndex, endIndex);
257         for (List<TimeBlock> dList : wList) {
258             Collections.sort(dList, new Comparator<TimeBlock>() { 
259                 public int compare(TimeBlock tb1, TimeBlock tb2) {
260                     if (tb1 != null && tb2 != null)
261                         return tb1.getBeginTimestamp().compareTo(tb2.getBeginTimestamp());
262                     return 0;
263                 }
264             });
265         }
266 
267 		return wList;
268 	}
269 	
270 	
271 
272 
273 
274 
275 
276 
277 
278 
279 
280 
281 
282 
283 
284 	public List<List<LeaveBlock>> getWeekLeaveBlocks(int week){
285 		int startIndex = week*7;
286 		int endIndex = (week*7)+7;
287 		endIndex = endIndex > dayLeaveBlockList.size() ? dayLeaveBlockList.size() : endIndex;
288 
289         
290         List<List<LeaveBlock>> wList = dayLeaveBlockList.subList(startIndex, endIndex);
291         for (List<LeaveBlock> dList : wList) {
292             Collections.sort(dList, new Comparator<LeaveBlock>() { 
293                 public int compare(LeaveBlock lb1, LeaveBlock lb2) {
294                     if (lb1 != null && lb2 != null)
295                         return lb1.getLeaveDate().compareTo(lb2.getLeaveDate());
296                     return 0;
297                 }
298             });
299         }
300 
301 		return wList;
302 	}
303 
304 	
305 
306 
307 
308 
309 
310 
311 
312 	public List<FlsaWeek> getFlsaWeeks(DateTimeZone zone){
313 		int flsaDayConstant = payCalendar.getFlsaBeginDayConstant();
314 		Time flsaBeginTime  = payCalendar.getFlsaBeginTime();
315 
316 		
317 		
318 		LocalTime flsaBeginLocalTime = LocalTime.fromDateFields(flsaBeginTime);
319 
320 		
321 		
322 		
323 		
324         LocalDateTime startLDT = payCalendarEntry.getBeginLocalDateTime();
325 
326 
327 
328 		List<FlsaWeek> flsaWeeks = new ArrayList<FlsaWeek>();
329 		List<TimeBlock> flattenedTimeBlocks = getFlattenedTimeBlockList();
330 		List<LeaveBlock> flattenedLeaveBlocks = getFlattenedLeaveBlockList();
331 		FlsaWeek currentWeek = new FlsaWeek(flsaDayConstant, flsaBeginLocalTime, LocalTime.fromDateFields(payCalendarEntry.getBeginPeriodDateTime()));
332 		FlsaDay flsaDay = new FlsaDay(startLDT, flattenedTimeBlocks, flattenedLeaveBlocks, zone);
333 		currentWeek.addFlsaDay(flsaDay);
334 		flsaWeeks.add(currentWeek);
335 
336 		for (int i = 1; i < dayTimeBlockList.size(); i++) {
337 			LocalDateTime currentDate = startLDT.plusDays(i);
338 			flsaDay = new FlsaDay(currentDate, flattenedTimeBlocks, flattenedLeaveBlocks, zone);
339 
340 			if (currentDate.getDayOfWeek() == flsaDayConstant) {
341 				currentWeek = new FlsaWeek(flsaDayConstant, flsaBeginLocalTime, flsaBeginLocalTime);
342 				flsaWeeks.add(currentWeek);	
343 			}
344 			
345 			currentWeek.addFlsaDay(flsaDay);
346 		}
347 
348 		return flsaWeeks;
349 	}
350 	
351 	public List<List<FlsaWeek>> getFlsaWeeks(DateTimeZone zone, String principalId) {
352 		List<List<FlsaWeek>> flsaWeeks = new ArrayList<List<FlsaWeek>>();
353 		
354 		List<FlsaWeek> currentWeeks = getFlsaWeeks(zone);
355 		
356 		for (ListIterator<FlsaWeek> weekIterator = currentWeeks.listIterator(); weekIterator.hasNext(); ) {
357 			List<FlsaWeek> flsaWeek = new ArrayList<FlsaWeek>();
358 			
359 			int index = weekIterator.nextIndex();
360 			FlsaWeek currentWeek = weekIterator.next();
361 			
362 			if (index == 0 && !currentWeek.isFirstWeekFull()) {
363 				CalendarEntries previousCalendarEntry = TkServiceLocator.getCalendarEntriesService().getPreviousCalendarEntriesByCalendarId(payCalendar.getHrCalendarId(), payCalendarEntry);
364 				if (previousCalendarEntry != null) {
365 					TimesheetDocumentHeader timesheetDocumentHeader = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(principalId, previousCalendarEntry.getBeginPeriodDateTime(), previousCalendarEntry.getEndPeriodDateTime());
366 					if (timesheetDocumentHeader != null) { 
367 		                TimesheetDocument timesheetDocument = TkServiceLocator.getTimesheetService().getTimesheetDocument(timesheetDocumentHeader.getDocumentId());
368 		                List<String> assignmentKeys = new ArrayList<String>();
369 		                for(Assignment assignment : timesheetDocument.getAssignments()) {
370 		                	assignmentKeys.add(assignment.getAssignmentKey());
371 		                }
372 		                
373 						List<TimeBlock> timeBlocks = TkServiceLocator.getTimeBlockService().getTimeBlocks(timesheetDocumentHeader.getDocumentId());
374 						List<LeaveBlock> leaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(principalId, previousCalendarEntry.getBeginPeriodDateTime(), previousCalendarEntry.getEndPeriodDateTime(), assignmentKeys);
375 						if (CollectionUtils.isNotEmpty(timeBlocks)) {
376 							TkTimeBlockAggregate previousAggregate = new TkTimeBlockAggregate(timeBlocks, leaveBlocks, previousCalendarEntry, payCalendar, true);
377 							List<FlsaWeek> previousWeek = previousAggregate.getFlsaWeeks(zone);
378 							if (CollectionUtils.isNotEmpty(previousWeek)) {
379 								flsaWeek.add(previousWeek.get(previousWeek.size() - 1));
380 							}
381 						}
382 					 }
383 				}
384 			}
385 			
386 			flsaWeek.add(currentWeek);
387 			
388 			if (index == currentWeeks.size() - 1 && !currentWeek.isLastWeekFull()) {
389 				CalendarEntries nextCalendarEntry = TkServiceLocator.getCalendarEntriesService().getNextCalendarEntriesByCalendarId(payCalendar.getHrCalendarId(), payCalendarEntry);
390 				if (nextCalendarEntry != null) {
391 					TimesheetDocumentHeader timesheetDocumentHeader = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(principalId, nextCalendarEntry.getBeginPeriodDateTime(), nextCalendarEntry.getEndPeriodDateTime());
392 					if (timesheetDocumentHeader != null) {
393 		                TimesheetDocument timesheetDocument = TkServiceLocator.getTimesheetService().getTimesheetDocument(timesheetDocumentHeader.getDocumentId());
394 		                List<String> assignmentKeys = new ArrayList<String>();
395 		                for(Assignment assignment : timesheetDocument.getAssignments()) {
396 		                	assignmentKeys.add(assignment.getAssignmentKey());
397 		                }
398 		                
399 						List<TimeBlock> timeBlocks = TkServiceLocator.getTimeBlockService().getTimeBlocks(timesheetDocumentHeader.getDocumentId());
400 						List<LeaveBlock> leaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksForTimeCalendar(principalId, nextCalendarEntry.getBeginPeriodDateTime(), nextCalendarEntry.getEndPeriodDateTime(), assignmentKeys);
401 						if (CollectionUtils.isNotEmpty(timeBlocks)) {
402 							TkTimeBlockAggregate nextAggregate = new TkTimeBlockAggregate(timeBlocks, leaveBlocks, nextCalendarEntry, payCalendar, true);
403 							List<FlsaWeek> nextWeek = nextAggregate.getFlsaWeeks(zone);
404 							if (CollectionUtils.isNotEmpty(nextWeek)) {
405 								flsaWeek.add(nextWeek.get(0));
406 							}
407 						}
408 					 }
409 				}
410 			}
411 			
412 			flsaWeeks.add(flsaWeek);
413 		}
414 		
415 		return flsaWeeks;
416 	}
417 
418 	
419 
420 
421 	public int numberOfAggregatedWeeks() {
422 		int weeks = 0;
423 
424 		if (this.dayTimeBlockList.size() > 0) {
425 			weeks = this.dayTimeBlockList.size() / 7;
426 			if (this.dayTimeBlockList.size() % 7 > 0)
427 				weeks++;
428 		}
429 
430 		return weeks;
431 	}
432 
433 	public List<List<TimeBlock>> getDayTimeBlockList() {
434 		return dayTimeBlockList;
435 	}
436 	
437 	public List<List<LeaveBlock>> getDayLeaveBlockList() {
438 		return dayLeaveBlockList;
439 	}
440 
441 	public CalendarEntries getPayCalendarEntry() {
442 		return payCalendarEntry;
443 	}
444 
445 	public void setPayCalendarEntry(CalendarEntries payCalendarEntry) {
446 		this.payCalendarEntry = payCalendarEntry;
447 	}
448 
449 	public Calendar getPayCalendar() {
450 		return payCalendar;
451 	}
452 
453 	public void setPayCalendar(Calendar payCalendar) {
454 		this.payCalendar = payCalendar;
455 	}
456 
457     
458     public static TkTimeBlockAggregate combineTimeAndLeaveAggregates(TkTimeBlockAggregate tbAggregate, LeaveBlockAggregate lbAggregate) {
459         if (tbAggregate != null
460                 && lbAggregate != null
461                 && tbAggregate.getDayTimeBlockList().size() == lbAggregate.getDayLeaveBlockList().size()) {
462             DateTimeZone dtz = TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
463             for (int i = 0; i < tbAggregate.getDayTimeBlockList().size(); i++) {
464                 List<LeaveBlock> leaveBlocks = lbAggregate.getDayLeaveBlockList().get(i);
465                 if (CollectionUtils.isNotEmpty(leaveBlocks)) {
466                     for (LeaveBlock lb : leaveBlocks) {
467                         
468                         
469                         TimeBlock timeBlock = new TimeBlock();
470                         timeBlock.setHours(lb.getLeaveAmount().negate());
471                         
472                         
473                         DateTime beginTime = new DateTime(lb.getLeaveDate()).toLocalDate().toDateTimeAtStartOfDay().withZoneRetainFields(dtz);
474                         timeBlock.setBeginTimestamp(new Timestamp(beginTime.getMillis()));
475                         timeBlock.setEndTimestamp(new Timestamp(beginTime.plusMinutes(timeBlock.getHours().intValue()).getMillis()));
476                         timeBlock.setAssignmentKey(lb.getAssignmentKey());
477                         timeBlock.setEarnCode(lb.getEarnCode());
478                         timeBlock.setPrincipalId(lb.getPrincipalId());
479                         timeBlock.setWorkArea(lb.getWorkArea());
480                         TimeHourDetail timeHourDetail = new TimeHourDetail();
481                         timeHourDetail.setEarnCode(timeBlock.getEarnCode());
482                         timeHourDetail.setHours(timeBlock.getHours());
483                         timeHourDetail.setAmount(BigDecimal.ZERO);
484                         timeBlock.addTimeHourDetail(timeHourDetail);
485                         tbAggregate.getDayTimeBlockList().get(i).add(timeBlock);
486                     }
487                 }
488 
489             }
490         }
491         return tbAggregate;
492     }
493 
494 }