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 }