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.balancetransfer.web; 017 018 import java.math.BigDecimal; 019 import java.sql.Date; 020 import java.util.ArrayList; 021 import java.util.List; 022 023 import javax.servlet.http.HttpServletRequest; 024 import javax.servlet.http.HttpServletResponse; 025 026 import org.apache.commons.collections.CollectionUtils; 027 import org.apache.commons.lang.time.DateUtils; 028 import org.apache.commons.lang3.StringUtils; 029 import org.apache.struts.action.ActionForm; 030 import org.apache.struts.action.ActionForward; 031 import org.apache.struts.action.ActionMapping; 032 import org.apache.struts.action.ActionRedirect; 033 import org.kuali.hr.lm.LMConstants; 034 import org.kuali.hr.lm.accrual.AccrualCategoryRule; 035 import org.kuali.hr.lm.balancetransfer.BalanceTransfer; 036 import org.kuali.hr.lm.balancetransfer.validation.BalanceTransferValidationUtils; 037 import org.kuali.hr.lm.leaveSummary.LeaveSummary; 038 import org.kuali.hr.lm.leaveSummary.LeaveSummaryRow; 039 import org.kuali.hr.lm.leaveblock.LeaveBlock; 040 import org.kuali.hr.lm.leavecalendar.LeaveCalendarDocument; 041 import org.kuali.hr.lm.timeoff.SystemScheduledTimeOff; 042 import org.kuali.hr.lm.workflow.LeaveCalendarDocumentHeader; 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.earncode.EarnCode; 047 import org.kuali.hr.time.service.base.TkServiceLocator; 048 import org.kuali.hr.time.timesheet.TimesheetDocument; 049 import org.kuali.hr.time.util.TKUtils; 050 import org.kuali.hr.time.workflow.TimesheetDocumentHeader; 051 import org.kuali.rice.krad.service.KRADServiceLocator; 052 import org.kuali.rice.krad.util.GlobalVariables; 053 import org.kuali.rice.krad.util.ObjectUtils; 054 055 public class BalanceTransferAction extends TkAction { 056 057 public ActionForward balanceTransferOnLeaveApproval(ActionMapping mapping, ActionForm form, 058 HttpServletRequest request, HttpServletResponse response) throws Exception { 059 060 //if action was submit, execute the transfer 061 BalanceTransferForm btf = (BalanceTransferForm) form; 062 BalanceTransfer balanceTransfer = btf.getBalanceTransfer(); 063 064 boolean valid = BalanceTransferValidationUtils.validateTransfer(balanceTransfer); 065 066 //if transfer amount has changed, and the resulting change produces forfeiture 067 //or changes the forfeiture amount, prompt for confirmation with the amount of 068 //forfeiture that the entered amount would produce. 069 070 if(valid) { 071 072 String accrualRuleId = balanceTransfer.getAccrualCategoryRule(); 073 074 String documentId = balanceTransfer.getLeaveCalendarDocumentId(); 075 TimesheetDocumentHeader tsdh = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(documentId); 076 LeaveCalendarDocumentHeader lcdh = TkServiceLocator.getLeaveCalendarDocumentHeaderService().getDocumentHeader(documentId); 077 CalendarEntries calendarEntry = null; 078 String strutsActionForward = ""; 079 String methodToCall = "approveLeaveCalendar"; 080 if(ObjectUtils.isNull(tsdh) && ObjectUtils.isNull(lcdh)) { 081 throw new RuntimeException("No document found"); 082 } 083 else if(ObjectUtils.isNotNull(tsdh)) { 084 //Throws runtime exception, separate action forwards for timesheet/leave calendar transfers. 085 TimesheetDocument tsd = TkServiceLocator.getTimesheetService().getTimesheetDocument(documentId); 086 calendarEntry = tsd.getCalendarEntry(); 087 strutsActionForward = "timesheetTransferSuccess"; 088 methodToCall = "approveTimesheet"; 089 } 090 else { 091 LeaveCalendarDocument lcd = TkServiceLocator.getLeaveCalendarService().getLeaveCalendarDocument(documentId); 092 calendarEntry = lcd.getCalendarEntry(); 093 strutsActionForward = "leaveCalendarTransferSuccess"; 094 methodToCall = "approveLeaveCalendar"; 095 } 096 097 if(ObjectUtils.isNull(calendarEntry)) { 098 throw new RuntimeException("Could not retreive calendar entry for document " + documentId); 099 } 100 101 AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualRuleId); 102 Date effectiveDate = TKUtils.getCurrentDate(); 103 if(TKUtils.getCurrentDate().after(DateUtils.addSeconds(calendarEntry.getEndPeriodDate(),-1))) 104 effectiveDate = new Date(DateUtils.addSeconds(calendarEntry.getEndPeriodDate(),-1).getTime()); 105 // if submitting a delinquent calendar, use the calendar's end period date for the effective date. 106 // could adjust the end period date by subtracting a day so that the leave blocks appear on the month in question. 107 108 LeaveSummary ls = TkServiceLocator.getLeaveSummaryService().getLeaveSummaryAsOfDate(balanceTransfer.getPrincipalId(), effectiveDate); 109 LeaveSummaryRow transferRow = ls.getLeaveSummaryRowForAccrualCategory(accrualRule.getLmAccrualCategoryId()); 110 BalanceTransfer defaultBT = TkServiceLocator.getBalanceTransferService().initializeTransfer(balanceTransfer.getPrincipalId(), accrualRuleId, transferRow.getAccruedBalance(), effectiveDate); 111 if(balanceTransfer.getTransferAmount().compareTo(defaultBT.getTransferAmount()) != 0) { 112 //employee changed the transfer amount, recalculate forfeiture. 113 //Note: transfer form has been validated. 114 balanceTransfer = defaultBT.adjust(balanceTransfer.getTransferAmount()); 115 // showing the adjusted balance transfer via the execution of another forward 116 // would cause a loop that would break only if the original transfer amount was re-established in the form. 117 // javascript must be written if the forfeited amount is to be updated on the form object. 118 // an alternative to javascript would be to render a "re-calculate" button attached to a dedicated action forward method. 119 // must re-set leaveCalendarDocumentId, as balanceTransfer is now just an adjustment of the default initialized BT with no leave calendar doc id. 120 balanceTransfer.setLeaveCalendarDocumentId(documentId); 121 } 122 123 TkServiceLocator.getBalanceTransferService().submitToWorkflow(balanceTransfer); 124 125 if(ObjectUtils.isNotNull(documentId)) { 126 if(StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.LEAVE_APPROVE) || 127 StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(), LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) { 128 ActionForward forward = new ActionForward(mapping.findForward(strutsActionForward)); 129 forward.setPath(forward.getPath()+"?documentId="+documentId+"&action=R&methodToCall="+methodToCall); 130 return forward; 131 } 132 else 133 return mapping.findForward("closeBalanceTransferDoc"); 134 } 135 else 136 return mapping.findForward("closeBalanceTransferDoc"); 137 } 138 else //show user errors. 139 return mapping.findForward("basic"); 140 } 141 142 public ActionForward cancel(ActionMapping mapping, ActionForm form, 143 HttpServletRequest request, HttpServletResponse response) 144 throws Exception { 145 146 BalanceTransferForm btf = (BalanceTransferForm) form; 147 BalanceTransfer bt = btf.getBalanceTransfer(); 148 149 if(btf.isSstoTransfer()) { 150 return mapping.findForward("closeBalanceTransferDoc"); 151 } 152 153 String accrualCategoryRuleId = bt.getAccrualCategoryRule(); 154 AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualCategoryRuleId); 155 String actionFrequency = accrualRule.getMaxBalanceActionFrequency(); 156 157 if(StringUtils.equals(actionFrequency,LMConstants.MAX_BAL_ACTION_FREQ.ON_DEMAND)) 158 return mapping.findForward("closeBalanceTransferDoc"); 159 else 160 if(StringUtils.equals(actionFrequency, LMConstants.MAX_BAL_ACTION_FREQ.LEAVE_APPROVE) || 161 StringUtils.equals(actionFrequency, LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) { 162 String documentId = bt.getLeaveCalendarDocumentId(); 163 TimesheetDocumentHeader tsdh = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(documentId); 164 LeaveCalendarDocumentHeader lcdh = TkServiceLocator.getLeaveCalendarDocumentHeaderService().getDocumentHeader(documentId); 165 String strutsActionForward = ""; 166 if(ObjectUtils.isNull(tsdh) && ObjectUtils.isNull(lcdh)) { 167 strutsActionForward = "/"; 168 } 169 else if(ObjectUtils.isNotNull(tsdh)) { 170 //Throws runtime exception, separate action forwards for timesheet/leave calendar transfers. 171 strutsActionForward = mapping.findForward("timesheetCancel").getPath() + "?documentId=" + bt.getLeaveCalendarDocumentId(); 172 } 173 else { 174 strutsActionForward = mapping.findForward("leaveCalendarCancel").getPath() + "?documentId=" + bt.getLeaveCalendarDocumentId(); 175 } 176 177 ActionRedirect redirect = new ActionRedirect(); 178 redirect.setPath(strutsActionForward); 179 return redirect; 180 } 181 else 182 throw new RuntimeException("Action should only be reachable through triggers with frequency ON_DEMAND or LEAVE_APPROVE"); 183 } 184 185 //Entry point for BalanceTransfer.do for accrual category rule triggered transfers with action frequency On Demand. 186 //May be better suited in the LeaveCalendarAction class. 187 public ActionForward balanceTransferOnDemand(ActionMapping mapping, ActionForm form, 188 HttpServletRequest request, HttpServletResponse response) 189 throws Exception { 190 GlobalVariables.getMessageMap().putWarning("document.transferAmount","balanceTransfer.transferAmount.adjust"); 191 192 BalanceTransferForm btf = (BalanceTransferForm) form; 193 //the leave calendar document that triggered this balance transfer. 194 String documentId = request.getParameter("documentId"); 195 String accrualRuleId = request.getParameter("accrualRuleId"); 196 String timesheet = request.getParameter("timesheet"); 197 boolean isTimesheet = false; 198 if(StringUtils.equals(timesheet, "true")) { 199 btf.isTimesheet(true); 200 isTimesheet = true; 201 } 202 if(ObjectUtils.isNotNull(accrualRuleId)) { 203 AccrualCategoryRule aRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualRuleId); 204 if(ObjectUtils.isNotNull(aRule)) { 205 //should somewhat safegaurd against url fabrication. 206 if(!StringUtils.equals(aRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.ON_DEMAND)) 207 throw new RuntimeException("attempted to execute on-demand balance transfer for accrual category with action frequency " + aRule.getMaxBalanceActionFrequency()); 208 else { 209 TimesheetDocument tsd = null; 210 LeaveCalendarDocument lcd = null; 211 String principalId = null; 212 CalendarEntries calendarEntry = null; 213 214 if(isTimesheet) { 215 tsd = TkServiceLocator.getTimesheetService().getTimesheetDocument(documentId); 216 principalId = tsd.getPrincipalId(); 217 calendarEntry = tsd.getCalendarEntry(); 218 } 219 else { 220 lcd = TkServiceLocator.getLeaveCalendarService().getLeaveCalendarDocument(documentId); 221 principalId = lcd.getPrincipalId(); 222 calendarEntry = lcd.getCalendarEntry(); 223 } 224 225 Date effectiveDate = TKUtils.getCurrentDate(); 226 if(TKUtils.getCurrentDate().after(DateUtils.addSeconds(calendarEntry.getEndPeriodDate(),-1))) 227 effectiveDate = new Date(DateUtils.addSeconds(calendarEntry.getEndPeriodDate(),-1).getTime()); 228 229 LeaveSummary ls = TkServiceLocator.getLeaveSummaryService().getLeaveSummaryAsOfDate(principalId, effectiveDate); 230 231 232 LeaveSummaryRow transferRow = ls.getLeaveSummaryRowForAccrualCategory(aRule.getLmAccrualCategoryId()); 233 BalanceTransfer balanceTransfer = TkServiceLocator.getBalanceTransferService().initializeTransfer(principalId, accrualRuleId, transferRow.getAccruedBalance(), effectiveDate); 234 balanceTransfer.setLeaveCalendarDocumentId(documentId); 235 if(ObjectUtils.isNotNull(balanceTransfer)) { 236 if(StringUtils.equals(aRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.LOSE)) { 237 // this particular combination of action / action frequency does not particularly make sense 238 // unless for some reason users still need to be prompted to submit the loss. 239 // For now, we treat as though it is a valid use-case. 240 //TkServiceLocator.getBalanceTransferService().submitToWorkflow(balanceTransfer); 241 // May need to update to save the business object to KPME's tables for record keeping. 242 balanceTransfer = TkServiceLocator.getBalanceTransferService().transfer(balanceTransfer); 243 // May need to update to save the business object to KPME's tables for record keeping. 244 LeaveBlock forfeitedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(balanceTransfer.getForfeitedLeaveBlockId()); 245 forfeitedLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED); 246 TkServiceLocator.getLeaveBlockService().updateLeaveBlock(forfeitedLeaveBlock, principalId); 247 return mapping.findForward("closeBalanceTransferDoc"); 248 } 249 else { 250 ActionForward forward = mapping.findForward("basic"); 251 btf.setLeaveCalendarDocumentId(documentId); 252 btf.setBalanceTransfer(balanceTransfer); 253 btf.setTransferAmount(balanceTransfer.getTransferAmount()); 254 return forward; 255 } 256 } 257 else 258 throw new RuntimeException("could not initialize a balance transfer"); 259 260 } 261 } 262 else 263 throw new RuntimeException("No rule for this accrual category could be found"); 264 } 265 else 266 throw new RuntimeException("No accrual category rule id has been sent in the request."); 267 } 268 269 //Entry point for BalanceTransfer.do for accrual category rule triggered transfers with action frequency Leave Approve. 270 //TODO: Rename method to differentiate from ActionForward with same name in LeaveCalendarSubmit. 271 public ActionForward approveLeaveCalendar(ActionMapping mapping, ActionForm form, 272 HttpServletRequest request, HttpServletResponse response) 273 throws Exception { 274 275 GlobalVariables.getMessageMap().putWarning("document.newMaintainableObj.transferAmount","balanceTransfer.transferAmount.adjust"); 276 BalanceTransferForm btf = (BalanceTransferForm) form; 277 278 int categoryCounter = 0; 279 List<String> transferableAccrualCategoryRules = new ArrayList<String>(); 280 String accrualRuleId = request.getParameter("accrualCategory0"); 281 while(ObjectUtils.isNotNull(accrualRuleId)) { 282 //TODO: Get rid of this loop 283 categoryCounter++; 284 transferableAccrualCategoryRules.add(accrualRuleId); 285 accrualRuleId = request.getParameter("accrualCategory"+categoryCounter); 286 } 287 288 //Bad.... User must be prompted for each transfer that needs to be made. 289 //For now, assuming not more than one accrual category is eligible for transfer. 290 if(!transferableAccrualCategoryRules.isEmpty()) { 291 //This is the leave calendar document that triggered this balance transfer. 292 String leaveCalendarDocumentId = request.getParameter("documentId"); 293 ActionForward forward = new ActionForward(mapping.findForward("basic")); 294 LeaveCalendarDocument lcd = TkServiceLocator.getLeaveCalendarService().getLeaveCalendarDocument(leaveCalendarDocumentId); 295 296 Date effectiveDate = TKUtils.getCurrentDate(); 297 if(TKUtils.getCurrentDate().after(DateUtils.addSeconds(lcd.getCalendarEntry().getEndPeriodDate(),-1))) 298 effectiveDate = new Date(DateUtils.addSeconds(lcd.getCalendarEntry().getEndPeriodDate(),-1).getTime()); 299 300 LeaveSummary leaveSummary = TkServiceLocator.getLeaveSummaryService().getLeaveSummaryAsOfDate(lcd.getPrincipalId(), effectiveDate); 301 302 accrualRuleId = transferableAccrualCategoryRules.get(0); 303 AccrualCategoryRule aRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualRuleId); 304 LeaveSummaryRow transferRow = leaveSummary.getLeaveSummaryRowForAccrualCategory(aRule.getLmAccrualCategoryId()); 305 BalanceTransfer balanceTransfer = TkServiceLocator.getBalanceTransferService().initializeTransfer(lcd.getPrincipalId(), accrualRuleId, transferRow.getAccruedBalance(), effectiveDate); 306 balanceTransfer.setLeaveCalendarDocumentId(leaveCalendarDocumentId); 307 308 if(ObjectUtils.isNotNull(balanceTransfer)) { 309 AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualRuleId); 310 if(StringUtils.equals(accrualRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.LOSE)) { 311 312 //TkServiceLocator.getBalanceTransferService().submitToWorkflow(balanceTransfer); 313 balanceTransfer = TkServiceLocator.getBalanceTransferService().transfer(balanceTransfer); 314 // May need to update to save the business object to KPME's tables for record keeping. 315 LeaveBlock forfeitedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(balanceTransfer.getForfeitedLeaveBlockId()); 316 KRADServiceLocator.getBusinessObjectService().save(balanceTransfer); 317 forfeitedLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED); 318 TkServiceLocator.getLeaveBlockService().updateLeaveBlock(forfeitedLeaveBlock, lcd.getPrincipalId()); 319 320 ActionRedirect redirect = new ActionRedirect(); 321 if(ObjectUtils.isNotNull(leaveCalendarDocumentId)) { 322 if(StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.LEAVE_APPROVE) || 323 StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(), LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) { 324 ActionForward loseForward = new ActionForward(mapping.findForward("leaveCalendarTransferSuccess")); 325 loseForward.setPath(loseForward.getPath()+"?documentId="+leaveCalendarDocumentId+"&action=R&methodToCall=approveLeaveCalendar"); 326 return loseForward; 327 } 328 //on demand handled in separate action forward. 329 } 330 331 } else { 332 btf.setLeaveCalendarDocumentId(leaveCalendarDocumentId); 333 btf.setBalanceTransfer(balanceTransfer); 334 btf.setTransferAmount(balanceTransfer.getTransferAmount()); 335 return forward; 336 } 337 338 } 339 throw new RuntimeException("could not initialize balance transfer"); 340 341 } 342 else 343 throw new RuntimeException("unable to fetch the accrual category that triggerred this transfer"); 344 } 345 346 public ActionForward approveTimesheet(ActionMapping mapping, ActionForm form, 347 HttpServletRequest request, HttpServletResponse response) 348 throws Exception { 349 350 GlobalVariables.getMessageMap().putWarning("document.newMaintainableObj.transferAmount","balanceTransfer.transferAmount.adjust"); 351 BalanceTransferForm btf = (BalanceTransferForm) form; 352 353 int categoryCounter = 0; 354 List<String> transferableAccrualCategoryRules = new ArrayList<String>(); 355 String accrualRuleId = request.getParameter("accrualCategory0"); 356 while(ObjectUtils.isNotNull(accrualRuleId)) { 357 //TODO: Get rid of this loop 358 categoryCounter++; 359 transferableAccrualCategoryRules.add(accrualRuleId); 360 accrualRuleId = request.getParameter("accrualCategory"+categoryCounter); 361 } 362 363 //Bad.... User must be prompted for each transfer that needs to be made. 364 //For now, assuming not more than one accrual category is eligible for transfer. 365 if(!transferableAccrualCategoryRules.isEmpty()) { 366 //This is the leave calendar document that triggered this balance transfer. 367 String timesheetDocumentId = request.getParameter("documentId"); 368 ActionForward forward = new ActionForward(mapping.findForward("basic")); 369 TimesheetDocument tsd = TkServiceLocator.getTimesheetService().getTimesheetDocument(timesheetDocumentId); 370 CalendarEntries timeCalendarEntry = tsd.getCalendarEntry(); 371 372 Date effectiveDate = TKUtils.getCurrentDate(); 373 if(TKUtils.getCurrentDate().after(DateUtils.addSeconds(timeCalendarEntry.getEndPeriodDate(),-1))) 374 effectiveDate = new Date(DateUtils.addSeconds(timeCalendarEntry.getEndPeriodDate(),-1).getTime()); 375 376 LeaveSummary leaveSummary = TkServiceLocator.getLeaveSummaryService().getLeaveSummaryAsOfDate(tsd.getPrincipalId(), effectiveDate); 377 378 /* Uncommenting changes pending input on KPME-2138 379 * 380 * Calendar calendar = TkServiceLocator.getCalendarService().getCalendarByPrincipalIdAndDate(tsd.getPrincipalId(), timeCalendarEntry.getBeginPeriodDate(), true); 381 Date beginDate = timeCalendarEntry.getBeginPeriodDate(); 382 Date endDate = timeCalendarEntry.getEndPeriodDate(); 383 List<CalendarEntries> leaveCalendarEntries = new ArrayList<CalendarEntries>(); 384 leaveCalendarEntries.addAll(TkServiceLocator.getCalendarEntriesService().getCalendarEntriesEndingBetweenBeginAndEndDate(calendar.getHrCalendarId(), beginDate, endDate)); 385 if(!leaveCalendarEntries.isEmpty()) { 386 if(leaveCalendarEntries.size() < 2) { 387 CalendarEntries endingLeaveEntry = leaveCalendarEntries.get(0); 388 effectiveDate = new Date(DateUtils.addMinutes(endingLeaveEntry.getEndPeriodDate(), -1).getTime()); 389 } 390 else { 391 throw new RuntimeException("Unable to determine effective date"); 392 } 393 } 394 else 395 effectiveDate = new Date(DateUtils.addMinutes(timeCalendarEntry.getEndPeriodDate(),-1).getTime()); 396 */ 397 398 accrualRuleId = transferableAccrualCategoryRules.get(0); 399 AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualRuleId); 400 LeaveSummaryRow transferRow = leaveSummary.getLeaveSummaryRowForAccrualCategory(accrualRule.getLmAccrualCategoryId()); 401 BalanceTransfer balanceTransfer = TkServiceLocator.getBalanceTransferService().initializeTransfer(tsd.getPrincipalId(), accrualRuleId, transferRow.getAccruedBalance(), effectiveDate); 402 balanceTransfer.setLeaveCalendarDocumentId(timesheetDocumentId); 403 404 if(ObjectUtils.isNotNull(balanceTransfer)) { 405 if(StringUtils.equals(accrualRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.LOSE)) { 406 // TODO: Redirect user to prompt stating excess leave will be forfeited and ask for confirmation. 407 // Do not submit the object to workflow for this max balance action. 408 balanceTransfer = TkServiceLocator.getBalanceTransferService().transfer(balanceTransfer); 409 KRADServiceLocator.getBusinessObjectService().save(balanceTransfer); 410 411 // May need to update to save the business object to KPME's tables for record keeping. 412 LeaveBlock forfeitedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(balanceTransfer.getForfeitedLeaveBlockId()); 413 forfeitedLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED); 414 TkServiceLocator.getLeaveBlockService().updateLeaveBlock(forfeitedLeaveBlock, tsd.getPrincipalId()); 415 ActionRedirect redirect = new ActionRedirect(); 416 if(ObjectUtils.isNotNull(timesheetDocumentId)) { 417 if(StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.LEAVE_APPROVE) || 418 StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(), LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) { 419 ActionForward loseForward = new ActionForward(mapping.findForward("timesheetTransferSuccess")); 420 loseForward.setPath(loseForward.getPath()+"?documentId="+timesheetDocumentId+"&action=R&methodToCall=approveTimesheet"); 421 return loseForward; 422 } 423 //on demand handled in separate action forward. 424 } 425 426 } else { 427 btf.setLeaveCalendarDocumentId(timesheetDocumentId); 428 btf.setBalanceTransfer(balanceTransfer); 429 btf.setTransferAmount(balanceTransfer.getTransferAmount()); 430 return forward; 431 } 432 433 } 434 throw new RuntimeException("could not initialize balance transfer"); 435 436 } 437 else 438 throw new RuntimeException("unable to fetch the accrual category that triggerred this transfer"); 439 } 440 441 public ActionForward closeBalanceTransferDoc(ActionMapping mapping, ActionForm form, 442 HttpServletRequest request, HttpServletResponse response) 443 throws Exception { 444 return mapping.findForward("closeBalanceTransferDoc"); 445 } 446 447 /* Delete system scheduled time off usage leave block from Leave or Time Calendar 448 */ 449 public ActionForward deleteSSTOLeaveBlock(ActionMapping mapping, ActionForm form, 450 HttpServletRequest request, HttpServletResponse response) 451 throws Exception { 452 BalanceTransferForm btf = (BalanceTransferForm) form; 453 buildBalanceTransferForLeaveBlock(btf, request.getParameter("leaveBlockId")); 454 455 return new ActionForward(mapping.findForward("basic")); 456 } 457 458 /* Build balance transfer based on the to-be-deleted leave block 459 */ 460 private void buildBalanceTransferForLeaveBlock(BalanceTransferForm btf, String lbId) { 461 LeaveBlock lb = TkServiceLocator.getLeaveBlockService().getLeaveBlock(lbId); 462 // this leave block is a ssto usage block, need to use it fo find the accrualed leave block which has a positive amount 463 if(lb == null && StringUtils.isEmpty(lb.getScheduleTimeOffId())) { 464 throw new RuntimeException("could not find the System Scheduled Time Off leave block that needs to be transferred!"); 465 } 466 SystemScheduledTimeOff ssto = TkServiceLocator.getSysSchTimeOffService().getSystemScheduledTimeOff(lb.getScheduleTimeOffId()); 467 BigDecimal amountTransferred = ssto.getTransferConversionFactor() == null ? lb.getLeaveAmount() : lb.getLeaveAmount().multiply(ssto.getTransferConversionFactor()); 468 EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(ssto.getTransfertoEarnCode(), lb.getLeaveDate()); 469 470 BalanceTransfer bt = new BalanceTransfer(); 471 bt.setTransferAmount(lb.getLeaveAmount().abs()); // the usage leave block's leave amount is negative 472 bt.setFromAccrualCategory(lb.getAccrualCategory()); 473 bt.setAmountTransferred(amountTransferred.abs()); 474 bt.setToAccrualCategory(ec.getAccrualCategory()); 475 bt.setSstoId(lb.getScheduleTimeOffId()); 476 bt.setEffectiveDate(lb.getLeaveDate()); 477 bt.setPrincipalId(lb.getPrincipalId()); 478 479 btf.setBalanceTransfer(bt); 480 btf.setTransferAmount(bt.getTransferAmount()); 481 GlobalVariables.getMessageMap().putWarning("document.newMaintainableObj.transferAmount","balanceTransfer.transferSSTO", 482 bt.getTransferAmount().toString(), bt.getAmountTransferred().toString()); 483 } 484 /* 485 * Submit a balance transfer document when deleting a ssto usage leave block from current Leave/time calendar 486 * delete both accrued and usage ssto leave blocks, a pending transferred leave block is created by the BT doc 487 */ 488 public ActionForward balanceTransferOnSSTO(ActionMapping mapping, ActionForm form, 489 HttpServletRequest request, HttpServletResponse response) throws Exception { 490 BalanceTransferForm btf = (BalanceTransferForm) form; 491 BalanceTransfer bt = btf.getBalanceTransfer(); 492 493 if(StringUtils.isEmpty(bt.getSstoId())) { 494 throw new RuntimeException("System Scheduled Time Off not found for this balance transfer!"); 495 } 496 List<LeaveBlock> lbList = TkServiceLocator.getLeaveBlockService().getSSTOLeaveBlocks(bt.getPrincipalId(), bt.getSstoId(), bt.getEffectiveDate()); 497 if(CollectionUtils.isEmpty(lbList) || (CollectionUtils.isNotEmpty(lbList) && lbList.size() != 2)) { 498 throw new RuntimeException("There should be 2 system scheduled time off leave blocks!"); 499 } 500 TkServiceLocator.getBalanceTransferService().submitToWorkflow(bt); 501 // delete both SSTO accrualed and usage leave blocks 502 for(LeaveBlock lb : lbList) { 503 TkServiceLocator.getLeaveBlockService().deleteLeaveBlock(lb.getLmLeaveBlockId(), lb.getPrincipalId()); 504 } 505 return mapping.findForward("closeBalanceTransferDoc"); 506 } 507 508 }