View Javadoc

1   /**
2    * Copyright 2004-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.kpme.tklm.utils;
17  
18  import java.math.BigDecimal;
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.LinkedList;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.log4j.Logger;
26  import org.joda.time.DateTime;
27  import org.joda.time.DateTimeZone;
28  import org.joda.time.Days;
29  import org.joda.time.Duration;
30  import org.joda.time.LocalDate;
31  import org.junit.Assert;
32  import org.kuali.kpme.core.assignment.Assignment;
33  import org.kuali.kpme.core.job.Job;
34  import org.kuali.kpme.core.service.HrServiceLocator;
35  import org.kuali.kpme.core.util.HrConstants;
36  import org.kuali.kpme.core.util.TKUtils;
37  import org.kuali.kpme.tklm.time.flsa.FlsaDay;
38  import org.kuali.kpme.tklm.time.flsa.FlsaWeek;
39  import org.kuali.kpme.tklm.time.service.TkServiceLocator;
40  import org.kuali.kpme.tklm.time.timeblock.TimeBlock;
41  import org.kuali.kpme.tklm.time.timeblock.service.TimeBlockService;
42  import org.kuali.kpme.tklm.time.timehourdetail.TimeHourDetail;
43  import org.kuali.kpme.tklm.time.timesheet.TimesheetDocument;
44  import org.kuali.kpme.tklm.time.util.TkTimeBlockAggregate;
45  import org.kuali.rice.kew.api.exception.WorkflowException;
46  
47  public class TkTestUtils {
48  
49  	private static final Logger LOG = Logger.getLogger(TkTestUtils.class);
50  
51  	public static TimesheetDocument populateBlankTimesheetDocument(DateTime calDate, String principalId) {
52  		try {
53  			TimesheetDocument timesheet = TkServiceLocator.getTimesheetService().openTimesheetDocument(principalId,
54  							HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates(principalId,
55                                      calDate));
56  			for(TimeBlock timeBlock : timesheet.getTimeBlocks()){
57  				TkServiceLocator.getTimeBlockService().deleteTimeBlock(timeBlock);
58  			}
59  
60  			return timesheet;
61  		} catch (WorkflowException e) {
62  			throw new RuntimeException("Problem fetching document");
63  		}
64  	}
65  
66  	public static TimesheetDocument populateTimesheetDocument(DateTime calDate, String principalId) {
67  		try {
68  			TimesheetDocument timesheet = TkServiceLocator.getTimesheetService().openTimesheetDocument(principalId,
69  							HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates(principalId,
70  									calDate));
71  			for(TimeBlock timeBlock : timesheet.getTimeBlocks()){
72  				TkServiceLocator.getTimeBlockService().deleteTimeBlock(timeBlock);
73  			}
74  
75  			//refetch clean document
76  			timesheet = TkServiceLocator.getTimesheetService().openTimesheetDocument(principalId,
77  					HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates(principalId, calDate));
78  			List<TimeBlock> timeBlocks = new LinkedList<TimeBlock>();
79  			for(int i = 0;i<5;i++){
80  				TimeBlock timeBlock = createTimeBlock(timesheet, i+1, 10);
81  				timeBlocks.add(timeBlock);
82  				timesheet.setTimeBlocks(timeBlocks);
83  			}
84  			
85  			//Add a TEX accrual earn code
86  			TimeBlock timeBlock = createTimeBlock(timesheet, 1, 4,"TEX");
87  			timeBlocks.add(timeBlock);
88  			timesheet.setTimeBlocks(timeBlocks);
89  			return timesheet;
90  
91  		} catch (WorkflowException e) {
92  			throw new RuntimeException("Problem fetching document");
93  		}
94  	}
95  
96  	/**
97  	 * Helper method to create regular time blocks for use in testing.
98  	 *
99  	 * @param start
100 	 * @param days
101 	 * @param hours
102 	 * @param earnCode
103 	 * @param jobNumber
104 	 * @param workArea
105 	 * @return
106 	 */
107 	public static List<TimeBlock> createUniformTimeBlocks(DateTime start, int days, BigDecimal hours, String earnCode, Long jobNumber, Long workArea) {
108 		return TkTestUtils.createUniformTimeBlocks(start, days, hours, earnCode, jobNumber, workArea, null);
109 	}
110 
111 	public static List<TimeBlock> createUniformTimeBlocks(DateTime start, int days, BigDecimal hours, String earnCode, Long jobNumber, Long workArea, Long task) {
112 		List<TimeBlock> blocks = new ArrayList<TimeBlock>();
113 
114 		for (int i=0; i<days; i++) {
115 			DateTime ci = start.plusDays(i);
116 			DateTime co = ci.plusHours(hours.intValue());
117 			TimeBlock block = TkTestUtils.createDummyTimeBlock(ci, co, hours, earnCode, jobNumber, workArea);
118 			block.setTask(task);
119 			blocks.add(block);
120 		}
121 
122 		return blocks;
123 	}
124 
125 	public static TimeBlock createDummyTimeBlock(DateTime clockIn, DateTime clockOut, BigDecimal hours, String earnCode) {
126 		return TkTestUtils.createDummyTimeBlock(clockIn, clockOut, hours, earnCode, -1L, -1L);
127 	}
128 
129 	public static TimeBlock createDummyTimeBlock(DateTime clockIn, DateTime clockOut, BigDecimal hours, String earnCode, Long jobNumber, Long workArea) {
130 		TimeBlock block = new TimeBlock();
131 		block.setBeginDateTime(clockIn);
132 		block.setEndDateTime(clockOut);
133 		block.setHours(hours);
134         block.setBeginTimeDisplay(clockIn);
135         block.setEndTimeDisplay(clockOut);
136 
137         block.setEarnCode(earnCode);
138 		block.setJobNumber(jobNumber);
139 		block.setWorkArea(workArea);
140 
141 		TimeHourDetail thd = new TimeHourDetail();
142 		thd.setHours(hours);
143 		thd.setEarnCode(earnCode);
144 		List<TimeHourDetail> timeHourDetails = new ArrayList<TimeHourDetail>();
145 		timeHourDetails.add(thd);
146 		block.setTimeHourDetails(timeHourDetails);
147 
148 		return block;
149 	}
150 
151 	public static TimeBlock createTimeBlock(TimesheetDocument timesheetDocument, int dayInPeriod, int numHours){
152 		return createTimeBlock(timesheetDocument, dayInPeriod, numHours,"RGN");
153 	}
154 	public static TimeBlock createTimeBlock(TimesheetDocument timesheetDocument, int dayInPeriod, int numHours, String earnCode){
155 		TimeBlock timeBlock = new TimeBlock();
156 		DateTime beginPeriodDateTime = timesheetDocument.getCalendarEntry().getBeginPeriodFullDateTime();
157 		DateTime beginDateTime = beginPeriodDateTime.plusDays(dayInPeriod).withHourOfDay(8).withMinuteOfHour(0);
158 		DateTime endDateTime = beginDateTime.plusHours(numHours);
159 		
160 		timeBlock.setDocumentId(timesheetDocument.getDocumentId());
161 		timeBlock.setBeginDateTime(beginDateTime);
162 		timeBlock.setBeginTimeDisplay(beginDateTime);
163 		timeBlock.setEndDateTime(endDateTime);
164 		timeBlock.setEndTimeDisplay(endDateTime);
165 		timeBlock.setEarnCode(earnCode);
166 		timeBlock.setJobNumber(1L);
167 		timeBlock.setWorkArea(1234L);
168 		timeBlock.setTask(1L);
169 		timeBlock.setHours((new BigDecimal(numHours)).setScale(HrConstants.BIG_DECIMAL_SCALE, HrConstants.BIG_DECIMAL_SCALE_ROUNDING));
170 
171 		return timeBlock;
172 	}
173 
174 	public static List<Job> getJobs(LocalDate calDate, String principalId){
175 		return HrServiceLocator.getJobService().getJobs(principalId, calDate);
176 	}
177 
178 	@SuppressWarnings("serial")
179 	public static void verifyAggregateHourSumsFlatList(String msg, final Map<String,BigDecimal> ecToHoursMap, TkTimeBlockAggregate aggregate) {
180 		// Initializes sum map to zeros, since we only care about the entires
181 		// that were passed in.
182 		Map<String,BigDecimal> ecToSumMap = new HashMap<String,BigDecimal>() {{ for (String ec : ecToHoursMap.keySet()) { put(ec, BigDecimal.ZERO); }}};
183 
184 		for (TimeBlock bl : aggregate.getFlattenedTimeBlockList()) {
185 			for (TimeHourDetail thd : bl.getTimeHourDetails()) {
186 				if (ecToSumMap.containsKey(thd.getEarnCode())) {
187 					ecToSumMap.put(thd.getEarnCode(), ecToSumMap.get(thd.getEarnCode()).add(thd.getHours()));
188                 }
189             }
190         }
191 
192 		// Assert that our values are correct.
193 		for (String key : ecToHoursMap.keySet()) {
194 			Assert.assertEquals(
195 					msg + " >> ("+key+") Wrong number of hours expected: " + ecToHoursMap.get(key) + " found: " + ecToSumMap.get(key) + " :: ",
196 					0,
197 					ecToHoursMap.get(key).compareTo(ecToSumMap.get(key)));
198         }
199 	}
200 
201 	/**
202 	 * Helper method to verify that the aggregate contains the correct sums as
203 	 * indicated in the ecToHoursMapping, on a SINGLE given flsaWeek.
204 	 *
205 	 * Warning! Contains Assertions, use only with Test Cases.
206 	 *
207 	 * @param ecToHoursMap ex: { 'REG' => 40, 'OVT' => 10 }
208 	 * @param aggregate An aggregate object containing the time blocks
209 	 * @param flsaWeek 0 indexed start week (pulling from aggregate)
210 	 */
211 	@SuppressWarnings("serial")
212 	public static void verifyAggregateHourSums(String msg, final Map<String,BigDecimal> ecToHoursMap, TkTimeBlockAggregate aggregate, int flsaWeek) {
213 		// Initializes sum map to zeros, since we only care about the entires
214 		// that were passed in.
215 		Map<String,BigDecimal> ecToSumMap = new HashMap<String,BigDecimal>() {{ for (String ec : ecToHoursMap.keySet()) { put(ec, BigDecimal.ZERO); }}};
216 
217 		List<FlsaWeek> flsaWeeks = aggregate.getFlsaWeeks(DateTimeZone.forID(TKUtils.getSystemTimeZone()), 0, false);
218 		Assert.assertTrue(msg + " >> Not enough FLSA weeks to verify aggregate hours, max: " + (flsaWeeks.size() - 1), flsaWeeks.size() > flsaWeek);
219 
220 		// Build our Sum Map.
221 		FlsaWeek week = flsaWeeks.get(flsaWeek);
222 		List<FlsaDay> flsaDays = week.getFlsaDays();
223 		for (FlsaDay day : flsaDays) {
224 			for (TimeBlock bl : day.getAppliedTimeBlocks()) {
225 				for (TimeHourDetail thd : bl.getTimeHourDetails()) {
226 					if (ecToSumMap.containsKey(thd.getEarnCode())) {
227 						ecToSumMap.put(thd.getEarnCode(), ecToSumMap.get(thd.getEarnCode()).add(thd.getHours()));
228                     }
229                 }
230             }
231         }
232 
233 
234 		// Assert that our values are correct.
235 		for (String key : ecToHoursMap.keySet()) {
236 			Assert.assertEquals(
237 					msg + " >> ("+key+") Wrong number of hours expected: " + ecToHoursMap.get(key) + " found: " + ecToSumMap.get(key) + " :: ",
238 					0,
239 					ecToHoursMap.get(key).compareTo(ecToSumMap.get(key)));
240         }
241 	}
242 
243 
244 	public static void verifyAggregateHourSums(final Map<String,BigDecimal> ecToHoursMap, TkTimeBlockAggregate aggregate, int flsaWeek) {
245 		TkTestUtils.verifyAggregateHourSums("", ecToHoursMap, aggregate, flsaWeek);
246 	}
247 
248 
249 	/**
250 	 * Helper method to generate time blocks suitable for db persistence in
251 	 * unit tests.
252 	 */
253 	public static List<TimeBlock> createUniformActualTimeBlocks(TimesheetDocument timesheetDocument, Assignment assignment, String earnCode, DateTime start, int days, BigDecimal hours, BigDecimal amount, String principalId) {
254 		TimeBlockService service = TkServiceLocator.getTimeBlockService();
255 		List<TimeBlock> blocks = new ArrayList<TimeBlock>();
256 
257 		for (int i=0; i<days; i++) {
258 			DateTime ci = start.plusDays(i);
259 			DateTime co = ci.plusHours(hours.intValue());
260 
261 			blocks.addAll(service.buildTimeBlocks(assignment, earnCode, timesheetDocument, ci, co, hours, amount,
262                     false, false, principalId, null, null));
263 		}
264 
265 		return blocks;
266 	}
267 
268 	public static Map<DateTime, BigDecimal> getDateToHoursMap(TimeBlock timeBlock, TimeHourDetail timeHourDetail) {
269 		Map<DateTime, BigDecimal> dateToHoursMap = new HashMap<DateTime, BigDecimal>();
270 		DateTime beginTime = timeBlock.getBeginDateTime();
271 		DateTime endTime = timeBlock.getEndDateTime();
272 
273 		Days d = Days.daysBetween(beginTime, endTime);
274 		int numberOfDays = d.getDays();
275 		if (numberOfDays < 1) {
276 			dateToHoursMap.put(timeBlock.getBeginDateTime(), timeHourDetail.getHours());
277 			return dateToHoursMap;
278 		}
279 		DateTime currentTime = beginTime;
280 		for (int i = 0; i < numberOfDays; i++) {
281 			DateTime nextDayAtMidnight = currentTime.plusDays(1);
282 			nextDayAtMidnight = nextDayAtMidnight.hourOfDay().setCopy(12);
283 			nextDayAtMidnight = nextDayAtMidnight.minuteOfDay().setCopy(0);
284 			nextDayAtMidnight = nextDayAtMidnight.secondOfDay().setCopy(0);
285 			nextDayAtMidnight = nextDayAtMidnight.millisOfSecond().setCopy(0);
286 			Duration dur = new Duration(currentTime, nextDayAtMidnight);
287 			long duration = dur.getStandardSeconds();
288 			BigDecimal hrs = new BigDecimal(duration / 3600, HrConstants.MATH_CONTEXT);
289 			dateToHoursMap.put(currentTime, hrs);
290 			currentTime = nextDayAtMidnight;
291 		}
292 		Duration dur = new Duration(currentTime, endTime);
293 		long duration = dur.getStandardSeconds();
294 		BigDecimal hrs = new BigDecimal(duration / 3600, HrConstants.MATH_CONTEXT);
295 		dateToHoursMap.put(currentTime, hrs);
296 
297 		return dateToHoursMap;
298 	}
299 
300 }