1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.kpme.tklm.leave.calendar.service;
17
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.log4j.Logger;
21 import org.joda.time.DateTime;
22 import org.joda.time.LocalDate;
23 import org.kuali.kpme.core.api.assignment.Assignment;
24 import org.kuali.kpme.core.api.calendar.entry.CalendarEntry;
25 import org.kuali.kpme.core.api.job.Job;
26 import org.kuali.kpme.core.batch.BatchJobUtil;
27 import org.kuali.kpme.core.document.calendar.CalendarDocument;
28 import org.kuali.kpme.core.role.KPMERole;
29 import org.kuali.kpme.core.service.HrServiceLocator;
30 import org.kuali.kpme.core.util.HrConstants;
31 import org.kuali.kpme.core.util.TKUtils;
32 import org.kuali.kpme.tklm.api.leave.block.LeaveBlock;
33 import org.kuali.kpme.tklm.common.LMConstants;
34 import org.kuali.kpme.tklm.leave.calendar.LeaveCalendarDocument;
35 import org.kuali.kpme.tklm.leave.calendar.dao.LeaveCalendarDao;
36 import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
37 import org.kuali.kpme.tklm.leave.workflow.LeaveCalendarDocumentHeader;
38 import org.kuali.kpme.tklm.leave.workflow.LeaveRequestDocument;
39 import org.kuali.kpme.tklm.time.service.TkServiceLocator;
40 import org.kuali.rice.core.api.config.property.ConfigContext;
41 import org.kuali.rice.kew.api.KewApiServiceLocator;
42 import org.kuali.rice.kew.api.WorkflowDocument;
43 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
44 import org.kuali.rice.kew.api.action.ActionRequest;
45 import org.kuali.rice.kew.api.exception.WorkflowException;
46 import org.kuali.rice.kew.api.note.Note;
47 import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
48 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
49 import org.kuali.rice.krad.service.KRADServiceLocator;
50 import org.kuali.rice.krad.util.GlobalVariables;
51
52 import java.util.ArrayList;
53 import java.util.List;
54 import java.util.Map;
55
56 public class LeaveCalendarServiceImpl implements LeaveCalendarService {
57
58 private static final Logger LOG = Logger.getLogger(LeaveCalendarServiceImpl.class);
59
60 private LeaveCalendarDao leaveCalendarDao;
61
62 @Override
63 public LeaveCalendarDocument getLeaveCalendarDocument(String documentId) {
64 LeaveCalendarDocument lcd;
65 LeaveCalendarDocumentHeader lcdh = LmServiceLocator.getLeaveCalendarDocumentHeaderService().getDocumentHeader(documentId);
66
67 if (lcdh != null) {
68 lcd = new LeaveCalendarDocument(lcdh);
69 CalendarEntry pce = HrServiceLocator.getCalendarEntryService().getCalendarDatesByPayEndDate(lcdh.getPrincipalId(), lcdh.getEndDateTime(), HrConstants.LEAVE_CALENDAR_TYPE);
70 lcd.setCalendarEntry(pce);
71 } else {
72 LOG.error("Could not find LeaveCalendarDocumentHeader for DocumentID: " + documentId);
73 return null;
74 }
75
76 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForDocumentId(documentId);
77 lcd.setLeaveBlocks(leaveBlocks);
78
79
80 Map<LocalDate, List<Assignment>> assignments = HrServiceLocator.getAssignmentService().getAssignmentsByCalEntryForLeaveCalendar(lcdh.getPrincipalId(), lcd.getCalendarEntry());
81 lcd.setAssignments(assignments);
82
83 return lcd;
84 }
85
86 @Override
87 public LeaveCalendarDocument openLeaveCalendarDocument(String principalId, CalendarEntry calEntry) throws WorkflowException {
88 LeaveCalendarDocument doc;
89
90 DateTime begin = calEntry.getBeginPeriodFullDateTime();
91 DateTime end = calEntry.getEndPeriodFullDateTime();
92
93 LeaveCalendarDocumentHeader header = LmServiceLocator.getLeaveCalendarDocumentHeaderService().getDocumentHeader(principalId, begin, end);
94 if (header == null) {
95 EntityNamePrincipalName person = KimApiServiceLocator.getIdentityService().getDefaultNamesForPrincipalId(principalId);
96 String principalName = person != null && person.getDefaultName() != null ? person.getDefaultName().getCompositeName() : StringUtils.EMPTY;
97 String beginDateString = TKUtils.formatDate(begin.toLocalDate());
98 String endDateString = TKUtils.formatDate(end.toLocalDate());
99 String leaveCalendarDocumentTitle = LeaveCalendarDocument.LEAVE_CALENDAR_DOCUMENT_TYPE + " - " + principalName + " (" + principalId + ") - " + beginDateString + "-" + endDateString;
100
101 doc = initiateWorkflowDocument(principalId, begin, end, calEntry, LeaveCalendarDocument.LEAVE_CALENDAR_DOCUMENT_TYPE, leaveCalendarDocumentTitle);
102 } else {
103 doc = getLeaveCalendarDocument(header.getDocumentId());
104 }
105 if (doc != null) {
106 doc.setCalendarEntry(calEntry);
107 }
108
109 return doc;
110 }
111
112
113 public boolean shouldCreateLeaveDocument(String principalId, CalendarEntry calEntry){
114 if (StringUtils.isEmpty(principalId) || calEntry == null) {
115 return false;
116 }
117
118 boolean isPlanningCalendar = LmServiceLocator.getLeaveCalendarService().isLeavePlanningCalendar(principalId, calEntry.getBeginPeriodFullDateTime().toLocalDate(), calEntry.getEndPeriodFullDateTime().toLocalDate());
119 if (isPlanningCalendar) {
120 return false;
121 }
122
123 List<Assignment> assignments = HrServiceLocator.getAssignmentService().getAssignmentsByPayEntry(principalId, calEntry);
124 List<Assignment> results = HrServiceLocator.getAssignmentService().filterAssignments(assignments, HrConstants.FLSA_STATUS_EXEMPT, true);
125 return CollectionUtils.isNotEmpty(results);
126 }
127
128 protected LeaveCalendarDocument initiateWorkflowDocument(String principalId, DateTime payBeginDate, DateTime payEndDate, CalendarEntry calendarEntry, String documentType, String title) throws WorkflowException {
129 LeaveCalendarDocument leaveCalendarDocument;
130 WorkflowDocument workflowDocument;
131
132 workflowDocument = WorkflowDocumentFactory.createDocument(principalId, documentType, title);
133
134 String status = workflowDocument.getStatus().getCode();
135 LeaveCalendarDocumentHeader documentHeader = new LeaveCalendarDocumentHeader(workflowDocument.getDocumentId(), principalId, payBeginDate.toDate(), payEndDate.toDate(), status);
136
137 documentHeader.setDocumentId(workflowDocument.getDocumentId());
138 documentHeader.setDocumentStatus(HrConstants.ROUTE_STATUS.INITIATED);
139
140 KRADServiceLocator.getBusinessObjectService().save(documentHeader);
141
142 leaveCalendarDocument = new LeaveCalendarDocument(documentHeader);
143 leaveCalendarDocument.setCalendarEntry(calendarEntry);
144 loadLeaveCalendarDocumentData(leaveCalendarDocument, principalId, calendarEntry);
145 TkServiceLocator.getTkSearchableAttributeService().updateSearchableAttribute(leaveCalendarDocument, payEndDate.toLocalDate());
146
147 updateLeaveBlockDocumentIds(principalId, payBeginDate.toLocalDate(), payEndDate.toLocalDate(), workflowDocument.getDocumentId());
148
149 updatePlannedLeaveBlocks(principalId, payBeginDate.toLocalDate(), payEndDate.toLocalDate());
150
151 return leaveCalendarDocument;
152 }
153
154 private void updateLeaveBlockDocumentIds(String principalId, LocalDate beginDate, LocalDate endDate, String documentId) {
155 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocks(principalId, beginDate, endDate);
156 List<LeaveBlock> lbToUpdate = new ArrayList<LeaveBlock>();
157 for (LeaveBlock leaveBlock : leaveBlocks) {
158 LeaveBlock.Builder builder = LeaveBlock.Builder.create(leaveBlock);
159 builder.setDocumentId(documentId);
160 lbToUpdate.add(builder.build());
161 }
162
163 LmServiceLocator.getLeaveBlockService().saveLeaveBlocks(lbToUpdate);
164 }
165
166 private void updatePlannedLeaveBlocks(String principalId, LocalDate beginDate, LocalDate endDate) {
167 String batchUserPrincipalId = BatchJobUtil.getBatchUserPrincipalId();
168
169 if (batchUserPrincipalId != null) {
170 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocks(principalId, beginDate, endDate);
171
172 for (LeaveBlock leaveBlock : leaveBlocks) {
173 if (StringUtils.equals(leaveBlock.getRequestStatus(), HrConstants.REQUEST_STATUS.PLANNED)
174 || StringUtils.equals(leaveBlock.getRequestStatus(), HrConstants.REQUEST_STATUS.DEFERRED)) {
175 LmServiceLocator.getLeaveBlockService().deleteLeaveBlock(leaveBlock.getLmLeaveBlockId(), batchUserPrincipalId);
176 } else if (StringUtils.equals(leaveBlock.getRequestStatus(), HrConstants.REQUEST_STATUS.REQUESTED)) {
177 if (StringUtils.equals(getInitiateLeaveRequestAction(), LMConstants.INITIATE_LEAVE_REQUEST_ACTION_OPTIONS.DELETE)) {
178 LmServiceLocator.getLeaveRequestDocumentService().suCancelLeave(
179 leaveBlock.getLeaveRequestDocumentId(), batchUserPrincipalId);
180 LmServiceLocator.getLeaveBlockService().deleteLeaveBlock(leaveBlock.getLmLeaveBlockId(), batchUserPrincipalId);
181 } else if (StringUtils.equals(getInitiateLeaveRequestAction(), LMConstants.INITIATE_LEAVE_REQUEST_ACTION_OPTIONS.APPROVE)) {
182 List<LeaveRequestDocument> leaveRequestDocuments = LmServiceLocator.getLeaveRequestDocumentService().getLeaveRequestDocumentsByLeaveBlockId(leaveBlock.getLmLeaveBlockId());
183 for (LeaveRequestDocument leaveRequestDocument : leaveRequestDocuments) {
184 LmServiceLocator.getLeaveRequestDocumentService().suBlanketApproveLeave(leaveRequestDocument.getDocumentNumber(), batchUserPrincipalId);
185 }
186 }
187 }
188 }
189 } else {
190 String principalName = BatchJobUtil.getBatchUserPrincipalName();
191 LOG.error("Could not update leave request blocks due to missing batch user " + principalName);
192 }
193 }
194
195 private String getInitiateLeaveRequestAction() {
196 return ConfigContext.getCurrentContextConfig().getProperty(LMConstants.INITIATE_LEAVE_REQUEST_ACTION);
197 }
198
199
200
201
202
203
204
205
206 protected void loadLeaveCalendarDocumentData(LeaveCalendarDocument ldoc, String principalId, CalendarEntry calEntry) {
207 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksForDocumentId(ldoc.getDocumentId());
208 ldoc.setLeaveBlocks(leaveBlocks);
209 Map<LocalDate, List<Assignment>> assignments = HrServiceLocator.getAssignmentService().getAssignmentsByCalEntryForLeaveCalendar(principalId, calEntry);
210 ldoc.setAssignments(assignments);
211 }
212
213 public LeaveCalendarDao getLeaveCalendarDao() {
214 return leaveCalendarDao;
215 }
216
217 public void setLeaveCalendarDao(LeaveCalendarDao leaveCalendarDao) {
218 this.leaveCalendarDao = leaveCalendarDao;
219 }
220
221 @Override
222 public LeaveCalendarDocument getLeaveCalendarDocument(
223 String principalId, CalendarEntry calendarEntry) {
224 LeaveCalendarDocument leaveCalendarDocument = new LeaveCalendarDocument(calendarEntry);
225 LeaveCalendarDocumentHeader lcdh = new LeaveCalendarDocumentHeader();
226 lcdh.setBeginDate(calendarEntry.getBeginPeriodFullDateTime().toDate());
227 lcdh.setEndDate(calendarEntry.getEndPeriodFullDateTime().toDate());
228 leaveCalendarDocument.setDocumentHeader(lcdh);
229
230 Map<LocalDate, List<Assignment>> assignments = HrServiceLocator.getAssignmentService().getAssignmentsByCalEntryForLeaveCalendar(principalId, calendarEntry);
231 leaveCalendarDocument.setAssignments(assignments);
232 return leaveCalendarDocument;
233 }
234
235 @Override
236 public void routeLeaveCalendar(String principalId, LeaveCalendarDocument leaveCalendarDocument) {
237 leaveCalendarDocumentAction(HrConstants.DOCUMENT_ACTIONS.ROUTE, principalId, leaveCalendarDocument);
238 }
239
240 @Override
241 public void routeLeaveCalendar(String principalId, LeaveCalendarDocument leaveCalendarDocument, String action) {
242 leaveCalendarDocumentAction(action, principalId, leaveCalendarDocument);
243 }
244
245 @Override
246 public void approveLeaveCalendar(String principalId, LeaveCalendarDocument leaveCalendarDocument) {
247 leaveCalendarDocumentAction(HrConstants.DOCUMENT_ACTIONS.APPROVE, principalId, leaveCalendarDocument);
248 }
249
250 @Override
251 public void approveLeaveCalendar(String principalId, LeaveCalendarDocument leaveCalendarDocument, String action) {
252 leaveCalendarDocumentAction(action, principalId, leaveCalendarDocument);
253 }
254
255 @Override
256 public void disapproveLeaveCalendar(String principalId, LeaveCalendarDocument leaveCalendarDocument) {
257 leaveCalendarDocumentAction(HrConstants.DOCUMENT_ACTIONS.DISAPPROVE, principalId, leaveCalendarDocument);
258 }
259
260 public boolean isReadyToApprove(CalendarDocument document) {
261 if (document == null) {
262 return false;
263 }
264 List<LeaveBlock> leaveBlocks = LmServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(document.getPrincipalId(),
265 document.getCalendarEntry().getBeginPeriodFullDateTime().toLocalDate(), document.getCalendarEntry().getEndPeriodFullDateTime().toLocalDate(), LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
266 leaveBlocks.addAll(LmServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(document.getPrincipalId(),
267 document.getCalendarEntry().getBeginPeriodFullDateTime().toLocalDate(), document.getCalendarEntry().getEndPeriodFullDateTime().toLocalDate(), LMConstants.LEAVE_BLOCK_TYPE.LEAVE_PAYOUT));
268 for(LeaveBlock lb : leaveBlocks) {
269 if(!StringUtils.equals(lb.getRequestStatus(),HrConstants.REQUEST_STATUS.APPROVED) &&
270 !StringUtils.equals(lb.getRequestStatus(), HrConstants.REQUEST_STATUS.DISAPPROVED))
271 return false;
272 }
273
274 LeaveCalendarDocumentHeader lcdh = LmServiceLocator.getLeaveCalendarDocumentHeaderService().getMinBeginDatePendingLeaveCalendar(document.getPrincipalId());
275 if (lcdh != null){
276
277 if (LmServiceLocator.getLeaveCalendarDocumentHeaderService().getDocumentHeader(document.getDocumentId()).getBeginDate().compareTo(lcdh.getEndDate()) >= 0){
278 return false;
279 }
280 }
281
282 return true;
283 }
284
285 protected void leaveCalendarDocumentAction(String action, String principalId, LeaveCalendarDocument leaveCalendarDocument) {
286 WorkflowDocument wd;
287 if (leaveCalendarDocument != null) {
288 String rhid = leaveCalendarDocument.getDocumentId();
289 wd = WorkflowDocumentFactory.loadDocument(principalId, rhid);
290 List<ActionRequest> actionRequests = KewApiServiceLocator.getWorkflowDocumentService().getPendingActionRequests(rhid);
291
292 if (StringUtils.equals(action, HrConstants.DOCUMENT_ACTIONS.ROUTE)) {
293 wd.route("Routing for Approval");
294 } else if (StringUtils.equals(action, HrConstants.BATCH_JOB_ACTIONS.BATCH_JOB_ROUTE)) {
295 Note.Builder builder = Note.Builder.create(rhid, principalId);
296 builder.setCreateDate(new DateTime());
297 builder.setText("Routed via Employee Approval batch job");
298 KewApiServiceLocator.getNoteService().createNote(builder.build());
299
300 wd.route("Batch job routing leave calendar");
301 } else if (StringUtils.equals(action, HrConstants.DOCUMENT_ACTIONS.APPROVE)) {
302 if (HrServiceLocator.getHRPermissionService().canSuperUserAdministerCalendarDocument(GlobalVariables.getUserSession().getPrincipalId(), leaveCalendarDocument)
303 && !HrServiceLocator.getHRPermissionService().canApproveCalendarDocument(GlobalVariables.getUserSession().getPrincipalId(), leaveCalendarDocument)) {
304 wd.superUserBlanketApprove("Superuser approving timesheet.");
305 } else {
306 wd.approve("Approving timesheet.");
307 }
308 } else if (StringUtils.equals(action, HrConstants.BATCH_JOB_ACTIONS.BATCH_JOB_APPROVE)) {
309 boolean approverFlag = false;
310 for (ActionRequest ar : actionRequests) {
311 if(StringUtils.equals(ar.getQualifiedRoleNameLabel(), KPMERole.APPROVER.getRoleName())) {
312 approverFlag = true;
313 break;
314 }
315 }
316
317
318 if(approverFlag) {
319
320 Note.Builder builder = Note.Builder.create(rhid, principalId);
321 builder.setCreateDate(new DateTime());
322 builder.setText("Approved via Supervisor Approval batch job");
323 KewApiServiceLocator.getNoteService().createNote(builder.build());
324 wd.approve("Supervisor Batch job approving leave calendar on behalf of approvers.");
325 }
326 } else if (StringUtils.equals(action, HrConstants.BATCH_JOB_ACTIONS.PAYROLL_JOB_APPROVE)) {
327 boolean payrollProcessorFlag = false;
328 for (ActionRequest ar : actionRequests) {
329 if(StringUtils.equals(ar.getQualifiedRoleNameLabel(), KPMERole.PAYROLL_PROCESSOR.getRoleName())) {
330 payrollProcessorFlag = true;
331 break;
332 }
333 }
334 if(payrollProcessorFlag) {
335 Note.Builder builder = Note.Builder.create(rhid, principalId);
336 builder.setCreateDate(new DateTime());
337 builder.setText("Approved via Payroll Processor Approval batch job");
338 KewApiServiceLocator.getNoteService().createNote(builder.build());
339 wd.approve("Payroll Processor Batch job approving leave calendar on behalf of approvers.");
340 }
341 } else if (StringUtils.equals(action, HrConstants.DOCUMENT_ACTIONS.DISAPPROVE)) {
342 if (HrServiceLocator.getHRPermissionService().canSuperUserAdministerCalendarDocument(GlobalVariables.getUserSession().getPrincipalId(), leaveCalendarDocument)
343 && !HrServiceLocator.getHRPermissionService().canApproveCalendarDocument(GlobalVariables.getUserSession().getPrincipalId(), leaveCalendarDocument)) {
344 wd.superUserDisapprove("Superuser disapproving leave calendar.");
345 } else {
346 wd.disapprove("Disapproving timesheet.");
347 }
348 }
349 }
350 }
351
352 public boolean isLeavePlanningCalendar(String principalId, LocalDate beginDate, LocalDate endDate) {
353 LocalDate today = LocalDate.now();
354
355 List<Job> jobs = HrServiceLocator.getJobService().getJobs(principalId, endDate);
356 for (Job job : jobs) {
357
358 if (job.isEligibleForLeave()) {
359
360 if (job.getFlsaStatus().equalsIgnoreCase(HrConstants.FLSA_STATUS_NON_EXEMPT)) {
361 return true;
362 } else {
363
364 if ( beginDate.isAfter(today) ) {
365
366 return true;
367 } else {
368
369 return false;
370 }
371 }
372 } else {
373
374 return false;
375 }
376 }
377 return false;
378 }
379
380 }
381