001/**
002 * Copyright 2004-2014 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 */
016package org.kuali.kpme.tklm.leave.request.service;
017
018
019import org.apache.commons.lang.StringUtils;
020import org.apache.log4j.Logger;
021import org.kuali.kpme.core.api.assignment.Assignment;
022import org.kuali.kpme.core.api.calendar.entry.CalendarEntry;
023import org.kuali.kpme.core.api.job.Job;
024import org.kuali.kpme.core.api.job.JobContract;
025import org.kuali.kpme.core.api.workarea.WorkArea;
026import org.kuali.kpme.core.calendar.entry.CalendarEntryBo;
027import org.kuali.kpme.core.service.HrServiceLocator;
028import org.kuali.kpme.core.util.HrContext;
029import org.kuali.kpme.core.util.TKUtils;
030import org.kuali.kpme.tklm.api.leave.block.LeaveBlock;
031import org.kuali.kpme.tklm.leave.request.LeaveRequestActionValue;
032import org.kuali.kpme.tklm.leave.request.dao.LeaveRequestDocumentDao;
033import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
034import org.kuali.kpme.tklm.leave.workflow.LeaveRequestDocument;
035import org.kuali.rice.kew.api.KewApiServiceLocator;
036import org.kuali.rice.kew.api.WorkflowDocument;
037import org.kuali.rice.kew.api.action.*;
038import org.kuali.rice.kew.api.document.DocumentStatus;
039import org.kuali.rice.kew.api.exception.WorkflowException;
040import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
041import org.kuali.rice.kim.api.identity.principal.Principal;
042import org.kuali.rice.kim.api.services.KimApiServiceLocator;
043import org.kuali.rice.krad.bo.DocumentHeader;
044import org.kuali.rice.krad.exception.UnknownDocumentIdException;
045import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
046import org.kuali.rice.krad.util.GlobalVariables;
047
048import java.util.ArrayList;
049import java.util.HashMap;
050import java.util.List;
051import java.util.Map;
052
053public class LeaveRequestDocumentServiceImpl implements LeaveRequestDocumentService {
054    private static final Logger LOG = Logger.getLogger(LeaveRequestDocumentServiceImpl.class);
055    private LeaveRequestDocumentDao leaveRequestDocumentDao;
056
057    @Override
058    public LeaveRequestDocument getLeaveRequestDocument(String documentId) {
059        LeaveRequestDocument document = null;
060        try {
061            document = (LeaveRequestDocument)KRADServiceLocatorWeb.getDocumentService().getByDocumentHeaderId(documentId);
062        } catch (WorkflowException e) {
063            LOG.error("Document with documentId: " + documentId + " does not exist");
064        } catch (UnknownDocumentIdException e) {
065                LOG.error("Document with documentId: " + documentId + " does not exist");
066            return document;
067        }
068        return document;
069    }
070    
071    @Override
072    public List<LeaveRequestDocument> getLeaveRequestDocumentsByLeaveBlockId(String leaveBlockId) {
073        List<LeaveRequestDocument> docList = getLeaveRequestDocumentDao().getLeaveRequestDocumentsByLeaveBlockId(leaveBlockId);
074        List<LeaveRequestDocument> results = new ArrayList<LeaveRequestDocument>();
075        for(LeaveRequestDocument aDoc : docList) {
076                LeaveRequestDocument lrd = this.getLeaveRequestDocument(aDoc.getDocumentNumber());              
077                if(lrd != null){
078                        results.add(lrd);
079                }
080        }
081        return results;
082    }
083
084    @Override
085    public LeaveRequestDocument saveLeaveRequestDocument(LeaveRequestDocument document) {
086        LeaveRequestDocument lrd = null;
087        try {
088            lrd = (LeaveRequestDocument)KRADServiceLocatorWeb.getDocumentService().saveDocument(document);
089        } catch (WorkflowException e) {
090            LOG.error(e.getStackTrace());
091            return null;
092        }
093        return lrd;
094    }
095
096    @Override
097    public LeaveRequestDocument createLeaveRequestDocument(String leaveBlockId) {
098        LeaveRequestDocument lrd = initiateLeaveRequestDocument(HrContext.getTargetPrincipalId(), leaveBlockId);
099
100        return saveLeaveRequestDocument(lrd);
101    }
102
103    @Override
104    public void requestLeave(String documentId) {
105        LeaveRequestDocument doc = getLeaveRequestDocument(documentId);
106        doc.getDocumentHeader().getWorkflowDocument().route("");
107
108    }
109
110    @Override
111    public void approveLeave(String documentId, String principalId, String reason) {
112        //verify principal has an action item to approve...
113        //KewApiServiceLocator.
114        LeaveRequestDocument doc = getLeaveRequestDocument(documentId);
115        initiateSearchableAttributes(doc);
116        //do we need to switch ids?
117        doc.getDocumentHeader().getWorkflowDocument().switchPrincipal(principalId);
118        ValidActions validActions = doc.getDocumentHeader().getWorkflowDocument().getValidActions();
119        if (validActions.getValidActions().contains(ActionType.APPROVE)) {
120                if(StringUtils.isNotEmpty(reason)) {
121                doc.setDescription(reason);
122                saveLeaveRequestDocument(doc);
123            }
124            doc.getDocumentHeader().getWorkflowDocument().approve("");
125        }
126    }
127
128    @Override
129    public void disapproveLeave(String documentId, String principalId, String reason) {
130        LeaveRequestDocument doc = getLeaveRequestDocument(documentId);
131        initiateSearchableAttributes(doc);
132        doc.getDocumentHeader().getWorkflowDocument().switchPrincipal(principalId);
133        ValidActions validActions = doc.getDocumentHeader().getWorkflowDocument().getValidActions();        
134        if (validActions.getValidActions().contains(ActionType.DISAPPROVE)) {
135                if(StringUtils.isNotEmpty(reason)) {
136                doc.setDescription(reason);
137                saveLeaveRequestDocument(doc);
138            }
139            doc.getDocumentHeader().getWorkflowDocument().disapprove("");
140        }
141    }
142
143    @Override
144    public void deferLeave(String documentId, String principalId, String reason) {
145        LeaveRequestDocument doc = getLeaveRequestDocument(documentId);
146        initiateSearchableAttributes(doc);
147        doc.getDocumentHeader().getWorkflowDocument().switchPrincipal(principalId);
148        ValidActions validActions = doc.getDocumentHeader().getWorkflowDocument().getValidActions();       
149        if (validActions.getValidActions().contains(ActionType.CANCEL)) {
150                 if(StringUtils.isNotEmpty(reason)) {
151                doc.setDescription(reason);
152                saveLeaveRequestDocument(doc);
153             }
154                doc.getDocumentHeader().getWorkflowDocument().cancel("");
155        }
156    }
157    
158    @Override
159    public void recallAndCancelLeave(String documentId, String principalId, String reason) {
160        LeaveRequestDocument doc = getLeaveRequestDocument(documentId);
161        initiateSearchableAttributes(doc);
162        if (principalId.equals(doc.getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId())) {
163            doc.getDocumentHeader().getWorkflowDocument().switchPrincipal(principalId);
164            if(StringUtils.isNotEmpty(reason)) {
165                doc.setDescription(reason);
166                saveLeaveRequestDocument(doc);
167             }
168            doc.getDocumentHeader().getWorkflowDocument().recall("", true);
169        }
170    }
171
172    @Override
173    public void suBlanketApproveLeave(String documentId, String principalId) {
174        WorkflowDocumentActionsService docActionService = KewApiServiceLocator.getWorkflowDocumentActionsService();
175        DocumentActionParameters parameters = DocumentActionParameters.create(documentId, principalId);
176        docActionService.superUserBlanketApprove(parameters, true);
177    }
178
179    @Override
180    public void suCancelLeave(String documentId, String principalId) {
181        if (StringUtils.isNotEmpty(documentId)) {
182            WorkflowDocumentActionsService docActionService = KewApiServiceLocator.getWorkflowDocumentActionsService();
183            DocumentActionParameters parameters = DocumentActionParameters.create(documentId, principalId);
184            docActionService.superUserCancel(parameters, true);
185        }
186    }
187
188    public LeaveRequestDocumentDao getLeaveRequestDocumentDao() {
189        return leaveRequestDocumentDao;
190    }
191
192    public void setLeaveRequestDocumentDao(LeaveRequestDocumentDao leaveRequestDocumentDao) {
193        this.leaveRequestDocumentDao = leaveRequestDocumentDao;
194    }
195
196    private LeaveRequestDocument initiateLeaveRequestDocument(String principalId, String leaveBlockId) {
197        //LeaveRequestDocument leaveRequestDocument = new LeaveRequestDocument(leaveBlockId);
198        LeaveRequestDocument leaveRequestDocument = null;
199        try {
200            leaveRequestDocument = (LeaveRequestDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument(LeaveRequestDocument.LEAVE_REQUEST_DOCUMENT_TYPE);
201        } catch (WorkflowException e) {
202            LOG.error(e.getMessage());
203            return null;
204        }
205        
206        EntityNamePrincipalName person = KimApiServiceLocator.getIdentityService().getDefaultNamesForPrincipalId(principalId);
207        LeaveBlock leaveBlock = LmServiceLocator.getLeaveBlockService().getLeaveBlock(leaveBlockId);
208
209        String principalName = person != null && person.getDefaultName() != null ? person.getDefaultName().getCompositeName() : StringUtils.EMPTY;
210        String leaveRequestDateString = leaveBlock != null ? TKUtils.formatDate(leaveBlock.getLeaveLocalDate()) : StringUtils.EMPTY;
211        String leaveRequestDocumentTitle = principalName + " (" + principalId + ") - " + leaveRequestDateString;
212        
213        leaveRequestDocument.setLmLeaveBlockId(leaveBlockId);
214        leaveRequestDocument.getDocumentHeader().setDocumentDescription(leaveRequestDocumentTitle);
215        leaveRequestDocument.setDescription(leaveBlock != null ? leaveBlock.getDescription() : StringUtils.EMPTY);
216        leaveRequestDocument.setActionCode(LeaveRequestActionValue.NO_ACTION.getCode());
217        initiateSearchableAttributes(leaveRequestDocument);
218
219        return leaveRequestDocument;
220    }
221
222    private void initiateSearchableAttributes(LeaveRequestDocument leaveRequestDocument) {
223        DocumentHeader dh = leaveRequestDocument.getDocumentHeader();
224        WorkflowDocument workflowDocument = dh.getWorkflowDocument();
225        if (!DocumentStatus.FINAL.equals(workflowDocument.getStatus())) {
226            try {
227                workflowDocument.setApplicationContent(createSearchableAttributeXml(leaveRequestDocument, leaveRequestDocument.getLeaveBlock()));
228                workflowDocument.saveDocument("");
229                if (!"I".equals(workflowDocument.getStatus().getCode())) {
230                    if (GlobalVariables.getUserSession() != null && workflowDocument.getInitiatorPrincipalId().equals(GlobalVariables.getUserSession().getPrincipalId())) {
231                        workflowDocument.saveDocument("");
232                    } else{
233                        workflowDocument.saveDocumentData();
234                    }
235                } else{
236                    workflowDocument.saveDocument("");
237                }
238
239
240            } catch (Exception e) {
241                LOG.warn("Exception during searchable attribute update.");
242                throw new RuntimeException(e);
243            }
244        }
245    }
246
247    private String createSearchableAttributeXml(LeaveRequestDocument document, LeaveBlock leaveBlock) {
248        List<Long> workAreas = new ArrayList<Long>();
249        Map<String,List<Long>> deptToListOfWorkAreas = new HashMap<String,List<Long>>();
250        List<String> salGroups = new ArrayList<String>();
251        CalendarEntry ce = getCalendarEntry(leaveBlock);
252        Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(document.getLeaveBlock().getPrincipalId());
253        if (ce != null) {
254            List<Assignment> assignments = HrServiceLocator.getAssignmentService().getAllAssignmentsByCalEntryForLeaveCalendar(leaveBlock.getPrincipalId(), ce);
255
256            for(Assignment assign: assignments){
257                if(!workAreas.contains(assign.getWorkArea())){
258                    workAreas.add(assign.getWorkArea());
259                }
260                Job job = HrServiceLocator.getJobService().getJob(assign.getPrincipalId(), assign.getJobNumber(), leaveBlock.getLeaveLocalDate());
261                if(!salGroups.contains(job.getHrSalGroup())){
262                    salGroups.add(job.getHrSalGroup());
263                }
264            }
265        }
266        Map<String, String> deptGroupKey = new HashMap<String, String>();
267        for(Long workArea : workAreas){
268            WorkArea workAreaObj = HrServiceLocator.getWorkAreaService().getWorkArea(workArea, leaveBlock.getLeaveLocalDate());
269            if(deptToListOfWorkAreas.containsKey(workAreaObj.getDept())){
270                List<Long> deptWorkAreas = deptToListOfWorkAreas.get(workAreaObj.getDept());
271                deptWorkAreas.add(workArea);
272            } else {
273                List<Long> deptWorkAreas = new ArrayList<Long>();
274                deptWorkAreas.add(workArea);
275                deptToListOfWorkAreas.put(workAreaObj.getDept(), deptWorkAreas);
276                deptGroupKey.put(workAreaObj.getDept(), workAreaObj.getGroupKeyCode());
277            }
278        }
279        StringBuilder sb = new StringBuilder();
280        String className = document.getClass().getSimpleName();
281        sb.append("<documentContext><applicationContent><").append(className).append(">");
282        sb.append("<DEPARTMENTS>");
283        for(Map.Entry<String, List<Long>> dept : deptToListOfWorkAreas.entrySet()){
284            sb.append("<DEPARTMENT value=\""+dept.getKey()+"\">");
285            sb.append("<GROUPKEY value=\""+deptGroupKey.get(dept.getKey())+"\"/>");
286            for(Long workArea : dept.getValue()){
287                sb.append("<WORKAREA value=\""+workArea+"\"/>");
288            }
289            sb.append("</DEPARTMENT>");
290        }
291        sb.append("</DEPARTMENTS>");
292        for(String salGroup : salGroups){
293            sb.append("<SALGROUP value=\""+salGroup+"\"/>");
294        }
295        sb.append("<CALENTRYID value=\""+ce.getHrCalendarEntryId()+"\"/>");
296        sb.append("<PRINCIPALNAME value=\""+principal.getPrincipalName()+"\"/>");
297        sb.append("<PAYENDDATE value=\""+leaveBlock.getLeaveLocalDate()+"\"/>");
298        sb.append("</").append(className).append("></applicationContent></documentContext>");
299
300        return sb.toString();
301    }
302
303    private CalendarEntry getCalendarEntry(LeaveBlock leaveBlock) {
304        return  HrServiceLocator.getCalendarEntryService().getCalendarEntry(leaveBlock.getCalendarId());
305    }
306    
307    public List<String> getApproverIdList(String documentId) {
308        List<String> idList = new ArrayList<String>();
309        List<ActionTaken> actions = KewApiServiceLocator.getWorkflowDocumentService().getActionsTaken(documentId);
310        for(ActionTaken anAction : actions) {
311                if(anAction.getActionTaken().getCode().equals(ActionType.APPROVE.getCode())
312                                && StringUtils.isNotEmpty(anAction.getPrincipalId()) ) {
313                        idList.add(anAction.getPrincipalId());
314                }
315        }
316        return idList;
317    }
318    
319}