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