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