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.detail.web; 017 018 019 import java.util.ArrayList; 020 import java.util.Comparator; 021 import java.util.HashSet; 022 import java.util.List; 023 import java.util.Map; 024 import java.util.Map.Entry; 025 import java.util.Set; 026 027 import javax.servlet.http.HttpServletRequest; 028 import javax.servlet.http.HttpServletResponse; 029 030 import org.apache.commons.lang.StringUtils; 031 import org.apache.commons.lang.time.DateUtils; 032 import org.apache.struts.action.ActionForm; 033 import org.apache.struts.action.ActionForward; 034 import org.apache.struts.action.ActionMapping; 035 import org.apache.struts.action.ActionRedirect; 036 import org.displaytag.tags.TableTagParameters; 037 import org.displaytag.util.ParamEncoder; 038 import org.joda.time.DateTime; 039 import org.joda.time.Interval; 040 import org.kuali.hr.lm.LMConstants; 041 import org.kuali.hr.lm.accrual.AccrualCategoryRule; 042 import org.kuali.hr.lm.leaveblock.LeaveBlock; 043 import org.kuali.hr.lm.leavecalendar.LeaveCalendarDocument; 044 import org.kuali.hr.lm.leaveplan.LeavePlan; 045 import org.kuali.hr.time.base.web.TkAction; 046 import org.kuali.hr.time.calendar.Calendar; 047 import org.kuali.hr.time.calendar.CalendarEntries; 048 import org.kuali.hr.time.principal.PrincipalHRAttributes; 049 import org.kuali.hr.time.roles.TkUserRoles; 050 import org.kuali.hr.time.roles.UserRoles; 051 import org.kuali.hr.time.service.base.TkServiceLocator; 052 import org.kuali.hr.time.timesheet.TimesheetDocument; 053 import org.kuali.hr.time.util.TKContext; 054 import org.kuali.hr.time.util.TKUser; 055 import org.kuali.hr.time.util.TKUtils; 056 import org.kuali.hr.time.util.TkConstants; 057 import org.kuali.rice.kew.api.document.DocumentStatus; 058 import org.kuali.rice.krad.exception.AuthorizationException; 059 import org.kuali.rice.krad.util.GlobalVariables; 060 import org.kuali.rice.krad.util.ObjectUtils; 061 062 import edu.emory.mathcs.backport.java.util.Collections; 063 064 public class TimesheetSubmitAction extends TkAction { 065 066 @Override 067 protected void checkTKAuthorization(ActionForm form, String methodToCall) throws AuthorizationException { 068 TimesheetSubmitActionForm tsaf = (TimesheetSubmitActionForm)form; 069 070 String principal = TKContext.getPrincipalId(); 071 UserRoles roles = TkUserRoles.getUserRoles(GlobalVariables.getUserSession().getPrincipalId()); 072 073 TimesheetDocument document = TkServiceLocator.getTimesheetService().getTimesheetDocument(tsaf.getDocumentId()); 074 if (!roles.isDocumentWritable(document)) { 075 throw new AuthorizationException(principal, "TimesheetSubmitAction", ""); 076 } 077 } 078 079 080 081 082 public ActionForward approveTimesheet(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 083 TimesheetSubmitActionForm tsaf = (TimesheetSubmitActionForm)form; 084 TimesheetDocument document = TkServiceLocator.getTimesheetService().getTimesheetDocument(tsaf.getDocumentId()); 085 086 // Switched to grab the target (chain, resolution: target -> backdoor -> actual) user. 087 // Approvals still using backdoor > actual 088 if (StringUtils.equals(tsaf.getAction(), TkConstants.DOCUMENT_ACTIONS.ROUTE)) { 089 if (DocumentStatus.INITIATED.getCode().equals(document.getDocumentHeader().getDocumentStatus()) 090 || DocumentStatus.SAVED.getCode().equals(document.getDocumentHeader().getDocumentStatus())) { 091 092 boolean nonExemptLE = TkServiceLocator.getLeaveApprovalService().isActiveAssignmentFoundOnJobFlsaStatus(document.getPrincipalId(), 093 TkConstants.FLSA_STATUS_NON_EXEMPT, true); 094 if(nonExemptLE) { 095 Map<String,Set<LeaveBlock>> eligibilities = TkServiceLocator.getAccrualCategoryMaxBalanceService().getMaxBalanceViolations(document.getCalendarEntry(), document.getPrincipalId()); 096 PrincipalHRAttributes pha = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(document.getPrincipalId(), document.getCalendarEntry().getEndPeriodDate()); 097 Calendar cal = pha.getLeaveCalObj(); 098 if(cal == null) { 099 //non exempt leave eligible employee without a leave calendar? 100 throw new RuntimeException("Principal is without a leave calendar"); 101 } 102 List<LeaveBlock> eligibleTransfers = new ArrayList<LeaveBlock>(); 103 List<LeaveBlock> eligiblePayouts = new ArrayList<LeaveBlock>(); 104 Interval interval = new Interval(document.getCalendarEntry().getBeginPeriodDate().getTime(), document.getCalendarEntry().getEndPeriodDate().getTime()); 105 106 for(Entry<String,Set<LeaveBlock>> entry : eligibilities.entrySet()) { 107 108 for(LeaveBlock lb : entry.getValue()) { 109 if(interval.contains(lb.getLeaveDate().getTime())) { 110 //maxBalanceViolations should, if a violation exists, return a leave block with leave date either current date, or the end period date - 1 days. 111 AccrualCategoryRule aRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(lb.getAccrualCategoryRuleId()); 112 113 if(ObjectUtils.isNotNull(aRule) 114 && !StringUtils.equals(aRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.ON_DEMAND)) { 115 if(StringUtils.equals(aRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) { 116 DateTime rollOverDate = TkServiceLocator.getLeavePlanService().getRolloverDayOfLeavePlan(pha.getLeavePlan(), document.getCalendarEntry().getBeginPeriodDate()); 117 //the final calendar period of the leave plan should end within this time sheet 118 if(interval.contains(rollOverDate.minusDays(1).getMillis())) { 119 //only leave blocks belonging to the calendar entry being submitted may reach this point 120 //if the infraction occurs before the relative end date of the leave plan year, then action will be executed. 121 if(lb.getLeaveDate().before(rollOverDate.toDate())) { 122 if(StringUtils.equals(aRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.PAYOUT)) { 123 eligiblePayouts.add(lb); 124 } 125 else if(StringUtils.equals(aRule.getActionAtMaxBalance(), LMConstants.ACTION_AT_MAX_BAL.TRANSFER) 126 || StringUtils.equals(aRule.getActionAtMaxBalance(), LMConstants.ACTION_AT_MAX_BAL.LOSE)) { 127 eligibleTransfers.add(lb); 128 } 129 } 130 } 131 } 132 if(StringUtils.equals(aRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.LEAVE_APPROVE)) { 133 //a leave period should end within the time period. 134 CalendarEntries leaveEntry = TkServiceLocator.getCalendarEntriesService().getCurrentCalendarEntriesByCalendarId(cal.getHrCalendarId(), lb.getLeaveDate()); 135 if(ObjectUtils.isNotNull(leaveEntry)) { 136 //only leave blocks belonging to the calendar entry being submitted may reach this point. 137 //if the infraction occurs before the end of the leave calendar entry, then action will be executed. 138 if(interval.contains(DateUtils.addDays(leaveEntry.getEndPeriodDate(),-1).getTime())) { 139 140 if(StringUtils.equals(aRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.PAYOUT)) { 141 eligiblePayouts.add(lb); 142 } 143 else if(StringUtils.equals(aRule.getActionAtMaxBalance(), LMConstants.ACTION_AT_MAX_BAL.TRANSFER) 144 || StringUtils.equals(aRule.getActionAtMaxBalance(), LMConstants.ACTION_AT_MAX_BAL.LOSE)) { 145 eligibleTransfers.add(lb); 146 } 147 } 148 } 149 } 150 } 151 } 152 } 153 } 154 ActionRedirect transferRedirect = new ActionRedirect(); 155 ActionRedirect payoutRedirect = new ActionRedirect(); 156 if(!eligibleTransfers.isEmpty()) { 157 transferRedirect.setPath("/BalanceTransfer.do?"+request.getQueryString()); 158 request.getSession().setAttribute("eligibilities", eligibleTransfers); 159 return transferRedirect; 160 } 161 if(!eligiblePayouts.isEmpty()) { 162 payoutRedirect.setPath("/LeavePayout.do?"+request.getQueryString()); 163 request.getSession().setAttribute("eligibilities", eligiblePayouts); 164 return payoutRedirect; 165 } 166 } 167 TkServiceLocator.getTimesheetService().routeTimesheet(TKContext.getTargetPrincipalId(), document); 168 } 169 } else if (StringUtils.equals(tsaf.getAction(), TkConstants.DOCUMENT_ACTIONS.APPROVE)) { 170 if(TkServiceLocator.getTimesheetService().isReadyToApprove(document)) { 171 if (document.getDocumentHeader().getDocumentStatus().equals(DocumentStatus.ENROUTE.getCode())) { 172 TkServiceLocator.getTimesheetService().approveTimesheet(TKContext.getPrincipalId(), document); 173 } 174 } else { 175 //ERROR!!! 176 } 177 } else if (StringUtils.equals(tsaf.getAction(), TkConstants.DOCUMENT_ACTIONS.DISAPPROVE)) { 178 if (document.getDocumentHeader().getDocumentStatus().equals(DocumentStatus.ENROUTE.getCode())) { 179 TkServiceLocator.getTimesheetService().disapproveTimesheet(TKContext.getPrincipalId(), document); 180 } 181 } 182 183 TkServiceLocator.getTkSearchableAttributeService().updateSearchableAttribute(document, document.getAsOfDate()); 184 ActionRedirect rd = new ActionRedirect(mapping.findForward("timesheetRedirect")); 185 rd.addParameter("documentId", tsaf.getDocumentId()); 186 187 return rd; 188 } 189 190 public ActionForward approveApprovalTab(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 191 TimesheetSubmitActionForm tsaf = (TimesheetSubmitActionForm)form; 192 TimesheetDocument document = TkServiceLocator.getTimesheetService().getTimesheetDocument(tsaf.getDocumentId()); 193 194 // Switched to grab the target (chain, resolution: target -> backdoor -> actual) user. 195 // Approvals still using backdoor > actual 196 if (StringUtils.equals(tsaf.getAction(), TkConstants.DOCUMENT_ACTIONS.ROUTE)) { 197 if (document.getDocumentHeader().getDocumentStatus().equals(DocumentStatus.INITIATED.getCode())) { 198 TkServiceLocator.getTimesheetService().routeTimesheet(TKContext.getTargetPrincipalId(), document); 199 } 200 } else if (StringUtils.equals(tsaf.getAction(), TkConstants.DOCUMENT_ACTIONS.APPROVE)) { 201 if(TkServiceLocator.getTimesheetService().isReadyToApprove(document)) { 202 if (document.getDocumentHeader().getDocumentStatus().equals(DocumentStatus.ENROUTE.getCode())) { 203 TkServiceLocator.getTimesheetService().approveTimesheet(TKContext.getPrincipalId(), document); 204 } 205 } else { 206 //ERROR!!! 207 } 208 } else if (StringUtils.equals(tsaf.getAction(), TkConstants.DOCUMENT_ACTIONS.DISAPPROVE)) { 209 if (document.getDocumentHeader().getDocumentStatus().equals(DocumentStatus.ENROUTE.getCode())) { 210 TkServiceLocator.getTimesheetService().disapproveTimesheet(TKContext.getPrincipalId(), document); 211 } 212 } 213 TKUser.clearTargetUser(); 214 String page = new ParamEncoder(TkConstants.APPROVAL_TABLE_ID).encodeParameterName(TableTagParameters.PARAMETER_PAGE); 215 String pageVal = request.getParameter(page); 216 217 218 ActionRedirect ar = new ActionRedirect(mapping.findForward("approverRedirect")); 219 if (StringUtils.isNotEmpty(pageVal)) { 220 ar.addParameter(page, pageVal); 221 } 222 return ar; 223 224 225 } 226 }