1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.hr.lm.balancetransfer.service;
17
18 import java.math.BigDecimal;
19 import java.sql.Date;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.apache.commons.collections.CollectionUtils;
26 import org.apache.commons.lang.StringUtils;
27
28 import org.kuali.hr.lm.LMConstants;
29 import org.kuali.hr.lm.accrual.AccrualCategory;
30 import org.kuali.hr.lm.accrual.AccrualCategoryRule;
31 import org.kuali.hr.lm.balancetransfer.BalanceTransfer;
32 import org.kuali.hr.lm.balancetransfer.dao.BalanceTransferDao;
33 import org.kuali.hr.lm.employeeoverride.EmployeeOverride;
34 import org.kuali.hr.lm.leaveblock.LeaveBlock;
35 import org.kuali.hr.lm.leaveblock.LeaveBlockHistory;
36
37 import org.kuali.hr.time.service.base.TkServiceLocator;
38 import org.kuali.hr.time.util.TKUtils;
39
40 import org.kuali.rice.kew.api.exception.WorkflowException;
41 import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
42 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
43 import org.kuali.rice.krad.maintenance.MaintenanceDocument;
44 import org.kuali.rice.krad.service.KRADServiceLocator;
45 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
46 import org.kuali.rice.krad.util.KRADConstants;
47 import org.kuali.rice.krad.util.ObjectUtils;
48
49 public class BalanceTransferServiceImpl implements BalanceTransferService {
50
51 private BalanceTransferDao balanceTransferDao;
52
53 @Override
54 public List<BalanceTransfer> getAllBalanceTransfersForPrincipalId(
55 String principalId) {
56 return balanceTransferDao.getAllBalanceTransfersForPrincipalId(principalId);
57 }
58
59 @Override
60 public List<BalanceTransfer> getAllBalanceTransferForPrincipalIdAsOfDate(
61 String principalId, Date effectiveDate) {
62 return balanceTransferDao.getAllBalanceTransferForPrincipalIdAsOfDate(principalId,effectiveDate);
63 }
64
65 @Override
66 public List<BalanceTransfer> getAllBalanceTransferByEffectiveDate(
67 Date effectiveDate) {
68 return balanceTransferDao.getAllBalanceTransferByEffectiveDate(effectiveDate);
69 }
70
71 @Override
72 public BalanceTransfer getBalanceTransferById(String balanceTransferId) {
73 return balanceTransferDao.getBalanceTransferById(balanceTransferId);
74 }
75
76 @Override
77 public BalanceTransfer initializeTransfer(String principalId, String accrualCategoryRule, BigDecimal accruedBalance, Date effectiveDate) {
78
79
80
81 BalanceTransfer bt = null;
82 AccrualCategoryRule accrualRule = TkServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualCategoryRule);
83
84 if(ObjectUtils.isNotNull(accrualRule) && ObjectUtils.isNotNull(accruedBalance)) {
85 bt = new BalanceTransfer();
86
87
88 AccrualCategory fromAccrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(accrualRule.getLmAccrualCategoryId());
89 AccrualCategory toAccrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(accrualRule.getMaxBalanceTransferToAccrualCategory(),effectiveDate);
90 BigDecimal fullTimeEngagement = TkServiceLocator.getJobService().getFteSumForAllActiveLeaveEligibleJobs(principalId, effectiveDate);
91
92 BigDecimal transferConversionFactor = null;
93 if(ObjectUtils.isNotNull(accrualRule.getMaxBalanceTransferConversionFactor()))
94 transferConversionFactor = accrualRule.getMaxBalanceTransferConversionFactor();
95
96
97
98 BigDecimal maxBalance = accrualRule.getMaxBalance();
99 BigDecimal adjustedMaxBalance = maxBalance.multiply(fullTimeEngagement).setScale(2);
100
101 BigDecimal maxTransferAmount = null;
102 BigDecimal adjustedMaxTransferAmount = null;
103 if(ObjectUtils.isNotNull(accrualRule.getMaxTransferAmount())) {
104 maxTransferAmount = new BigDecimal(accrualRule.getMaxTransferAmount());
105 adjustedMaxTransferAmount = maxTransferAmount.multiply(fullTimeEngagement).setScale(2);
106 }
107 else {
108
109 maxTransferAmount = new BigDecimal(Long.MAX_VALUE);
110 adjustedMaxTransferAmount = maxTransferAmount;
111 }
112
113 BigDecimal maxCarryOver = null;
114 BigDecimal adjustedMaxCarryOver = null;
115 if(ObjectUtils.isNotNull(accrualRule.getMaxCarryOver())) {
116 maxCarryOver = new BigDecimal(accrualRule.getMaxCarryOver());
117 adjustedMaxCarryOver = maxCarryOver.multiply(fullTimeEngagement).setScale(2);
118 }
119 else {
120
121 maxCarryOver = new BigDecimal(Long.MAX_VALUE);
122 adjustedMaxCarryOver = maxCarryOver;
123 }
124
125 List<EmployeeOverride> overrides = TkServiceLocator.getEmployeeOverrideService().getEmployeeOverrides(principalId, effectiveDate);
126 for(EmployeeOverride override : overrides) {
127 if(StringUtils.equals(override.getAccrualCategory(),fromAccrualCategory.getAccrualCategory())) {
128
129 if(StringUtils.equals(override.getOverrideType(),"MB"))
130 adjustedMaxBalance = new BigDecimal(override.getOverrideValue());
131 if(StringUtils.equals(override.getOverrideType(),"MTA"))
132 adjustedMaxTransferAmount = new BigDecimal(override.getOverrideValue());
133 if(StringUtils.equals(override.getOverrideType(),"MAC"))
134 adjustedMaxCarryOver = new BigDecimal(override.getOverrideValue());
135 }
136 }
137
138 BigDecimal transferAmount = accruedBalance.subtract(adjustedMaxBalance);
139 if(StringUtils.equals(accrualRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.LOSE)) {
140
141 bt.setForfeitedAmount(transferAmount);
142
143 bt.setTransferAmount(BigDecimal.ZERO);
144 bt.setAmountTransferred(BigDecimal.ZERO);
145
146
147 bt.setToAccrualCategory(fromAccrualCategory.getAccrualCategory());
148 }
149 else {
150
151 bt.setToAccrualCategory(toAccrualCategory.getAccrualCategory());
152 if(transferAmount.compareTo(adjustedMaxTransferAmount) > 0) {
153
154
155
156
157 BigDecimal forfeiture = transferAmount.subtract(adjustedMaxTransferAmount).setScale(2);
158 forfeiture = forfeiture.stripTrailingZeros();
159 bt.setForfeitedAmount(forfeiture);
160 bt.setTransferAmount(adjustedMaxTransferAmount);
161 }
162 else {
163 bt.setTransferAmount(transferAmount);
164 bt.setForfeitedAmount(BigDecimal.ZERO);
165 }
166 }
167
168 assert(adjustedMaxBalance.compareTo(accruedBalance.subtract(bt.getTransferAmount().add(bt.getForfeitedAmount()))) == 0);
169
170
171 if(StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(),LMConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) {
172
173
174
175 if(adjustedMaxBalance.compareTo(adjustedMaxCarryOver) > 0) {
176 BigDecimal carryOverDiff = adjustedMaxBalance.subtract(adjustedMaxCarryOver);
177
178 if(StringUtils.equals(accrualRule.getActionAtMaxBalance(),LMConstants.ACTION_AT_MAX_BAL.LOSE)){
179
180 bt.setForfeitedAmount(bt.getForfeitedAmount().add(carryOverDiff));
181 }
182 else {
183
184 BigDecimal potentialTransferAmount = bt.getTransferAmount().add(carryOverDiff);
185
186
187 if(potentialTransferAmount.compareTo(adjustedMaxTransferAmount) <= 0) {
188
189 bt.setTransferAmount(bt.getTransferAmount().add(carryOverDiff));
190 }
191 else {
192
193 BigDecimal carryOverExcess = potentialTransferAmount.subtract(adjustedMaxTransferAmount);
194
195 bt.setForfeitedAmount(bt.getForfeitedAmount().add(carryOverExcess));
196
197 bt.setTransferAmount(bt.getTransferAmount().add(carryOverDiff.subtract(carryOverExcess)));
198
199 assert(bt.getTransferAmount().compareTo(adjustedMaxTransferAmount)==0);
200
201 }
202 }
203 assert(adjustedMaxCarryOver.compareTo(accruedBalance.subtract(bt.getTransferAmount().add(bt.getForfeitedAmount()))) == 0);
204 }
205
206 }
207
208 bt.setEffectiveDate(effectiveDate);
209 bt.setAccrualCategoryRule(accrualCategoryRule);
210 bt.setFromAccrualCategory(fromAccrualCategory.getAccrualCategory());
211 bt.setPrincipalId(principalId);
212 if(ObjectUtils.isNotNull(transferConversionFactor))
213 bt.setAmountTransferred(bt.getTransferAmount().multiply(transferConversionFactor).setScale(2));
214 else
215 bt.setAmountTransferred(bt.getTransferAmount());
216 }
217 return bt;
218 }
219
220 @Override
221 public BalanceTransfer transfer(BalanceTransfer balanceTransfer) {
222 if(ObjectUtils.isNull(balanceTransfer))
223 throw new RuntimeException("did not supply a valid BalanceTransfer object.");
224 else {
225 List<LeaveBlock> leaveBlocks = new ArrayList<LeaveBlock>();
226 BigDecimal transferAmount = balanceTransfer.getTransferAmount();
227 LeaveBlock aLeaveBlock = null;
228
229 if(ObjectUtils.isNotNull(balanceTransfer.getAmountTransferred())) {
230 if(balanceTransfer.getAmountTransferred().compareTo(BigDecimal.ZERO) > 0 ) {
231
232 aLeaveBlock = new LeaveBlock();
233
234 aLeaveBlock.setPrincipalId(balanceTransfer.getPrincipalId());
235 aLeaveBlock.setLeaveDate(balanceTransfer.getEffectiveDate());
236 aLeaveBlock.setEarnCode(balanceTransfer.getCreditedAccrualCategory().getEarnCode());
237 aLeaveBlock.setAccrualCategory(balanceTransfer.getToAccrualCategory());
238 aLeaveBlock.setDescription("Amount transferred");
239 aLeaveBlock.setLeaveAmount(balanceTransfer.getAmountTransferred());
240 aLeaveBlock.setAccrualGenerated(true);
241 aLeaveBlock.setTransactionDocId(balanceTransfer.getDocumentHeaderId());
242 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
243 aLeaveBlock.setDocumentId(balanceTransfer.getLeaveCalendarDocumentId());
244 aLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.REQUESTED);
245 aLeaveBlock.setBlockId(0L);
246
247
248
249
250 aLeaveBlock = KRADServiceLocator.getBusinessObjectService().save(aLeaveBlock);
251
252 balanceTransfer.setAccruedLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
253
254 LeaveBlockHistory lbh = new LeaveBlockHistory(aLeaveBlock);
255 lbh.setAction(LMConstants.ACTION.ADD);
256 TkServiceLocator.getLeaveBlockHistoryService().saveLeaveBlockHistory(lbh);
257 leaveBlocks.add(aLeaveBlock);
258 }
259 }
260
261 if(ObjectUtils.isNotNull(transferAmount)) {
262 if(transferAmount.compareTo(BigDecimal.ZERO) > 0) {
263
264 aLeaveBlock = new LeaveBlock();
265 aLeaveBlock.setPrincipalId(balanceTransfer.getPrincipalId());
266 aLeaveBlock.setLeaveDate(balanceTransfer.getEffectiveDate());
267 aLeaveBlock.setEarnCode(balanceTransfer.getDebitedAccrualCategory().getEarnCode());
268 aLeaveBlock.setAccrualCategory(balanceTransfer.getFromAccrualCategory());
269 aLeaveBlock.setDescription("Transferred amount");
270 aLeaveBlock.setLeaveAmount(balanceTransfer.getTransferAmount().negate());
271 aLeaveBlock.setAccrualGenerated(true);
272 aLeaveBlock.setTransactionDocId(balanceTransfer.getDocumentHeaderId());
273 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
274 aLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.REQUESTED);
275 aLeaveBlock.setDocumentId(balanceTransfer.getLeaveCalendarDocumentId());
276 aLeaveBlock.setBlockId(0L);
277
278
279
280
281 aLeaveBlock = KRADServiceLocator.getBusinessObjectService().save(aLeaveBlock);
282
283 balanceTransfer.setDebitedLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
284
285 LeaveBlockHistory lbh = new LeaveBlockHistory(aLeaveBlock);
286 lbh.setAction(LMConstants.ACTION.ADD);
287 TkServiceLocator.getLeaveBlockHistoryService().saveLeaveBlockHistory(lbh);
288
289 leaveBlocks.add(aLeaveBlock);
290 }
291 }
292
293 BigDecimal forfeitedAmount = balanceTransfer.getForfeitedAmount();
294 if(ObjectUtils.isNotNull(forfeitedAmount)) {
295
296 if(forfeitedAmount.compareTo(BigDecimal.ZERO) > 0) {
297
298 aLeaveBlock = new LeaveBlock();
299 aLeaveBlock.setPrincipalId(balanceTransfer.getPrincipalId());
300 aLeaveBlock.setLeaveDate(balanceTransfer.getEffectiveDate());
301 aLeaveBlock.setEarnCode(balanceTransfer.getDebitedAccrualCategory().getEarnCode());
302 aLeaveBlock.setAccrualCategory(balanceTransfer.getFromAccrualCategory());
303 aLeaveBlock.setDescription("Forfeited balance transfer amount");
304 aLeaveBlock.setLeaveAmount(forfeitedAmount.negate());
305 aLeaveBlock.setAccrualGenerated(true);
306 aLeaveBlock.setTransactionDocId(balanceTransfer.getDocumentHeaderId());
307 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
308 aLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.REQUESTED);
309 aLeaveBlock.setDocumentId(balanceTransfer.getLeaveCalendarDocumentId());
310 aLeaveBlock.setBlockId(0L);
311
312
313
314
315 aLeaveBlock = KRADServiceLocator.getBusinessObjectService().save(aLeaveBlock);
316
317 balanceTransfer.setForfeitedLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
318
319 LeaveBlockHistory lbh = new LeaveBlockHistory(aLeaveBlock);
320 lbh.setAction(LMConstants.ACTION.ADD);
321 TkServiceLocator.getLeaveBlockHistoryService().saveLeaveBlockHistory(lbh);
322
323 leaveBlocks.add(aLeaveBlock);
324 }
325 }
326
327 return balanceTransfer;
328 }
329 }
330
331 public BalanceTransferDao getBalanceTransferDao() {
332 return balanceTransferDao;
333 }
334
335 public void setBalanceTransferDao(BalanceTransferDao balanceTransferDao) {
336 this.balanceTransferDao = balanceTransferDao;
337 }
338
339 @Override
340 public void submitToWorkflow(BalanceTransfer balanceTransfer)
341 throws WorkflowException {
342
343
344 EntityNamePrincipalName principalName = null;
345 if (balanceTransfer.getPrincipalId() != null) {
346 principalName = KimApiServiceLocator.getIdentityService().getDefaultNamesForPrincipalId(balanceTransfer.getPrincipalId());
347 }
348
349 MaintenanceDocument document = KRADServiceLocatorWeb.getMaintenanceDocumentService().setupNewMaintenanceDocument(BalanceTransfer.class.getName(),
350 "BalanceTransferDocumentType",KRADConstants.MAINTENANCE_NEW_ACTION);
351
352 String personName = (principalName != null && principalName.getDefaultName() != null) ? principalName.getDefaultName().getCompositeName() : StringUtils.EMPTY;
353 String date = TKUtils.formatDate(new java.sql.Date(balanceTransfer.getEffectiveDate().getTime()));
354 document.getDocumentHeader().setDocumentDescription(personName + " (" + balanceTransfer.getPrincipalId() + ") - " + date);
355 Map<String,String[]> params = new HashMap<String,String[]>();
356
357 KRADServiceLocatorWeb.getMaintenanceDocumentService().setupMaintenanceObject(document, KRADConstants.MAINTENANCE_NEW_ACTION, params);
358 BalanceTransfer btObj = (BalanceTransfer) document.getNewMaintainableObject().getDataObject();
359
360 btObj.setAccrualCategoryRule(balanceTransfer.getAccrualCategoryRule());
361 btObj.setEffectiveDate(balanceTransfer.getEffectiveDate());
362 btObj.setForfeitedAmount(balanceTransfer.getForfeitedAmount());
363 btObj.setFromAccrualCategory(balanceTransfer.getFromAccrualCategory());
364 btObj.setPrincipalId(balanceTransfer.getPrincipalId());
365 btObj.setToAccrualCategory(balanceTransfer.getToAccrualCategory());
366 btObj.setTransferAmount(balanceTransfer.getTransferAmount());
367 btObj.setAmountTransferred(balanceTransfer.getAmountTransferred());
368 btObj.setLeaveCalendarDocumentId(balanceTransfer.getLeaveCalendarDocumentId());
369 btObj.setSstoId(balanceTransfer.getSstoId());
370 btObj.setDocumentHeaderId(document.getDocumentHeader().getWorkflowDocument().getDocumentId());
371
372
373 KRADServiceLocatorWeb.getDocumentService().saveDocument(document);
374 document.getDocumentHeader().getWorkflowDocument().saveDocument("");
375
376 document.getDocumentHeader().getWorkflowDocument().route("");
377
378 }
379
380 @Override
381 public BalanceTransfer transferSsto(BalanceTransfer balanceTransfer) {
382 if(ObjectUtils.isNull(balanceTransfer))
383 throw new RuntimeException("did not supply a valid BalanceTransfer object.");
384 else {
385 List<LeaveBlock> sstoLbList = TkServiceLocator.getLeaveBlockService().getSSTOLeaveBlocks(balanceTransfer.getPrincipalId(), balanceTransfer.getSstoId(), balanceTransfer.getEffectiveDate());
386 String leaveDocId = "";
387 if(CollectionUtils.isNotEmpty(sstoLbList)) {
388 leaveDocId = sstoLbList.get(0).getDocumentId();
389 }
390 List<LeaveBlock> lbList = new ArrayList<LeaveBlock>();
391
392 LeaveBlock aLeaveBlock = new LeaveBlock();
393 aLeaveBlock.setPrincipalId(balanceTransfer.getPrincipalId());
394 aLeaveBlock.setLeaveDate(balanceTransfer.getEffectiveDate());
395 aLeaveBlock.setEarnCode(balanceTransfer.getCreditedAccrualCategory().getEarnCode());
396 aLeaveBlock.setAccrualCategory(balanceTransfer.getToAccrualCategory());
397 aLeaveBlock.setDescription("System Scheduled Time off Amount transferred");
398 aLeaveBlock.setLeaveAmount(balanceTransfer.getAmountTransferred());
399 aLeaveBlock.setAccrualGenerated(false);
400 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
401 aLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.REQUESTED);
402 aLeaveBlock.setBlockId(0L);
403 aLeaveBlock.setScheduleTimeOffId(balanceTransfer.getSstoId());
404 aLeaveBlock.setDocumentId(leaveDocId);
405
406 lbList.add(aLeaveBlock);
407 TkServiceLocator.getLeaveBlockService().saveLeaveBlocks(lbList);
408
409 balanceTransfer.setAccruedLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
410 return balanceTransfer;
411 }
412 }
413
414 @Override
415 public List<BalanceTransfer> getBalanceTransfers(String viewPrincipal,
416 Date beginPeriodDate, Date endPeriodDate) {
417
418 return balanceTransferDao.getBalanceTransfers(viewPrincipal, beginPeriodDate, endPeriodDate);
419 }
420
421 @Override
422 public void saveOrUpdate(BalanceTransfer balanceTransfer) {
423
424 balanceTransferDao.saveOrUpdate(balanceTransfer);
425 }
426 }