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 (Map.Entry<String, LeaveBlock> entry : existingCarryOver.entrySet()) {
112 LeaveBlock carryOverBlock = entry.getValue();
113 LeaveSummaryRow lsr = leaveSummary.getLeaveSummaryRowForAccrualCtgy(entry.getKey());
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 principalName = ConfigContext.getCurrentContextConfig().getProperty(TkConstants.BATCH_USER_PRINCIPAL_NAME);
274 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalName);
275 return principal == null ? null : principal.getPrincipalId();
276 }
277
278 }