001    /**
002     * Copyright 2004-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.hr.time.batch;
017    
018    import org.apache.commons.collections.CollectionUtils;
019    import org.apache.log4j.Logger;
020    import org.joda.time.DateTime;
021    import org.joda.time.LocalDate;
022    import org.joda.time.LocalDateTime;
023    import org.kuali.hr.lm.LMConstants;
024    import org.kuali.hr.lm.accrual.AccrualCategory;
025    import org.kuali.hr.lm.accrual.service.AccrualCategoryService;
026    import org.kuali.hr.lm.leaveSummary.LeaveSummary;
027    import org.kuali.hr.lm.leaveSummary.LeaveSummaryRow;
028    import org.kuali.hr.lm.leaveSummary.service.LeaveSummaryService;
029    import org.kuali.hr.lm.leaveblock.LeaveBlock;
030    import org.kuali.hr.lm.leaveblock.service.LeaveBlockService;
031    import org.kuali.hr.lm.leaveplan.LeavePlan;
032    import org.kuali.hr.lm.leaveplan.service.LeavePlanService;
033    import org.kuali.hr.time.assignment.Assignment;
034    import org.kuali.hr.time.assignment.service.AssignmentService;
035    import org.kuali.hr.time.calendar.service.CalendarEntriesService;
036    import org.kuali.hr.time.principal.PrincipalHRAttributes;
037    import org.kuali.hr.time.principal.service.PrincipalHRAttributesService;
038    import org.kuali.hr.time.service.base.TkServiceLocator;
039    import org.kuali.hr.time.util.TKUtils;
040    import org.kuali.hr.time.util.TkConstants;
041    import org.kuali.rice.core.api.config.property.ConfigContext;
042    import org.kuali.rice.kim.api.identity.principal.Principal;
043    import org.kuali.rice.kim.api.services.KimApiServiceLocator;
044    import org.quartz.Job;
045    import org.quartz.JobDataMap;
046    import org.quartz.JobExecutionContext;
047    import org.quartz.JobExecutionException;
048    
049    import java.sql.Date;
050    import java.sql.Timestamp;
051    import java.util.*;
052    
053    public class CarryOverJob implements Job{
054    
055            private static final Logger LOG = Logger.getLogger(CarryOverJob.class);
056    
057            private AccrualCategoryService accrualCategoryService;
058            private AssignmentService assignmentService;
059            private LeavePlanService leavePlanService;
060            private PrincipalHRAttributesService principalHRAttributesService;
061            private LeaveSummaryService leaveSummaryService;
062            private CalendarEntriesService calendarEntriesService;
063            private LeaveBlockService leaveBlockService;
064    
065            @Override
066            public void execute(JobExecutionContext context) throws JobExecutionException {
067            String batchUserPrincipalId = getBatchUserPrincipalId();
068    
069            if (batchUserPrincipalId != null) {
070                JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
071                String leavePlan = jobDataMap.getString("leavePlan");
072                if (leavePlan!= null) {
073    
074                    Date asOfDate = TKUtils.getCurrentDate();
075                    LeavePlan leavePlanObj = getLeavePlanService().getLeavePlan(leavePlan, asOfDate);
076                    List<Assignment> assignments = getAssignmentService().getActiveAssignments(asOfDate);
077    
078                    //holds a list of principalIds so this isn't run multiple time for the same person
079                    Set<String> principalIds = new HashSet<String>();
080                    for (Assignment assignment : assignments) {
081                        String principalId = assignment.getPrincipalId();
082                        if (assignment.getJob().isEligibleForLeave() && !principalIds.contains(principalId)) {
083    
084                            PrincipalHRAttributes principalHRAttributes = getPrincipalHRAttributesService().getPrincipalCalendar(principalId, asOfDate);
085                            principalIds.add(principalId);
086    
087                            if (principalHRAttributes != null) {
088                                Date serviceDate = principalHRAttributes.getServiceDate();
089                                if(serviceDate != null){
090    
091                                    if (leavePlanObj != null && leavePlanObj.getLeavePlan().equalsIgnoreCase(principalHRAttributes.getLeavePlan())) {
092    
093                                        DateTime leavePlanStartDate = getLeavePlanService().getFirstDayOfLeavePlan(leavePlan, TKUtils.getCurrentDate());
094    
095                                        DateTime lpPreviousLastDay = (new LocalDateTime(leavePlanStartDate)).toDateTime().minus(1);
096                                        DateTime lpPreviousFirstDay = new DateTime(getLeavePlanService().getFirstDayOfLeavePlan(leavePlan, new Date(lpPreviousLastDay.toDateTime().toDateMidnight().getMillis())));
097    
098                                        List<LeaveBlock> prevYearCarryOverleaveBlocks = getLeaveBlockService().getLeaveBlocksWithType(principalId,  lpPreviousFirstDay.toDateMidnight().toDate(), lpPreviousLastDay.toDateMidnight().toDate(), LMConstants.LEAVE_BLOCK_TYPE.CARRY_OVER);
099                                        LeaveSummary leaveSummary = getLeaveSummaryService().getLeaveSummaryAsOfDateWithoutFuture(principalId, new java.sql.Date(lpPreviousLastDay.getMillis()));
100                                        //no existing carry over blocks.  just create new
101                                        if(CollectionUtils.isEmpty(prevYearCarryOverleaveBlocks)){
102                                            getLeaveBlockService().saveLeaveBlocks(createCarryOverLeaveBlocks(principalId, lpPreviousLastDay, leaveSummary));
103                                        } else {
104                                            Map<String, LeaveBlock> existingCarryOver = new HashMap<String, LeaveBlock>(prevYearCarryOverleaveBlocks.size());
105                                            // just easier to get to things when in a map...
106                                            for (LeaveBlock lb : prevYearCarryOverleaveBlocks) {
107                                                existingCarryOver.put(lb.getAccrualCategory(), lb);
108                                            }
109    
110                                            // update existing first
111                                            for (String ac : existingCarryOver.keySet()) {
112                                                LeaveBlock carryOverBlock = existingCarryOver.get(ac);
113                                                LeaveSummaryRow lsr = leaveSummary.getLeaveSummaryRowForAccrualCtgy(ac);
114    
115                                                //update values
116                                                if(lsr.getAccruedBalance() != null)  {
117                                                    if(lsr.getMaxCarryOver() != null && lsr.getAccruedBalance().compareTo(lsr.getMaxCarryOver()) > 0 ){
118                                                        carryOverBlock.setLeaveAmount(lsr.getMaxCarryOver());
119                                                    } else {
120                                                        carryOverBlock.setLeaveAmount(lsr.getAccruedBalance());
121                                                    }
122                                                }
123                                                getLeaveBlockService().updateLeaveBlock(carryOverBlock, batchUserPrincipalId);
124                                                //remove row from leave summary
125                                                leaveSummary.getLeaveSummaryRows().remove(lsr);
126                                            }
127    
128    
129                                            // create for any new accrual categories
130                                            getLeaveBlockService().saveLeaveBlocks(createCarryOverLeaveBlocks(principalId, lpPreviousLastDay, leaveSummary));
131                                        }
132                                    }
133                                }
134                            }
135                        }
136                    }
137                }
138            } else {
139                String principalName = ConfigContext.getCurrentContextConfig().getProperty(TkConstants.BATCH_USER_PRINCIPAL_NAME);
140                LOG.error("Could not run batch jobs due to missing batch user " + principalName);
141            }
142            
143            }
144    
145            private AccrualCategoryService getAccrualCategoryService() {
146            if (accrualCategoryService == null) {
147                accrualCategoryService = TkServiceLocator.getAccrualCategoryService();
148            }
149                    return accrualCategoryService;
150            }
151    
152            public void setAccrualCategoryService(AccrualCategoryService accrualCategoryService) {
153                    this.accrualCategoryService = accrualCategoryService;
154            }
155    
156            private AssignmentService getAssignmentService() {
157                    if (assignmentService == null) {
158                assignmentService = TkServiceLocator.getAssignmentService();
159            }
160                    return assignmentService;
161            }
162    
163            public void setAssignmentService(AssignmentService assignmentService) {
164                    this.assignmentService = assignmentService;
165            }
166    
167            public LeavePlanService getLeavePlanService() {
168            if (leavePlanService == null) {
169                        leavePlanService = TkServiceLocator.getLeavePlanService();
170            }
171                    return leavePlanService;
172            }
173    
174            public void setLeavePlanService(LeavePlanService leavePlanService) {
175                    this.leavePlanService = leavePlanService;
176            }
177    
178            private PrincipalHRAttributesService getPrincipalHRAttributesService() {
179            if (principalHRAttributesService == null) {
180                        principalHRAttributesService = TkServiceLocator.getPrincipalHRAttributeService();
181            }
182                    return principalHRAttributesService;
183            }
184    
185            public void setPrincipalHRAttributesService(PrincipalHRAttributesService principalHRAttributesService) {
186                    this.principalHRAttributesService = principalHRAttributesService;
187            }
188    
189            private LeaveSummaryService getLeaveSummaryService() {
190            if (leaveSummaryService == null) {
191                        leaveSummaryService = TkServiceLocator.getLeaveSummaryService();
192            }
193                    return leaveSummaryService;
194            }
195    
196            public void setLeaveSummaryService(LeaveSummaryService leaveSummaryService) {
197                    this.leaveSummaryService = leaveSummaryService;
198            }
199    
200            private CalendarEntriesService getCalendarEntriesService() {
201            if (calendarEntriesService == null) {
202                        calendarEntriesService = TkServiceLocator.getCalendarEntriesService();
203            }
204                    return calendarEntriesService;
205            }
206    
207            public void setCalendarEntriesService(CalendarEntriesService calendarEntriesService) {
208                    this.calendarEntriesService = calendarEntriesService;
209            }
210    
211            private LeaveBlockService getLeaveBlockService() {
212            if (leaveBlockService == null) {
213                        leaveBlockService = TkServiceLocator.getLeaveBlockService();
214            }
215                    return leaveBlockService;
216            }
217    
218            public void setLeaveBlockService(LeaveBlockService leaveBlockService) {
219                    this.leaveBlockService = leaveBlockService;
220            }
221            
222            private List<LeaveBlock> createCarryOverLeaveBlocks(String principalId,
223                                                            DateTime prevCalEndDate,
224                                                            LeaveSummary leaveSummary) {
225    
226            List<LeaveBlock> leaveBlocks = new ArrayList<LeaveBlock>();
227            List<LeaveSummaryRow> leaveSummaryRows = leaveSummary.getLeaveSummaryRows();
228            if(leaveSummaryRows !=null && !leaveSummaryRows.isEmpty()){
229    
230                for(LeaveSummaryRow lsr : leaveSummaryRows){
231                    AccrualCategory accrualCategory = getAccrualCategoryService().getAccrualCategory(lsr.getAccrualCategoryId());
232    
233                    LeaveBlock leaveBlock = new LeaveBlock();
234                    leaveBlock.setAccrualCategory(lsr.getAccrualCategory());
235                    leaveBlock.setLeaveDate(TKUtils.getTimelessDate(prevCalEndDate.toDateMidnight().toDate()));
236                    leaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.CARRY_OVER);
237    
238                    //More than one earn code can be associated with an accrual category. Which one does this get?
239                    if(accrualCategory != null && accrualCategory.getEarnCode() != null ){
240                        leaveBlock.setEarnCode(accrualCategory.getEarnCode());
241                    }
242    
243                    leaveBlock.setDateAndTime(new Timestamp(new java.util.Date().getTime()));
244                    leaveBlock.setAccrualGenerated(true);
245                    leaveBlock.setBlockId(0L);
246    
247                    // ASk--Set null
248                    leaveBlock.setScheduleTimeOffId(null);
249    
250                    if(lsr.getAccruedBalance() != null)  {
251                        if(lsr.getMaxCarryOver() != null && lsr.getAccruedBalance().compareTo(lsr.getMaxCarryOver()) > 0 ){
252                            leaveBlock.setLeaveAmount(lsr.getMaxCarryOver());
253                        } else {
254                            leaveBlock.setLeaveAmount(lsr.getAccruedBalance());
255                        }
256                    }
257    
258                    leaveBlock.setPrincipalId(principalId);
259                    leaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED);
260    
261                    // Set EarnCode
262                    if(leaveBlock.getLeaveAmount() != null && leaveBlock.getEarnCode() != null) {
263                        leaveBlocks.add(leaveBlock);
264                    }
265                }
266            }
267    
268    
269                    return leaveBlocks;
270            }
271    
272        private String getBatchUserPrincipalId() {
273            String principalId = null;
274    
275            String principalName = ConfigContext.getCurrentContextConfig().getProperty(TkConstants.BATCH_USER_PRINCIPAL_NAME);
276            Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalName);
277            if (principal != null) {
278                principalId = principal.getPrincipalId();
279            }
280    
281            return principalId;
282        }
283    
284    }