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.lm.approval.web;
017    
018    import java.sql.Date;
019    import java.text.SimpleDateFormat;
020    import java.util.*;
021    
022    import javax.servlet.http.HttpServletRequest;
023    import javax.servlet.http.HttpServletResponse;
024    
025    import org.apache.commons.collections.CollectionUtils;
026    import org.apache.commons.lang.ObjectUtils;
027    import org.apache.commons.lang.StringUtils;
028    import org.apache.commons.lang.math.NumberUtils;
029    import org.apache.struts.action.ActionForm;
030    import org.apache.struts.action.ActionForward;
031    import org.apache.struts.action.ActionMapping;
032    import org.displaytag.tags.TableTagParameters;
033    import org.displaytag.util.ParamEncoder;
034    import org.hsqldb.lib.StringUtil;
035    import org.joda.time.DateTime;
036    import org.kuali.hr.core.document.calendar.CalendarDocumentContract;
037    import org.kuali.hr.lm.leavecalendar.LeaveCalendarDocument;
038    import org.kuali.hr.lm.workflow.LeaveCalendarDocumentHeader;
039    import org.kuali.hr.time.approval.web.ApprovalLeaveSummaryRow;
040    import org.kuali.hr.time.assignment.Assignment;
041    import org.kuali.hr.time.base.web.ApprovalAction;
042    import org.kuali.hr.time.base.web.ApprovalForm;
043    import org.kuali.hr.time.calendar.Calendar;
044    import org.kuali.hr.time.calendar.CalendarEntries;
045    import org.kuali.hr.time.detail.web.ActionFormUtils;
046    import org.kuali.hr.time.roles.TkUserRoles;
047    import org.kuali.hr.time.roles.UserRoles;
048    import org.kuali.hr.time.service.base.TkServiceLocator;
049    import org.kuali.hr.time.util.TKContext;
050    import org.kuali.hr.time.util.TKUser;
051    import org.kuali.hr.time.util.TKUtils;
052    import org.kuali.hr.time.util.TkConstants;
053    import org.kuali.hr.time.workarea.WorkArea;
054    
055    public class LeaveApprovalAction extends ApprovalAction{
056            
057            public ActionForward searchResult(ActionMapping mapping, ActionForm form,
058                            HttpServletRequest request, HttpServletResponse response)
059                            throws Exception {
060                    LeaveApprovalActionForm laaf = (LeaveApprovalActionForm)form;
061                    
062            if (StringUtils.equals("documentId", laaf.getSearchField())) {
063                    LeaveCalendarDocumentHeader lcd = TkServiceLocator.getLeaveCalendarDocumentHeaderService().getDocumentHeader(laaf.getSearchTerm());
064                    laaf.setSearchTerm(lcd != null ? lcd.getPrincipalId() : StringUtils.EMPTY);
065            }
066            
067            laaf.setSearchField("principalId");
068            List<String> principalIds = new ArrayList<String>();
069            principalIds.add(laaf.getSearchTerm());
070            CalendarEntries payCalendarEntries = TkServiceLocator.getCalendarEntriesService().getCalendarEntries(laaf.getHrPyCalendarEntriesId());
071            if (principalIds.isEmpty()) {
072                    laaf.setLeaveApprovalRows(new ArrayList<ApprovalLeaveSummaryRow>());
073                    laaf.setResultSize(0);
074            } else {
075                    this.setApprovalTables(laaf, principalIds, request, payCalendarEntries);
076                    
077                    laaf.setPayCalendarEntries(payCalendarEntries);
078                    laaf.setLeaveCalendarDates(TkServiceLocator.getLeaveSummaryService().getLeaveSummaryDates(payCalendarEntries));
079                    
080                    List<Assignment> assignments = TkServiceLocator.getAssignmentService().getAssignments(laaf.getSearchTerm(), payCalendarEntries.getEndPeriodDate());
081                    if(!assignments.isEmpty()){
082                             for(Long wa : laaf.getWorkAreaDescr().keySet()){
083                                    for (Assignment assign : assignments) {
084                                    if (assign.getWorkArea().toString().equals(wa.toString())) {
085                                            laaf.setSelectedWorkArea(wa.toString());
086                                            break;
087                                    }
088                                    }
089                         }
090                    }
091            }
092     
093                    return mapping.findForward("basic");
094            }
095            
096        public ActionForward approve(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
097            LeaveApprovalActionForm laaf = (LeaveApprovalActionForm) form;
098           
099            List<ApprovalLeaveSummaryRow> lstLeaveRows = laaf.getLeaveApprovalRows();
100            for (ApprovalLeaveSummaryRow ar : lstLeaveRows) {
101                if (ar.isApprovable() && StringUtils.equals(ar.getSelected(), "on")) {
102                    String documentNumber = ar.getDocumentId();
103                    LeaveCalendarDocument lcd = TkServiceLocator.getLeaveCalendarService().getLeaveCalendarDocument(documentNumber);
104                    TkServiceLocator.getLeaveCalendarService().approveLeaveCalendar(TKContext.getPrincipalId(), lcd);
105                }
106            }  
107            
108            return mapping.findForward("basic");
109        }
110            
111            public ActionForward selectNewDept(ActionMapping mapping, ActionForm form,
112                            HttpServletRequest request, HttpServletResponse response)
113                            throws Exception {
114                    LeaveApprovalActionForm laaf = (LeaveApprovalActionForm)form;
115                    laaf.setSearchField(null);
116                    laaf.setSearchTerm(null);
117    
118            CalendarEntries payCalendarEntries = TkServiceLocator.getCalendarEntriesService().getCalendarEntries(laaf.getHrPyCalendarEntriesId());
119            laaf.setPayCalendarEntries(payCalendarEntries);
120            laaf.setLeaveCalendarDates(TkServiceLocator.getLeaveSummaryService().getLeaveSummaryDates(payCalendarEntries));
121    
122                    laaf.getWorkAreaDescr().clear();
123                    laaf.setSelectedWorkArea("");
124            List<WorkArea> workAreas = TkServiceLocator.getWorkAreaService().getWorkAreas(laaf.getSelectedDept(), new java.sql.Date(laaf.getPayBeginDate().getTime()));
125            for(WorkArea wa : workAreas){
126                    if (TKUser.getApproverWorkAreas().contains(wa.getWorkArea())
127                                    || TKUser.getReviewerWorkAreas().contains(wa.getWorkArea())) {
128                            laaf.getWorkAreaDescr().put(wa.getWorkArea(),wa.getDescription()+"("+wa.getWorkArea()+")");
129                    }
130            }
131            
132            List<String> principalIds = this.getPrincipalIdsToPopulateTable(laaf);
133            this.setApprovalTables(laaf, principalIds, request, payCalendarEntries);
134            
135            this.populateCalendarAndPayPeriodLists(request, laaf);
136                    return mapping.findForward("basic");
137            }
138            
139            public ActionForward selectNewWorkArea(ActionMapping mapping, ActionForm form,
140                            HttpServletRequest request, HttpServletResponse response)
141                            throws Exception {
142                    LeaveApprovalActionForm laaf = (LeaveApprovalActionForm)form;
143                    laaf.setSearchField(null);
144                    laaf.setSearchTerm(null);
145    
146                CalendarEntries payCalendarEntries = TkServiceLocator.getCalendarEntriesService().getCalendarEntries(laaf.getHrPyCalendarEntriesId());
147            laaf.setLeaveCalendarDates(TkServiceLocator.getLeaveSummaryService().getLeaveSummaryDates(payCalendarEntries));
148       
149            List<String> idList = this.getPrincipalIdsToPopulateTable(laaf);
150            this.setApprovalTables(laaf, idList , request, payCalendarEntries);
151            
152                    return mapping.findForward("basic");
153            }       
154    
155            private List<String> getPrincipalIdsToPopulateTable(LeaveApprovalActionForm laaf) {
156            List<String> workAreaList = new ArrayList<String>();
157            if(StringUtil.isEmpty(laaf.getSelectedWorkArea())) {
158                    for(Long aKey : laaf.getWorkAreaDescr().keySet()) {
159                            workAreaList.add(aKey.toString());
160                    }
161            } else {
162                    workAreaList.add(laaf.getSelectedWorkArea());
163            }
164            java.sql.Date endDate = new java.sql.Date(laaf.getPayEndDate().getTime());
165            java.sql.Date beginDate = new java.sql.Date(laaf.getPayBeginDate().getTime());
166    
167            List<String> idList = TkServiceLocator.getLeaveApprovalService()
168                            .getLeavePrincipalIdsWithSearchCriteria(workAreaList, laaf.getSelectedPayCalendarGroup(), endDate, beginDate, endDate);      
169            return idList;
170            }       
171            
172            private void setApprovalTables(LeaveApprovalActionForm laaf, List<String> principalIds, HttpServletRequest request, CalendarEntries payCalendarEntries) {
173                    laaf.setLeaveCalendarDates(TkServiceLocator.getLeaveSummaryService().getLeaveSummaryDates(payCalendarEntries));
174                    
175                    if (principalIds.isEmpty()) {
176                            laaf.setLeaveApprovalRows(new ArrayList<ApprovalLeaveSummaryRow>());
177                            laaf.setResultSize(0);
178                    } else {
179                            
180                //List<ApprovalLeaveSummaryRow> approvalRows = getApprovalLeaveRows(laaf, getSubListPrincipalIds(request, persons));
181                List<ApprovalLeaveSummaryRow> approvalRows = getApprovalLeaveRows(laaf, principalIds);
182    
183                            String sortField = getSortField(request, laaf);
184                        if (StringUtils.isEmpty(sortField) ||
185                        StringUtils.equals(sortField, "name")) {
186                                final boolean sortNameAscending = isAscending(request, laaf);
187                            Collections.sort(approvalRows, new Comparator<ApprovalLeaveSummaryRow>() {
188                                            @Override
189                                            public int compare(ApprovalLeaveSummaryRow row1, ApprovalLeaveSummaryRow row2) {
190                                                    if (sortNameAscending) {
191                                                            return ObjectUtils.compare(StringUtils.lowerCase(row1.getName()), StringUtils.lowerCase(row2.getName()));
192                                                    } else {
193                                                            return ObjectUtils.compare(StringUtils.lowerCase(row2.getName()), StringUtils.lowerCase(row1.getName()));
194                                                    }
195                                            }
196                            });
197                        } else if (StringUtils.equals(sortField, "documentID")) {
198                                final boolean sortDocumentIdAscending = isAscending(request, laaf);
199                            Collections.sort(approvalRows, new Comparator<ApprovalLeaveSummaryRow>() {
200                                            @Override
201                                            public int compare(ApprovalLeaveSummaryRow row1, ApprovalLeaveSummaryRow row2) {
202                                                    if (sortDocumentIdAscending) {
203                                                            return ObjectUtils.compare(NumberUtils.toInt(row1.getDocumentId()), NumberUtils.toInt(row2.getDocumentId()));
204                                                    } else {
205                                                            return ObjectUtils.compare(NumberUtils.toInt(row2.getDocumentId()), NumberUtils.toInt(row1.getDocumentId()));
206                                                    }
207                                            }
208                            });
209                        } else if (StringUtils.equals(sortField, "status")) {
210                                final boolean sortStatusIdAscending = isAscending(request, laaf);
211                            Collections.sort(approvalRows, new Comparator<ApprovalLeaveSummaryRow>() {
212                                            @Override
213                                            public int compare(ApprovalLeaveSummaryRow row1, ApprovalLeaveSummaryRow row2) {
214                                                    if (sortStatusIdAscending) {
215                                                            return ObjectUtils.compare(StringUtils.lowerCase(row1.getApprovalStatus()), StringUtils.lowerCase(row2.getApprovalStatus()));
216                                                    } else {
217                                                            return ObjectUtils.compare(StringUtils.lowerCase(row2.getApprovalStatus()), StringUtils.lowerCase(row1.getApprovalStatus()));
218                                                    }
219                                            }
220                            });
221                        }
222                //String page = request.getParameter((new ParamEncoder(TkConstants.APPROVAL_TABLE_ID).encodeParameterName(TableTagParameters.PARAMETER_PAGE)));
223                String page = getPage(request, laaf);
224                Integer beginIndex = StringUtils.isBlank(page) || StringUtils.equals(page, "1") ? 0 : (Integer.parseInt(page) - 1)*TkConstants.PAGE_SIZE;
225                Integer endIndex = beginIndex + TkConstants.PAGE_SIZE > approvalRows.size() ? approvalRows.size() : beginIndex + TkConstants.PAGE_SIZE;
226                if (beginIndex > endIndex
227                        || beginIndex >= approvalRows.size()) {
228                    beginIndex = StringUtils.isBlank(page) || StringUtils.equals(page, "1") ? 0 : (Integer.parseInt(page) - 1)*TkConstants.PAGE_SIZE;
229                    endIndex = beginIndex + TkConstants.PAGE_SIZE > approvalRows.size() ? approvalRows.size() : beginIndex + TkConstants.PAGE_SIZE;
230                }
231                            laaf.setLeaveApprovalRows(approvalRows.subList(beginIndex, endIndex));
232                        laaf.setResultSize(principalIds.size());
233                    }
234            }
235            
236            @Override
237            public ActionForward loadApprovalTab(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
238                                    throws Exception {
239                    ActionForward fwd = mapping.findForward("basic");
240            LeaveApprovalActionForm laaf = (LeaveApprovalActionForm) form;
241            Date currentDate = null;
242            CalendarEntries payCalendarEntries = null;
243            Calendar currentPayCalendar = null;
244            //String page = request.getParameter((new ParamEncoder(TkConstants.APPROVAL_TABLE_ID).encodeParameterName(TableTagParameters.PARAMETER_PAGE)));
245            String page = getPage(request, laaf);
246    
247            //reset state
248            if(StringUtils.isBlank(laaf.getSelectedDept())){
249                    resetState(form, request);
250            }
251    
252            LeaveCalendarDocument lcd = null;
253            if (laaf.getDocumentId() != null) {
254                lcd = TkServiceLocator.getLeaveCalendarService().getLeaveCalendarDocument(laaf.getDocumentId());
255                laaf.setHrPyCalendarEntriesId(lcd.getCalendarEntry().getHrCalendarEntriesId());
256                payCalendarEntries = lcd.getCalendarEntry();
257            }
258    
259            // Set current pay calendar entries if present. Decide if the current date should be today or the end period date
260            if (laaf.getHrPyCalendarEntriesId() != null) {
261                if(payCalendarEntries == null){
262                   payCalendarEntries = TkServiceLocator.getCalendarEntriesService().getCalendarEntries(laaf.getHrPyCalendarEntriesId());
263                }
264                currentDate = payCalendarEntries.getEndPeriodDate();
265            } else {
266                currentDate = TKUtils.getTimelessDate(null);
267            }
268            //Set<Long> workAreas = TkServiceLocator.getTkRoleService().getWorkAreasForApprover(TKContext.getPrincipalId(), currentDate);
269            // should we use all three roles to find work areas???
270            UserRoles userRoles = TkUserRoles.getUserRoles(TKContext.getTargetPrincipalId());
271            Set<Long> workAreas = new HashSet<Long>();
272            workAreas.addAll(userRoles.getApproverWorkAreas());
273            workAreas.addAll(userRoles.getReviewerWorkAreas());
274            //List<String> roleNameList = Arrays.asList(TkConstants.ROLE_TK_APPROVER, TkConstants.ROLE_TK_APPROVER_DELEGATE, TkConstants.ROLE_TK_REVIEWER);
275            //Set<Long> workAreas = TkServiceLocator.getTkRoleService().getWorkArea.getWorkAreasForRoleNames(TKContext.getPrincipalId(), roleNameList, currentDate);
276            
277            List<String> principalIds = new ArrayList<String>();
278            for (Long workArea : workAreas) {
279                List<Assignment> assignments = TkServiceLocator.getAssignmentService().getActiveAssignmentsForWorkArea(workArea, currentDate);
280                for (Assignment a : assignments) {
281                    principalIds.add(a.getPrincipalId());
282                }
283            }
284    
285    
286    
287            // Set calendar groups
288            List<String> calGroups =  new ArrayList<String>();
289            if (CollectionUtils.isNotEmpty(principalIds)) {
290                calGroups = TkServiceLocator.getLeaveApprovalService().getUniqueLeavePayGroupsForPrincipalIds(principalIds);
291            }
292            laaf.setPayCalendarGroups(calGroups);
293    
294            if (StringUtils.isBlank(laaf.getSelectedPayCalendarGroup())
295                    && CollectionUtils.isNotEmpty(calGroups)) {
296                if (lcd == null) {
297                    laaf.setSelectedPayCalendarGroup(calGroups.get(0));
298                } else {
299                    laaf.setSelectedPayCalendarGroup(lcd.getCalendarEntry().getCalendarName());
300                }
301    
302            }
303            
304            // Set current pay calendar entries if present. Decide if the current date should be today or the end period date
305            if (laaf.getHrPyCalendarEntriesId() != null) {
306                if (payCalendarEntries == null || !StringUtils.equals(payCalendarEntries.getHrCalendarEntriesId(), laaf.getHrPyCalendarEntriesId())) {
307                    payCalendarEntries = TkServiceLocator.getCalendarEntriesService().getCalendarEntries(laaf.getHrPyCalendarEntriesId());
308                }
309            } else {
310                if (lcd == null) {
311                    currentPayCalendar = TkServiceLocator.getCalendarService().getCalendarByGroup(laaf.getSelectedPayCalendarGroup());
312                    if (currentPayCalendar != null) {
313                        payCalendarEntries = TkServiceLocator.getCalendarEntriesService().getCurrentCalendarEntriesByCalendarId(currentPayCalendar.getHrCalendarId(), currentDate);
314                    }
315                } else {
316                    payCalendarEntries = lcd.getCalendarEntry();
317                }
318            }
319            laaf.setPayCalendarEntries(payCalendarEntries);
320    
321            if(laaf.getPayCalendarEntries() != null) {
322                populateCalendarAndPayPeriodLists(request, laaf);
323            }
324    
325    
326            /*    if (lcd != null) {
327                    laaf.setSelectedPayCalendarGroup(lcd.getCalendarEntry().getCalendarName());
328                    laaf.setSelectedPayPeriod(lcd.getCalendarEntry().getHrCalendarEntriesId());
329                    laaf.setSelectedCalendarYear(new DateTime(lcd.getCalendarEntry().getBeginPeriodDate()).year().getAsString());
330                }
331            }*/
332    
333    
334            setupDocumentOnFormContext(request,laaf,payCalendarEntries, page, lcd);
335            /*if (lcd != null) {
336                for (Assignment a : lcd.getAssignments()) {
337                    WorkArea wa = TkServiceLocator.getWorkAreaService().getWorkArea(a.getWorkArea(), a.getEffectiveDate());
338                    if (laaf.getDepartments().contains(wa.getDept())) {
339                        laaf.setSelectedDept(wa.getDept());
340                        break;
341                    }
342                }
343            }*/
344    
345            return fwd;
346            }
347    
348            @Override
349            protected void setupDocumentOnFormContext(HttpServletRequest request,ApprovalForm form, CalendarEntries payCalendarEntries, String page, CalendarDocumentContract calDoc) {
350                    super.setupDocumentOnFormContext(request, form, payCalendarEntries, page, calDoc);
351                    LeaveApprovalActionForm laaf = (LeaveApprovalActionForm)form;
352    
353            if (payCalendarEntries != null) {
354                        laaf.setLeaveCalendarDates(TkServiceLocator.getLeaveSummaryService().getLeaveSummaryDates(payCalendarEntries));         
355                        List<String> principalIds = this.getPrincipalIdsToPopulateTable(laaf); 
356                this.setApprovalTables(laaf, principalIds, request, payCalendarEntries);
357                laaf.setOnCurrentPeriod(ActionFormUtils.getOnCurrentPeriodFlag(laaf.getPayCalendarEntries()));
358            }
359            }
360            
361            public ActionForward selectNewPayCalendar(ActionMapping mapping, ActionForm form,
362                            HttpServletRequest request, HttpServletResponse response)
363                            throws Exception {
364                    // resets the common fields for approval pages
365                    super.resetMainFields(form);
366                    LeaveApprovalActionForm laaf = (LeaveApprovalActionForm)form;
367            // KPME-909
368            laaf.setLeaveApprovalRows(new ArrayList<ApprovalLeaveSummaryRow>());
369                    
370                    return loadApprovalTab(mapping, form, request, response);
371            }
372               
373        protected List<ApprovalLeaveSummaryRow> getApprovalLeaveRows(LeaveApprovalActionForm laaf, List<String> assignmentPrincipalIds) {
374            return TkServiceLocator.getLeaveApprovalService().getLeaveApprovalSummaryRows
375                    (assignmentPrincipalIds, laaf.getPayCalendarEntries(), laaf.getLeaveCalendarDates());
376        }
377            
378        public void resetState(ActionForm form, HttpServletRequest request) {
379            LeaveApprovalActionForm laaf = (LeaveApprovalActionForm) form;
380                //String page = request.getParameter((new ParamEncoder(TkConstants.APPROVAL_TABLE_ID).encodeParameterName(TableTagParameters.PARAMETER_PAGE)));
381            String page = getPage(request, laaf);
382            if (StringUtils.isBlank(page)) {
383                            laaf.getDepartments().clear();
384                            laaf.getWorkAreaDescr().clear();
385                            laaf.setLeaveApprovalRows(new ArrayList<ApprovalLeaveSummaryRow>());
386                            laaf.setSelectedDept(null);
387                            laaf.setSearchField(null);
388                            laaf.setSearchTerm(null);
389                }
390    
391            }
392        
393        @Override
394        protected void populateCalendarAndPayPeriodLists(HttpServletRequest request, ApprovalForm taf) {
395             LeaveApprovalActionForm laaf = (LeaveApprovalActionForm) taf;
396                    // set calendar year list
397                    Set<String> yearSet = new HashSet<String>();
398                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
399                    // if selected calendar year is passed in
400                    if(!StringUtils.isEmpty(request.getParameter("selectedCY"))) {
401                            laaf.setSelectedCalendarYear(request.getParameter("selectedCY").toString());
402                    } else {
403                            laaf.setSelectedCalendarYear(sdf.format(laaf.getPayCalendarEntries().getBeginPeriodDate()));
404                    }
405                    
406                    List<CalendarEntries> pcListForYear = new ArrayList<CalendarEntries>();
407                    List<CalendarEntries> pceList =  new ArrayList<CalendarEntries>();
408                    pceList.addAll(TkServiceLocator.getLeaveApprovalService()
409                            .getAllLeavePayCalendarEntriesForApprover(TKContext.getPrincipalId(), TKUtils.getTimelessDate(null)));
410                    
411                for(CalendarEntries pce : pceList) {
412                    yearSet.add(sdf.format(pce.getBeginPeriodDate()));
413                    if(sdf.format(pce.getBeginPeriodDate()).equals(laaf.getSelectedCalendarYear())) {
414                            pcListForYear.add(pce);
415                    }
416                }
417                List<String> yearList = new ArrayList<String>(yearSet);
418                Collections.sort(yearList);
419                Collections.reverse(yearList);      // newest on top
420                laaf.setCalendarYears(yearList);
421                    
422                    // set pay period list contents
423                    if(!StringUtils.isEmpty(request.getParameter("selectedPP"))) {
424                            laaf.setSelectedPayPeriod(request.getParameter("selectedPP").toString());
425                    } else {
426                            laaf.setSelectedPayPeriod(laaf.getPayCalendarEntries().getHrCalendarEntriesId());
427                            laaf.setPayPeriodsMap(ActionFormUtils.getPayPeriodsMap(pcListForYear, null));
428                    }
429                    if(laaf.getPayPeriodsMap().isEmpty()) {
430                        laaf.setPayPeriodsMap(ActionFormUtils.getPayPeriodsMap(pcListForYear, null));
431                    }
432            }
433    
434    }