1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.hr.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 org.apache.commons.lang.StringUtils;
25 import org.joda.time.DateTime;
26 import org.joda.time.DateTimeZone;
27 import org.joda.time.Interval;
28 import org.joda.time.LocalDateTime;
29 import org.kuali.hr.lm.leaveblock.LeaveBlock;
30 import org.kuali.hr.time.timeblock.TimeBlock;
31 import org.kuali.hr.time.timeblock.TimeHourDetail;
32 import org.kuali.hr.time.util.TKUtils;
33 import org.kuali.hr.time.util.TkConstants;
34
35 public class FlsaDay {
36
37 private Map<String,List<TimeBlock>> earnCodeToTimeBlocks = new HashMap<String,List<TimeBlock>>();
38 private List<TimeBlock> appliedTimeBlocks = new ArrayList<TimeBlock>();
39
40 private Map<String,List<LeaveBlock>> earnCodeToLeaveBlocks = new HashMap<String,List<LeaveBlock>>();
41 private List<LeaveBlock> appliedLeaveBlocks = new ArrayList<LeaveBlock>();
42
43 Interval flsaDateInterval;
44 LocalDateTime flsaDate;
45 DateTimeZone timeZone;
46
47
48
49
50
51
52
53
54 public FlsaDay(LocalDateTime flsaDate, List<TimeBlock> timeBlocks, List<LeaveBlock> leaveBlocks, DateTimeZone timeZone) {
55 this.flsaDate = flsaDate;
56 this.timeZone = timeZone;
57 flsaDateInterval = new Interval(flsaDate.toDateTime(timeZone), flsaDate.toDateTime(timeZone).plusHours(24));
58 this.setTimeBlocks(timeBlocks);
59 this.setLeaveBlocks(leaveBlocks);
60 }
61
62
63
64
65
66
67
68
69
70
71 public void setTimeBlocks(List<TimeBlock> timeBlocks) {
72 for (TimeBlock block : timeBlocks) {
73 applyBlock(block, this.appliedTimeBlocks);
74
75
76
77 }
78 }
79
80
81
82
83
84
85
86
87
88
89 public void setLeaveBlocks(List<LeaveBlock> leaveBlocks) {
90 for (LeaveBlock block : leaveBlocks) {
91 applyBlock(block, this.appliedLeaveBlocks);
92
93
94
95 }
96 }
97
98
99
100
101
102
103
104
105 public void remapTimeHourDetails() {
106 List<TimeBlock> reApplied = new ArrayList<TimeBlock>(appliedTimeBlocks.size());
107 earnCodeToTimeBlocks.clear();
108 for (TimeBlock block : appliedTimeBlocks) {
109 applyBlock(block, reApplied);
110 }
111 }
112
113
114
115
116
117
118
119
120 public void remapLeaveHourDetails() {
121 List<LeaveBlock> reApplied = new ArrayList<LeaveBlock>(appliedLeaveBlocks.size());
122 earnCodeToLeaveBlocks.clear();
123 for (LeaveBlock block : appliedLeaveBlocks) {
124 applyBlock(block, reApplied);
125 }
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 private boolean applyBlock(TimeBlock block, List<TimeBlock> applyList) {
157 DateTime beginDateTime = new DateTime(block.getBeginTimestamp(), this.timeZone);
158 DateTime endDateTime = new DateTime(block.getEndTimestamp(), this.timeZone);
159
160 if (beginDateTime.isAfter(flsaDateInterval.getEnd())) {
161 return false;
162 }
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(),TkConstants.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(), TkConstants.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 Interval leaveBlockInterval = null;
248 if(endDateTime.getMillis() > beginDateTime.getMillis()){
249 leaveBlockInterval = new Interval(beginDateTime,endDateTime);
250 }
251
252 Interval overlapInterval = flsaDateInterval.overlap(leaveBlockInterval);
253 long overlap = (overlapInterval == null) ? 0L : overlapInterval.toDurationMillis();
254 BigDecimal overlapHours = TKUtils.convertMillisToHours(overlap);
255 if((overlapHours.compareTo(BigDecimal.ZERO) == 0) && flsaDateInterval.contains(beginDateTime) && flsaDateInterval.contains(endDateTime)){
256 if(block.getLeaveAmount().negate().compareTo(BigDecimal.ZERO) > 0){
257 overlapHours = block.getLeaveAmount().negate();
258 }
259 }
260
261 if (overlapHours.compareTo(BigDecimal.ZERO) > 0) {
262 List<LeaveBlock> blocks = earnCodeToLeaveBlocks.get(block.getEarnCode());
263 if (blocks == null) {
264 blocks = new ArrayList<LeaveBlock>();
265 earnCodeToLeaveBlocks.put(block.getEarnCode(), blocks);
266 }
267 blocks.add(block);
268 applyList.add(block);
269 }
270
271 return true;
272 }
273
274 public Map<String, List<TimeBlock>> getEarnCodeToTimeBlocks() {
275 return earnCodeToTimeBlocks;
276 }
277
278 public void setEarnCodeToTimeBlocks(Map<String, List<TimeBlock>> earnCodeToTimeBlocks) {
279 this.earnCodeToTimeBlocks = earnCodeToTimeBlocks;
280 }
281
282 public List<TimeBlock> getAppliedTimeBlocks() {
283 return appliedTimeBlocks;
284 }
285
286 public void setAppliedTimeBlocks(List<TimeBlock> appliedTimeBlocks) {
287 this.appliedTimeBlocks = appliedTimeBlocks;
288 }
289
290 public Map<String, List<LeaveBlock>> getEarnCodeToLeaveBlocks() {
291 return earnCodeToLeaveBlocks;
292 }
293
294 public void setEarnCodeToLeaveBlocks(Map<String, List<LeaveBlock>> earnCodeToLeaveBlocks) {
295 this.earnCodeToLeaveBlocks = earnCodeToLeaveBlocks;
296 }
297
298 public List<LeaveBlock> getAppliedLeaveBlocks() {
299 return appliedLeaveBlocks;
300 }
301
302 public void setAppliedLeaveBlocks(List<LeaveBlock> appliedLeaveBlocks) {
303 this.appliedLeaveBlocks = appliedLeaveBlocks;
304 }
305
306 }