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