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 }