001    /**
002     * Copyright 2004-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.hr.time.shiftdiff.rule.service;
017    
018    import java.math.BigDecimal;
019    import java.sql.Date;
020    import java.sql.Time;
021    import java.util.ArrayList;
022    import java.util.HashMap;
023    import java.util.List;
024    
025    import org.joda.time.DateTime;
026    import org.joda.time.DateTimeZone;
027    import org.joda.time.LocalDate;
028    import org.joda.time.LocalTime;
029    import org.junit.Assert;
030    import org.junit.Ignore;
031    import org.junit.Test;
032    import org.kuali.hr.test.KPMETestCase;
033    import org.kuali.hr.time.assignment.Assignment;
034    import org.kuali.hr.time.assignment.AssignmentDescriptionKey;
035    import org.kuali.hr.time.calendar.CalendarEntries;
036    import org.kuali.hr.time.service.base.TkServiceLocator;
037    import org.kuali.hr.time.shiftdiff.rule.ShiftDifferentialRule;
038    import org.kuali.hr.time.test.TkTestUtils;
039    import org.kuali.hr.time.timeblock.TimeBlock;
040    import org.kuali.hr.time.timesheet.TimesheetDocument;
041    import org.kuali.hr.time.util.TKContext;
042    import org.kuali.hr.time.util.TKUtils;
043    import org.kuali.hr.time.util.TkConstants;
044    import org.kuali.hr.time.util.TkTimeBlockAggregate; 
045    /**
046     *
047     * @author djunk
048     *
049     */
050    public class ShiftDifferentialRuleServiceProcessTest extends KPMETestCase {
051    
052    
053            public static final String USER_PRINCIPAL_ID = "admin";
054            private Date JAN_AS_OF_DATE = new Date((new DateTime(2010, 1, 1, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone())).getMillis());
055    
056    
057            /**
058             * Test with boundary carryover and overlapping rules.
059             *
060             * Rule 1:
061             *
062             * Runs on Tu, Wed, Th on the interval: [22:00, 4:00)
063             * Max Gap: 15 minutes
064             * Min Hours: 3
065             *
066             * Rule 2:
067             *
068             * Runs on Tu, Th on the interval: [23:00, 2:00)
069             * Max Gap: 2 hours
070             * Min Hours: 3
071             *
072             * Rule 3:
073             *
074             * Runs on W, Th on the interval: [5:00, 12:00)
075             * Max Gap: 15 minutes
076             * Min Hours: 7 hours
077             *
078             * Rule 4:
079             *
080             * Runs on W on the interval: [5:00, 12:00)
081             * Max Gap: 15 minutes
082             * Min Hours: 5
083             *
084             *
085             * |--------------+----+------------+------------|
086             * | Tu : 8/31/10 | XX | W : 9/1/10 | Th: 9/2/10 |
087             * |--------------+----+------------+------------|
088             * | 9:45p - 11:45| XX | Mid - 5a   | 5p - 11p   |
089             * |              | XX | 6a - Noon  |            |
090             * |--------------+----+------------+------------|
091         *
092         *
093         * Aug 31: 2h  : 21:45 - 23:45 (Tue) **
094         *                           [1: 5h 45m]  // [2: 2h 45m] - Not qualifying, min hours must be 3.
095         * Sep  1: 5h  : 00:00 - 05:00 (Wed) **
096         * Sep  1: 6h  : 06:00 - 12:00 (Wed) [4: 6h]
097         *
098         * Sep  1: 2h  : 22:00 - 24:00 (Wed)
099         * Sep  2: 1h  : 00:00 - 01:00 (Thu) [1: 3h]
100         *
101         * Sep  2: 6h  : 17:00 - 22:00 (Thu)
102         *
103         * 1: [22:00,  4:00) (Tue/Wed/Thu) minimum: 3h gap: 15m
104         * 2: [23:00,  2:00) (Tue/Thu)     minimum: 3h gap: 2h
105         * 3: [05:00, 12:00) (Wed/Thu)     minimum: 7h gap: 15m
106         * 4: [05:00, 12:00) (Wed)         minimum: 5h gap: 15m
107         *
108             */
109            @SuppressWarnings("serial")
110            @Test
111            public void testProcessTimesheetBoundaryCarryoverOverlapCase() throws Exception {
112            DateTimeZone tz = TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback();
113                    // Create the Rule    Sun,   Mon,   Tue,  Wed,   Thu,  Fri,  Sat
114                    boolean[] dayArray = {false, false, true, true, true, true, true};
115                    // Matches HR Job ID #1 (job # 30)
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), // minHours
123                                    new BigDecimal("0.25"), // maxGap
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), // minHours
132                                    new BigDecimal("2.0"), // maxGap
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"), // minHours
141                                    new BigDecimal(".25"), // maxGap
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"), // minHours
149                                    new BigDecimal("0.25"), // maxGap
150                                    dayArray);
151    
152                    // Timeblocks
153    
154                    // August
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                    // September
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                    // Verify carry over and applied PRM bucket
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             * Test where previous time sheet contains hours that should be added to
201             * the next pay periods first day shift.
202             *
203             * Runs on Tu, Th on the interval: [22:00, 4:00)
204             * Max Gap: 15 minutes
205             * Min Hours: 3
206             *
207             * |--------------+----+------------+-------------|
208             * | Tu : 8/31/10 | XX | W : 9/1/10 | Th : 9/2/10 |
209             * |--------------+----+------------+-------------|
210             * | 10pm - Mid   | XX | Mid - 5am  | 5pm - 11pm  |
211             * |--------------+----+------------+-------------|
212             *
213             * @throws Exception
214             */
215            @SuppressWarnings("serial")
216            @Test
217            public void testProcessShiftTimesheeetBoundaryCarryoverCase() throws Exception {
218                    // Create the Rule    Sun,   Mon,   Tue,  Wed,   Thu,  Fri,  Sat
219                    boolean[] dayArray = {false, false, true, false, true, true, true};
220                    // Matches HR Job ID #1 (job # 30)
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), // minHours
235                                    new BigDecimal("0.25"), // maxGap
236                                    dayArray);
237    
238                    // August
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                    // September
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                    // Verify carry over and applied PRM bucket
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             * Runs on every day on the interval: [16:00, 24:00)
275             * Max Gap: 15 minutes
276             * Min Hours: 4
277             *
278             * Added some extra time blocks that are not in the shift interval, but
279             * close to the time blocks that are.
280             *
281             * @throws Exception
282             */
283            public void testProcessShiftSimpleNoisyCase() throws Exception {
284                    // Create the Rule
285                    boolean[] dayArray = {true, true, true, true, true, true, true};
286                    // Matches HR Job ID #1 (job # 30)
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), // minHours
299                                    new BigDecimal("15"), // maxGap
300                                    dayArray);
301    
302                    // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
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                    // Verify pre-Rule Run
312                    TkTestUtils.verifyAggregateHourSums("Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("RGN", new BigDecimal(14));}},aggregate,2);
313    
314                    // Run Rule
315                    TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(new Date(start.getMillis()));
316                    tdoc.setTimeBlocks(blocks);
317                    TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
318    
319                    // Verify post-Rule Run
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             * Runs on every day on the interval: [16:00, 24:00)
327             * Max Gap: 15 minutes
328             * Min Hours: 4
329             *
330             * @throws Exception
331             */
332            public void testProcessShiftSimpleCase() throws Exception {
333                    // Create the Rule
334                    boolean[] dayArray = {true, true, true, true, true, true, true};
335                    // Matches HR Job ID #1 (job # 30)
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), // minHours
348                                    new BigDecimal("15"), // maxGap
349                                    dayArray);
350    
351                    // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
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                    // Verify pre-Rule Run
360                    TkTestUtils.verifyAggregateHourSums("Pre-Check", new HashMap<String,BigDecimal>() {{put("PRM", BigDecimal.ZERO);put("REG", new BigDecimal(12));}},aggregate,2);
361    
362                    // Run Rule
363                    TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(new Date(start.getMillis()));
364                    tdoc.setTimeBlocks(blocks);
365                    TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
366    
367                    // Verify post-Rule Run
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             * Stores the Shift Differential Rule in the database for testing.
373             *
374             * dayBooleans[] is a 7 element array of booleans, [0, 6] is [sun, sat]
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         * Tests WorkSchedules impact on Shift Differential Rule: Simple Case
442         *
443         * Create a timeblock on two days, one day has normal REG shift eligible
444         * hours, one day has HOL time.
445         *
446         * Modified version of the simple case, SDR from 12:00 to 17:00, every day,
447         * must have at least 4 hours with a maximum 15 minute gap.
448         *
449         */
450        public void simpleCaseWithWorkSchedule() throws Exception {
451                    // Create the Rule
452                    boolean[] dayArray = {true, true, true, true, true, true, true};
453                    // Matches HR Job ID #1 (job # 30)
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), // minHours
466                                    new BigDecimal("0.25"), // maxGap
467                                    dayArray);
468    
469                    // Create Time Blocks (2 days, 2 blocks on each day, 15 minute gap between blocks, 4 hours total each.
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                    // Verify pre-Rule Run
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                    // Run Rule
483                    TimesheetDocument tdoc = TkTestUtils.populateBlankTimesheetDocument(new Date(start.getMillis()));
484                    tdoc.setTimeBlocks(blocks);
485                    TkServiceLocator.getShiftDifferentialRuleService().processShiftDifferentialRules(tdoc, aggregate);
486    
487                    // Verify post-Rule Run
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    }