org.kuali.kpme.tklm.leave.approval.service.LeaveApprovalServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.kuali.kpme.tklm.leave.approval.service.LeaveApprovalServiceImpl.java

Source

/**
 * Copyright 2004-2014 The Kuali Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.opensource.org/licenses/ecl2.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.kuali.kpme.tklm.leave.approval.service;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.DateTimeFieldType;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.kuali.kpme.core.api.accrualcategory.AccrualCategory;
import org.kuali.kpme.core.api.accrualcategory.AccrualCategoryContract;
import org.kuali.kpme.core.api.accrualcategory.rule.AccrualCategoryRuleContract;
import org.kuali.kpme.core.api.assignment.Assignment;
import org.kuali.kpme.core.api.calendar.Calendar;
import org.kuali.kpme.core.api.calendar.entry.CalendarEntry;
import org.kuali.kpme.core.api.principal.PrincipalHRAttributes;
import org.kuali.kpme.core.service.HrServiceLocator;
import org.kuali.kpme.core.util.HrConstants;
import org.kuali.kpme.tklm.api.common.TkConstants;
import org.kuali.kpme.tklm.api.leave.approval.ApprovalLeaveSummaryRowContract;
import org.kuali.kpme.tklm.api.leave.approval.LeaveApprovalService;
import org.kuali.kpme.tklm.api.leave.block.LeaveBlock;
import org.kuali.kpme.tklm.api.leave.block.LeaveBlockContract;
import org.kuali.kpme.tklm.api.leave.summary.LeaveSummaryContract;
import org.kuali.kpme.tklm.api.leave.summary.LeaveSummaryRowContract;
import org.kuali.kpme.tklm.api.leave.workflow.LeaveCalendarDocumentHeaderContract;
import org.kuali.kpme.tklm.common.LMConstants;
import org.kuali.kpme.tklm.leave.approval.web.ApprovalLeaveSummaryRow;
import org.kuali.kpme.tklm.leave.calendar.LeaveCalendarDocument;
import org.kuali.kpme.tklm.leave.calendar.validation.LeaveCalendarValidationUtil;
import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
import org.kuali.kpme.tklm.leave.workflow.LeaveCalendarDocumentHeader;
import org.kuali.rice.kew.api.KewApiServiceLocator;
import org.kuali.rice.kew.api.action.ActionRequest;
import org.kuali.rice.kew.api.exception.WorkflowException;
import org.kuali.rice.kew.api.note.Note;
import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
import org.kuali.rice.kim.api.services.KimApiServiceLocator;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;

public class LeaveApprovalServiceImpl implements LeaveApprovalService {

    public static final int DAYS_WINDOW_DELTA = 31;

    @Override
    public List<ApprovalLeaveSummaryRowContract> getLeaveApprovalSummaryRows(List<String> principalIds,
            CalendarEntry payCalendarEntry, List<LocalDateTime> leaveSummaryDates, String docIdSearchTerm) {

        DateTime payBeginDate = payCalendarEntry.getBeginPeriodFullDateTime();
        DateTime payEndDate = payCalendarEntry.getEndPeriodFullDateTime();
        List<ApprovalLeaveSummaryRowContract> rowList = new ArrayList<ApprovalLeaveSummaryRowContract>();
        for (String principalId : principalIds) {

            ApprovalLeaveSummaryRow aRow = new ApprovalLeaveSummaryRow();
            List<Note> notes = new ArrayList<Note>();
            //            List<String> warnings = new ArrayList<String>();
            EntityNamePrincipalName name = KimApiServiceLocator.getIdentityService()
                    .getDefaultNamesForPrincipalId(principalId);
            aRow.setName(name != null && name.getDefaultName() != null
                    && name.getDefaultName().getCompositeName() != null ? name.getDefaultName().getCompositeName()
                            : principalId);
            aRow.setPrincipalId(principalId);

            try {
                aRow.setLeaveSummary(
                        LmServiceLocator.getLeaveSummaryService().getLeaveSummary(principalId, payCalendarEntry));
            } catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

            String lastApprovedString = "No previous approved leave calendar information";
            LeaveCalendarDocumentHeader lastApprovedDoc = LmServiceLocator.getLeaveCalendarDocumentHeaderService()
                    .getMaxEndDateApprovedLeaveCalendar(principalId);
            if (lastApprovedDoc != null) {
                lastApprovedString = "Last Approved: "
                        + (new SimpleDateFormat("MMM yyyy")).format(lastApprovedDoc.getBeginDate());
            }
            aRow.setLastApproveMessage(lastApprovedString);

            LeaveCalendarDocumentHeader aDoc = LmServiceLocator.getLeaveCalendarDocumentHeaderService()
                    .getDocumentHeader(principalId, payBeginDate, payEndDate);
            if (aDoc != null) {
                if (StringUtils.isNotBlank(docIdSearchTerm) && !aDoc.getDocumentId().contains(docIdSearchTerm)) {
                    continue; // if the leave document of this pricipalId does not match the docIdSearchTerm, move on to the next principalId
                }
                aRow.setDocumentId(aDoc.getDocumentId());
                aRow.setApprovalStatus(HrConstants.DOC_ROUTE_STATUS.get(aDoc.getDocumentStatus()));
                notes = getNotesForDocument(aDoc.getDocumentId());
                if (StringUtils.isNotBlank(aRow.getDocumentId())) {
                    List<ActionRequest> actionRequests = KewApiServiceLocator.getWorkflowDocumentService()
                            .getPendingActionRequests(aRow.getDocumentId());
                    Map<String, String> roleNames = new HashMap<String, String>();
                    for (ActionRequest ar : actionRequests) {
                        roleNames.put(ar.getPrincipalId(), ar.getQualifiedRoleNameLabel());
                    }
                    aRow.setRoleNames(roleNames);
                }
            }
            List<LeaveCalendarDocumentHeader> docList = LmServiceLocator.getLeaveCalendarDocumentHeaderService()
                    .getApprovalDelinquentDocumentHeaders(principalId);
            if (docList.size() > LMConstants.DELINQUENT_LEAVE_CALENDARS_LIMIT) {
                aRow.setMoreThanOneCalendar(true);
            }

            // if the time of the last day of the pay period is 00:00 or 12:00 am, we should subtract a day from the calendar's end date
            // since the leave blocks from that day should go into next pay period
            LocalDate endDate = payEndDate.toLocalDate();
            if (payEndDate.getHourOfDay() == 0) {
                endDate = endDate.plusDays(-1);
            }
            List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocks(principalId,
                    payBeginDate.toLocalDate(), endDate);
            if (aDoc != null) {
                Map<Integer, String> weeklyDistribution = getWeekHeadersForSummary(principalId, aDoc,
                        payCalendarEntry, aRow.getWeekDates(), aRow.getWeekDateList(), aRow.getDetailMap(),
                        aRow.getEnableWeekDetails());
                aRow.setWeeklyDistribution(weeklyDistribution);
            } else {

                if (payCalendarEntry != null) {
                    try {
                        LeaveCalendarDocument leaveCalendarDocument = null;
                        if (LmServiceLocator.getLeaveCalendarService().shouldCreateLeaveDocument(principalId,
                                payCalendarEntry)) {
                            leaveCalendarDocument = LmServiceLocator.getLeaveCalendarService()
                                    .openLeaveCalendarDocument(principalId, payCalendarEntry);
                        } else {
                            aDoc = LmServiceLocator.getLeaveCalendarDocumentHeaderService().getDocumentHeader(
                                    principalId, payCalendarEntry.getBeginPeriodFullDateTime(),
                                    payCalendarEntry.getEndPeriodFullDateTime());
                            if (aDoc != null) {
                                leaveCalendarDocument = LmServiceLocator.getLeaveCalendarService()
                                        .getLeaveCalendarDocument(aDoc.getDocumentId());
                            }
                        }

                    } catch (WorkflowException e) {
                        e.printStackTrace();
                    }
                }

                Map<Integer, String> weeklyDistribution = getWeekHeadersForSummary(principalId, aDoc,
                        payCalendarEntry, aRow.getWeekDates(), aRow.getWeekDateList(), aRow.getDetailMap(),
                        aRow.getEnableWeekDetails());
                aRow.setWeeklyDistribution(weeklyDistribution);

            }

            aRow.setLeaveBlockList(leaveBlocks);

            Map<LocalDateTime, Map<String, BigDecimal>> earnCodeLeaveHours = getEarnCodeLeaveHours(leaveBlocks,
                    leaveSummaryDates);
            aRow.setEarnCodeLeaveHours(earnCodeLeaveHours);
            aRow.setNotes(notes);

            Map<String, Set<String>> allMessages = findWarnings(principalId, payCalendarEntry, leaveBlocks);

            Map<String, Set<String>> transactionalMessages = findTransactionsWithinPeriod(aDoc, payCalendarEntry);

            allMessages.get("infoMessages").addAll(transactionalMessages.get("infoMessages"));
            allMessages.get("warningMessages").addAll(transactionalMessages.get("warningMessages"));
            allMessages.get("actionMessages").addAll(transactionalMessages.get("actionMessages"));

            if (aRow.getLeaveSummary() != null && aRow.getLeaveSummary().getLeaveSummaryRows().size() > 0) {
                for (LeaveSummaryRowContract summaryRow : aRow.getLeaveSummary().getLeaveSummaryRows()) {
                    // check for negative available balance for accrual category.
                    if (summaryRow.getLeaveBalance() != null
                            && summaryRow.getLeaveBalance().compareTo(BigDecimal.ZERO) < 0) {
                        String message = "Negative available balance found for the accrual category '"
                                + summaryRow.getAccrualCategory() + "'.";
                        allMessages.get("warningMessages").add(message);
                    }
                }
            }

            List<String> warningMessages = new ArrayList<String>();
            warningMessages.addAll(allMessages.get("warningMessages"));
            warningMessages.addAll(allMessages.get("infoMessages"));
            warningMessages.addAll(allMessages.get("actionMessages"));

            aRow.setWarnings(warningMessages); //these are only warning messages.

            rowList.add(aRow);

        }

        return rowList;
    }

    private Calendar getPayCalendarForEntry(CalendarEntry calEntry) {
        Calendar cal = null;

        if (calEntry != null) {
            cal = HrServiceLocator.getCalendarService().getCalendar(calEntry.getHrCalendarId());
        }

        return cal;
    }

    private Map<Integer, String> getWeekHeadersForSummary(String principalId, LeaveCalendarDocumentHeader lcdh,
            CalendarEntry cal, Map<String, String> weekDates, Map<String, Set<LocalDateTime>> weekDateList,
            Map<String, List<Map<String, Object>>> weekDetailMap, Map<String, Boolean> enableWeekDetails) {

        Map<Integer, String> header = new LinkedHashMap<Integer, String>();
        header.put(DateTimeConstants.SUNDAY, "Sun");
        header.put(DateTimeConstants.MONDAY, "Mon");
        header.put(DateTimeConstants.TUESDAY, "Tue");
        header.put(DateTimeConstants.WEDNESDAY, "Wed");
        header.put(DateTimeConstants.THURSDAY, "Thu");
        header.put(DateTimeConstants.FRIDAY, "Fri");
        header.put(DateTimeConstants.SATURDAY, "Sat");

        int flsaBeginDay = this.getPayCalendarForEntry(cal).getFlsaBeginDayConstant();
        if (flsaBeginDay <= 0) {
            flsaBeginDay = DateTimeConstants.SUNDAY;
        }
        LocalDateTime startDate = cal.getBeginPeriodLocalDateTime();
        LocalDateTime endDate = cal.getEndPeriodLocalDateTime();

        LocalDateTime actualStartDate = cal.getBeginPeriodLocalDateTime();
        LocalDateTime actualEndDate = cal.getEndPeriodLocalDateTime();
        // if the time of the last day of the pay period is 00:00 or 12:00 am, we should subtract a day from the calendar's end date
        // since the leave blocks from that day should go into next pay periodd
        if (cal.getEndPeriodFullDateTime().getHourOfDay() == 0) {
            endDate = endDate.plusDays(-1);
        }

        int daysToMinus = 0;
        if (DateTimeConstants.SUNDAY != startDate.getDayOfWeek()) {
            daysToMinus = startDate.getDayOfWeek();
        }

        actualStartDate = startDate.minusDays(daysToMinus);
        int daysToAdd = 0;
        if (endDate.getDayOfWeek() != DateTimeConstants.SUNDAY) {
            daysToAdd = DateTimeConstants.SATURDAY - endDate.getDayOfWeek();
        } else {
            daysToAdd = DateTimeConstants.SATURDAY;
        }

        actualEndDate = endDate.plusDays(daysToAdd);

        // Increment end date if we are on a virtual day calendar, so that the
        // for loop can account for having the proper amount of days on the
        // summary calendar.
        if (endDate.get(DateTimeFieldType.hourOfDay()) != 0 || endDate.get(DateTimeFieldType.minuteOfHour()) != 0
                || endDate.get(DateTimeFieldType.secondOfMinute()) != 0) {
            actualEndDate = endDate.plusDays(1);
        }

        boolean afterFirstDay = false;
        int week = 1;

        LocalDateTime weekStart = actualStartDate;
        LocalDateTime weekEnd = actualStartDate;
        Set<LocalDateTime> dates = new TreeSet<LocalDateTime>();
        for (LocalDateTime currentDate = actualStartDate; currentDate
                .compareTo(actualEndDate) <= 0; currentDate = currentDate.plusDays(1)) {

            if ((currentDate.getDayOfWeek() == flsaBeginDay && afterFirstDay)
                    || currentDate.compareTo(actualEndDate) == 0) {
                String weekString = "Week " + week;
                StringBuilder display = new StringBuilder();
                // show the week's range within the calendar period
                String startDateString = weekStart.isBefore(startDate)
                        ? startDate.toString(TkConstants.DT_ABBREV_DATE_FORMAT)
                        : weekStart.toString(TkConstants.DT_ABBREV_DATE_FORMAT);
                display.append(startDateString);
                display.append(" - ");
                String endDateString = weekEnd.minusDays(1).isAfter(endDate)
                        ? endDate.toString(TkConstants.DT_ABBREV_DATE_FORMAT)
                        : weekEnd.minusDays(1).toString(TkConstants.DT_ABBREV_DATE_FORMAT);
                display.append(endDateString);
                weekDates.put(weekString, display.toString());
                if (currentDate.compareTo(actualEndDate) == 0) {
                    dates.add(currentDate);
                }
                weekDateList.put(weekString, dates);
                dates = new TreeSet<LocalDateTime>();
                dates.add(currentDate);
                weekStart = currentDate;
                week++;
            } else {
                dates.add(currentDate);
            }
            weekEnd = weekEnd.plusDays(1);
            afterFirstDay = true;
        }

        // We may have a very small final "week" on this pay period. For now
        // we will mark it as a week, and if someone doesn't like it, it can
        // be removed.
        if (!header.isEmpty() && !header.get(header.size() - 1).startsWith("Week")) {
            if (weekStart.compareTo(endDate) < 0) {
                StringBuilder display = new StringBuilder();
                // show the week's range within the calendar period
                String startDateString = weekStart.isBefore(startDate)
                        ? startDate.toString(TkConstants.DT_ABBREV_DATE_FORMAT)
                        : weekStart.toString(TkConstants.DT_ABBREV_DATE_FORMAT);
                display.append(startDateString);
                display.append(" - ");
                String endDateString = actualEndDate.isAfter(endDate)
                        ? endDate.toString(TkConstants.DT_ABBREV_DATE_FORMAT)
                        : actualEndDate.toString(TkConstants.DT_ABBREV_DATE_FORMAT);
                display.append(endDateString);
                weekDates.put("Week " + week, display.toString());
                dates.add(actualEndDate);
                weekDateList.put("Week " + week, dates);
            }

        }

        // get Accrual category map for week
        int cnt = 1;
        for (String key : weekDateList.keySet()) {

            Set<LocalDateTime> dateList = weekDateList.get(key);
            LocalDateTime[] datesArray = new LocalDateTime[dateList.size()];
            datesArray = dateList.toArray(datesArray);
            LocalDateTime sd = new LocalDateTime(datesArray[0]);
            LocalDateTime ed = new LocalDateTime(datesArray[datesArray.length - 1]);
            if (cnt == 1) {
                sd = startDate;
            }
            if (cnt == weekDateList.size()) {
                ed = endDate;
            }
            List<Map<String, Object>> detailMap = this.getLeaveApprovalDetailSections(principalId, lcdh,
                    sd.toDateTime(), ed.toDateTime(), new ArrayList<LocalDateTime>(dateList), key,
                    enableWeekDetails);
            weekDetailMap.put(key, detailMap);
            cnt++;
        }

        return header;
    }

    private Map<String, Set<String>> findTransactionsWithinPeriod(LeaveCalendarDocumentHeader aDoc,
            CalendarEntry payCalendarEntry) {
        Map<String, Set<String>> allMessages = new HashMap<String, Set<String>>();

        allMessages.put("actionMessages", new HashSet<String>());
        allMessages.put("infoMessages", new HashSet<String>());
        allMessages.put("warningMessages", new HashSet<String>());
        if (aDoc != null) {
            allMessages = LeaveCalendarValidationUtil.validatePendingTransactions(aDoc.getPrincipalId(),
                    payCalendarEntry.getBeginPeriodFullDateTime().toLocalDate(),
                    payCalendarEntry.getEndPeriodFullDateTime().toLocalDate());
        }
        return allMessages;
    }

    private Map<String, Set<String>> findWarnings(String principalId, CalendarEntry calendarEntry,
            List<LeaveBlock> leaveBlocks) {
        //        List<String> warnings = LeaveCalendarValidationUtil.getWarningMessagesForLeaveBlocks(leaveBlocks);
        Map<String, Set<String>> allMessages = LeaveCalendarValidationUtil.getWarningMessagesForLeaveBlocks(
                leaveBlocks, calendarEntry.getBeginPeriodFullDateTime(), calendarEntry.getEndPeriodFullDateTime());
        //get LeaveSummary and check for warnings
        Map<String, Set<LeaveBlock>> eligibilities;
        try {
            eligibilities = LmServiceLocator.getAccrualCategoryMaxBalanceService()
                    .getMaxBalanceViolations(calendarEntry, principalId);
        } catch (Exception e) {
            eligibilities = null;
        }
        if (eligibilities != null) {
            for (Entry<String, Set<LeaveBlock>> entry : eligibilities.entrySet()) {
                for (LeaveBlock block : entry.getValue()) {
                    AccrualCategoryRuleContract rule = block.getAccrualCategoryRule();
                    if (rule != null) {
                        AccrualCategory accrualCategory = HrServiceLocator.getAccrualCategoryService()
                                .getAccrualCategory(rule.getLmAccrualCategoryId());
                        if (rule.getActionAtMaxBalance().equals(HrConstants.ACTION_AT_MAX_BALANCE.TRANSFER)) {
                            //Todo: add link to balance transfer
                            allMessages.get("warningMessages").add("Accrual Category '"
                                    + accrualCategory.getAccrualCategory() + "' is over max balance."); //warningMessages
                        } else if (rule.getActionAtMaxBalance().equals(HrConstants.ACTION_AT_MAX_BALANCE.LOSE)) {
                            //Todo: compute and display amount of time lost.
                            allMessages.get("warningMessages").add("Accrual Category '"
                                    + accrualCategory.getAccrualCategory() + "' is over max balance."); //warningMessages
                        } else if (rule.getActionAtMaxBalance().equals(HrConstants.ACTION_AT_MAX_BALANCE.PAYOUT)) {
                            //Todo: display information about the payout
                            allMessages.get("warningMessages").add("Accrual Category '"
                                    + accrualCategory.getAccrualCategory() + "' is over max balance."); //warningMessages

                        }

                    }
                }
            }
        }
        return allMessages;
    }

    @Override
    public Map<LocalDateTime, Map<String, BigDecimal>> getEarnCodeLeaveHours(List<LeaveBlock> leaveBlocks,
            List<LocalDateTime> leaveSummaryDates) {
        Map<LocalDateTime, Map<String, BigDecimal>> earnCodeLeaveHours = new LinkedHashMap<LocalDateTime, Map<String, BigDecimal>>();

        for (LocalDateTime leaveSummaryDate : leaveSummaryDates) {
            earnCodeLeaveHours.put(leaveSummaryDate, new LinkedHashMap<String, BigDecimal>());
        }

        for (LeaveBlock lb : leaveBlocks) {
            DateTime leaveDate = lb.getLeaveLocalDate().toDateTimeAtStartOfDay();

            if (earnCodeLeaveHours.get(leaveDate.toLocalDateTime()) != null) {

                Map<String, BigDecimal> leaveHours = earnCodeLeaveHours.get(leaveDate.toLocalDateTime());

                BigDecimal amount = lb.getLeaveAmount();
                String key = lb.getEarnCode() + "|" + lb.getRequestStatus() + "|" + lb.getLeaveBlockType();
                if (leaveHours.get(key) != null) {
                    amount = leaveHours.get(key).add(lb.getLeaveAmount());
                }

                leaveHours.put(key, amount);
            }
        }

        return earnCodeLeaveHours;
    }

    @Override
    public List<Map<String, Object>> getLeaveApprovalDetailSections(LeaveCalendarDocumentHeaderContract lcdh) {

        List<Map<String, Object>> acRows = new ArrayList<Map<String, Object>>();

        if (lcdh == null) {
            return acRows;
        }

        String principalId = lcdh.getPrincipalId();
        CalendarEntry calendarEntry = LmServiceLocator.getLeaveCalendarService()
                .getLeaveCalendarDocument(lcdh.getDocumentId()).getCalendarEntry();
        if (calendarEntry != null) {
            DateTime beginDate = calendarEntry.getBeginPeriodFullDateTime();
            DateTime endDate = calendarEntry.getEndPeriodFullDateTime();
            LeaveSummaryContract leaveSummary;
            List<LocalDateTime> leaveSummaryDates = LmServiceLocator.getLeaveSummaryService()
                    .getLeaveSummaryDates(calendarEntry);
            try {
                leaveSummary = LmServiceLocator.getLeaveSummaryService().getLeaveSummary(principalId,
                        calendarEntry);
            } catch (Exception e) {
                leaveSummary = null;
            }
            List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocks(principalId,
                    beginDate.toLocalDate(), endDate.toLocalDate());
            Map<LocalDateTime, Map<String, BigDecimal>> accrualCategoryLeaveHours = getAccrualCategoryLeaveHours(
                    leaveBlocks, leaveSummaryDates);

            //get all accrual categories of this employee
            PrincipalHRAttributes pha = HrServiceLocator.getPrincipalHRAttributeService()
                    .getPrincipalCalendar(principalId, endDate.toLocalDate());
            if (pha != null) {
                List<AccrualCategory> acList = HrServiceLocator.getAccrualCategoryService()
                        .getActiveAccrualCategoriesForLeavePlan(pha.getLeavePlan(), endDate.toLocalDate());
                for (AccrualCategory ac : acList) {
                    List<BigDecimal> acDayDetails = new ArrayList<BigDecimal>();
                    Map<String, Object> displayMap = new HashMap<String, Object>();
                    BigDecimal totalAmount = BigDecimal.ZERO;
                    displayMap.put("accrualCategory", ac.getAccrualCategory());
                    int index = 0;
                    for (LocalDateTime leaveSummaryDate : leaveSummaryDates) {
                        acDayDetails.add(index, null);
                        if (accrualCategoryLeaveHours.get(leaveSummaryDate) != null) {
                            Map<String, BigDecimal> leaveHours = accrualCategoryLeaveHours.get(leaveSummaryDate);
                            if (leaveHours.containsKey(ac.getAccrualCategory())) {
                                BigDecimal amount = leaveHours.get(ac.getAccrualCategory());
                                totalAmount = totalAmount.add(amount);
                                acDayDetails.set(index, amount);
                            }
                        }
                        index++;
                    }
                    LeaveSummaryRowContract lsr = leaveSummary == null ? null
                            : leaveSummary.getLeaveSummaryRowForAccrualCtgy(ac.getAccrualCategory());
                    displayMap.put("periodUsage", totalAmount);
                    displayMap.put("availableBalance", BigDecimal.ZERO);
                    displayMap.put("availableBalance", lsr == null ? BigDecimal.ZERO : lsr.getLeaveBalance());
                    displayMap.put("daysDetail", acDayDetails);
                    displayMap.put("daysSize", acDayDetails.size());
                    acRows.add(displayMap);
                }
            }

        }
        return acRows;
    }

    public List<Map<String, Object>> getLeaveApprovalDetailSections(String principalId,
            LeaveCalendarDocumentHeader lcdh, DateTime beginDate, DateTime endDate,
            List<LocalDateTime> leaveSummaryDates, String week, Map<String, Boolean> enableWeekDetails) {
        List<Map<String, Object>> acRows = new ArrayList<Map<String, Object>>();

        //CalendarEntry calendarEntry = LmServiceLocator.getLeaveCalendarService().getLeaveCalendarDocument(lcdh.getDocumentId()).getCalendarEntry();
        //CalendarEntries calendarEntry = TkServiceLocator.getCalendarEntriesService().getCalendarEntriesByBeginAndEndDate(lcdh.getBeginDate(), lcdh.getEndDate());
        LeaveSummaryContract leaveSummary;
        PrincipalHRAttributes pha;
        //         List<Date> leaveSummaryDates = LmServiceLocator.getLeaveSummaryService().getLeaveSummaryDates(calendarEntry);
        try {
            leaveSummary = LmServiceLocator.getLeaveSummaryService().getLeaveSummaryAsOfDate(principalId,
                    endDate.toLocalDate());
            pha = HrServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId,
                    endDate.toLocalDate());
        } catch (Exception e) {
            leaveSummary = null;
            pha = null;
        }
        List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocks(principalId,
                beginDate.toLocalDate(), endDate.toLocalDate());
        Map<LocalDateTime, Map<String, BigDecimal>> accrualCategoryLeaveHours = getAccrualCategoryLeaveHours(
                leaveBlocks, leaveSummaryDates);
        //get all accrual categories of this employee

        if (pha != null) {
            List<? extends AccrualCategoryContract> acList = HrServiceLocator.getAccrualCategoryService()
                    .getActiveAccrualCategoriesForLeavePlan(pha.getLeavePlan(), endDate.toLocalDate());
            for (AccrualCategoryContract ac : acList) {
                List<BigDecimal> acDayDetails = new ArrayList<BigDecimal>();
                Map<String, Object> displayMap = new HashMap<String, Object>();
                BigDecimal totalAmount = BigDecimal.ZERO;
                displayMap.put("accrualCategory", ac.getAccrualCategory());
                int index = 0;
                for (LocalDateTime leaveSummaryDate : leaveSummaryDates) {
                    if (leaveSummaryDate.compareTo(beginDate.toLocalDateTime()) >= 0
                            && leaveSummaryDate.compareTo(endDate.toLocalDateTime()) <= 0) {
                        acDayDetails.add(index, null);
                        if (accrualCategoryLeaveHours.get(leaveSummaryDate) != null) {
                            Map<String, BigDecimal> leaveHours = accrualCategoryLeaveHours.get(leaveSummaryDate);
                            if (leaveHours.containsKey(ac.getAccrualCategory())) {
                                BigDecimal amount = leaveHours.get(ac.getAccrualCategory());
                                totalAmount = totalAmount.add(amount);
                                acDayDetails.set(index, amount);
                            }
                        }
                        index++;
                    }
                }
                LeaveSummaryRowContract lsr = leaveSummary == null ? null
                        : leaveSummary.getLeaveSummaryRowForAccrualCtgy(ac.getAccrualCategory());
                if (!totalAmount.equals(BigDecimal.ZERO)) {
                    enableWeekDetails.put(week, Boolean.TRUE);

                }
                displayMap.put("periodUsage", totalAmount);
                displayMap.put("availableBalance", BigDecimal.ZERO);
                displayMap.put("availableBalance", lsr == null ? BigDecimal.ZERO : lsr.getLeaveBalance());
                displayMap.put("daysDetail", acDayDetails);
                displayMap.put("daysSize", acDayDetails.size());
                acRows.add(displayMap);
            }
        }
        return acRows;
    }

    @Override
    public List<Note> getNotesForDocument(String documentNumber) {
        return KewApiServiceLocator.getNoteService().getNotes(documentNumber);
    }

    @Override
    public Map<LocalDateTime, Map<String, BigDecimal>> getAccrualCategoryLeaveHours(List<LeaveBlock> leaveBlocks,
            List<LocalDateTime> leaveSummaryDates) {
        Map<LocalDateTime, Map<String, BigDecimal>> accrualCategoryLeaveHours = new LinkedHashMap<LocalDateTime, Map<String, BigDecimal>>();

        for (LocalDateTime leaveSummaryDate : leaveSummaryDates) {
            accrualCategoryLeaveHours.put(leaveSummaryDate, new LinkedHashMap<String, BigDecimal>());
        }

        for (LeaveBlock lb : leaveBlocks) {
            DateTime leaveDate = lb.getLeaveLocalDate().toDateTimeAtStartOfDay();

            AccrualCategoryContract ac = lb.getAccrualCategoryObj();
            if (ac != null && ac.getShowOnGrid().equals("Y")) {
                if (accrualCategoryLeaveHours.get(leaveDate.toLocalDateTime()) != null) {
                    Map<String, BigDecimal> leaveHours = accrualCategoryLeaveHours.get(leaveDate.toLocalDateTime());

                    BigDecimal amount = lb.getLeaveAmount();
                    if (leaveHours.get(ac.getAccrualCategory()) != null) {
                        amount = leaveHours.get(ac.getAccrualCategory()).add(lb.getLeaveAmount());
                    }

                    leaveHours.put(ac.getAccrualCategory(), amount);
                }
            }
        }

        return accrualCategoryLeaveHours;
    }

    @Override
    public void removeNonLeaveEmployees(List<String> principalIds) {
        if (CollectionUtils.isNotEmpty(principalIds)) {
            LocalDate asOfDate = LocalDate.now();
            List<String> idList = new ArrayList<String>();
            idList.addAll(principalIds);
            for (String principalId : idList) {
                boolean leaveFlag = false;
                List<Assignment> activeAssignments = HrServiceLocator.getAssignmentService()
                        .getAssignments(principalId, asOfDate);
                if (CollectionUtils.isNotEmpty(activeAssignments)) {
                    for (Assignment assignment : activeAssignments) {
                        if (assignment != null && assignment.getJob() != null
                                && assignment.getJob().isEligibleForLeave()) {
                            leaveFlag = true;
                            break;
                        }
                    }
                    if (!leaveFlag) { // employee is not eligible for leave, remove the id from principalIds
                        principalIds.remove(principalId);
                    }
                }
            }
        }
    }

    @Override
    public List<String> getLeavePrincipalIdsWithSearchCriteria(List<String> workAreaList, String calendarGroup,
            LocalDate effdt, LocalDate beginDate, LocalDate endDate) {
        if (CollectionUtils.isEmpty(workAreaList)) {
            return new ArrayList<String>();
        }

        List<String> principalIds = HrServiceLocator.getAssignmentService().getPrincipalIds(workAreaList, effdt,
                beginDate, endDate);
        LmServiceLocator.getLeaveApprovalService().removeNonLeaveEmployees(principalIds);

        if (CollectionUtils.isEmpty(principalIds)) {
            return new ArrayList<String>();
        }
        // use unique principalIds and selected calendarGroup to get unique ids from principalHRAttributes table
        List<String> idList = CollectionUtils.isEmpty(principalIds) ? new ArrayList<String>()
                : HrServiceLocator.getPrincipalHRAttributeService()
                        .getActiveEmployeesIdForLeaveCalendarAndIdList(calendarGroup, principalIds, endDate);

        return idList;
    }

    @Override
    public Map<String, LeaveCalendarDocumentHeaderContract> getPrincipalDocumentHeader(List<String> principalIds,
            DateTime payBeginDate, DateTime payEndDate) {
        Map<String, LeaveCalendarDocumentHeaderContract> principalDocumentHeader = new LinkedHashMap<String, LeaveCalendarDocumentHeaderContract>();
        for (String principalId : principalIds) {
            LeaveCalendarDocumentHeader lcdh = LmServiceLocator.getLeaveCalendarDocumentHeaderService()
                    .getDocumentHeader(principalId, payBeginDate, payEndDate);
            if (lcdh != null) {
                principalDocumentHeader.put(principalId, lcdh);
            }
        }

        return principalDocumentHeader;
    }

    @Override
    public boolean isActiveAssignmentFoundOnJobFlsaStatus(String principalId, String flsaStatus,
            boolean chkForLeaveEligible) {
        boolean isActiveAssFound = false;
        LocalDate asOfDate = LocalDate.now();
        List<Assignment> activeAssignments = HrServiceLocator.getAssignmentService().getAssignments(principalId,
                asOfDate);
        if (activeAssignments != null && !activeAssignments.isEmpty()) {
            for (Assignment assignment : activeAssignments) {
                if (assignment != null && assignment.getJob() != null && assignment.getJob().getFlsaStatus() != null
                        && assignment.getJob().getFlsaStatus().equalsIgnoreCase(flsaStatus)) {
                    if (chkForLeaveEligible) {
                        isActiveAssFound = assignment.getJob().isEligibleForLeave();
                        if (!isActiveAssFound) {
                            continue;
                        }
                    }
                    isActiveAssFound = true;
                    break;
                }
            }
        }
        return isActiveAssFound;
    }
}