1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.kuali.kpme.tklm.time.flsa;
17  
18  import java.math.BigDecimal;
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import java.math.BigDecimal;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  import org.apache.commons.lang.StringUtils;
31  import org.joda.time.DateTime;
32  import org.joda.time.DateTimeZone;
33  import org.joda.time.Interval;
34  import org.joda.time.LocalDateTime;
35  import org.kuali.kpme.core.util.HrConstants;
36  import org.kuali.kpme.core.util.TKUtils;
37  import org.kuali.kpme.tklm.api.time.flsa.FlsaDayContract;
38  import org.kuali.kpme.tklm.leave.block.LeaveBlock;
39  import org.kuali.kpme.tklm.time.timeblock.TimeBlock;
40  import org.kuali.kpme.tklm.time.timehourdetail.TimeHourDetail;
41  
42  public class FlsaDay implements FlsaDayContract {
43  
44  	private Map<String,List<TimeBlock>> earnCodeToTimeBlocks = new HashMap<String,List<TimeBlock>>();
45  	private List<TimeBlock> appliedTimeBlocks = new ArrayList<TimeBlock>();
46  	
47  	private Map<String,List<LeaveBlock>> earnCodeToLeaveBlocks = new HashMap<String,List<LeaveBlock>>();
48  	private List<LeaveBlock> appliedLeaveBlocks = new ArrayList<LeaveBlock>();
49  
50  	Interval flsaDateInterval;
51  	LocalDateTime flsaDate;
52      DateTimeZone timeZone;
53  
54      
55  
56  
57  
58  
59  
60  
61  	public FlsaDay(LocalDateTime flsaDate, List<TimeBlock> timeBlocks, List<LeaveBlock> leaveBlocks, DateTimeZone timeZone) {
62  		this.flsaDate = flsaDate;
63          this.timeZone = timeZone;
64  		flsaDateInterval = new Interval(flsaDate.toDateTime(timeZone), flsaDate.toDateTime(timeZone).plusDays(1));
65  		this.setTimeBlocks(timeBlocks);
66  		this.setLeaveBlocks(leaveBlocks);
67  	}
68  
69  	
70  
71  
72  
73  
74  
75  
76  
77  
78  	public void setTimeBlocks(List<TimeBlock> timeBlocks) {
79  		for (TimeBlock block : timeBlocks) {
80              applyBlock(block, this.appliedTimeBlocks);
81          }
82  	}
83  	
84  	
85  
86  
87  
88  
89  
90  
91  
92  
93  	public void setLeaveBlocks(List<LeaveBlock> leaveBlocks) {
94  		for (LeaveBlock block : leaveBlocks) {
95              applyBlock(block, this.appliedLeaveBlocks);
96          }
97  	}
98  
99  	
100 
101 
102 
103 
104 
105 
106 	public void remapTimeHourDetails() {
107 		List<TimeBlock> reApplied = new ArrayList<TimeBlock>(appliedTimeBlocks.size());
108 		earnCodeToTimeBlocks.clear();
109 		for (TimeBlock block : appliedTimeBlocks) {
110 			applyBlock(block, reApplied);
111 		}
112 	}
113 	
114 	
115 
116 
117 
118 
119 
120 
121 	public void remapLeaveHourDetails() {
122 		List<LeaveBlock> reApplied = new ArrayList<LeaveBlock>(appliedLeaveBlocks.size());
123 		earnCodeToLeaveBlocks.clear();
124 		for (LeaveBlock block : appliedLeaveBlocks) {
125 			applyBlock(block, reApplied);
126 		}
127 	}
128 
129 	
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 	private boolean applyBlock(TimeBlock block, List<TimeBlock> applyList) {
158 		DateTime beginDateTime = block.getBeginDateTime().withZone(timeZone);
159 		DateTime endDateTime = block.getEndDateTime().withZone(timeZone);
160 
161 		if (beginDateTime.isAfter(flsaDateInterval.getEnd()))
162 			return false;
163 
164 		Interval timeBlockInterval = null;
165 		
166 		boolean zeroHoursTimeBlock = false;
167 		if(endDateTime.getMillis() > beginDateTime.getMillis()){
168 			timeBlockInterval = new Interval(beginDateTime,endDateTime);
169 		}
170 		
171 		if(flsaDateInterval.contains(beginDateTime)){
172 			zeroHoursTimeBlock = true;
173 		}
174 
175 		Interval overlapInterval = flsaDateInterval.overlap(timeBlockInterval);
176 		long overlap = (overlapInterval == null) ? 0L : overlapInterval.toDurationMillis();
177 		BigDecimal overlapHours = TKUtils.convertMillisToHours(overlap);
178 		if((overlapHours.compareTo(BigDecimal.ZERO) == 0) && flsaDateInterval.contains(beginDateTime) && flsaDateInterval.contains(endDateTime)){
179 			if(block.getHours().compareTo(BigDecimal.ZERO) > 0){
180 				overlapHours = block.getHours();
181 			}
182 		}
183 
184         
185         
186         
187         
188         Map<String,BigDecimal> localEarnCodeToHours = new HashMap<String,BigDecimal>();
189 
190 		if (zeroHoursTimeBlock || overlapHours.compareTo(BigDecimal.ZERO) > 0 || (flsaDateInterval.contains(beginDateTime) && StringUtils.equals(block.getEarnCodeType(),HrConstants.EARN_CODE_AMOUNT)))  {
191 
192             List<TimeHourDetail> details = block.getTimeHourDetails();
193             for (TimeHourDetail thd : details) {
194                 BigDecimal localEcHours = localEarnCodeToHours.containsKey(thd.getEarnCode()) ? localEarnCodeToHours.get(thd.getEarnCode()) : BigDecimal.ZERO;
195                 
196                 if (overlapHours.compareTo(localEcHours) >= 0 || thd.getAmount().compareTo(BigDecimal.ZERO) == 0) {
197                     localEcHours = localEcHours.add(thd.getHours(), HrConstants.MATH_CONTEXT);
198                     localEarnCodeToHours.put(thd.getEarnCode(), localEcHours);
199                 }
200             }
201 
202 			List<TimeBlock> blocks = earnCodeToTimeBlocks.get(block.getEarnCode());
203 			if (blocks == null) {
204 				blocks = new ArrayList<TimeBlock>();
205 				earnCodeToTimeBlocks.put(block.getEarnCode(), blocks);
206 			}
207 			blocks.add(block);
208 			applyList.add(block);
209 		}
210 
211 		return true;
212 	}
213 	
214 	
215 
216 
217 
218 
219 
220 
221 
222 
223 
224 
225 
226 
227 
228 
229 
230 
231 
232 
233 
234 
235 
236 
237 
238 
239 
240 	private boolean applyBlock(LeaveBlock block, List<LeaveBlock> applyList) {
241 		DateTime beginDateTime = new DateTime(block.getLeaveDate(), this.timeZone);
242 		DateTime endDateTime = new DateTime(block.getLeaveDate(), this.timeZone);
243 
244 		if (beginDateTime.isAfter(flsaDateInterval.getEnd())) {
245 			return false;
246         }
247 
248 		Interval leaveBlockInterval = null;
249 		if(endDateTime.getMillis() > beginDateTime.getMillis()){
250 			leaveBlockInterval = new Interval(beginDateTime,endDateTime);
251 		}
252 
253 		Interval overlapInterval = flsaDateInterval.overlap(leaveBlockInterval);
254 		long overlap = (overlapInterval == null) ? 0L : overlapInterval.toDurationMillis();
255 		BigDecimal overlapHours = TKUtils.convertMillisToHours(overlap);
256 		if((overlapHours.compareTo(BigDecimal.ZERO) == 0) && flsaDateInterval.contains(beginDateTime) && flsaDateInterval.contains(endDateTime)){
257 			if(block.getLeaveAmount().negate().compareTo(BigDecimal.ZERO) > 0){
258 				overlapHours = block.getLeaveAmount().negate();
259 			}
260 		}
261 		
262 		if (overlapHours.compareTo(BigDecimal.ZERO) > 0)  {
263 			List<LeaveBlock> blocks = earnCodeToLeaveBlocks.get(block.getEarnCode());
264 			if (blocks == null) {
265 				blocks = new ArrayList<LeaveBlock>();
266 				earnCodeToLeaveBlocks.put(block.getEarnCode(), blocks);
267 			}
268 			blocks.add(block);
269 			applyList.add(block);
270 		}
271 
272 		return true;
273 	}
274 
275 	public Map<String, List<TimeBlock>> getEarnCodeToTimeBlocks() {
276 		return earnCodeToTimeBlocks;
277 	}
278 
279 	public void setEarnCodeToTimeBlocks(Map<String, List<TimeBlock>> earnCodeToTimeBlocks) {
280 		this.earnCodeToTimeBlocks = earnCodeToTimeBlocks;
281 	}
282 
283 	public List<TimeBlock> getAppliedTimeBlocks() {
284 		return appliedTimeBlocks;
285 	}
286 
287 	public void setAppliedTimeBlocks(List<TimeBlock> appliedTimeBlocks) {
288 		this.appliedTimeBlocks = appliedTimeBlocks;
289 	}
290 
291 	public Map<String, List<LeaveBlock>> getEarnCodeToLeaveBlocks() {
292 		return earnCodeToLeaveBlocks;
293 	}
294 
295 	public void setEarnCodeToLeaveBlocks(Map<String, List<LeaveBlock>> earnCodeToLeaveBlocks) {
296 		this.earnCodeToLeaveBlocks = earnCodeToLeaveBlocks;
297 	}
298 
299 	public List<LeaveBlock> getAppliedLeaveBlocks() {
300 		return appliedLeaveBlocks;
301 	}
302 
303 	public void setAppliedLeaveBlocks(List<LeaveBlock> appliedLeaveBlocks) {
304 		this.appliedLeaveBlocks = appliedLeaveBlocks;
305 	}
306 
307 	public LocalDateTime getFlsaDate() {
308 		return flsaDate;
309 	}
310 
311 	public void setFlsaDate(LocalDateTime flsaDate) {
312 		this.flsaDate = flsaDate;
313 	}
314 
315 }