1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.hr.lm.accrual.service;
17
18 import java.math.BigDecimal;
19 import java.sql.Date;
20 import java.sql.Timestamp;
21 import java.util.ArrayList;
22 import java.util.Calendar;
23 import java.util.GregorianCalendar;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.apache.commons.collections.CollectionUtils;
31 import org.apache.commons.lang.StringUtils;
32 import org.joda.time.DateTime;
33 import org.joda.time.Interval;
34 import org.kuali.hr.job.Job;
35 import org.kuali.hr.lm.LMConstants;
36 import org.kuali.hr.lm.accrual.AccrualCategory;
37 import org.kuali.hr.lm.accrual.AccrualCategoryRule;
38 import org.kuali.hr.lm.accrual.PrincipalAccrualRan;
39 import org.kuali.hr.lm.accrual.RateRange;
40 import org.kuali.hr.lm.accrual.RateRangeAggregate;
41 import org.kuali.hr.lm.leaveblock.LeaveBlock;
42 import org.kuali.hr.lm.leaveplan.LeavePlan;
43 import org.kuali.hr.lm.timeoff.SystemScheduledTimeOff;
44 import org.kuali.hr.lm.workflow.LeaveCalendarDocumentHeader;
45 import org.kuali.hr.time.assignment.Assignment;
46 import org.kuali.hr.time.calendar.CalendarEntries;
47 import org.kuali.hr.time.earncode.EarnCode;
48 import org.kuali.hr.time.principal.PrincipalHRAttributes;
49 import org.kuali.hr.time.service.base.TkServiceLocator;
50 import org.kuali.hr.time.util.TKContext;
51 import org.kuali.hr.time.util.TKUtils;
52 import org.kuali.hr.time.util.TkConstants;
53
54 import edu.emory.mathcs.backport.java.util.Collections;
55
56 public class AccrualServiceImpl implements AccrualService {
57
58 @Override
59 public void runAccrual(String principalId) {
60 Date startDate = getStartAccrualDate(principalId);
61 Date endDate = getEndAccrualDate(principalId);
62
63 System.out.println("AccrualServiceImpl.runAccrual() STARTED with Principal: "+principalId);
64
65 runAccrual(principalId,startDate,endDate, true);
66
67 }
68
69 @Override
70 public void runAccrual(String principalId, Date startDate, Date endDate, boolean recordRanData) {
71 runAccrual(principalId, startDate, endDate, recordRanData, TKContext.getPrincipalId());
72 }
73
74 @SuppressWarnings("unchecked")
75 @Override
76 public void runAccrual(String principalId, Date startDate, Date endDate, boolean recordRanData, String runAsPrincipalId) {
77 List<LeaveBlock> accrualLeaveBlocks = new ArrayList<LeaveBlock>();
78 Map<String, BigDecimal> accumulatedAccrualCatToAccrualAmounts = new HashMap<String,BigDecimal>();
79 Map<String, BigDecimal> accumulatedAccrualCatToNegativeAccrualAmounts = new HashMap<String,BigDecimal>();
80
81 if (startDate != null && endDate != null) {
82 System.out.println("AccrualServiceImpl.runAccrual() STARTED with Principal: "+principalId+" Start: "+startDate.toString()+" End: "+endDate.toString());
83 }
84 if(startDate.after(endDate)) {
85 throw new RuntimeException("Start Date " + startDate.toString() + " should not be later than End Date " + endDate.toString());
86 }
87
88 deactivateOldAccruals(principalId, startDate, endDate, runAsPrincipalId);
89
90
91
92 RateRangeAggregate rrAggregate = this.buildRateRangeAggregate(principalId, startDate, endDate);
93 PrincipalHRAttributes phra = null;
94 PrincipalHRAttributes endPhra = null;
95 LeavePlan lp = null;
96 List<AccrualCategory> accrCatList = null;
97
98
99 Calendar aCal = Calendar.getInstance();
100 aCal.setTime(startDate);
101 while (!aCal.getTime().after(endDate)) {
102 java.util.Date currentDate = aCal.getTime();
103 RateRange currentRange = rrAggregate.getRateOnDate(currentDate);
104 if(currentRange == null) {
105 aCal.add(Calendar.DATE, 1);
106 continue;
107 }
108
109 phra = currentRange.getPrincipalHRAttributes();
110 if(phra == null || TKUtils.removeTime(currentDate).before(TKUtils.removeTime(phra.getServiceDate()))) {
111 aCal.add(Calendar.DATE, 1);
112 continue;
113 }
114
115
116
117
118
119 endPhra = currentRange.getEndPrincipalHRAttributes();
120 if(endPhra != null && TKUtils.removeTime(currentDate).after(TKUtils.removeTime(endPhra.getEffectiveDate()))) {
121 aCal.add(Calendar.DATE, 1);
122 continue;
123 }
124
125
126 if(endDate.before(phra.getServiceDate())) {
127 return;
128 }
129 lp = currentRange.getLeavePlan();
130 accrCatList = currentRange.getAcList();
131
132 if(currentRange.isStatusChanged()) {
133 this.createEmptyLeaveBlockForStatusChange(principalId, accrualLeaveBlocks, currentDate);
134 }
135
136 if(CollectionUtils.isEmpty(currentRange.getJobs())) {
137 aCal.add(Calendar.DATE, 1);
138 continue;
139 }
140
141 BigDecimal ftePercentage = currentRange.getAccrualRatePercentageModifier();
142 BigDecimal totalOfStandardHours = currentRange.getStandardHours();
143 boolean fullFteGranted = false;
144 for(AccrualCategory anAC : accrCatList) {
145 fullFteGranted = false;
146 if(!currentDate.before(phra.getEffectiveDate()) && !anAC.getAccrualEarnInterval().equals("N")) {
147 boolean prorationFlag = this.getProrationFlag(anAC.getProration());
148
149 AccrualCategoryRule currentAcRule = this.getRuleForAccrualCategory(currentRange.getAcRuleList(), anAC);
150
151
152 if(currentAcRule != null) {
153 java.util.Date ruleStartDate = getRuleStartDate(currentAcRule.getServiceUnitOfTime(), phra.getServiceDate(), currentAcRule.getStart());
154 Date ruleStartSqlDate = new java.sql.Date(ruleStartDate.getTime());
155 java.util.Date previousIntervalDay = this.getPrevIntervalDate(ruleStartSqlDate, anAC.getAccrualEarnInterval(), phra.getPayCalendar(), rrAggregate.getCalEntryMap());
156 java.util.Date nextIntervalDay = this.getNextIntervalDate(ruleStartSqlDate, anAC.getAccrualEarnInterval(), phra.getPayCalendar(), rrAggregate.getCalEntryMap());
157
158 RateRange previousRange = rrAggregate.getRateOnDate(previousIntervalDay);
159 AccrualCategoryRule previousAcRule = null;
160 if(previousRange != null) {
161 previousAcRule = this.getRuleForAccrualCategory(previousRange.getAcRuleList(), anAC);
162 }
163
164 if(previousAcRule != null && !previousAcRule.getLmAccrualCategoryRuleId().equals(currentAcRule.getLmAccrualCategoryRuleId())) {
165 if(TKUtils.removeTime(currentDate).compareTo(TKUtils.removeTime(previousIntervalDay)) >= 0
166 && TKUtils.removeTime(currentDate).compareTo(TKUtils.removeTime(nextIntervalDay)) <= 0) {
167 int workDaysInBetween = TKUtils.getWorkDays(ruleStartSqlDate, nextIntervalDay);
168 boolean minReachedFlag = minimumPercentageReachedForPayPeriod(anAC.getMinPercentWorked(),
169 anAC.getAccrualEarnInterval(), workDaysInBetween, new java.sql.Date(nextIntervalDay.getTime()),
170 phra.getPayCalendar(), rrAggregate.getCalEntryMap());
171 if(prorationFlag) {
172 if(minReachedFlag) {
173
174
175 } else {
176
177 currentAcRule = previousAcRule;
178 }
179 } else {
180 if(minReachedFlag) {
181
182 accumulatedAccrualCatToAccrualAmounts.put(anAC.getLmAccrualCategoryId(), currentAcRule.getAccrualRate());
183 fullFteGranted = true;
184 } else {
185
186 accumulatedAccrualCatToAccrualAmounts.put(anAC.getLmAccrualCategoryId(), previousAcRule.getAccrualRate());
187 fullFteGranted = true;
188 }
189 }
190 }
191 }
192 }
193
194
195 java.util.Date firstIntervalDate = this.getNextIntervalDate(phra.getEffectiveDate(), anAC.getAccrualEarnInterval(), phra.getPayCalendar(), rrAggregate.getCalEntryMap());
196 if(!TKUtils.removeTime(currentDate).before(TKUtils.removeTime(phra.getEffectiveDate()))
197 && !TKUtils.removeTime(currentDate).after(TKUtils.removeTime(firstIntervalDate))) {
198 int workDaysInBetween = TKUtils.getWorkDays(phra.getEffectiveDate(), firstIntervalDate);
199 boolean minReachedFlag = minimumPercentageReachedForPayPeriod(anAC.getMinPercentWorked(), anAC.getAccrualEarnInterval(),
200 workDaysInBetween, new java.sql.Date(firstIntervalDate.getTime()),
201 phra.getPayCalendar(), rrAggregate.getCalEntryMap());
202
203 if(prorationFlag) {
204 if(minReachedFlag) {
205
206
207 } else {
208
209 accumulatedAccrualCatToAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
210 accumulatedAccrualCatToNegativeAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
211 continue;
212 }
213 } else {
214 if(minReachedFlag) {
215
216 accumulatedAccrualCatToAccrualAmounts.put(anAC.getLmAccrualCategoryId(), currentAcRule.getAccrualRate());
217 fullFteGranted = true;
218 } else {
219
220 accumulatedAccrualCatToAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
221 accumulatedAccrualCatToNegativeAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
222 continue;
223 }
224 }
225 }
226
227 if(endPhra != null) {
228 java.util.Date previousIntervalDate = this.getPrevIntervalDate(endPhra.getEffectiveDate(), anAC.getAccrualEarnInterval(), phra.getPayCalendar(), rrAggregate.getCalEntryMap());
229
230 if(!TKUtils.removeTime(currentDate).after(TKUtils.removeTime(endPhra.getEffectiveDate()))
231 && TKUtils.removeTime(currentDate).after(TKUtils.removeTime(previousIntervalDate))) {
232 java.util.Date lastIntervalDate = this.getNextIntervalDate(endPhra.getEffectiveDate(), anAC.getAccrualEarnInterval(), phra.getPayCalendar(), rrAggregate.getCalEntryMap());
233 int workDaysInBetween = TKUtils.getWorkDays(previousIntervalDate, endPhra.getEffectiveDate());
234 boolean minReachedFlag = minimumPercentageReachedForPayPeriod(anAC.getMinPercentWorked(), anAC.getAccrualEarnInterval(),
235 workDaysInBetween, new java.sql.Date(lastIntervalDate.getTime()),
236 phra.getPayCalendar(), rrAggregate.getCalEntryMap());
237 if(prorationFlag) {
238 if(minReachedFlag) {
239
240
241 } else {
242
243 accumulatedAccrualCatToAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
244 accumulatedAccrualCatToNegativeAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
245 continue;
246 }
247 } else {
248 if(minReachedFlag) {
249
250 accumulatedAccrualCatToAccrualAmounts.put(anAC.getLmAccrualCategoryId(), currentAcRule.getAccrualRate());
251 fullFteGranted = true;
252 } else {
253
254 accumulatedAccrualCatToAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
255 accumulatedAccrualCatToNegativeAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
256 continue;
257 }
258 }
259 }
260 }
261
262 if(currentAcRule == null) {
263 accumulatedAccrualCatToAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
264 accumulatedAccrualCatToNegativeAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
265 continue;
266 }
267
268
269 if(!TKUtils.isWeekend(currentDate) && !fullFteGranted) {
270 BigDecimal accrualRate = currentAcRule.getAccrualRate();
271 int numberOfWorkDays = this.getWorkDaysInInterval(new java.sql.Date(currentDate.getTime()), anAC.getAccrualEarnInterval(), phra.getPayCalendar(), rrAggregate.getCalEntryMap());
272 BigDecimal dayRate = numberOfWorkDays > 0 ? accrualRate.divide(new BigDecimal(numberOfWorkDays), 6, BigDecimal.ROUND_HALF_UP) : new BigDecimal(0);
273
274
275
276 this.calculateHours(anAC.getLmAccrualCategoryId(), ftePercentage, dayRate, accumulatedAccrualCatToAccrualAmounts);
277
278
279 BigDecimal noAccrualHours = getNotEligibleForAccrualHours(principalId, new java.sql.Date(currentDate.getTime()));
280
281 if(noAccrualHours.compareTo(BigDecimal.ZERO) != 0 && totalOfStandardHours.compareTo(BigDecimal.ZERO) != 0) {
282 BigDecimal dayHours = totalOfStandardHours.divide(new BigDecimal(5), 6, BigDecimal.ROUND_HALF_UP);
283 BigDecimal noAccrualRate = dayRate.multiply(noAccrualHours.divide(dayHours));
284 this.calculateHours(anAC.getLmAccrualCategoryId(), ftePercentage, noAccrualRate, accumulatedAccrualCatToNegativeAccrualAmounts);
285 }
286 }
287
288
289 if(this.isDateAnIntervalDate(currentDate, anAC.getAccrualEarnInterval(), phra.getPayCalendar(), rrAggregate.getCalEntryMap())) {
290 BigDecimal acHours = accumulatedAccrualCatToAccrualAmounts.get(anAC.getLmAccrualCategoryId());
291
292 if(acHours != null) {
293 createLeaveBlock(principalId, accrualLeaveBlocks, currentDate, acHours, anAC, null, true, currentRange.getLeaveCalendarDocumentId());
294 accumulatedAccrualCatToAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
295 fullFteGranted = false;
296 }
297
298 BigDecimal adjustmentHours = accumulatedAccrualCatToNegativeAccrualAmounts.get(anAC.getLmAccrualCategoryId());
299 if(adjustmentHours != null && adjustmentHours.compareTo(BigDecimal.ZERO) != 0) {
300
301 createLeaveBlock(principalId, accrualLeaveBlocks, currentDate, adjustmentHours, anAC, null, false, currentRange.getLeaveCalendarDocumentId());
302 accumulatedAccrualCatToNegativeAccrualAmounts.remove(anAC.getLmAccrualCategoryId());
303 }
304 }
305 }
306 }
307
308 SystemScheduledTimeOff ssto = currentRange.getSysScheTimeOff();
309 if(ssto != null) {
310 AccrualCategory anAC = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(ssto.getAccrualCategory(), ssto.getEffectiveDate());
311 if(anAC == null) {
312 throw new RuntimeException("Cannot find Accrual Category for system scheduled time off " + ssto.getLmSystemScheduledTimeOffId());
313 }
314 BigDecimal hrs = ssto.getAmountofTime().multiply(ftePercentage);
315
316 createLeaveBlock(principalId, accrualLeaveBlocks, currentDate, hrs, anAC, ssto.getLmSystemScheduledTimeOffId(), true, currentRange.getLeaveCalendarDocumentId());
317
318 createLeaveBlock(principalId, accrualLeaveBlocks, currentDate, hrs.negate(), anAC, ssto.getLmSystemScheduledTimeOffId(), true, currentRange.getLeaveCalendarDocumentId());
319 }
320
321 if(endPhra != null && TKUtils.removeTime(currentDate).equals(TKUtils.removeTime(endPhra.getEffectiveDate()))){
322
323 if(!accumulatedAccrualCatToAccrualAmounts.isEmpty()) {
324 for(Map.Entry<String, BigDecimal> entry : accumulatedAccrualCatToAccrualAmounts.entrySet()) {
325 if(entry.getValue() != null && entry.getValue().compareTo(BigDecimal.ZERO) != 0) {
326 AccrualCategory anAC = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(entry.getKey());
327 createLeaveBlock(principalId, accrualLeaveBlocks, currentDate, entry.getValue(), anAC, null, true, currentRange.getLeaveCalendarDocumentId());
328 }
329 }
330 accumulatedAccrualCatToAccrualAmounts = new HashMap<String,BigDecimal>();
331 }
332
333 if(!accumulatedAccrualCatToNegativeAccrualAmounts.isEmpty()) {
334 for(Map.Entry<String, BigDecimal> entry : accumulatedAccrualCatToNegativeAccrualAmounts.entrySet()) {
335 if(entry.getValue() != null && entry.getValue().compareTo(BigDecimal.ZERO) != 0) {
336 AccrualCategory anAC = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(entry.getKey());
337 createLeaveBlock(principalId, accrualLeaveBlocks, currentDate, entry.getValue(), anAC, null, true, currentRange.getLeaveCalendarDocumentId());
338 }
339 }
340 accumulatedAccrualCatToNegativeAccrualAmounts = new HashMap<String,BigDecimal>();
341 }
342 phra = null;
343 endPhra = null;
344 }
345
346 aCal.add(Calendar.DATE, 1);
347 }
348
349
350 TkServiceLocator.getLeaveBlockService().saveLeaveBlocks(accrualLeaveBlocks);
351
352
353 if(recordRanData) {
354 TkServiceLocator.getPrincipalAccrualRanService().updatePrincipalAccrualRanInfo(principalId);
355 }
356
357 }
358
359 private void deactivateOldAccruals(String principalId, Date startDate, Date endDate, String runAsPrincipalId) {
360 List<LeaveBlock> previousLB = TkServiceLocator.getLeaveBlockService().getAccrualGeneratedLeaveBlocks(principalId, startDate, endDate);
361 List<LeaveBlock> sstoAccrualList = new ArrayList<LeaveBlock>();
362 List<LeaveBlock> sstoUsageList = new ArrayList<LeaveBlock>();
363
364 for(LeaveBlock lb : previousLB) {
365 if(StringUtils.isNotEmpty(lb.getScheduleTimeOffId())) {
366 if(lb.getLeaveAmount().compareTo(BigDecimal.ZERO) > 0) {
367 sstoAccrualList.add(lb);
368 } else if(lb.getLeaveAmount().compareTo(BigDecimal.ZERO) < 0) {
369 sstoUsageList.add(lb);
370 }
371 } else {
372 TkServiceLocator.getLeaveBlockService().deleteLeaveBlock(lb.getLmLeaveBlockId(), runAsPrincipalId);
373 }
374 }
375
376 for(LeaveBlock accrualLb : sstoAccrualList) {
377 for(LeaveBlock usageLb : sstoUsageList) {
378
379
380 if(accrualLb.getScheduleTimeOffId().equals(usageLb.getScheduleTimeOffId())) {
381 TkServiceLocator.getLeaveBlockService().deleteLeaveBlock(accrualLb.getLmLeaveBlockId(), runAsPrincipalId);
382 TkServiceLocator.getLeaveBlockService().deleteLeaveBlock(usageLb.getLmLeaveBlockId(), runAsPrincipalId);
383 }
384 }
385 }
386
387 }
388
389 private BigDecimal getNotEligibleForAccrualHours(String principalId, Date currentDate) {
390 BigDecimal hours = BigDecimal.ZERO;
391
392 List<LeaveBlock> lbs = TkServiceLocator.getLeaveBlockService().getNotAccrualGeneratedLeaveBlocksForDate(principalId, currentDate);
393 for(LeaveBlock lb : lbs) {
394 EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(lb.getEarnCode(), currentDate);
395 if(ec == null) {
396 throw new RuntimeException("Cannot find Earn Code for Leave block " + lb.getLmLeaveBlockId());
397 }
398 if(ec.getEligibleForAccrual().equals("N") && lb.getLeaveAmount().compareTo(BigDecimal.ZERO) != 0) {
399 hours = hours.add(lb.getLeaveAmount());
400 }
401 }
402 return hours;
403 }
404
405 private void createLeaveBlock(String principalId, List<LeaveBlock> accrualLeaveBlocks,
406 java.util.Date currentDate, BigDecimal hrs, AccrualCategory anAC, String sysSchTimeOffId,
407 boolean createZeroLeaveBlock, String leaveDocId) {
408
409 EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(anAC.getEarnCode(), anAC.getEffectiveDate());
410 if(ec == null) {
411 throw new RuntimeException("Cannot find Earn Code for Accrual category " + anAC.getAccrualCategory());
412 }
413
414 BigDecimal roundedHours = TkServiceLocator.getEarnCodeService().roundHrsWithEarnCode(hrs, ec);
415 if(!createZeroLeaveBlock && roundedHours.compareTo(BigDecimal.ZERO) == 0) {
416 return;
417 }
418 LeaveBlock aLeaveBlock = new LeaveBlock();
419 aLeaveBlock.setAccrualCategory(anAC.getAccrualCategory());
420 aLeaveBlock.setLeaveDate(new java.sql.Date(currentDate.getTime()));
421 aLeaveBlock.setPrincipalId(principalId);
422
423 aLeaveBlock.setEarnCode(anAC.getEarnCode());
424 aLeaveBlock.setDateAndTime(new Timestamp(currentDate.getTime()));
425 aLeaveBlock.setAccrualGenerated(true);
426 aLeaveBlock.setBlockId(0L);
427 aLeaveBlock.setScheduleTimeOffId(sysSchTimeOffId);
428 aLeaveBlock.setLeaveAmount(roundedHours);
429 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.ACCRUAL_SERVICE);
430 aLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED);
431 aLeaveBlock.setDocumentId(leaveDocId);
432
433 accrualLeaveBlocks.add(aLeaveBlock);
434
435 }
436
437 private void createEmptyLeaveBlockForStatusChange(String principalId, List<LeaveBlock> accrualLeaveBlocks, java.util.Date currentDate) {
438 LeaveBlock aLeaveBlock = new LeaveBlock();
439 aLeaveBlock.setAccrualCategory(null);
440 aLeaveBlock.setLeaveDate(new java.sql.Date(currentDate.getTime()));
441 aLeaveBlock.setPrincipalId(principalId);
442 aLeaveBlock.setEarnCode(LMConstants.STATUS_CHANGE_EARN_CODE);
443 aLeaveBlock.setDateAndTime(new Timestamp(currentDate.getTime()));
444 aLeaveBlock.setAccrualGenerated(true);
445 aLeaveBlock.setBlockId(0L);
446 aLeaveBlock.setScheduleTimeOffId(null);
447 aLeaveBlock.setLeaveAmount(BigDecimal.ZERO);
448 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.ACCRUAL_SERVICE);
449 aLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED);
450
451 accrualLeaveBlocks.add(aLeaveBlock);
452
453 }
454
455 private void calculateHours(String accrualCategoryId, BigDecimal fte, BigDecimal rate, Map<String, BigDecimal> accumulatedAmounts ) {
456 BigDecimal hours = rate.multiply(fte);
457 BigDecimal oldHours = accumulatedAmounts.get(accrualCategoryId);
458 BigDecimal newHours = oldHours == null ? hours : hours.add(oldHours);
459 accumulatedAmounts.put(accrualCategoryId, newHours);
460 }
461
462 public Date getStartAccrualDate(String principalId){
463 return null;
464 }
465
466 public Date getEndAccrualDate(String principalId){
467
468
469 return null;
470 }
471
472 @Override
473 public void runAccrual(List<String> principalIds) {
474 for(String principalId : principalIds){
475 runAccrual(principalId);
476 }
477 }
478
479 private boolean isDateAnIntervalDate(java.util.Date aDate, String earnInterval, String payCalName, Map<String, List<CalendarEntries>> aMap) {
480 if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.PAY_CAL)) {
481 return isDateAtPayCalInterval(aDate, earnInterval, payCalName, aMap);
482 } else {
483 return this.isDateAtEarnInterval(aDate, earnInterval);
484 }
485 }
486
487 private boolean isDateAtPayCalInterval(java.util.Date aDate, String earnInterval, String payCalName, Map<String, List<CalendarEntries>> aMap) {
488 if(StringUtils.isNotEmpty(payCalName)
489 && !aMap.isEmpty()
490 && earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.PAY_CAL)) {
491 List<CalendarEntries> entryList = aMap.get(payCalName);
492 if(CollectionUtils.isNotEmpty(entryList)) {
493 for(CalendarEntries anEntry : entryList) {
494
495 java.util.Date endDate = TKUtils.addDates(anEntry.getEndPeriodDate(), -1);
496 if(aDate.compareTo(endDate) == 0) {
497 return true;
498 }
499 }
500 }
501 }
502 return false;
503 }
504
505 @Override
506 public boolean isDateAtEarnInterval(java.util.Date aDate, String earnInterval) {
507 boolean atEarnInterval = false;
508 if(LMConstants.ACCRUAL_EARN_INTERVAL_MAP.containsKey(earnInterval)) {
509 Calendar aCal = Calendar.getInstance();
510 aCal.setTime(aDate);
511
512 if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.DAILY)) {
513 atEarnInterval = true;
514 } else if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.WEEKLY)) {
515
516 if(aCal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
517 atEarnInterval = true;
518 }
519 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.SEMI_MONTHLY)) {
520
521 if(aCal.get(Calendar.DAY_OF_MONTH) == 15 || aCal.get(Calendar.DAY_OF_MONTH) == aCal.getActualMaximum(Calendar.DAY_OF_MONTH)) {
522 atEarnInterval = true;
523 }
524 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.MONTHLY)) {
525
526 if(aCal.get(Calendar.DAY_OF_MONTH) == aCal.getActualMaximum(Calendar.DAY_OF_MONTH)) {
527 atEarnInterval = true;
528 }
529 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.YEARLY)) {
530
531 if(aCal.get(Calendar.DAY_OF_YEAR) == aCal.getActualMaximum(Calendar.DAY_OF_YEAR)) {
532 atEarnInterval = true;
533 }
534 }else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.NO_ACCRUAL)) {
535
536 }
537 }
538 return atEarnInterval;
539 }
540
541
542 @Override
543 public RateRangeAggregate buildRateRangeAggregate(String principalId, Date startDate, Date endDate) {
544 RateRangeAggregate rrAggregate = new RateRangeAggregate();
545 List<RateRange> rateRangeList = new ArrayList<RateRange>();
546 Calendar gc = new GregorianCalendar();
547 gc.setTime(startDate);
548
549 List<Job> activeJobs = TkServiceLocator.getJobService().getAllActiveLeaveJobs(principalId, endDate);
550 List<Job> inactiveJobs = TkServiceLocator.getJobService().getAllInActiveLeaveJobsInRange(principalId, startDate, endDate);
551
552 List<PrincipalHRAttributes> phaList = TkServiceLocator.getPrincipalHRAttributeService().getAllActivePrincipalHrAttributesForPrincipalId(principalId, endDate);
553 List<PrincipalHRAttributes> inactivePhaList = TkServiceLocator.getPrincipalHRAttributeService().getAllInActivePrincipalHrAttributesForPrincipalId(principalId, endDate);
554
555 if(activeJobs.isEmpty() || phaList.isEmpty()) {
556 return rrAggregate;
557 }
558
559 Set<String> phaLpSet = new HashSet<String>();
560 Set<String> calNameSet = new HashSet<String>();
561 if(CollectionUtils.isNotEmpty(phaList)) {
562 for(PrincipalHRAttributes pha : phaList) {
563 phaLpSet.add(pha.getLeavePlan());
564 calNameSet.add(pha.getPayCalendar());
565 }
566 }
567
568 List<LeavePlan> activeLpList = new ArrayList<LeavePlan> ();
569 List<LeavePlan> inactiveLpList = new ArrayList<LeavePlan> ();
570 for(String lpString : phaLpSet) {
571 List<LeavePlan> aList = TkServiceLocator.getLeavePlanService().getAllActiveLeavePlan(lpString, endDate);
572 activeLpList.addAll(aList);
573
574 aList = TkServiceLocator.getLeavePlanService().getAllInActiveLeavePlan(lpString, endDate);
575 inactiveLpList.addAll(aList);
576 }
577
578
579 Map<String, List<CalendarEntries>> calEntryMap = new HashMap<String, List<CalendarEntries>>();
580 for(String calName : calNameSet) {
581 org.kuali.hr.time.calendar.Calendar aCal = TkServiceLocator.getCalendarService().getCalendarByGroup(calName);
582 if(aCal != null) {
583 List<CalendarEntries> aList = TkServiceLocator.getCalendarEntriesService().getAllCalendarEntriesForCalendarId(aCal.getHrCalendarId());
584 Collections.sort(aList);
585 calEntryMap.put(calName, aList);
586 }
587 }
588 rrAggregate.setCalEntryMap(calEntryMap);
589
590 Set<String> lpStringSet = new HashSet<String>();
591 if(CollectionUtils.isNotEmpty(activeLpList)) {
592 for(LeavePlan lp : activeLpList) {
593 lpStringSet.add(lp.getLeavePlan());
594 }
595 }
596 List<SystemScheduledTimeOff> sstoList = new ArrayList<SystemScheduledTimeOff>();
597 for(String lpString : lpStringSet) {
598 List<SystemScheduledTimeOff> aList =TkServiceLocator.getSysSchTimeOffService().getSystemScheduledTimeOffsForLeavePlan(startDate, endDate, lpString);
599 if(CollectionUtils.isNotEmpty(aList)) {
600 sstoList.addAll(aList);
601 }
602 }
603
604 List<AccrualCategory> activeAccrCatList = new ArrayList<AccrualCategory>();
605 List<AccrualCategory> inactiveAccrCatList = new ArrayList<AccrualCategory>();
606 for(String lpString : lpStringSet) {
607 List<AccrualCategory> aList = TkServiceLocator.getAccrualCategoryService().getActiveLeaveAccrualCategoriesForLeavePlan(lpString, endDate);
608 if(CollectionUtils.isNotEmpty(aList)) {
609 activeAccrCatList.addAll(aList);
610 }
611
612 aList = TkServiceLocator.getAccrualCategoryService().getInActiveLeaveAccrualCategoriesForLeavePlan(lpString, endDate);
613 if(CollectionUtils.isNotEmpty(aList)) {
614 inactiveAccrCatList.addAll(aList);
615 }
616 }
617
618 List<AccrualCategoryRule> activeRuleList = new ArrayList<AccrualCategoryRule>();
619 List<AccrualCategoryRule> inactiveRuleList = new ArrayList<AccrualCategoryRule>();
620 for(AccrualCategory ac : activeAccrCatList) {
621 List<AccrualCategoryRule> aRuleList = TkServiceLocator.getAccrualCategoryRuleService().getActiveRulesForAccrualCategoryId(ac.getLmAccrualCategoryId(), endDate);
622 activeRuleList.addAll(aRuleList);
623
624 aRuleList = TkServiceLocator.getAccrualCategoryRuleService().getInActiveRulesForAccrualCategoryId(ac.getLmAccrualCategoryId(), endDate);
625 inactiveRuleList.addAll(aRuleList);
626 }
627
628 List<LeaveCalendarDocumentHeader> lcDocList = TkServiceLocator.getLeaveCalendarDocumentHeaderService().getAllDocumentHeadersInRangeForPricipalId(principalId, startDate, endDate);
629
630 BigDecimal previousFte = null;
631 List<Job> jobs = new ArrayList<Job>();
632
633 while (!gc.getTime().after(endDate)) {
634 RateRange rateRange = new RateRange();
635 java.util.Date currentDate = gc.getTime();
636
637 jobs = this.getJobsForDate(activeJobs, inactiveJobs, currentDate);
638 if(jobs.isEmpty()) {
639 gc.add(Calendar.DATE, 1);
640 continue;
641 }
642 rateRange.setJobs(jobs);
643
644
645 BigDecimal fteSum = TkServiceLocator.getJobService().getFteSumForJobs(jobs);
646 rateRange.setAccrualRatePercentageModifier(fteSum);
647 BigDecimal standardHours = TkServiceLocator.getJobService().getStandardHoursSumForJobs(jobs);
648 rateRange.setStandardHours(standardHours);
649
650 if(previousFte != null && !previousFte.equals(fteSum)) {
651 rateRange.setStatusChanged(true);
652 rrAggregate.setRateRangeChanged(true);
653 }
654 previousFte = fteSum;
655
656
657 PrincipalHRAttributes phra = this.getPrincipalHrAttributesForDate(phaList, currentDate);
658 rateRange.setPrincipalHRAttributes(phra);
659
660 if(rateRange.getPrincipalHRAttributes() != null) {
661
662 PrincipalHRAttributes endPhra = this.getInactivePrincipalHrAttributesForDate(inactivePhaList, rateRange.getPrincipalHRAttributes().getEffectiveDate(), currentDate);
663 rateRange.setEndPrincipalHRAttributes(endPhra);
664 }
665
666
667 if(rateRange.getPrincipalHRAttributes()!= null) {
668 rateRange.setLeavePlan(this.getLeavePlanForDate(activeLpList, inactiveLpList, rateRange.getPrincipalHRAttributes().getLeavePlan(), currentDate));
669 }
670
671 if(rateRange.getLeavePlan() != null) {
672
673 List<AccrualCategory> acsForDay = this.getAccrualCategoriesForDate(activeAccrCatList, inactiveAccrCatList, rateRange.getLeavePlan().getLeavePlan(), currentDate);
674 rateRange.setAcList(acsForDay);
675
676
677 for(SystemScheduledTimeOff ssto : sstoList) {
678 if(TKUtils.removeTime(ssto.getAccruedDate()).equals(TKUtils.removeTime(currentDate) )
679 && ssto.getLeavePlan().equals(rateRange.getLeavePlan().getLeavePlan())) {
680
681
682
683 List<LeaveBlock> sstoLbList = TkServiceLocator.getLeaveBlockService().getSSTOLeaveBlocks(principalId, ssto.getLmSystemScheduledTimeOffId(), ssto.getAccruedDate());
684 if(CollectionUtils.isEmpty(sstoLbList)) {
685 rateRange.setSysScheTimeOff(ssto);
686 }
687 }
688 }
689 }
690
691 if(CollectionUtils.isNotEmpty(rateRange.getAcList())) {
692 List<AccrualCategoryRule> rulesForDay = new ArrayList<AccrualCategoryRule>();
693 for(AccrualCategory ac : rateRange.getAcList()) {
694 rulesForDay.addAll(this.getAccrualCategoryRulesForDate
695 (activeRuleList, ac.getLmAccrualCategoryId(), currentDate, rateRange.getPrincipalHRAttributes().getServiceDate()));
696 }
697 rateRange.setAcRuleList(rulesForDay);
698
699 }
700
701 DateTime beginInterval = new DateTime(gc.getTime());
702 gc.add(Calendar.DATE, 1);
703 DateTime endInterval = new DateTime(gc.getTime());
704 Interval range = new Interval(beginInterval, endInterval);
705 rateRange.setRange(range);
706
707
708 rateRange.setLeaveCalendarDocumentId(this.getLeaveDocumentForDate(lcDocList, currentDate));
709 rateRangeList.add(rateRange);
710 }
711 rrAggregate.setRateRanges(rateRangeList);
712 rrAggregate.setCurrentRate(null);
713 return rrAggregate;
714 }
715
716 private String getLeaveDocumentForDate(List<LeaveCalendarDocumentHeader> lcDocList, java.util.Date currentDate) {
717 for(LeaveCalendarDocumentHeader lcdh : lcDocList) {
718 if(!lcdh.getBeginDate().after(currentDate) && lcdh.getEndDate().after(currentDate)) {
719 return lcdh.getDocumentId();
720 }
721 }
722 return "";
723 }
724
725 public List<Job> getJobsForDate(List<Job> activeJobs, List<Job> inactiveJobs, java.util.Date currentDate) {
726 List<Job> jobs = new ArrayList<Job>();
727 for(Job aJob : activeJobs) {
728 if(!aJob.getEffectiveDate().after(currentDate)) {
729 jobs.add(aJob);
730 }
731 }
732 if(CollectionUtils.isNotEmpty(jobs)) {
733 List<Job> tempList = new ArrayList<Job>();
734 tempList.addAll(jobs);
735 for(Job aJob : tempList) {
736 for(Job inactiveJob : inactiveJobs) {
737 if(inactiveJob.getJobNumber().equals(aJob.getJobNumber())
738 && inactiveJob.getEffectiveDate().after(aJob.getEffectiveDate())
739 && !inactiveJob.getEffectiveDate().after(currentDate)) {
740
741 jobs.remove(aJob);
742 }
743 }
744 }
745 }
746 return jobs;
747 }
748
749 public PrincipalHRAttributes getPrincipalHrAttributesForDate(List<PrincipalHRAttributes> activeList, java.util.Date currentDate) {
750 List<PrincipalHRAttributes> phasForDay = new ArrayList<PrincipalHRAttributes>();
751 for(PrincipalHRAttributes pha : activeList) {
752 if(!pha.getEffectiveDate().after(currentDate) && !pha.getServiceDate().after(currentDate)) {
753 phasForDay.add(pha);
754 }
755 }
756 if(CollectionUtils.isNotEmpty(phasForDay)) {
757 PrincipalHRAttributes pha = phasForDay.get(0);
758 int indexOfMaxEffDt = 0;
759 if(phasForDay.size() > 1) {
760 for(int i = 1; i < phasForDay.size(); i++) {
761 if( (phasForDay.get(i).getEffectiveDate().after(phasForDay.get(indexOfMaxEffDt).getEffectiveDate()))
762 ||(phasForDay.get(i).getEffectiveDate().equals(phasForDay.get(indexOfMaxEffDt).getEffectiveDate())
763 && phasForDay.get(i).getTimestamp().after(phasForDay.get(indexOfMaxEffDt).getTimestamp()))) {
764 indexOfMaxEffDt = i;
765 }
766 }
767 pha = phasForDay.get(indexOfMaxEffDt);
768 }
769 return pha;
770 }
771 return null;
772 }
773
774 public PrincipalHRAttributes getInactivePrincipalHrAttributesForDate(List<PrincipalHRAttributes> inactiveList, java.util.Date activeDate, java.util.Date currentDate) {
775 List<PrincipalHRAttributes> inactivePhasForDay = new ArrayList<PrincipalHRAttributes>();
776 for(PrincipalHRAttributes pha : inactiveList) {
777 if( pha.getEffectiveDate().after(activeDate) && !pha.getServiceDate().after(currentDate)) {
778 inactivePhasForDay.add(pha);
779 }
780 }
781 if(CollectionUtils.isNotEmpty(inactivePhasForDay)) {
782 PrincipalHRAttributes pha = inactivePhasForDay.get(0);
783 int indexOfMaxEffDt = 0;
784 if(inactivePhasForDay.size() > 1) {
785 for(int i = 1; i < inactivePhasForDay.size(); i++) {
786 if( (inactivePhasForDay.get(i).getEffectiveDate().after(inactivePhasForDay.get(indexOfMaxEffDt).getEffectiveDate()))
787 ||(inactivePhasForDay.get(i).getEffectiveDate().equals(inactivePhasForDay.get(indexOfMaxEffDt).getEffectiveDate())
788 && inactivePhasForDay.get(i).getTimestamp().after(inactivePhasForDay.get(indexOfMaxEffDt).getTimestamp()))) {
789 indexOfMaxEffDt = i;
790 }
791 }
792 pha = inactivePhasForDay.get(indexOfMaxEffDt);
793 }
794 return pha;
795 }
796 return null;
797 }
798
799 public LeavePlan getLeavePlanForDate(List<LeavePlan> activeLpList, List<LeavePlan> inactiveLpList, String leavePlan, java.util.Date currentDate) {
800 List<LeavePlan> lpsForDay = new ArrayList<LeavePlan>();
801 for(LeavePlan lp : activeLpList) {
802 if(lp.getLeavePlan().equals(leavePlan) && !lp.getEffectiveDate().after(currentDate)) {
803 lpsForDay.add(lp);
804 }
805 }
806 List<LeavePlan> aList = new ArrayList<LeavePlan>();
807 aList.addAll(lpsForDay);
808 for(LeavePlan lp : aList) {
809 for(LeavePlan inactiveLp : inactiveLpList) {
810 if(inactiveLp.getLeavePlan().equals(lp.getLeavePlan())
811 && inactiveLp.getEffectiveDate().after(lp.getEffectiveDate())
812 && !inactiveLp.getEffectiveDate().after(currentDate)) {
813
814 lpsForDay.remove(lp);
815 }
816 }
817 }
818 if(CollectionUtils.isNotEmpty(lpsForDay)) {
819 LeavePlan aLp = lpsForDay.get(0);
820 int indexOfMaxEffDt = 0;
821 if(lpsForDay.size() > 1) {
822 for(int i = 1; i < lpsForDay.size(); i++) {
823 if( (lpsForDay.get(i).getEffectiveDate().after(lpsForDay.get(indexOfMaxEffDt).getEffectiveDate()))
824 ||(lpsForDay.get(i).getEffectiveDate().equals(lpsForDay.get(indexOfMaxEffDt).getEffectiveDate())
825 && lpsForDay.get(i).getTimestamp().after(lpsForDay.get(indexOfMaxEffDt).getTimestamp()))) {
826 indexOfMaxEffDt = i;
827 }
828 }
829 aLp = lpsForDay.get(indexOfMaxEffDt);
830 }
831 return aLp;
832 }
833 return null;
834 }
835
836 public List<AccrualCategory> getAccrualCategoriesForDate(List<AccrualCategory> activeAccrCatList, List<AccrualCategory> inactiveAccrCatList, String leavePlan, java.util.Date currentDate) {
837 Set<AccrualCategory> aSet = new HashSet<AccrualCategory>();
838 for(AccrualCategory ac : activeAccrCatList) {
839 if(ac.getLeavePlan().equals(leavePlan) && !ac.getEffectiveDate().after(currentDate)) {
840 aSet.add(ac);
841 }
842 }
843 List<AccrualCategory> list1 = new ArrayList<AccrualCategory>();
844 list1.addAll(aSet);
845 for(AccrualCategory ac : list1) {
846 for(AccrualCategory inactiveAc : inactiveAccrCatList) {
847 if(inactiveAc.getAccrualCategory().equals(ac.getAccrualCategory())
848 && inactiveAc.getEffectiveDate().after(ac.getEffectiveDate())
849 && !inactiveAc.getEffectiveDate().after(currentDate)) {
850
851 aSet.remove(ac);
852 }
853 }
854 }
855 List<AccrualCategory> acsForDay = new ArrayList<AccrualCategory>();
856 acsForDay.addAll(aSet);
857 return acsForDay;
858 }
859
860 @Override
861 public boolean isEmpoyeementFutureStatusChanged(String principalId, Date startDate, Date endDate) {
862 Date currentDate = TKUtils.getCurrentDate();
863 if(endDate.after(currentDate)) {
864 RateRangeAggregate rrAggregate = this.buildRateRangeAggregate(principalId, startDate, endDate);
865 if(rrAggregate.isRateRangeChanged()) {
866 return true;
867 }
868 }
869 return false;
870 }
871
872 @Override
873 public void calculateFutureAccrualUsingPlanningMonth(String principalId, Date asOfDate) {
874 PrincipalHRAttributes phra = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, asOfDate);
875 if(phra != null) {
876
877 LeavePlan lp = TkServiceLocator.getLeavePlanService().getLeavePlan(phra.getLeavePlan(), asOfDate);
878 if(lp != null && StringUtils.isNotEmpty(lp.getPlanningMonths())) {
879 Calendar aCal = Calendar.getInstance();
880
881 aCal.setTime(asOfDate);
882 aCal.add(Calendar.YEAR, -1);
883 if(aCal.getActualMaximum(Calendar.DAY_OF_MONTH) < aCal.get(Calendar.DATE)) {
884 aCal.set(Calendar.DATE, aCal.getActualMaximum(Calendar.DAY_OF_MONTH));
885 }
886 Date startDate = new java.sql.Date(aCal.getTime().getTime());
887
888 aCal.setTime(asOfDate);
889 aCal.add(Calendar.MONTH, Integer.parseInt(lp.getPlanningMonths()));
890
891 if(aCal.getActualMaximum(Calendar.DAY_OF_MONTH) < aCal.get(Calendar.DATE)) {
892 aCal.set(Calendar.DATE, aCal.getActualMaximum(Calendar.DAY_OF_MONTH));
893 }
894 Date endDate = new java.sql.Date(aCal.getTime().getTime());
895 TkServiceLocator.getLeaveAccrualService().runAccrual(principalId, startDate, endDate, true);
896 }
897 }
898 }
899
900 private boolean minimumPercentageReachedForPayPeriod(BigDecimal min, String earnInterval, int workDays, Date intervalDate, String payCalName, Map<String, List<CalendarEntries>> aMap) {
901 if(min == null || min.compareTo(BigDecimal.ZERO) == 0) {
902 return true;
903 }
904 int daysInInterval = this.getWorkDaysInInterval(intervalDate, earnInterval, payCalName, aMap);
905 if(daysInInterval == 0) {
906 return true;
907 }
908 BigDecimal actualPercentage = new BigDecimal(workDays).divide(new BigDecimal(daysInInterval), 2, BigDecimal.ROUND_HALF_EVEN);
909 if(actualPercentage.compareTo(min) >= 0) {
910 return true;
911 }
912
913 return false;
914 }
915
916 private java.util.Date getPrevIntervalDate(Date aDate, String earnInterval, String payCalName, Map<String, List<CalendarEntries>> aMap) {
917 if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.PAY_CAL)) {
918 return this.getPrevPayCalIntervalDate(aDate, earnInterval, payCalName, aMap);
919 } else {
920 return this.getPreviousAccrualIntervalDate(earnInterval, aDate);
921 }
922 }
923
924 @Override
925 public java.util.Date getPreviousAccrualIntervalDate(String earnInterval, Date aDate) {
926 Calendar aCal = Calendar.getInstance();
927 aCal.setTime(aDate);
928
929 if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.DAILY)) {
930 aCal.add(Calendar.DAY_OF_YEAR, -1);
931 } else if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.WEEKLY)) {
932 aCal.add(Calendar.WEEK_OF_YEAR, -1);
933 aCal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
934 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.SEMI_MONTHLY)) {
935 aCal.add(Calendar.DAY_OF_YEAR, -15);
936 if(aCal.get(Calendar.DAY_OF_MONTH) <=15) {
937 aCal.set(Calendar.DAY_OF_MONTH, 15);
938 } else {
939 aCal.set(Calendar.DAY_OF_MONTH, aCal.getActualMaximum(Calendar.DAY_OF_MONTH));
940 }
941 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.MONTHLY)) {
942 aCal.add(Calendar.MONTH, -1);
943 aCal.set(Calendar.DAY_OF_MONTH, aCal.getActualMaximum(Calendar.DAY_OF_MONTH));
944 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.YEARLY)) {
945 aCal.add(Calendar.YEAR, -1);
946 aCal.set(Calendar.DAY_OF_YEAR, aCal.getActualMaximum(Calendar.DAY_OF_YEAR));
947 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.NO_ACCRUAL)) {
948
949 }
950 return aCal.getTime();
951 }
952
953 private java.util.Date getPrevPayCalIntervalDate(java.util.Date aDate, String earnInterval, String payCalName, Map<String, List<CalendarEntries>> aMap) {
954 if(StringUtils.isNotEmpty(payCalName)
955 && !aMap.isEmpty()
956 && earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.PAY_CAL)) {
957 List<CalendarEntries> entryList = aMap.get(payCalName);
958 if(CollectionUtils.isNotEmpty(entryList)) {
959 for(CalendarEntries anEntry : entryList) {
960
961 java.util.Date endDate = TKUtils.addDates(anEntry.getEndPeriodDate(), -1);
962 if(anEntry.getBeginPeriodDate().compareTo(aDate) <= 0 && endDate.compareTo(aDate) >= 0) {
963
964 java.util.Date prevIntvDate = TKUtils.addDates(anEntry.getBeginPeriodDate(), -1);
965 return prevIntvDate;
966 }
967 }
968 }
969 }
970 return aDate;
971 }
972
973 private java.util.Date getNextIntervalDate(Date aDate, String earnInterval, String payCalName, Map<String, List<CalendarEntries>> aMap) {
974 if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.PAY_CAL)) {
975 return this.getNextPayCalIntervalDate(aDate, earnInterval, payCalName, aMap);
976 } else {
977 return this.getNextAccrualIntervalDate(earnInterval, aDate);
978 }
979 }
980
981 private java.util.Date getNextPayCalIntervalDate(Date aDate, String earnInterval, String payCalName, Map<String, List<CalendarEntries>> aMap) {
982 if(StringUtils.isNotEmpty(payCalName)
983 && !aMap.isEmpty()
984 && earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.PAY_CAL)) {
985 List<CalendarEntries> entryList = aMap.get(payCalName);
986 if(CollectionUtils.isNotEmpty(entryList)) {
987 for(CalendarEntries anEntry : entryList) {
988
989 java.util.Date endDate = TKUtils.addDates(anEntry.getEndPeriodDate(), -1);
990 if(anEntry.getBeginPeriodDate().compareTo(aDate) <= 0 && endDate.compareTo(aDate) >= 0) {
991
992 return endDate;
993 }
994 }
995 }
996 }
997 return aDate;
998 }
999
1000 @Override
1001 public java.util.Date getNextAccrualIntervalDate(String earnInterval, Date aDate) {
1002 Calendar aCal = Calendar.getInstance();
1003 aCal.setTime(aDate);
1004
1005 if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.DAILY)) {
1006
1007 } else if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.WEEKLY)) {
1008 if(aCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY) {
1009 aCal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
1010 } else {
1011 aCal.add(Calendar.WEEK_OF_YEAR, 1);
1012 }
1013 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.SEMI_MONTHLY)) {
1014 if(aCal.get(Calendar.DAY_OF_MONTH) <=15) {
1015 aCal.set(Calendar.DAY_OF_MONTH, 15);
1016 } else {
1017 aCal.set(Calendar.DAY_OF_MONTH, aCal.getActualMaximum(Calendar.DAY_OF_MONTH));
1018 }
1019 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.MONTHLY)) {
1020 aCal.set(Calendar.DAY_OF_MONTH, aCal.getActualMaximum(Calendar.DAY_OF_MONTH));
1021 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.YEARLY)) {
1022 aCal.set(Calendar.DAY_OF_YEAR, aCal.getActualMaximum(Calendar.DAY_OF_YEAR));
1023 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.NO_ACCRUAL)) {
1024
1025 }
1026 return aCal.getTime();
1027 }
1028
1029 private int getWorkDaysInInterval(Date aDate, String earnInterval, String payCalName, Map<String, List<CalendarEntries>> aMap) {
1030 if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.PAY_CAL)) {
1031 return this.getWorkDaysInPayCalInterval(aDate, earnInterval, payCalName, aMap);
1032 } else {
1033 return this.getWorkDaysInAccrualInterval(earnInterval, aDate);
1034 }
1035 }
1036
1037 private int getWorkDaysInPayCalInterval(Date aDate, String earnInterval, String payCalName, Map<String, List<CalendarEntries>> aMap) {
1038 if(StringUtils.isNotEmpty(payCalName)
1039 && !aMap.isEmpty()
1040 && earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.PAY_CAL)) {
1041 List<CalendarEntries> entryList = aMap.get(payCalName);
1042 if(CollectionUtils.isNotEmpty(entryList)) {
1043 for(CalendarEntries anEntry : entryList) {
1044
1045 java.util.Date endDate = TKUtils.addDates(anEntry.getEndPeriodDate(), -1);
1046 if(anEntry.getBeginPeriodDate().compareTo(aDate) <= 0 && endDate.compareTo(aDate) >= 0) {
1047 return TKUtils.getWorkDays(anEntry.getBeginPeriodDate(), endDate);
1048 }
1049 }
1050 }
1051 }
1052 return 0;
1053 }
1054
1055 @Override
1056 public int getWorkDaysInAccrualInterval(String earnInterval, Date aDate) {
1057 Calendar aCal = Calendar.getInstance();
1058 aCal.setTime(aDate);
1059
1060 if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.DAILY)) {
1061 return 1;
1062 } else if(earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.WEEKLY)) {
1063 return 5;
1064 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.SEMI_MONTHLY)) {
1065 if(aCal.get(Calendar.DAY_OF_MONTH) <= 15) {
1066 aCal.set(Calendar.DAY_OF_MONTH, 1);
1067 java.util.Date start = aCal.getTime();
1068 aCal.set(Calendar.DAY_OF_MONTH, 15);
1069 java.util.Date end = aCal.getTime();
1070 return TKUtils.getWorkDays(start, end);
1071 } else {
1072 aCal.set(Calendar.DAY_OF_MONTH, 16);
1073 java.util.Date start = aCal.getTime();
1074 aCal.set(Calendar.DAY_OF_MONTH, aCal.getActualMaximum(Calendar.DAY_OF_MONTH));
1075 java.util.Date end = aCal.getTime();
1076 return TKUtils.getWorkDays(start, end);
1077 }
1078 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.MONTHLY)) {
1079 aCal.set(Calendar.DAY_OF_MONTH, 1);
1080 java.util.Date start = aCal.getTime();
1081 aCal.set(Calendar.DAY_OF_MONTH, aCal.getActualMaximum(Calendar.DAY_OF_MONTH));
1082 java.util.Date end = aCal.getTime();
1083 return TKUtils.getWorkDays(start, end);
1084 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.YEARLY)) {
1085 aCal.set(Calendar.DAY_OF_YEAR, 1);
1086 java.util.Date start = aCal.getTime();
1087 aCal.set(Calendar.DAY_OF_YEAR, aCal.getActualMaximum(Calendar.DAY_OF_YEAR));
1088 java.util.Date end = aCal.getTime();
1089 return TKUtils.getWorkDays(start, end);
1090 } else if (earnInterval.equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.NO_ACCRUAL)) {
1091 return 0;
1092 }
1093 return 0;
1094 }
1095
1096 public java.util.Date getRuleStartDate(String earnInterval, Date serviceDate, Long startAcc) {
1097 Calendar aCal = Calendar.getInstance();
1098 aCal.setTime(serviceDate);
1099 String intervalValue = TkConstants.SERVICE_UNIT_OF_TIME.get(earnInterval);
1100 int startInt = startAcc.intValue();
1101
1102 if (intervalValue.equals("Months")) {
1103 aCal.add(Calendar.MONTH, startInt);
1104 if(aCal.get(Calendar.DAY_OF_MONTH) > aCal.getActualMaximum(Calendar.DAY_OF_MONTH)) {
1105 aCal.set(Calendar.DAY_OF_MONTH, aCal.getActualMaximum(Calendar.DAY_OF_MONTH));
1106 }
1107 } else if (intervalValue.equals("Years")) {
1108 aCal.set(Calendar.YEAR, startInt);
1109 }else {
1110
1111 }
1112 return aCal.getTime();
1113 }
1114
1115 public boolean getProrationFlag(String proration) {
1116 if(proration == null) {
1117 return true;
1118 }
1119 return proration.equals("Y") ? true : false;
1120 }
1121
1122 @Override
1123 public boolean statusChangedSinceLastRun(String principalId) {
1124 PrincipalAccrualRan par = TkServiceLocator.getPrincipalAccrualRanService().getLastPrincipalAccrualRan(principalId);
1125 if(par == null) {
1126 return true;
1127 }
1128 Job aJob = TkServiceLocator.getJobService().getMaxTimestampJob(principalId);
1129
1130 if(aJob != null && aJob.getTimestamp().after(par.getLastRanTs())) {
1131 return true;
1132 }
1133
1134 Assignment anAssign = TkServiceLocator.getAssignmentService().getMaxTimestampAssignment(principalId);
1135 if(anAssign != null && anAssign.getTimestamp().after(par.getLastRanTs())) {
1136 return true;
1137 }
1138
1139 PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getMaxTimeStampPrincipalHRAttributes(principalId);
1140 if(pha != null && pha.getTimestamp().after(par.getLastRanTs())) {
1141 return true;
1142 }
1143
1144 List<LeaveBlock> lbList = TkServiceLocator.getLeaveBlockService().getABELeaveBlocksSinceTime(principalId, par.getLastRanTs());
1145 if(CollectionUtils.isNotEmpty(lbList)) {
1146 return true;
1147 }
1148 return false;
1149 }
1150
1151 public List<AccrualCategoryRule> getAccrualCategoryRulesForDate(List<AccrualCategoryRule> acrList, String accrualCategoryId, java.util.Date currentDate, java.util.Date serviceDate) {
1152 Calendar startCal = new GregorianCalendar();
1153 Calendar endCal = new GregorianCalendar();
1154 List<AccrualCategoryRule> aList = new ArrayList<AccrualCategoryRule>();
1155 if(CollectionUtils.isNotEmpty(acrList)) {
1156 for(AccrualCategoryRule acr : acrList) {
1157 if(acr.getLmAccrualCategoryId().equals(accrualCategoryId)) {
1158 String uot = acr.getServiceUnitOfTime();
1159 int startTime = acr.getStart().intValue();
1160 int endTime = acr.getEnd().intValue();
1161
1162 startCal.setTime(serviceDate);
1163 endCal.setTime(serviceDate);
1164 if(uot.equals("M")) {
1165 startCal.add(Calendar.MONTH, startTime);
1166 endCal.add(Calendar.MONTH, endTime);
1167 endCal.add(Calendar.DATE, -1);
1168 } else if(uot.endsWith("Y")) {
1169 startCal.add(Calendar.YEAR, startTime);
1170 endCal.add(Calendar.YEAR, endTime);
1171 endCal.add(Calendar.DATE, -1);
1172 }
1173
1174
1175 if(startCal.getActualMaximum(Calendar.DAY_OF_MONTH) < startCal.get(Calendar.DATE)) {
1176 startCal.set(Calendar.DATE, startCal.getActualMaximum(Calendar.DAY_OF_MONTH));
1177 }
1178 if(endCal.getActualMaximum(Calendar.DAY_OF_MONTH) < endCal.get(Calendar.DATE)) {
1179 endCal.set(Calendar.DATE, endCal.getActualMaximum(Calendar.DAY_OF_MONTH));
1180 }
1181
1182 if(TKUtils.removeTime(currentDate).compareTo(TKUtils.removeTime(startCal.getTime())) >= 0
1183 && TKUtils.removeTime(currentDate).compareTo(TKUtils.removeTime(endCal.getTime())) <=0 ) {
1184 aList.add(acr);
1185 }
1186 }
1187 }
1188 }
1189 return aList;
1190 }
1191
1192 public AccrualCategoryRule getRuleForAccrualCategory(List<AccrualCategoryRule> acrList, AccrualCategory ac) {
1193 if(CollectionUtils.isNotEmpty(acrList)) {
1194 for(AccrualCategoryRule acr : acrList) {
1195 if(acr.getLmAccrualCategoryId().equals(ac.getLmAccrualCategoryId())) {
1196 return acr;
1197 }
1198 }
1199 }
1200 return null;
1201 }
1202 }