View Javadoc

1   /**
2    * Copyright 2004-2014 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.leave.summary.service;
17  
18  import java.math.BigDecimal;
19  import java.util.ArrayList;
20  import java.util.Date;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  import java.util.SortedMap;
27  import java.util.TreeMap;
28  
29  import org.apache.commons.collections.CollectionUtils;
30  import org.apache.commons.lang.StringUtils;
31  import org.joda.time.DateTime;
32  import org.joda.time.Interval;
33  import org.joda.time.LocalDate;
34  import org.joda.time.LocalDateTime;
35  import org.joda.time.format.DateTimeFormat;
36  import org.joda.time.format.DateTimeFormatter;
37  import org.kuali.kpme.core.accrualcategory.AccrualCategory;
38  import org.kuali.kpme.core.accrualcategory.rule.AccrualCategoryRule;
39  import org.kuali.kpme.core.api.earncode.EarnCodeContract;
40  import org.kuali.kpme.core.calendar.entry.CalendarEntry;
41  import org.kuali.kpme.core.earncode.EarnCode;
42  import org.kuali.kpme.core.leaveplan.LeavePlan;
43  import org.kuali.kpme.core.principal.PrincipalHRAttributes;
44  import org.kuali.kpme.core.service.HrServiceLocator;
45  import org.kuali.kpme.core.util.HrConstants;
46  import org.kuali.kpme.tklm.common.LMConstants;
47  import org.kuali.kpme.tklm.common.TkConstants;
48  import org.kuali.kpme.tklm.leave.block.LeaveBlock;
49  import org.kuali.kpme.tklm.leave.block.service.LeaveBlockService;
50  import org.kuali.kpme.tklm.leave.override.EmployeeOverride;
51  import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
52  import org.kuali.kpme.tklm.leave.summary.LeaveSummary;
53  import org.kuali.kpme.tklm.leave.summary.LeaveSummaryRow;
54  import org.kuali.kpme.tklm.leave.workflow.LeaveCalendarDocumentHeader;
55  import org.kuali.rice.krad.util.ObjectUtils;
56  
57  public class LeaveSummaryServiceImpl implements LeaveSummaryService {
58  	private LeaveBlockService leaveBlockService;
59  
60      @Override
61      public LeaveSummary getLeaveSummaryAsOfDate(String principalId, LocalDate asOfDate) {
62          return getLeaveSummary(principalId, asOfDate, asOfDate, null, true);
63      }
64  
65      public LeaveSummary getLeaveSummaryAsOfDateWithoutFuture(String principalId, LocalDate asOfDate) {
66          return getLeaveSummary(principalId, asOfDate, asOfDate, null, false);
67      }
68  
69      @Override
70      public LeaveSummary getLeaveSummary(String principalId, CalendarEntry calendarEntry) {
71          return getLeaveSummary(principalId, calendarEntry.getBeginPeriodFullDateTime().toLocalDate(), calendarEntry.getEndPeriodFullDateTime().toLocalDate(), null, true);
72      }
73  
74      @Override
75      public LeaveSummary getLeaveSummaryAsOfDateForAccrualCategory(String principalId, LocalDate asOfDate, String accrualCategory) {
76          return getLeaveSummary(principalId, asOfDate, asOfDate, accrualCategory, true);
77      }
78  
79      @Override
80      // startDate is the leave request start date, endDat is leave request end date, usageEndDate is the date before next accrual interval date for leave requst end date
81      // will get leave balance up to the next earn interval for a certain date, including usage up to that next earn interval
82      public BigDecimal getLeaveBalanceForAccrCatUpToDate(String principalId, LocalDate startDate, LocalDate endDate, String accrualCategory, LocalDate usageEndDate) {
83      	BigDecimal leaveBalance = BigDecimal.ZERO;
84          if(StringUtils.isEmpty(principalId) || startDate == null || endDate == null || StringUtils.isEmpty(accrualCategory) || usageEndDate == null) {
85              return leaveBalance;
86          }
87  
88          LeaveSummaryRow lsr = new LeaveSummaryRow();
89          AccrualCategory ac = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(accrualCategory, endDate);
90          
91          if(ac != null) {
92              LeavePlan lp = HrServiceLocator.getLeavePlanService().getLeavePlan(ac.getLeavePlan(), ac.getEffectiveLocalDate());
93              if(lp == null) {
94                 return leaveBalance;
95              }
96              PrincipalHRAttributes pha = getPrincipalHrAttributes(principalId, startDate, endDate);
97              //until we have something that creates carry over, we need to grab everything.
98              // Calculating leave bLocks from Calendar Year start instead of Service Date
99              Map<String, LeaveBlock> carryOverBlocks = getLeaveBlockService().getLastCarryOverBlocks(principalId, startDate);
100             //remove unwanted carry over blocks from map
101             LeaveBlock carryOverBlock = carryOverBlocks.get(accrualCategory);
102             carryOverBlocks = new HashMap<String, LeaveBlock>(1);
103             if(ObjectUtils.isNotNull(carryOverBlock))
104             	carryOverBlocks.put(carryOverBlock.getAccrualCategory(), carryOverBlock);
105            
106             List<LeaveBlock> leaveBlocks = getLeaveBlockService().getLeaveBlocksSinceCarryOver(principalId, carryOverBlocks, endDate, true);
107             List<LeaveBlock> acLeaveBlocks = new ArrayList<LeaveBlock>();
108             for(LeaveBlock lb : leaveBlocks) {
109             	if(StringUtils.equals(lb.getAccrualCategory(), accrualCategory)) {
110             		acLeaveBlocks.add(lb);
111             	}
112             }
113             // get all leave blocks from the requested date to the usageEndDate
114             List<LeaveBlock> futureLeaveBlocks = getLeaveBlockService().getLeaveBlocksWithAccrualCategory(principalId, endDate, usageEndDate, accrualCategory);
115             EmployeeOverride maxUsageOverride = LmServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, lp.getLeavePlan(), accrualCategory, "MU", usageEndDate);
116 
117             //get max balances
118             AccrualCategoryRule acRule = HrServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(ac, LocalDate.now(), pha.getServiceLocalDate());
119             //accrual category rule id set on a leave summary row will be useful in generating a relevant balance transfer
120             //document from the leave calendar display. Could put this id in the request for balance transfer document.
121             lsr.setAccrualCategoryRuleId(acRule == null ? null : acRule.getLmAccrualCategoryRuleId());
122             if(acRule != null &&
123                     (acRule.getMaxBalance()!= null
124                             || acRule.getMaxUsage() != null)) {
125                 if (acRule.getMaxUsage() != null) {
126                     lsr.setUsageLimit(new BigDecimal(acRule.getMaxUsage()).setScale(2));
127                 } else {
128                     lsr.setUsageLimit(null);
129                 }
130             } else {
131                 lsr.setUsageLimit(null);
132             }
133 
134             if(maxUsageOverride !=null)
135                 lsr.setUsageLimit(new BigDecimal(maxUsageOverride.getOverrideValue()));
136 
137             //Fetching leaveblocks for accCat with type CarryOver -- This is logic according to the CO blocks creatLed from scheduler job.
138             BigDecimal carryOver = BigDecimal.ZERO.setScale(2);
139             lsr.setCarryOver(carryOver);
140 
141             assignApprovedValuesToRow(lsr, ac.getAccrualCategory(), acLeaveBlocks, lp, startDate, endDate);
142 
143             //merge key sets
144             if (carryOverBlocks.containsKey(lsr.getAccrualCategory())) {
145                 carryOver = carryOverBlocks.get(lsr.getAccrualCategory()).getLeaveAmount();
146             }
147             Set<String> keyset = new HashSet<String>();
148             keyset.addAll(lsr.getPriorYearsUsage().keySet());
149             keyset.addAll(lsr.getPriorYearsTotalAccrued().keySet());
150             for (String key : keyset) {
151                 BigDecimal value = lsr.getPriorYearsTotalAccrued().get(key);
152                 if (value == null) {
153                     value = BigDecimal.ZERO;
154                 }
155                 carryOver = carryOver.add(value);
156                 BigDecimal use = lsr.getPriorYearsUsage().containsKey(key) ? lsr.getPriorYearsUsage().get(key) : BigDecimal.ZERO;
157                 carryOver = carryOver.add(use);
158                 if (acRule != null  && acRule.getMaxCarryOver() != null && acRule.getMaxCarryOver() < carryOver.longValue()) {
159                     carryOver = new BigDecimal(acRule.getMaxCarryOver());
160                 }
161             }
162 
163             lsr.setCarryOver(carryOver);
164             //handle future leave blocks
165             assignPendingValuesToRow(lsr, ac.getAccrualCategory(), futureLeaveBlocks);
166             //compute Leave Balance
167             leaveBalance = lsr.getAccruedBalance().subtract(lsr.getPendingLeaveRequests());
168             if(lsr.getUsageLimit()!=null) { //should not set leave balance to usage limit simply because it's not null.
169                 BigDecimal availableUsage = lsr.getUsageLimit().subtract(lsr.getYtdApprovedUsage().add(lsr.getPendingLeaveRequests()));
170                 if(leaveBalance.compareTo( availableUsage ) > 0)
171                     lsr.setLeaveBalance(availableUsage);
172                 else
173                     lsr.setLeaveBalance(leaveBalance);
174             } else { //no usage limit
175                 lsr.setLeaveBalance(leaveBalance);
176             }
177         }
178         leaveBalance = lsr.getLeaveBalance();
179         return leaveBalance;    
180     }
181     
182     protected LeaveSummary getLeaveSummary(String principalId, LocalDate startDate, LocalDate endDate, String accrualCategory, boolean includeFuture) {
183         LeaveSummary ls = new LeaveSummary();
184         List<LeaveSummaryRow> rows = new ArrayList<LeaveSummaryRow>();
185 
186         if(StringUtils.isEmpty(principalId) || startDate == null || endDate == null) {
187             return ls;
188         }
189 
190         Set<String> leavePlans = getLeavePlans(principalId, startDate, endDate);
191         PrincipalHRAttributes pha = getPrincipalHrAttributes(principalId, startDate, endDate);
192         List<LeavePlan> leavePlanList = HrServiceLocator.getLeavePlanService().getLeavePlans(new ArrayList<String>(leavePlans), startDate);
193         if (CollectionUtils.isNotEmpty(leavePlanList)) {
194             LeaveCalendarDocumentHeader approvedLcdh = LmServiceLocator.getLeaveCalendarDocumentHeaderService().getMaxEndDateApprovedLeaveCalendar(principalId);
195             //until we have something that creates carry over, we need to grab everything.
196             // Calculating leave bLocks from Calendar Year start instead of Service Date
197             Map<String, LeaveBlock> carryOverBlocks = getLeaveBlockService().getLastCarryOverBlocks(principalId, startDate);
198             for(LeavePlan lp : leavePlanList) {
199                 DateTimeFormatter formatter = DateTimeFormat.forPattern("MMMM d");
200                 DateTimeFormatter formatter2 = DateTimeFormat.forPattern("MMMM d yyyy");
201                 DateTime entryEndDate = endDate.toDateTimeAtStartOfDay();
202                 if (entryEndDate.getHourOfDay() == 0) {
203                     entryEndDate = entryEndDate.minusDays(1);
204                 }
205                 String aString = formatter.print(startDate) + " - " + formatter2.print(entryEndDate);
206                 ls.setPendingDatesString(aString);
207 
208 
209                 if(approvedLcdh != null) {
210                     DateTime endApprovedDate = approvedLcdh.getEndDateTime();
211                     LocalDateTime aLocalTime = approvedLcdh.getEndDateTime().toLocalDateTime();
212                     DateTime endApprovedTime = aLocalTime.toDateTime(HrServiceLocator.getTimezoneService().getUserTimezoneWithFallback());
213                     if(endApprovedTime.getHourOfDay() == 0) {
214                         endApprovedDate = endApprovedDate.minusDays(1);
215                     }
216                     String datesString = formatter.print(approvedLcdh.getBeginDateTime()) + " - " + formatter2.print(endApprovedDate);
217                     ls.setYtdDatesString(datesString);
218                 }
219 
220 
221                 
222                 boolean filterByAccrualCategory = false;
223                 if (StringUtils.isNotEmpty(accrualCategory)) {
224                     filterByAccrualCategory = true;
225                     //remove unwanted carry over blocks from map
226                     LeaveBlock carryOverBlock = carryOverBlocks.get(accrualCategory);
227                     carryOverBlocks = new HashMap<String, LeaveBlock>(1);
228                     if(ObjectUtils.isNotNull(carryOverBlock)) {
229                     	carryOverBlocks.put(carryOverBlock.getAccrualCategory(), carryOverBlock);
230                     }
231                 }
232                 List<LeaveBlock> leaveBlocks = getLeaveBlockService().getLeaveBlocksSinceCarryOver(principalId, carryOverBlocks, endDate, filterByAccrualCategory);
233 
234                 List<LeaveBlock> futureLeaveBlocks = new ArrayList<LeaveBlock>();
235                 if (includeFuture) {
236                     if (!filterByAccrualCategory) {
237                         futureLeaveBlocks = getLeaveBlockService().getLeaveBlocks(principalId, endDate, endDate.plusMonths(Integer.parseInt(lp.getPlanningMonths())));
238                     } else {
239                         futureLeaveBlocks = getLeaveBlockService().getLeaveBlocksWithAccrualCategory(principalId, endDate, endDate.plusMonths(Integer.parseInt(lp.getPlanningMonths())), accrualCategory);
240                     }
241                 }
242                 Map<String, List<LeaveBlock>> leaveBlockMap = mapLeaveBlocksByAccrualCategory(leaveBlocks);
243                 Map<String, List<LeaveBlock>> futureLeaveBlockMap = mapLeaveBlocksByAccrualCategory(futureLeaveBlocks);
244                 List<AccrualCategory> acList = HrServiceLocator.getAccrualCategoryService().getActiveAccrualCategoriesForLeavePlan(lp.getLeavePlan(), endDate);
245                 if(CollectionUtils.isNotEmpty(acList)) {
246                     for(AccrualCategory ac : acList) {
247                         if(ac.getShowOnGrid().equals("Y")) {
248                         	
249                             LeaveSummaryRow lsr = new LeaveSummaryRow();
250                             lsr.setAccrualCategory(ac.getAccrualCategory());
251                             lsr.setAccrualCategoryId(ac.getLmAccrualCategoryId());
252                             //get max balances
253                             AccrualCategoryRule acRule = HrServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRuleForDate(ac, endDate, pha.getServiceLocalDate());
254                             //accrual category rule id set on a leave summary row will be useful in generating a relevant balance transfer
255                             //document from the leave calendar display. Could put this id in the request for balance transfer document.
256                             EmployeeOverride maxUsageOverride = LmServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, lp.getLeavePlan(), ac.getAccrualCategory(), "MU", endDate);
257 
258                             lsr.setAccrualCategoryRuleId(acRule == null ? null : acRule.getLmAccrualCategoryRuleId());
259                             if(acRule != null &&
260                                     (acRule.getMaxBalance()!= null
261                                             || acRule.getMaxUsage() != null)) {
262                                 if (acRule.getMaxUsage() != null) {
263                                     lsr.setUsageLimit(new BigDecimal(acRule.getMaxUsage()).setScale(2));
264                                     ls.setUsageLimit(true);
265                                 } else {
266                                     lsr.setUsageLimit(null);
267                                 }
268 
269                             } else {
270                                 lsr.setUsageLimit(null);
271                             }
272 
273                             if(maxUsageOverride !=null)
274                                 lsr.setUsageLimit(new BigDecimal(maxUsageOverride.getOverrideValue()));
275 
276                             //Fetching leaveblocks for accCat with type CarryOver -- This is logic according to the CO blocks created from scheduler job.
277                             BigDecimal carryOver = BigDecimal.ZERO.setScale(2);
278                             lsr.setCarryOver(carryOver);
279 
280                             //handle up to current leave blocks
281                             //CalendarEntry.getEndPeriodDate passed to fetch leave block amounts on last day of Calendar period
282                             assignApprovedValuesToRow(lsr, ac.getAccrualCategory(), leaveBlockMap.get(ac.getAccrualCategory()), lp, startDate, endDate);
283 
284                             //how about the leave blocks on the calendar entry being currently handled??
285 /*                            if(carryOverBlocks.containsKey(lsr.getAccrualCategory())) {
286                             	LeaveBlock carryOverBlock = carryOverBlocks.get(lsr.getAccrualCategory());
287                             	DateTime carryOverBlockLPStart = HrServiceLocator.getLeavePlanService().getFirstDayOfLeavePlan(lp.getLeavePlan(), carryOverBlock.getLeaveDate());
288                             	DateTime currentLPStart = HrServiceLocator.getLeavePlanService().getFirstDayOfLeavePlan(lp.getLeavePlan(), TKUtils.getCurrentDate());
289                             	if(carryOverBlockLPStart.equals(currentLPStart))
290                             		carryOver = carryOverBlock.getLeaveAmount();
291                             }*/
292                             //figure out past carry over values!!!
293                             //We now have list of past years accrual and use (with ordered keys!!!)
294 
295                             //merge key sets
296                             if (carryOverBlocks.containsKey(lsr.getAccrualCategory())) {
297                                 carryOver = carryOverBlocks.get(lsr.getAccrualCategory()).getLeaveAmount();
298                                 carryOver = carryOver.setScale(2);
299                             }
300                             Set<String> keyset = new HashSet<String>();
301                             keyset.addAll(lsr.getPriorYearsUsage().keySet());
302                             keyset.addAll(lsr.getPriorYearsTotalAccrued().keySet());
303                             EmployeeOverride carryOverOverride = LmServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, lp.getLeavePlan(), ac.getAccrualCategory(), "MAC", endDate);
304 
305                             for (String key : keyset) {
306                                 BigDecimal value = lsr.getPriorYearsTotalAccrued().get(key);
307                                 if (value == null) {
308                                     value = BigDecimal.ZERO;
309                                 }
310                                 carryOver = carryOver.add(value);
311                                 BigDecimal use = lsr.getPriorYearsUsage().containsKey(key) ? lsr.getPriorYearsUsage().get(key) : BigDecimal.ZERO;
312                                 carryOver = carryOver.add(use);
313                  	 	 	 	if (acRule != null  && acRule.getMaxCarryOver() != null) {
314                  	 	 	 		BigDecimal carryOverDisplay = BigDecimal.ZERO;
315                  	 	 	 		if(carryOverOverride != null) {
316                  	 	 	 			carryOverDisplay = new BigDecimal(carryOverOverride.getOverrideValue() < carryOver.longValue() ? carryOverOverride.getOverrideValue() : carryOver.longValue());
317                                     } else {
318                  	 	 	 			carryOverDisplay =  new BigDecimal(acRule.getMaxCarryOver() < carryOver.longValue() ? acRule.getMaxCarryOver() : carryOver.longValue());
319                                     }
320                  	 	 	 		carryOver = carryOverDisplay;
321                  	 	 	 	}
322                             }
323                             
324                             lsr.setCarryOver(carryOver);
325                             if (acRule != null && acRule.getMaxCarryOver() != null) {
326                  	 	 	 	if(carryOverOverride != null) {
327                  	 	 	 		lsr.setMaxCarryOver(new BigDecimal(carryOverOverride.getOverrideValue()));
328                                 } else {
329                  	 	 	 		lsr.setMaxCarryOver(new BigDecimal(acRule.getMaxCarryOver() < carryOver.longValue() ? acRule.getMaxCarryOver() : carryOver.longValue()));
330                                 }
331                             }
332 
333                             //handle future leave blocks
334                             assignPendingValuesToRow(lsr, ac.getAccrualCategory(), futureLeaveBlockMap.get(ac.getAccrualCategory()));
335 
336                             //compute Leave Balance
337                             BigDecimal leaveBalance = lsr.getAccruedBalance().subtract(lsr.getPendingLeaveRequests());
338                             //if leave balance is set
339                             //Employee overrides have already been taken into consideration and the appropriate values
340                             //for usage have been set by this point.
341 //                            if (acRule != null && StringUtils.equals(acRule.getMaxBalFlag(), "Y")) {
342                             //there exists an accrual category rule with max balance limit imposed.
343                             //max bal flag = 'Y' has no precedence here with max-bal / balance transfers implemented.
344                             //unless institutions are not required to define a max balance limit for action_at_max_bal = LOSE.
345                             //Possibly preferable to procure forfeiture blocks through balance transfer
346                             if(lsr.getUsageLimit()!=null) { //should not set leave balance to usage limit simply because it's not null.
347                                 BigDecimal availableUsage = lsr.getUsageLimit().subtract(lsr.getYtdApprovedUsage().add(lsr.getPendingLeaveRequests()));
348                                 if(leaveBalance.compareTo( availableUsage ) > 0)
349                                     lsr.setLeaveBalance(availableUsage);
350                                 else
351                                     lsr.setLeaveBalance(leaveBalance);
352                             } else { //no usage limit
353                                 lsr.setLeaveBalance(leaveBalance);
354                             }
355 
356                             rows.add(lsr);
357                         }
358                     }
359                     // let's check for 'empty' accrual categories
360                     if (leaveBlockMap.containsKey(null)
361                             || futureLeaveBlockMap.containsKey(null)) {
362                         LeaveSummaryRow otherLeaveSummary = new LeaveSummaryRow();
363                         //otherLeaveSummary.setAccrualCategory("Other");
364 
365                         assignApprovedValuesToRow(otherLeaveSummary, null, leaveBlockMap.get(null), lp, startDate, endDate);
366                         BigDecimal carryOver = BigDecimal.ZERO.setScale(2);
367                         for (Map.Entry<String, BigDecimal> entry : otherLeaveSummary.getPriorYearsTotalAccrued().entrySet()) {
368                             carryOver = carryOver.add(entry.getValue());
369                             BigDecimal use = otherLeaveSummary.getPriorYearsUsage().containsKey(entry.getKey()) ? otherLeaveSummary.getPriorYearsUsage().get(entry.getKey()) : BigDecimal.ZERO;
370                             carryOver = carryOver.add(use);
371                         }
372                         otherLeaveSummary.setCarryOver(carryOver);
373                         assignPendingValuesToRow(otherLeaveSummary, null, futureLeaveBlockMap.get(null));
374                         otherLeaveSummary.setAccrualCategory("Other");
375 
376                         //compute Leave Balance
377                         // blank the avail
378                         otherLeaveSummary.setUsageLimit(null);
379                         otherLeaveSummary.setLeaveBalance(null);
380 
381                         rows.add(otherLeaveSummary);
382                     }
383                 }
384             }
385         }
386         ls.setLeaveSummaryRows(rows);
387         return ls;
388     }
389 
390     private PrincipalHRAttributes getPrincipalHrAttributes(String principalId, LocalDate startDate, LocalDate endDate) {
391         PrincipalHRAttributes pha = HrServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, startDate);
392         if(pha == null) {	// principal hr attributes does not exist at the beginning of this calendar entry
393             pha = HrServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, endDate);
394         }
395         return pha;
396     }
397 
398     private Set<String> getLeavePlans(String principalId, LocalDate startDate, LocalDate endDate) {
399         Set<String> lpStrings = new HashSet<String>();     //
400 
401         PrincipalHRAttributes pha = getPrincipalHrAttributes(principalId, startDate, endDate);
402         // get list of principalHrAttributes that become active during this pay period
403         List<PrincipalHRAttributes> phaList = HrServiceLocator.getPrincipalHRAttributeService()
404                 .getActivePrincipalHrAttributesForRange(principalId, startDate, endDate);
405         if(pha != null) {
406             lpStrings.add(pha.getLeavePlan());
407         }
408         if(CollectionUtils.isNotEmpty(phaList)) {
409             for(PrincipalHRAttributes aPha : phaList) {
410                 lpStrings.add(aPha.getLeavePlan());
411             }
412         }
413 
414         return lpStrings;
415     }
416 
417 
418     private Map<String, List<LeaveBlock>> mapLeaveBlocksByAccrualCategory(List<LeaveBlock> leaveBlocks) {
419         Map<String, List<LeaveBlock>> map = new HashMap<String, List<LeaveBlock>>();
420         for (LeaveBlock lb : leaveBlocks) {
421             if (map.containsKey(lb.getAccrualCategory())) {
422                 map.get(lb.getAccrualCategory()).add(lb);
423             } else {
424                 List<LeaveBlock> splitLeaveBlocks = new ArrayList<LeaveBlock>();
425                 splitLeaveBlocks.add(lb);
426                 map.put(lb.getAccrualCategory(), splitLeaveBlocks);
427             }
428         }
429         return map;
430     }
431 
432 	private void assignApprovedValuesToRow(LeaveSummaryRow lsr, String accrualCategory, List<LeaveBlock> approvedLeaveBlocks, LeavePlan lp, LocalDate ytdEarnedEffectiveDate, LocalDate effectiveDate) {
433 
434         SortedMap<String, BigDecimal> yearlyAccrued = new TreeMap<String, BigDecimal>();
435         SortedMap<String, BigDecimal> yearlyUsage = new TreeMap<String, BigDecimal>();
436         BigDecimal accrualedBalance = BigDecimal.ZERO.setScale(2);
437 		BigDecimal approvedUsage = BigDecimal.ZERO.setScale(2);
438 		BigDecimal fmlaUsage = BigDecimal.ZERO.setScale(2);
439 
440         LocalDate cutOffDateToCheck = ytdEarnedEffectiveDate != null ? ytdEarnedEffectiveDate : effectiveDate;
441         DateTime cutOffDate = HrServiceLocator.getLeavePlanService().getFirstDayOfLeavePlan(lp.getLeavePlan(), cutOffDateToCheck).minus(1);
442 
443         if (CollectionUtils.isNotEmpty(approvedLeaveBlocks)) {
444             // create it here so we don't need to get instance every loop iteration
445             for(LeaveBlock aLeaveBlock : approvedLeaveBlocks) {
446              	// check if leave date is before the next calendar start.
447             	if(!aLeaveBlock.getLeaveBlockType().equals(LMConstants.LEAVE_BLOCK_TYPE.CARRY_OVER)
448                         && aLeaveBlock.getLeaveDate().getTime() < effectiveDate.toDate().getTime()) {
449                     if((StringUtils.isBlank(accrualCategory) && StringUtils.isBlank(aLeaveBlock.getAccrualCategory()))
450                             || (StringUtils.isNotBlank(aLeaveBlock.getAccrualCategory())
451                                 && StringUtils.equals(aLeaveBlock.getAccrualCategory(), accrualCategory))) {
452                     	// disapproved/deferred leave blocks should not be calculated into the approved values
453                     	 if(!(StringUtils.equals(HrConstants.REQUEST_STATUS.DISAPPROVED, aLeaveBlock.getRequestStatus()) ||
454                          		StringUtils.equals(HrConstants.REQUEST_STATUS.DEFERRED, aLeaveBlock.getRequestStatus()))) {
455                     		 EarnCode ec = HrServiceLocator.getEarnCodeService().getEarnCode(aLeaveBlock.getEarnCode(), aLeaveBlock.getLeaveLocalDate());
456                     		 // use accrualBalanceAction flag of the earn code to determine which bucket the leave block should go into
457                     		 if (ec != null && StringUtils.equals(ec.getAccrualBalanceAction(), HrConstants.ACCRUAL_BALANCE_ACTION.ADJUSTMENT)) {
458                     			 if (aLeaveBlock.getLeaveLocalDate().toDate().getTime() <= cutOffDate.toDate().getTime()) {
459                                      String yearKey = getYearKey(aLeaveBlock.getLeaveLocalDate(), lp);
460                                      BigDecimal co = yearlyAccrued.get(yearKey);
461                                      if (co == null) {
462                                          co = BigDecimal.ZERO.setScale(2);
463                                      }
464                                      co = co.add(aLeaveBlock.getLeaveAmount());
465                                      yearlyAccrued.put(yearKey, co);
466                                  } else if(aLeaveBlock.getLeaveDate().getTime() < ytdEarnedEffectiveDate.toDate().getTime()) {
467                                      accrualedBalance = accrualedBalance.add(aLeaveBlock.getLeaveAmount());
468                                  }                     			 
469                     		 } else if (ec != null && StringUtils.equals(ec.getAccrualBalanceAction(), HrConstants.ACCRUAL_BALANCE_ACTION.USAGE)) {
470                     			 // check for TC, LC and Leave Adjustment leave blocks
471                     			 if(StringUtils.equals(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR, aLeaveBlock.getLeaveBlockType()) ||
472                     					 StringUtils.equals(LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR, aLeaveBlock.getLeaveBlockType()) ||
473                     					 StringUtils.equals(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_ADJUSTMENT_MAINT, aLeaveBlock.getLeaveBlockType())) {
474 	                    			 if (aLeaveBlock.getLeaveDate().getTime() > cutOffDate.toDate().getTime()) {
475 	                    				//KPME-3094 - check if leaveblock has request status approved.
476 	                    				if(StringUtils.equals(HrConstants.REQUEST_STATUS.APPROVED, aLeaveBlock.getRequestStatus())) {
477 	                    					approvedUsage = approvedUsage.add(aLeaveBlock.getLeaveAmount());
478 	                    				}
479 	                     				if(ec.getFmla().equals("Y")) {
480 	                     					fmlaUsage = fmlaUsage.add(aLeaveBlock.getLeaveAmount());
481 	                     				}
482 	                     			} else {
483 	                     				//these usages are for previous years, to help figure out correct carry over values
484 	                     				String yearKey = getYearKey(aLeaveBlock.getLeaveLocalDate(), lp);
485 	                     				BigDecimal use = yearlyUsage.get(yearKey);
486 	                     				if (use == null) {
487 	                     					use = BigDecimal.ZERO.setScale(2);
488 	                     				}
489 	                     				use = use.add(aLeaveBlock.getLeaveAmount());
490 	                     				yearlyUsage.put(yearKey, use);
491 	                     			}
492                     			 }
493                     		 }
494                     	 }
495                     }
496                 } else {
497                     //we can actually use the carry over block!!
498 
499                 }
500             }
501         }
502 
503         lsr.setPriorYearsTotalAccrued(yearlyAccrued);
504         lsr.setPriorYearsUsage(yearlyUsage);
505 		lsr.setYtdAccruedBalance(accrualedBalance);
506 		lsr.setYtdApprovedUsage(approvedUsage.negate());
507 		lsr.setFmlaUsage(fmlaUsage.negate());
508 		
509 		//lsr.setLeaveBalance(lsr.getYtdAccruedBalance().add(approvedUsage));
510 	}
511 
512     private String getYearKey(LocalDate leaveDate, LeavePlan lp){
513         String yearKey = Integer.toString(leaveDate.getYear());
514         
515         LocalDate leavePlanDate = new LocalDate(leaveDate.getYear(), Integer.parseInt(lp.getCalendarYearStartMonth()), Integer.parseInt(lp.getCalendarYearStartDayOfMonth()));
516 
517         if (leaveDate.isBefore(leavePlanDate)) {
518             yearKey = Integer.toString(leaveDate.getYear() - 1);
519         }
520         return yearKey;
521     }
522 	
523 	private void assignPendingValuesToRow(LeaveSummaryRow lsr, String accrualCategory, List<LeaveBlock> pendingLeaveBlocks ) {
524 		BigDecimal pendingAccrual= BigDecimal.ZERO.setScale(2);
525 		BigDecimal pendingRequests = BigDecimal.ZERO.setScale(2);
526         if (CollectionUtils.isNotEmpty(pendingLeaveBlocks)) {
527             for(LeaveBlock aLeaveBlock : pendingLeaveBlocks) {
528             	if(aLeaveBlock.getLeaveBlockType().equals(LMConstants.LEAVE_BLOCK_TYPE.TIME_CALENDAR) || 
529             			aLeaveBlock.getLeaveBlockType().equals(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_CALENDAR) ||
530             			aLeaveBlock.getLeaveBlockType().equals(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_ADJUSTMENT_MAINT)) {
531             		// check if leave block is planned, requested or approved
532 	            	if(aLeaveBlock.getRequestStatus().equals(HrConstants.REQUEST_STATUS.PLANNED) || aLeaveBlock.getRequestStatus().equals(HrConstants.REQUEST_STATUS.REQUESTED) || aLeaveBlock.getRequestStatus().equals(HrConstants.REQUEST_STATUS.APPROVED) ) {
533 	            		// check if earncode is of Usage.
534 	            		EarnCodeContract ec = HrServiceLocator.getEarnCodeService().getEarnCode(aLeaveBlock.getEarnCode(), aLeaveBlock.getLeaveLocalDate());
535 	            		if (ec != null && StringUtils.equals(ec.getAccrualBalanceAction(), HrConstants.ACCRUAL_BALANCE_ACTION.USAGE)) {
536 			                if((StringUtils.isBlank(accrualCategory) && StringUtils.isBlank(aLeaveBlock.getAccrualCategory()))
537 			                        || (StringUtils.isNotBlank(aLeaveBlock.getAccrualCategory())
538 			                            && StringUtils.equals(aLeaveBlock.getAccrualCategory(), accrualCategory))) {
539 			                    if(aLeaveBlock.getLeaveAmount().compareTo(BigDecimal.ZERO) >= 0) {
540 			                        pendingAccrual = pendingAccrual.add(aLeaveBlock.getLeaveAmount());
541 			                    } else {
542 			                        pendingRequests = pendingRequests.add(aLeaveBlock.getLeaveAmount());
543 			                    }
544 			                }
545 	            		}
546 	            	}
547             	}
548             }
549         }
550 		lsr.setPendingLeaveAccrual(pendingAccrual);
551 		lsr.setPendingLeaveRequests(pendingRequests.negate());
552 	}
553 	
554 	@Override
555 	public List<Date> getLeaveSummaryDates(CalendarEntry calendarEntry) {
556 		List<Date> leaveSummaryDates = new ArrayList<Date>();
557 
558 		DateTime start = calendarEntry.getBeginPeriodLocalDateTime().toDateTime();
559 		DateTime end = calendarEntry.getEndPeriodLocalDateTime().toDateTime();
560         Interval interval = new Interval(start, end);
561 
562         for (DateTime day = interval.getStart(); day.isBefore(interval.getEnd()); day = day.plusDays(1)) {
563         	leaveSummaryDates.add(day.toLocalDate().toDateTimeAtStartOfDay().toDate());
564         }
565 		 
566 		 return leaveSummaryDates;
567 	}
568 
569     protected LeaveBlockService getLeaveBlockService() {
570         if (leaveBlockService == null) {
571             leaveBlockService = LmServiceLocator.getLeaveBlockService();
572         }
573         return leaveBlockService;
574     }
575 
576 
577 }
578