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 }