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.leavepayout.web;
017    
018    import java.math.BigDecimal;
019    import java.sql.Date;
020    import java.util.*;
021    
022    import org.apache.commons.lang.time.DateUtils;
023    import org.apache.commons.lang3.StringUtils;
024    import org.apache.struts.action.ActionForm;
025    import org.apache.struts.action.ActionForward;
026    import org.apache.struts.action.ActionMapping;
027    import org.apache.struts.action.ActionRedirect;
028    import org.joda.time.Interval;
029    import org.kuali.hr.lm.LMConstants;
030    import org.kuali.hr.lm.accrual.AccrualCategory;
031    import org.kuali.hr.lm.accrual.AccrualCategoryRule;
032    import org.kuali.hr.lm.leavepayout.LeavePayout;
033    import org.kuali.hr.lm.leavepayout.validation.LeavePayoutValidationUtils;
034    import org.kuali.hr.lm.leavepayout.web.LeavePayoutForm;
035    import org.kuali.hr.lm.leaveSummary.LeaveSummary;
036    import org.kuali.hr.lm.leaveSummary.LeaveSummaryRow;
037    import org.kuali.hr.lm.leaveblock.LeaveBlock;
038    import org.kuali.hr.lm.leavecalendar.LeaveCalendarDocument;
039    import org.kuali.hr.lm.workflow.LeaveCalendarDocumentHeader;
040    import org.kuali.hr.time.base.web.TkAction;
041    import org.kuali.hr.time.calendar.CalendarEntries;
042    import org.kuali.hr.time.service.base.TkServiceLocator;
043    import org.kuali.hr.time.timesheet.TimesheetDocument;
044    import org.kuali.hr.time.util.TKUtils;
045    import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
046    import org.kuali.rice.krad.service.KRADServiceLocator;
047    import org.kuali.rice.krad.util.GlobalVariables;
048    import org.kuali.rice.krad.util.ObjectUtils;
049    
050    import javax.servlet.http.HttpServletRequest;
051    import javax.servlet.http.HttpServletResponse;
052    
053    public class LeavePayoutAction extends TkAction {
054    
055            public ActionForward leavePayoutOnLeaveApproval(ActionMapping mapping, ActionForm form,
056                            HttpServletRequest request, HttpServletResponse response) throws Exception {
057    
058                    //if action was submit, execute the payout
059                    LeavePayoutForm lpf = (LeavePayoutForm) form;
060                    LeavePayout leavePayout = lpf.getLeavePayout();
061            
062                    boolean valid = LeavePayoutValidationUtils.validatePayout(leavePayout);
063                    
064                    //if payout amount has changed, and the resulting change produces forfeiture
065                    //or changes the forfeiture amount, prompt for confirmation with the amount of
066                    //forfeiture that the entered amount would produce.
067    
068                    if(valid) {
069                            
070                            String accrualRuleId = leavePayout.getAccrualCategoryRule();
071                            
072                            String documentId = leavePayout.getLeaveCalendarDocumentId();
073                            TimesheetDocumentHeader tsdh = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(documentId);
074                            LeaveCalendarDocumentHeader lcdh = TkServiceLocator.getLeaveCalendarDocumentHeaderService().getDocumentHeader(documentId);
075                            CalendarEntries calendarEntry = null;
076                            String strutsActionForward = "";
077                            String methodToCall = "approveLeaveCalendar";
078                            if(ObjectUtils.isNull(tsdh) && ObjectUtils.isNull(lcdh)) {
079                                    throw new RuntimeException("No document found");
080                            }
081                            else if(ObjectUtils.isNotNull(tsdh)) {
082                                    //Throws runtime exception, separate action forwards for timesheet/leave calendar payouts.
083                                    TimesheetDocument tsd = TkServiceLocator.getTimesheetService().getTimesheetDocument(documentId);
084                                    calendarEntry = tsd == null ? null : tsd.getCalendarEntry();
085                                    strutsActionForward = "timesheetPayoutSuccess";
086                                    methodToCall = "approveTimesheet";
087                            }
088                            else {
089                                    LeaveCalendarDocument lcd = TkServiceLocator.getLeaveCalendarService().getLeaveCalendarDocument(documentId);
090                                    calendarEntry = lcd == null ? null : lcd.getCalendarEntry();
091                                    strutsActionForward = "leaveCalendarPayoutSuccess";
092                                    methodToCall = "approveLeaveCalendar";
093                            }
094                            
095                            if(ObjectUtils.isNull(calendarEntry)) {
096                                    throw new RuntimeException("Could not retreive calendar entry for document " + documentId);
097                            }
098                            
099                            AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualRuleId);
100                            AccrualCategory accrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(accrualRule.getLmAccrualCategoryId());
101                            BigDecimal accruedBalance = TkServiceLocator.getAccrualCategoryService().getAccruedBalanceForPrincipal(leavePayout.getPrincipalId(), accrualCategory, leavePayout.getEffectiveDate());
102    
103                            LeavePayout defaultBT = TkServiceLocator.getLeavePayoutService().initializePayout(leavePayout.getPrincipalId(), accrualRuleId, accruedBalance, leavePayout.getEffectiveDate());
104                            if(leavePayout.getPayoutAmount().compareTo(defaultBT.getPayoutAmount()) != 0) {
105                                    //employee changed the payout amount, recalculate forfeiture.
106                                    //Note: payout form has been validated.
107                                    leavePayout = defaultBT.adjust(leavePayout.getPayoutAmount());
108                                    // showing the adjusted balance payout via the execution of another forward
109                                    // would cause a loop that would break only if the original payout amount was re-established in the form.
110                                    // javascript must be written if the forfeited amount is to be updated on the form object.
111                                    // an alternative to javascript would be to render a "re-calculate" button attached to a dedicated action forward method.
112                                    // must re-set leaveCalendarDocumentId, as leavePayout is now just an adjustment of the default initialized BT with no leave calendar doc id.
113                                    leavePayout.setLeaveCalendarDocumentId(documentId);
114                            }
115    
116                            TkServiceLocator.getLeavePayoutService().submitToWorkflow(leavePayout);
117                            
118                            if(ObjectUtils.isNotNull(documentId)) {
119                                    if(StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.LEAVE_APPROVE) ||
120                                                    StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(), LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) {
121                                            
122                                            ActionForward forward = new ActionForward(mapping.findForward(strutsActionForward));
123                                            forward.setPath(forward.getPath()+"?documentId="+documentId+"&action=R&methodToCall="+methodToCall);
124                                            return forward;
125                                    }
126                                    else
127                                            return mapping.findForward("closeLeavePayoutDoc");
128                            }
129                            else
130                                    return mapping.findForward("closeLeavePayoutDoc");
131                    }
132                    else //show user errors.
133                            return mapping.findForward("basic");
134            }
135            
136            public ActionForward cancel(ActionMapping mapping, ActionForm form,
137                            HttpServletRequest request, HttpServletResponse response)
138                            throws Exception {
139                    
140                    LeavePayoutForm lpf = (LeavePayoutForm) form;
141                    LeavePayout leavePayout = lpf.getLeavePayout();
142                    String accrualCategoryRuleId = leavePayout.getAccrualCategoryRule();
143                    AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualCategoryRuleId);
144                    String actionFrequency = accrualRule.getMaxBalanceActionFrequency();
145                    
146                    if(StringUtils.equals(actionFrequency,LMConstants.MAX_BAL_ACTION_FREQ.ON_DEMAND))
147                            return mapping.findForward("closeLeavePayoutDoc");
148                    else 
149                            if(StringUtils.equals(actionFrequency, LMConstants.MAX_BAL_ACTION_FREQ.LEAVE_APPROVE) ||
150                                            StringUtils.equals(actionFrequency, LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) {
151                                    
152                                    String documentId = leavePayout.getLeaveCalendarDocumentId();
153                                    TimesheetDocumentHeader tsdh = TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(documentId);
154                                    LeaveCalendarDocumentHeader lcdh = TkServiceLocator.getLeaveCalendarDocumentHeaderService().getDocumentHeader(documentId);
155                                    String strutsActionForward = "";
156                                    if(ObjectUtils.isNull(tsdh) && ObjectUtils.isNull(lcdh)) {
157                                            strutsActionForward = "/";
158                                    }
159                                    else if(ObjectUtils.isNotNull(tsdh)) {
160                                            //Throws runtime exception, separate action forwards for timesheet/leave calendar transfers.
161                                            strutsActionForward = mapping.findForward("timesheetCancel").getPath() + "?documentId=" + leavePayout.getLeaveCalendarDocumentId();
162                                    }
163                                    else {
164                                            strutsActionForward = mapping.findForward("leaveCalendarCancel").getPath() + "?documentId=" + leavePayout.getLeaveCalendarDocumentId();
165                                    }
166    
167                                    ActionRedirect redirect = new ActionRedirect();
168                                    redirect.setPath(strutsActionForward);
169                                    return redirect;
170    
171                            }
172                            else
173                                    throw new RuntimeException("Action should only be reachable through triggers with frequency ON_DEMAND or LEAVE_APPROVE");
174            }
175            
176            //Entry point for LeavePayout.do for accrual category rule triggered payouts with action frequency On Demand.
177            //May be better suited in the LeaveCalendarAction class.
178            public ActionForward leavePayoutOnDemand(ActionMapping mapping, ActionForm form,
179                            HttpServletRequest request, HttpServletResponse response)
180                            throws Exception {
181                    GlobalVariables.getMessageMap().putWarning("document.payoutAmount","leavePayout.payoutAmount.adjust");
182    
183                    LeavePayoutForm lpf = (LeavePayoutForm) form;
184                    //the leave calendar document that triggered this balance payout.
185                    String documentId = request.getParameter("documentId");
186                    String leaveBlockId = request.getParameter("accrualRuleId");
187                    String timesheet = request.getParameter("timesheet");
188    
189                    boolean isTimesheet = false;
190                    if(StringUtils.equals(timesheet, "true")) {
191                            lpf.isTimesheet(true);
192                            isTimesheet = true;
193                    }
194                    if(ObjectUtils.isNotNull(leaveBlockId)) {
195                            AccrualCategoryRule aRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(leaveBlockId);
196                            if(ObjectUtils.isNotNull(aRule)) {
197                                    //should somewhat safegaurd against url fabrication.
198                                    if(!StringUtils.equals(aRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.ON_DEMAND))
199                                            throw new RuntimeException("attempted to execute on-demand balance payout for accrual category with action frequency " + aRule.getMaxBalanceActionFrequency());
200                                    else {
201                                            TimesheetDocument tsd = null;
202                                            LeaveCalendarDocument lcd = null;
203                                            String principalId = null;
204                                            CalendarEntries calendarEntry = null;
205    
206                                            if(isTimesheet) {
207                                                    tsd = TkServiceLocator.getTimesheetService().getTimesheetDocument(documentId);
208                                                    principalId = tsd == null ? null : tsd.getPrincipalId();
209                                            }
210                                            else {
211                                                    lcd = TkServiceLocator.getLeaveCalendarService().getLeaveCalendarDocument(documentId);
212                                                    principalId = lcd == null ? null : lcd.getPrincipalId();
213                                            }
214                                            
215                                            AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(leaveBlockId);
216                                            AccrualCategory accrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(accrualRule.getLmAccrualCategoryId());
217                                            BigDecimal accruedBalance = TkServiceLocator.getAccrualCategoryService().getAccruedBalanceForPrincipal(principalId, accrualCategory, TKUtils.getCurrentDate());
218    
219                                            LeavePayout leavePayout = TkServiceLocator.getLeavePayoutService().initializePayout(principalId, leaveBlockId, accruedBalance, TKUtils.getCurrentDate());
220                                            leavePayout.setLeaveCalendarDocumentId(documentId);
221                                            if(ObjectUtils.isNotNull(leavePayout)) {
222                                                    if(StringUtils.equals(aRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.LOSE)) {      
223                                                            // this particular combination of action / action frequency does not particularly make sense
224                                                            // unless for some reason users still need to be prompted to submit the loss.
225                                                            // For now, we treat as though it is a valid use-case.
226                                                            //TkServiceLocator.getLeavePayoutService().submitToWorkflow(leavePayout);
227                                                            // May need to update to save the business object to KPME's tables for record keeping.
228                                                            leavePayout = TkServiceLocator.getLeavePayoutService().payout(leavePayout);
229                                                            // May need to update to save the business object to KPME's tables for record keeping.
230                                                            LeaveBlock forfeitedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(leavePayout.getForfeitedLeaveBlockId());
231                                                            forfeitedLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED);
232                                                            TkServiceLocator.getLeaveBlockService().updateLeaveBlock(forfeitedLeaveBlock, principalId);
233                                                            return mapping.findForward("closeLeavePayoutDoc");
234                                                    }
235                                                    else {
236                                                            ActionForward forward = mapping.findForward("basic");
237                                                            lpf.setLeaveCalendarDocumentId(documentId);
238                                                            lpf.setLeavePayout(leavePayout);
239                                                            lpf.setPayoutAmount(leavePayout.getPayoutAmount());
240                                                            return forward;
241                                                    }
242                                            }
243                                            else
244                                                    throw new RuntimeException("could not initialize a balance payout");
245    
246                                    }
247                            }
248                            else
249                                    throw new RuntimeException("No rule for this accrual category could be found");
250                    }
251                    else
252                            throw new RuntimeException("No accrual category rule id has been sent in the request.");
253            }
254    
255            //Entry point for LeavePayout.do for accrual category rule triggered transfers with action frequency Leave Approve.
256            //TODO: Rename method to differentiate from ActionForward with same name in LeaveCalendarSubmit.
257            public ActionForward approveLeaveCalendar(ActionMapping mapping, ActionForm form,
258                            HttpServletRequest request, HttpServletResponse response)
259                                            throws Exception {
260                    
261                    GlobalVariables.getMessageMap().putWarning("document.newMaintainableObj.transferAmount","leavePayout.transferAmount.adjust");
262                    LeavePayoutForm btf = (LeavePayoutForm) form;
263    
264                    List<LeaveBlock> eligiblePayouts = (List<LeaveBlock>) request.getSession().getAttribute("eligibilities");
265                    if(!eligiblePayouts.isEmpty()) {
266                            
267                            Collections.sort(eligiblePayouts, new Comparator() {
268    
269                    @Override
270                    public int compare(Object o1, Object o2) {
271                        LeaveBlock l1 = (LeaveBlock) o1;
272                        LeaveBlock l2 = (LeaveBlock) o2;
273                        return l1.getLeaveDate().compareTo(l2.getLeaveDate());
274                    }
275    
276                });
277                            
278                            //This is the leave calendar document that triggered this balance transfer.
279    
280                            String leaveCalendarDocumentId = request.getParameter("documentId");
281                            ActionForward forward = new ActionForward(mapping.findForward("basic"));
282                            LeaveCalendarDocument lcd = TkServiceLocator.getLeaveCalendarService().getLeaveCalendarDocument(leaveCalendarDocumentId);
283                            String principalId = lcd == null ? null : lcd.getPrincipalId();
284                            LeaveBlock leaveBlock = eligiblePayouts.get(0);
285                            Date effectiveDate = leaveBlock.getLeaveDate();
286                            String accrualCategoryRuleId = leaveBlock.getAccrualCategoryRuleId();
287                            if(!StringUtils.isBlank(accrualCategoryRuleId)) {
288                                    AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualCategoryRuleId);
289                                    AccrualCategory accrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(accrualRule.getLmAccrualCategoryId());
290                                    BigDecimal accruedBalance = TkServiceLocator.getAccrualCategoryService().getAccruedBalanceForPrincipal(principalId, accrualCategory, effectiveDate);
291                            
292                                    LeavePayout leavePayout = TkServiceLocator.getLeavePayoutService().initializePayout(principalId, accrualCategoryRuleId, accruedBalance, effectiveDate);
293                                    leavePayout.setLeaveCalendarDocumentId(leaveCalendarDocumentId);
294            
295                                    if(ObjectUtils.isNotNull(leavePayout)) {
296            
297                                    if(StringUtils.equals(accrualRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.LOSE)) {
298                                            //payouts should never contain losses.
299                                            //losses are treated as a special case of transfer
300                                            //TkServiceLocator.getLeavePayoutService().submitToWorkflow(leavePayout);
301                                            leavePayout = TkServiceLocator.getLeavePayoutService().payout(leavePayout);
302                                            // May need to update to save the business object to KPME's tables for record keeping.
303                                            LeaveBlock forfeitedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(leavePayout.getForfeitedLeaveBlockId());
304                                            KRADServiceLocator.getBusinessObjectService().save(leavePayout);
305                                            forfeitedLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED);
306                                            TkServiceLocator.getLeaveBlockService().updateLeaveBlock(forfeitedLeaveBlock, principalId);
307                                            
308                                            if(ObjectUtils.isNotNull(leaveCalendarDocumentId)) {
309                                                    if(StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.LEAVE_APPROVE) ||
310                                                                    StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(), LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) {
311                                                            ActionForward loseForward = new ActionForward(mapping.findForward("leaveCalendarPayoutSuccess"));
312                                                            loseForward.setPath(loseForward.getPath()+"?documentId="+leaveCalendarDocumentId+"&action=R&methodToCall=approveLeaveCalendar");
313                                                            return loseForward;
314                                                    }
315                                                    //on demand handled in separate action forward.
316                                            }
317    
318                                    } else {
319                                            btf.setLeaveCalendarDocumentId(leaveCalendarDocumentId);
320                                            btf.setLeavePayout(leavePayout);
321                                            btf.setPayoutAmount(leavePayout.getPayoutAmount());
322                                            return forward;
323                                    }
324    
325                            }
326                            throw new RuntimeException("could not initialize balance transfer");
327    
328                    }
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            public ActionForward approveTimesheet(ActionMapping mapping, ActionForm form,
337                            HttpServletRequest request, HttpServletResponse response)
338                                            throws Exception {
339                    
340                    GlobalVariables.getMessageMap().putWarning("document.newMaintainableObj.transferAmount","leavePayout.transferAmount.adjust");
341                    LeavePayoutForm btf = (LeavePayoutForm) form;
342    
343                    List<LeaveBlock> eligiblePayouts = (List<LeaveBlock>) request.getSession().getAttribute("eligibilities");
344                    if(!eligiblePayouts.isEmpty()) {
345                            
346                            Collections.sort(eligiblePayouts, new Comparator() {
347                                    
348                                    @Override
349                                    public int compare(Object o1, Object o2) {
350                                            LeaveBlock l1 = (LeaveBlock) o1;
351                                            LeaveBlock l2 = (LeaveBlock) o2;
352                                            return l1.getLeaveDate().compareTo(l2.getLeaveDate());
353                                    }
354                                    
355                            });
356                            
357                            //This is the leave calendar document that triggered this balance transfer.
358    
359                            String timesheetDocumentId = request.getParameter("documentId");
360                            ActionForward forward = new ActionForward(mapping.findForward("basic"));
361                            TimesheetDocument tsd = TkServiceLocator.getTimesheetService().getTimesheetDocument(timesheetDocumentId);
362                            String principalId = tsd == null ? null : tsd.getPrincipalId();
363    
364                            LeaveBlock leaveBlock = eligiblePayouts.get(0);
365                            Date effectiveDate = leaveBlock.getLeaveDate();
366                            String accrualCategoryRuleId = leaveBlock.getAccrualCategoryRuleId();
367                            if(!StringUtils.isBlank(accrualCategoryRuleId)) {
368                                    AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualCategoryRuleId);
369                                    AccrualCategory accrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(accrualRule.getLmAccrualCategoryId());
370                                    BigDecimal accruedBalance = TkServiceLocator.getAccrualCategoryService().getAccruedBalanceForPrincipal(principalId, accrualCategory, effectiveDate);
371    
372                                    LeavePayout leavePayout = TkServiceLocator.getLeavePayoutService().initializePayout(principalId, accrualCategoryRuleId, accruedBalance, effectiveDate);
373                                    leavePayout.setLeaveCalendarDocumentId(timesheetDocumentId);
374            
375                                    if(ObjectUtils.isNotNull(leavePayout)) {
376            
377                                            if(StringUtils.equals(accrualRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.LOSE)) {
378                                                    // TODO: Redirect user to prompt stating excess leave will be forfeited and ask for confirmation.
379                                                    // Do not submit the object to workflow for this max balance action.
380                                                    leavePayout = TkServiceLocator.getLeavePayoutService().payout(leavePayout);
381                                                    KRADServiceLocator.getBusinessObjectService().save(leavePayout);
382            
383                                                    // May need to update to save the business object to KPME's tables for record keeping.
384                                                    LeaveBlock forfeitedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(leavePayout.getForfeitedLeaveBlockId());
385                                                    forfeitedLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED);
386                                                    TkServiceLocator.getLeaveBlockService().updateLeaveBlock(forfeitedLeaveBlock, principalId);
387    
388                                                    if(ObjectUtils.isNotNull(timesheetDocumentId)) {
389                                                            if(StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.LEAVE_APPROVE) ||
390                                                                            StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(), LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) {
391                                                                    ActionForward loseForward = new ActionForward(mapping.findForward("timesheetPayoutSuccess"));
392                                                                    loseForward.setPath(loseForward.getPath()+"?documentId="+timesheetDocumentId+"&action=R&methodToCall=approveTimesheet");
393                                                                    return loseForward;
394                                                            }
395                                                            //on demand handled in separate action forward.
396                                                    }
397            
398                                            } else {
399                                                    btf.setLeaveCalendarDocumentId(timesheetDocumentId);
400                                                    btf.setLeavePayout(leavePayout);
401                                                    btf.setPayoutAmount(leavePayout.getPayoutAmount());
402                                                    return forward;
403                                            }
404            
405                                    }
406                                    throw new RuntimeException("could not initialize balance transfer");
407    
408                    }
409                    else
410                            throw new RuntimeException("unable to fetch the accrual category that triggerred this transfer");
411                    }
412                    else
413                            throw new RuntimeException("no eligible transfers exist");
414            }
415            
416            public ActionForward closeLeavePayoutDoc(ActionMapping mapping, ActionForm form,
417                            HttpServletRequest request, HttpServletResponse response)
418                            throws Exception {
419                    return mapping.findForward("closeLeavePayoutDoc");
420            }
421    }