1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.hr.time.shiftdiff.rule.service;
17
18 import java.math.BigDecimal;
19 import java.sql.Date;
20 import java.sql.Time;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24
25 import org.joda.time.DateTime;
26 import org.joda.time.DateTimeZone;
27 import org.joda.time.LocalDate;
28 import org.joda.time.LocalTime;
29 import org.junit.Assert;
30 import org.junit.Ignore;
31 import org.junit.Test;
32 import org.kuali.hr.test.KPMETestCase;
33 import org.kuali.hr.time.assignment.Assignment;
34 import org.kuali.hr.time.assignment.AssignmentDescriptionKey;
35 import org.kuali.hr.time.calendar.CalendarEntries;
36 import org.kuali.hr.time.service.base.TkServiceLocator;
37 import org.kuali.hr.time.shiftdiff.rule.ShiftDifferentialRule;
38 import org.kuali.hr.time.test.TkTestUtils;
39 import org.kuali.hr.time.timeblock.TimeBlock;
40 import org.kuali.hr.time.timesheet.TimesheetDocument;
41 import org.kuali.hr.time.util.TKContext;
42 import org.kuali.hr.time.util.TKUtils;
43 import org.kuali.hr.time.util.TkConstants;
44 import org.kuali.hr.time.util.TkTimeBlockAggregate;
45
46
47
48
49
50 public class ShiftDifferentialRuleServiceProcessTest extends KPMETestCase {
51
52
53 public static final String USER_PRINCIPAL_ID = "admin";
54 private Date JAN_AS_OF_DATE = new Date((new DateTime(2010, 1, 1, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone())).getMillis());
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 @SuppressWarnings("serial")
110 @Test
111 public void testProcessTimesheetBoundaryCarryoverOverlapCase() throws Exception {
112 DateTimeZone tz = TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
113
114 boolean[] dayArray = {false, false, true, true, true, true, true};
115
116 Long jobNumber = 30L;
117 Long workArea = 0L;
118 this.createShiftDifferentialRule(
119 "BWS-CAL", "REG", "PRM", "SD1", "SD1", "SD1",
120 (new DateTime(2010, 8, 31, 22, 0, 0, 0, tz)),
121 (new DateTime(2010, 8, 31, 4, 0, 0, 0, tz)),
122 new BigDecimal(3),
123 new BigDecimal("0.25"),
124 dayArray);
125
126 dayArray = new boolean [] {false, false, true, false, true, true, true};
127 this.createShiftDifferentialRule(
128 "BWS-CAL", "REG", "PRM", "SD1", "SD1", "SD1",
129 (new DateTime(2010, 8, 31, 23, 0, 0, 0, tz)),
130 (new DateTime(2010, 8, 31, 2, 0, 0, 0, tz)),
131 new BigDecimal(3),
132 new BigDecimal("2.0"),
133 dayArray);
134
135 dayArray = new boolean[] {false, false, false, true, true, false, false};
136 this.createShiftDifferentialRule(
137 "BWS-CAL", "REG", "PRM", "SD1", "SD1", "SD1",
138 (new DateTime(2010, 8, 31, 5, 0, 0, 0, tz)),
139 (new DateTime(2010, 8, 31, 12, 0, 0, 0, tz)),
140 new BigDecimal("7.0"),
141 new BigDecimal(".25"),
142 dayArray);
143 dayArray = new boolean[] {false, false, false, true, false, false, false};
144 this.createShiftDifferentialRule(
145 "BWS-CAL", "REG", "PRM", "SD1", "SD1", "SD1",
146 (new DateTime(2010, 8, 31, 5, 0, 0, 0, tz)),
147 (new DateTime(2010, 8, 31, 12, 0, 0, 0, tz)),
148 new BigDecimal("5"),
149 new BigDecimal("0.25"),
150 dayArray);
151
152
153
154
155 DateTime beginPeriodDate = new DateTime(2010, 8, 15, 0, 0, 0, 0, tz);
156 Date endPeriodDate = new Date(new DateTime(2010, 9, 1, 0, 0, 0, 0).getMillis());
157 CalendarEntries endOfAugust = TkServiceLocator.getCalendarEntriesService().getCalendarEntriesByIdAndPeriodEndDate("2", endPeriodDate);
158 DateTime start = new DateTime(2010, 8, 31, 21, 45, 0, 0, tz);
159 List<TimeBlock> blocks = new ArrayList<TimeBlock>();
160 TimesheetDocument tdoc = TkServiceLocator.getTimesheetService().openTimesheetDocument("admin", endOfAugust);
161 Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment("admin", new AssignmentDescriptionKey("30_30_30"), new Date(beginPeriodDate.getMillis()));
162 blocks.addAll(TkTestUtils.createUniformActualTimeBlocks(tdoc, assignment, "RGN", start, 1, new BigDecimal(2), BigDecimal.ZERO));
163 TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, endOfAugust, TkServiceLocator.getCalendarService().getCalendar(endOfAugust.getHrCalendarId()), true);
164 tdoc.setTimeBlocks(blocks);
165 TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
166 TkTestUtils.verifyAggregateHourSumsFlatList("August Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(2));}},aggregate);
167 TkServiceLocator.getTimeBlockService().saveTimeBlocks(new ArrayList<TimeBlock>(), aggregate.getFlattenedTimeBlockList(), TKContext.getPrincipalId());
168
169
170
171
172 start = new DateTime(2010, 9, 1, 0, 0, 0, 0, tz);
173 CalendarEntries payCalendarEntry = TkServiceLocator.getCalendarService().getCurrentCalendarDates("admin", start.toLocalDate().toDateMidnight().toDate());
174 tdoc = TkServiceLocator.getTimesheetService().openTimesheetDocument("admin", payCalendarEntry);
175 blocks = new ArrayList<TimeBlock>();
176 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start, 1, new BigDecimal("5"), "RGN", jobNumber, workArea));
177 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusHours(6), 1, new BigDecimal("6"), "RGN", jobNumber, workArea));
178 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusHours(22), 1, new BigDecimal("2"), "RGN", jobNumber, workArea));
179 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusDays(1), 1, new BigDecimal("1"), "RGN", jobNumber, workArea));
180 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusDays(1).plusHours(17), 1, new BigDecimal("6"), "RGN", jobNumber, workArea));
181 setDocumentIdOnBlocks(blocks, tdoc.getDocumentId());
182
183 aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry, TkServiceLocator.getCalendarService().getCalendar(payCalendarEntry.getHrCalendarId()), true);
184
185 TkTestUtils.verifyAggregateHourSumsFlatList("September Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(20));}},aggregate);
186
187
188 TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
189 TkTestUtils.verifyAggregateHourSumsFlatList("September Post-Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal("14.75"));put("RGN", new BigDecimal(20));}},aggregate);
190 }
191
192 private void setDocumentIdOnBlocks(List<TimeBlock> blocks, String id) {
193 for (TimeBlock b : blocks) {
194 b.setDocumentId(id);
195 }
196 }
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 @SuppressWarnings("serial")
216 @Test
217 public void testProcessShiftTimesheeetBoundaryCarryoverCase() throws Exception {
218
219 boolean[] dayArray = {false, false, true, false, true, true, true};
220
221 Long jobNumber = 30L;
222 Long workArea = 0L;
223
224 DateTimeZone tz = TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
225 this.createShiftDifferentialRule(
226 "BWS-CAL",
227 "REG",
228 "PRM",
229 "SD1",
230 "SD1",
231 "SD1",
232 (new DateTime(2010, 8, 31, 22, 0, 0, 0, tz)),
233 (new DateTime(2010, 8, 31, 5, 0, 0, 0, tz)),
234 new BigDecimal(3),
235 new BigDecimal("0.25"),
236 dayArray);
237
238
239 Date endPeriodDate = new Date(new DateTime(2010, 9, 1, 0, 0, 0, 0).getMillis());
240 CalendarEntries endOfAugust = TkServiceLocator.getCalendarEntriesService().getCalendarEntriesByIdAndPeriodEndDate("2", endPeriodDate);
241 DateTime start = new DateTime(2010, 8, 31, 22, 0, 0, 0, tz);
242 List<TimeBlock> blocks = new ArrayList<TimeBlock>();
243 TimesheetDocument tdoc = TkServiceLocator.getTimesheetService().openTimesheetDocument("admin", endOfAugust);
244 Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment("admin", new AssignmentDescriptionKey("30_30_30"), endOfAugust.getBeginPeriodDate());
245 blocks.addAll(TkTestUtils.createUniformActualTimeBlocks(tdoc, assignment, "RGN", start, 1, new BigDecimal(2), BigDecimal.ZERO));
246 TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, endOfAugust, TkServiceLocator.getCalendarService().getCalendar(endOfAugust.getHrCalendarId()), true);
247
248
249
250 tdoc.setTimeBlocks(blocks);
251 TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
252 TkTestUtils.verifyAggregateHourSumsFlatList("August Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(2));}},aggregate);
253 TkServiceLocator.getTimeBlockService().saveTimeBlocks(new ArrayList<TimeBlock>(), aggregate.getFlattenedTimeBlockList(), TKContext.getPrincipalId());
254
255
256
257 start = new DateTime(2010, 9, 1, 0, 0, 0, 0, tz);
258 java.util.Date septStartDate = new LocalDate(new DateTime(2010,9,1,0,0,0,0)).toDateMidnight().toDate();
259 CalendarEntries payCalendarEntry = TkServiceLocator.getCalendarService().getCurrentCalendarDates("admin", septStartDate);
260 tdoc = TkServiceLocator.getTimesheetService().openTimesheetDocument("admin", payCalendarEntry);
261 blocks = new ArrayList<TimeBlock>();
262 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start, 1, new BigDecimal("5"), "RGN", jobNumber, workArea));
263 aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry, TkServiceLocator.getCalendarService().getCalendar(payCalendarEntry.getHrCalendarId()), true);
264 TkTestUtils.verifyAggregateHourSumsFlatList("September Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(5));}},aggregate);
265
266
267 TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
268 TkTestUtils.verifyAggregateHourSumsFlatList("September Post-Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(7));put("RGN", new BigDecimal(5));}},aggregate);
269 }
270
271 @SuppressWarnings("serial")
272 @Test
273
274
275
276
277
278
279
280
281
282
283 public void testProcessShiftSimpleNoisyCase() throws Exception {
284
285 boolean[] dayArray = {true, true, true, true, true, true, true};
286
287 Long jobNumber = 30L;
288 Long workArea = 0L;
289 this.createShiftDifferentialRule(
290 "BWS-CAL",
291 "REG",
292 "PRM",
293 "SD1",
294 "SD1",
295 "SD1",
296 (new DateTime(2010, 3, 29, 16, 0, 0, 0, TKUtils.getSystemDateTimeZone())),
297 (new DateTime(2010, 3, 30, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone())),
298 new BigDecimal(4),
299 new BigDecimal("15"),
300 dayArray);
301
302
303 DateTime start = new DateTime(2010, 3, 29, 14, 0, 0, 0, TKUtils.getSystemDateTimeZone());
304 List<TimeBlock> blocks = new ArrayList<TimeBlock>();
305 CalendarEntries payCalendarEntry = TkServiceLocator.getCalendarService().getCurrentCalendarDates("admin", new Date(start.getMillis()));
306 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start, 2, new BigDecimal("4"), "RGN", jobNumber, workArea));
307 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusHours(4).plusMinutes(15), 2, new BigDecimal("2"), "RGN", jobNumber, workArea));
308 blocks.addAll(TkTestUtils.createUniformTimeBlocks(new DateTime(2010, 3, 29, 12, 58, 0, 0, TKUtils.getSystemDateTimeZone()), 2, new BigDecimal(1), "RGN", jobNumber, workArea));
309 TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);
310
311
312 TkTestUtils.verifyAggregateHourSums("Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(14));}},aggregate,2);
313
314
315 TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(new Date(start.getMillis()));
316 tdoc.setTimeBlocks(blocks);
317 TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
318
319
320 TkTestUtils.verifyAggregateHourSums("Post Rules Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(8));put("RGN", new BigDecimal(14));}},aggregate,2);
321 }
322
323 @SuppressWarnings("serial")
324 @Test
325
326
327
328
329
330
331
332 public void testProcessShiftSimpleCase() throws Exception {
333
334 boolean[] dayArray = {true, true, true, true, true, true, true};
335
336 Long jobNumber = 30L;
337 Long workArea = 0L;
338 this.createShiftDifferentialRule(
339 "BWS-CAL",
340 "REG",
341 "PRM",
342 "SD1",
343 "SD1",
344 "SD1",
345 (new DateTime(2010, 3, 29, 16, 0, 0, 0, TKUtils.getSystemDateTimeZone())),
346 (new DateTime(2010, 3, 30, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone())),
347 new BigDecimal(4),
348 new BigDecimal("15"),
349 dayArray);
350
351
352 DateTime start = new DateTime(2010, 3, 29, 14, 0, 0, 0, TKUtils.getSystemDateTimeZone());
353 List<TimeBlock> blocks = new ArrayList<TimeBlock>();
354 CalendarEntries payCalendarEntry = TkServiceLocator.getCalendarService().getCurrentCalendarDates("admin", new Date(start.getMillis()));
355 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start, 2, new BigDecimal("4"), "REG", jobNumber, workArea));
356 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start.plusHours(4).plusMinutes(15), 2, new BigDecimal("2"), "REG", jobNumber, workArea));
357 TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);
358
359
360 TkTestUtils.verifyAggregateHourSums("Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("REG", new BigDecimal(12));}},aggregate,2);
361
362
363 TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(new Date(start.getMillis()));
364 tdoc.setTimeBlocks(blocks);
365 TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
366
367
368 TkTestUtils.verifyAggregateHourSums("Post Rules Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(8));put("REG", new BigDecimal(12));}},aggregate,2);
369 }
370
371
372
373
374
375
376 private void createShiftDifferentialRule(String pyCalendarGroup, String fromEarnGroup, String premiumEarnCode, String location, String payGrade, String hrSalGroup, DateTime startTime, DateTime endTime, BigDecimal minHours, BigDecimal maxGap, boolean dayBooleans[]) {
377 Assert.assertTrue("Wrong number of day booleans", dayBooleans.length == 7);
378
379 ShiftDifferentialRuleService service = TkServiceLocator.getShiftDifferentialRuleService();
380 ShiftDifferentialRule sdr = new ShiftDifferentialRule();
381
382 sdr.setBeginTime(new Time(startTime.getMillis()));
383 sdr.setEndTime(new Time(endTime.getMillis()));
384 sdr.setMinHours(minHours);
385 sdr.setMaxGap(maxGap);
386 sdr.setActive(true);
387 sdr.setUserPrincipalId(USER_PRINCIPAL_ID);
388 sdr.setEffectiveDate(JAN_AS_OF_DATE);
389 sdr.setLocation(location);
390 sdr.setPayGrade(payGrade);
391 sdr.setHrSalGroup(hrSalGroup);
392 sdr.setFromEarnGroup(fromEarnGroup);
393 sdr.setPyCalendarGroup(pyCalendarGroup);
394 sdr.setEarnCode(premiumEarnCode);
395
396 for (int i=0; i<dayBooleans.length; i++) {
397 switch(i) {
398 case 0:
399 sdr.setSunday(dayBooleans[i]);
400 break;
401 case 1:
402 sdr.setMonday(dayBooleans[i]);
403 break;
404 case 2:
405 sdr.setTuesday(dayBooleans[i]);
406 break;
407 case 3:
408 sdr.setWednesday(dayBooleans[i]);
409 break;
410 case 4:
411 sdr.setThursday(dayBooleans[i]);
412 break;
413 case 5:
414 sdr.setFriday(dayBooleans[i]);
415 break;
416 case 6:
417 sdr.setSaturday(dayBooleans[i]);
418 break;
419 }
420 }
421
422 service.saveOrUpdate(sdr);
423
424 ShiftDifferentialRule sdrBack = service.getShiftDifferentialRule(sdr.getTkShiftDiffRuleId());
425
426 DateTimeZone tz = TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
427 LocalTime orig_start = new LocalTime(sdr.getBeginTime(), tz);
428 LocalTime orig_end = new LocalTime(sdr.getEndTime(), tz);
429
430 LocalTime stored_start = new LocalTime(sdrBack.getBeginTime(), tz);
431 LocalTime stored_end = new LocalTime(sdrBack.getEndTime(), tz);
432
433 Assert.assertTrue("Start times not equal.", orig_start.equals(stored_start));
434 Assert.assertTrue("End times not equal.", orig_end.equals(stored_end));
435 }
436
437
438 @Ignore
439 @Test
440
441
442
443
444
445
446
447
448
449
450 public void simpleCaseWithWorkSchedule() throws Exception {
451
452 boolean[] dayArray = {true, true, true, true, true, true, true};
453
454 Long jobNumber = 30L;
455 Long workArea = 0L;
456 this.createShiftDifferentialRule(
457 "BWS-CAL",
458 "REG",
459 "PRM",
460 "SD1",
461 "SD1",
462 "SD1",
463 (new DateTime(2010, 3, 29, 12, 0, 0, 0, TKUtils.getSystemDateTimeZone())),
464 (new DateTime(2010, 3, 29, 17, 0, 0, 0, TKUtils.getSystemDateTimeZone())),
465 new BigDecimal(4),
466 new BigDecimal("0.25"),
467 dayArray);
468
469
470 DateTime start = new DateTime(2010, 3, 29, 12, 0, 0, 0, TKUtils.getSystemDateTimeZone());
471 DateTime holtime = new DateTime(2010, 3, 30, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
472 List<TimeBlock> blocks = new ArrayList<TimeBlock>();
473 CalendarEntries payCalendarEntry = TkServiceLocator.getCalendarService().getCurrentCalendarDates("admin", new Date(start.getMillis()));
474 blocks.addAll(TkTestUtils.createUniformTimeBlocks(start, 1, new BigDecimal("4"), "REG", jobNumber, workArea));
475 blocks.addAll(TkTestUtils.createUniformTimeBlocks(holtime, 1, new BigDecimal("4"), "HOL", jobNumber, workArea));
476
477 TkTimeBlockAggregate aggregate = new TkTimeBlockAggregate(blocks, payCalendarEntry);
478
479
480 TkTestUtils.verifyAggregateHourSums("Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("REG", new BigDecimal(4));put("HOL", new BigDecimal(4));}},aggregate,2);
481
482
483 TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(new Date(start.getMillis()));
484 tdoc.setTimeBlocks(blocks);
485 TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
486
487
488 TkTestUtils.verifyAggregateHourSums("Post Rules Check", new HashMap<String,BigDecimal>() {{put("PRM", new BigDecimal(8));put("REG", new BigDecimal(4));}},aggregate,2);
489
490 }
491
492 }