1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
119
120
121
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
128 KRADServiceLocator.getBusinessObjectService().delete(leaveBlock);
129
130
131 KRADServiceLocator.getBusinessObjectService().save(leaveBlockHistory);
132
133
134 }
135
136 @Override
137 public void saveLeaveBlock(LeaveBlock leaveBlock, String principalId) {
138
139
140 KRADServiceLocator.getBusinessObjectService().delete(leaveBlock);
141
142
143 leaveBlock.setLmLeaveBlockId(null);
144 leaveBlock.setTimestamp(new Timestamp(System.currentTimeMillis()));
145 leaveBlock.setPrincipalIdModified(principalId);
146 KRADServiceLocator.getBusinessObjectService().save(leaveBlock);
147
148
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
159 DateTimeZone timezone = TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
160 DateTime calBeginDateTime = beginDate;
161 DateTime calEndDateTime = endDate;
162
163 if(ce != null) {
164 calBeginDateTime = ce.getBeginLocalDateTime().toDateTime();
165 calEndDateTime = ce.getEndLocalDateTime().toDateTime();
166 } else {
167 throw new RuntimeException("Calendar Entry parameter is null.");
168 }
169
170 Interval calendarInterval = new Interval(calBeginDateTime, calEndDateTime);
171
172
173
174
175 Calendar startCal = Calendar.getInstance();
176 startCal.setTimeInMillis(beginDate.getMillis());
177 startCal.set(Calendar.HOUR_OF_DAY, 0);
178 startCal.set(Calendar.MINUTE, 0);
179 startCal.set(Calendar.SECOND, 0);
180 startCal.set(Calendar.MILLISECOND, 0);
181
182
183 Calendar endCal = Calendar.getInstance();
184 endCal.setTimeInMillis(endDate.getMillis());
185 endCal.add(Calendar.DATE, 1);
186 endCal.set(Calendar.HOUR_OF_DAY, 0);
187 endCal.set(Calendar.MINUTE, 0);
188 endCal.set(Calendar.SECOND, 0);
189 endCal.set(Calendar.MILLISECOND, 0);
190
191 List<Interval> leaveBlockIntervals = TKUtils.createDaySpan(new DateTime(startCal.getTimeInMillis()), new DateTime(endCal.getTimeInMillis()), TKUtils.getSystemDateTimeZone());
192
193
194
195 List<LeaveBlock> currentLeaveBlocks = getLeaveBlocks(principalId, calBeginDateTime.toDate(), calEndDateTime.toDate());
196
197
198 LeaveCalendarDocumentHeader lcdh = TkServiceLocator.getLeaveCalendarDocumentHeaderService()
199 .getDocumentHeader(principalId, ce.getBeginLocalDateTime().toDateTime().toDate(), ce.getEndLocalDateTime().toDateTime().toDate());
200 String docId = lcdh == null ? null : lcdh.getDocumentId();
201
202
203 Timestamp beginTemp = new Timestamp(beginDate.getMillis());
204 Timestamp endTimestamp = new Timestamp(endDate.getMillis());
205 Interval firstDay = null;
206 for (Interval leaveBlockInt : leaveBlockIntervals) {
207 if (calendarInterval.contains(leaveBlockInt)) {
208
209 if (StringUtils.isEmpty(spanningWeeks) &&
210 (leaveBlockInt.getStart().getDayOfWeek() == DateTimeConstants.SATURDAY ||leaveBlockInt.getStart().getDayOfWeek() == DateTimeConstants.SUNDAY)) {
211
212
213 } else {
214
215
216
217
218 java.sql.Date sqlDate = new java.sql.Date(ce.getEndLocalDateTime().toDateTime().toDate().getTime());
219
220 CalendarEntries calendarEntry = TkServiceLocator.getCalendarEntriesService().getCurrentCalendarEntriesByCalendarId(ce.getHrCalendarId(), TKUtils.getCurrentDate());
221 Date leaveBlockDate = new DateTime(leaveBlockInt.getStartMillis()).toDate();
222
223 String requestStatus = LMConstants.REQUEST_STATUS.USAGE;
224 if (TkServiceLocator.getLeaveApprovalService().isActiveAssignmentFoundOnJobFlsaStatus(principalId, TkConstants.FLSA_STATUS_NON_EXEMPT, true)) {
225 TimesheetDocumentHeader tdh = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeaderForDate(principalId, leaveBlockDate);
226 if (tdh != null) {
227 if (DateUtils.isSameDay(leaveBlockDate, tdh.getEndDate()) || leaveBlockDate.after(tdh.getEndDate())) {
228 requestStatus = LMConstants.REQUEST_STATUS.PLANNED;
229 }
230 } else {
231 requestStatus = LMConstants.REQUEST_STATUS.PLANNED;
232 }
233 } else {
234 if (DateUtils.isSameDay(leaveBlockDate, calendarEntry.getEndPeriodDateTime()) || leaveBlockDate.after(calendarEntry.getEndPeriodDateTime())) {
235 requestStatus = LMConstants.REQUEST_STATUS.PLANNED;
236 }
237 }
238
239 EarnCode earnCodeObj = TkServiceLocator.getEarnCodeService().getEarnCode(selectedEarnCode, sqlDate);
240
241 if(earnCodeObj != null && earnCodeObj.getRecordMethod().equals(LMConstants.RECORD_METHOD.TIME)) {
242 if (firstDay != null) {
243 if(!leaveBlockInt.contains(endTimestamp.getTime())){
244 beginTemp = new Timestamp(leaveBlockInt.getStartMillis());
245 } else if((leaveBlockInt.getStartMillis() - endTimestamp.getTime()) != 0){
246
247 hours = TKUtils.getHoursBetween(leaveBlockInt.getStartMillis(), endTimestamp.getTime());
248 hours = negateHoursIfNecessary(leaveBlockType, hours);
249
250 LeaveBlock leaveBlock = buildLeaveBlock(new DateTime(leaveBlockInt.getStartMillis()), docId, principalId, selectedEarnCode, hours, description, earnCodeObj.getAccrualCategory(), selectedAssignment, requestStatus, leaveBlockType, new Timestamp(leaveBlockInt.getStartMillis()), endTimestamp);
251
252 if (!currentLeaveBlocks.contains(leaveBlock)) {
253 currentLeaveBlocks.add(leaveBlock);
254 }
255 break;
256 }
257 }
258 if (leaveBlockInt.contains(beginTemp.getTime())) {
259
260 firstDay = leaveBlockInt;
261
262 if (leaveBlockInt.contains(endTimestamp.getTime()) || (endTimestamp.getTime() == leaveBlockInt.getEnd().getMillis())) {
263
264 hours = TKUtils.getHoursBetween(beginTemp.getTime(), endTimestamp.getTime());
265 hours = negateHoursIfNecessary(leaveBlockType, hours);
266
267 LeaveBlock leaveBlock = buildLeaveBlock(new DateTime(leaveBlockInt.getStartMillis()), docId, principalId, selectedEarnCode, hours, description, earnCodeObj.getAccrualCategory(), selectedAssignment, requestStatus, leaveBlockType, beginTemp, endTimestamp);
268
269 if (!currentLeaveBlocks.contains(leaveBlock)) {
270 currentLeaveBlocks.add(leaveBlock);
271 }
272
273 break;
274
275 } else {
276
277 hours = TKUtils.getHoursBetween(beginTemp.getTime(), firstDay.getEndMillis());
278 hours = negateHoursIfNecessary(leaveBlockType, hours);
279
280 LeaveBlock leaveBlock = buildLeaveBlock(new DateTime(leaveBlockInt.getStartMillis()), docId, principalId, selectedEarnCode, hours, description, earnCodeObj.getAccrualCategory(), selectedAssignment, requestStatus, leaveBlockType, beginTemp, new Timestamp(firstDay.getEndMillis()));
281
282 if (!currentLeaveBlocks.contains(leaveBlock)) {
283 currentLeaveBlocks.add(leaveBlock);
284 }
285
286 }
287 }
288 } else {
289 hours = negateHoursIfNecessary(leaveBlockType, hours);
290 LeaveBlock leaveBlock = buildLeaveBlock(new DateTime(leaveBlockInt.getStartMillis()), docId, principalId, selectedEarnCode, hours, description, earnCodeObj.getAccrualCategory(),
291 selectedAssignment, requestStatus, leaveBlockType, null, null);
292 if (!currentLeaveBlocks.contains(leaveBlock)) {
293 currentLeaveBlocks.add(leaveBlock);
294 }
295 }
296 }
297 }
298 }
299 saveLeaveBlocks(currentLeaveBlocks);
300 }
301
302 private BigDecimal negateHoursIfNecessary(String leaveBlockType, BigDecimal hours) {
303 if ((leaveBlockType.equals(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR)
304 || leaveBlockType.equals((LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR)))
305 && BigDecimal.ZERO.compareTo(hours) < 0) {
306 hours = hours.negate();
307 }
308 return hours;
309 }
310
311
312 public LeaveBlock buildLeaveBlock(DateTime leaveDate, String docId, String principalId, String selectedEarnCode,
313 BigDecimal hours, String description, String accrualCategory, Assignment selectedAssignment, String requestStatus, String leaveBlockType, Timestamp beginTimeStamp, Timestamp endTimestamp) {
314
315 LeaveBlock leaveBlock = new LeaveBlock.Builder(leaveDate, docId, principalId, selectedEarnCode, hours)
316 .description(description)
317 .principalIdModified(principalId)
318 .timestamp(TKUtils.getCurrentTimestamp())
319 .scheduleTimeOffId("0")
320 .accrualCategory(accrualCategory)
321 .workArea(selectedAssignment.getWorkArea())
322 .jobNumber(selectedAssignment.getJobNumber())
323 .task(selectedAssignment.getTask())
324 .requestStatus(requestStatus)
325 .leaveBlockType(leaveBlockType)
326 .build();
327
328 leaveBlock.setBeginTimestamp(beginTimeStamp);
329 leaveBlock.setEndTimestamp(endTimestamp);
330
331 return leaveBlock;
332 }
333
334 @Override
335 public void updateLeaveBlock(LeaveBlock leaveBlock, String principalId) {
336
337 if ((LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR.equals(leaveBlock.getLeaveBlockType())
338 || LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR.equals(leaveBlock.getLeaveBlockType()))
339 && BigDecimal.ZERO.compareTo(leaveBlock.getLeaveAmount()) < 0) {
340 leaveBlock.setLeaveAmount(leaveBlock.getLeaveAmount().negate());
341 }
342
343
344 LeaveBlockHistory leaveBlockHistory = new LeaveBlockHistory(leaveBlock);
345 leaveBlockHistory.setPrincipalIdDeleted(principalId);
346 leaveBlockHistory.setTimestampDeleted(new Timestamp(System.currentTimeMillis()));
347 leaveBlockHistory.setAction(LMConstants.ACTION.MODIFIED);
348
349 KRADServiceLocator.getBusinessObjectService().save(leaveBlock);
350
351
352 KRADServiceLocator.getBusinessObjectService().save(leaveBlockHistory);
353 }
354
355 public static List<Interval> createDaySpan(DateTime beginDateTime, DateTime endDateTime, DateTimeZone zone) {
356 beginDateTime = beginDateTime.toDateTime(zone);
357 endDateTime = endDateTime.toDateTime(zone);
358 List<Interval> dayIntervals = new ArrayList<Interval>();
359
360 DateTime currDateTime = beginDateTime;
361 while (currDateTime.isBefore(endDateTime)) {
362 DateTime prevDateTime = currDateTime;
363 currDateTime = currDateTime.plusDays(1);
364 Interval daySpan = new Interval(prevDateTime, currDateTime);
365 dayIntervals.add(daySpan);
366 }
367
368 return dayIntervals;
369 }
370
371 @Override
372 public List<LeaveBlock> getLeaveBlocks(String principalId, String leaveBlockType, String requestStatus, Date currentDate) {
373 return leaveBlockDao.getLeaveBlocks(principalId, leaveBlockType, requestStatus, currentDate);
374 }
375
376 @Override
377 public List<LeaveBlock> getLeaveBlocks(String principalId, String leaveBlockType, String requestStatus, Date beginDate, Date endDate) {
378 return leaveBlockDao.getLeaveBlocks(principalId, leaveBlockType, requestStatus, beginDate, endDate);
379 }
380
381 @Override
382 public List<LeaveBlock> getLeaveBlocksForDate(String principalId, Date leaveDate) {
383 return leaveBlockDao.getLeaveBlocksForDate(principalId, leaveDate);
384 }
385
386 @Override
387 public List<LeaveBlock> getNotAccrualGeneratedLeaveBlocksForDate(String principalId, Date leaveDate) {
388 return leaveBlockDao.getNotAccrualGeneratedLeaveBlocksForDate(principalId, leaveDate);
389 }
390
391 public List<LeaveBlock> getLeaveBlocksForTimeCalendar(String principalId, Date beginDate, Date endDate, List<String> assignmentKeys) {
392 List<LeaveBlock> col = leaveBlockDao.getCalendarLeaveBlocks(principalId, beginDate, endDate);
393 List<LeaveBlock> leaveBlocks = filterLeaveBlocksForTimeCalendar(col, assignmentKeys);
394 return leaveBlocks;
395 }
396
397 public List<LeaveBlock> getLeaveBlocksForLeaveCalendar(String principalId, Date beginDate, Date endDate, List<String> assignmentKeys) {
398 List<LeaveBlock> col = leaveBlockDao.getLeaveBlocks(principalId, beginDate, endDate);
399 List<LeaveBlock> leaveBlocks = filterLeaveBlocksForLeaveCalendar(col, assignmentKeys);
400 return leaveBlocks;
401 }
402
403 public List<LeaveBlock> filterLeaveBlocksForTimeCalendar(List<LeaveBlock> lbs, List<String> assignmentKeys) {
404 if(CollectionUtils.isEmpty(assignmentKeys)) {
405 return lbs;
406 }
407 List<LeaveBlock> results = new ArrayList<LeaveBlock> ();
408 for(LeaveBlock lb : lbs) {
409 if(lb != null) {
410 if (StringUtils.equals(lb.getLeaveBlockType(), LMConstants.LEAVE_BLOCK_TYPE.ACCRUAL_SERVICE)
411 && StringUtils.isNotEmpty(lb.getScheduleTimeOffId())
412 && lb.getLeaveAmount().compareTo(BigDecimal.ZERO) < 0) {
413
414 results.add(lb);
415 } else if(StringUtils.isNotEmpty(lb.getAssignmentKey()) && assignmentKeys.contains(lb.getAssignmentKey())) {
416 if (StringUtils.equals(lb.getLeaveBlockType(), LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR)) {
417
418 if (StringUtils.equals(lb.getRequestStatus(), LMConstants.REQUEST_STATUS.APPROVED)) {
419 results.add(lb);
420 }
421 } else if(StringUtils.equals(lb.getLeaveBlockType(), LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR)) {
422 results.add(lb);
423 }
424 }
425 }
426 }
427 return results;
428 }
429
430 public List<LeaveBlock> filterLeaveBlocksForLeaveCalendar(List<LeaveBlock> lbs, List<String> assignmentKeys) {
431 if(CollectionUtils.isEmpty(assignmentKeys)) {
432 return lbs;
433 }
434 List<LeaveBlock> leaveBlocks = new ArrayList<LeaveBlock>();
435 for(LeaveBlock lb : lbs) {
436 if(lb != null) {
437 if(lb.getLeaveBlockType().equals(LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR)) {
438 if(StringUtils.isNotEmpty(lb.getAssignmentKey()) && assignmentKeys.contains(lb.getAssignmentKey())) {
439 leaveBlocks.add(lb);
440 }
441 } else {
442 leaveBlocks.add(lb);
443 }
444 }
445
446
447 }
448 return leaveBlocks;
449 }
450
451 @Override
452 public void deleteLeaveBlocksForDocumentId(String documentId){
453 leaveBlockDao.deleteLeaveBlocksForDocumentId(documentId);
454 }
455
456
457 @Override
458 public List<LeaveBlock> getAccrualGeneratedLeaveBlocks(String principalId, Date beginDate, Date endDate) {
459 return leaveBlockDao.getAccrualGeneratedLeaveBlocks(principalId, beginDate, endDate);
460 }
461
462 @Override
463 public List<LeaveBlock> getSSTOLeaveBlocks(String principalId, String sstoId, Date accruledDate) {
464 return leaveBlockDao.getSSTOLeaveBlocks(principalId, sstoId, accruledDate);
465 }
466
467 @Override
468 public List<LeaveBlock> getABELeaveBlocksSinceTime(String principalId, Timestamp lastRanTime) {
469 return leaveBlockDao.getABELeaveBlocksSinceTime(principalId, lastRanTime);
470 }
471 }