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