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.setRequestStatus(LMConstants.REQUEST_STATUS.REQUESTED);
244 aLeaveBlock.setBlockId(0L);
245
246
247
248
249 aLeaveBlock = KRADServiceLocator.getBusinessObjectService().save(aLeaveBlock);
250
251 balanceTransfer.setAccruedLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
252
253 LeaveBlockHistory lbh = new LeaveBlockHistory(aLeaveBlock);
254 lbh.setAction(LMConstants.ACTION.ADD);
255 TkServiceLocator.getLeaveBlockHistoryService().saveLeaveBlockHistory(lbh);
256 leaveBlocks.add(aLeaveBlock);
257 }
258 }
259
260 if(ObjectUtils.isNotNull(transferAmount)) {
261 if(transferAmount.compareTo(BigDecimal.ZERO) > 0) {
262
263 aLeaveBlock = new LeaveBlock();
264 aLeaveBlock.setPrincipalId(balanceTransfer.getPrincipalId());
265 aLeaveBlock.setLeaveDate(balanceTransfer.getEffectiveDate());
266 aLeaveBlock.setEarnCode(balanceTransfer.getDebitedAccrualCategory().getEarnCode());
267 aLeaveBlock.setAccrualCategory(balanceTransfer.getFromAccrualCategory());
268 aLeaveBlock.setDescription("Transferred amount");
269 aLeaveBlock.setLeaveAmount(balanceTransfer.getTransferAmount().negate());
270 aLeaveBlock.setAccrualGenerated(true);
271 aLeaveBlock.setTransactionDocId(balanceTransfer.getDocumentHeaderId());
272 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
273 aLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.REQUESTED);
274 aLeaveBlock.setBlockId(0L);
275
276
277
278
279 aLeaveBlock = KRADServiceLocator.getBusinessObjectService().save(aLeaveBlock);
280
281 balanceTransfer.setDebitedLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
282
283 LeaveBlockHistory lbh = new LeaveBlockHistory(aLeaveBlock);
284 lbh.setAction(LMConstants.ACTION.ADD);
285 TkServiceLocator.getLeaveBlockHistoryService().saveLeaveBlockHistory(lbh);
286
287 leaveBlocks.add(aLeaveBlock);
288 }
289 }
290
291 BigDecimal forfeitedAmount = balanceTransfer.getForfeitedAmount();
292 if(ObjectUtils.isNotNull(forfeitedAmount)) {
293
294 if(forfeitedAmount.compareTo(BigDecimal.ZERO) > 0) {
295
296 aLeaveBlock = new LeaveBlock();
297 aLeaveBlock.setPrincipalId(balanceTransfer.getPrincipalId());
298 aLeaveBlock.setLeaveDate(balanceTransfer.getEffectiveDate());
299 aLeaveBlock.setEarnCode(balanceTransfer.getDebitedAccrualCategory().getEarnCode());
300 aLeaveBlock.setAccrualCategory(balanceTransfer.getFromAccrualCategory());
301 aLeaveBlock.setDescription("Forfeited balance transfer amount");
302 aLeaveBlock.setLeaveAmount(forfeitedAmount.negate());
303 aLeaveBlock.setAccrualGenerated(true);
304 aLeaveBlock.setTransactionDocId(balanceTransfer.getDocumentHeaderId());
305 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
306 aLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.REQUESTED);
307 aLeaveBlock.setBlockId(0L);
308
309
310
311
312 aLeaveBlock = KRADServiceLocator.getBusinessObjectService().save(aLeaveBlock);
313
314 balanceTransfer.setForfeitedLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
315
316 LeaveBlockHistory lbh = new LeaveBlockHistory(aLeaveBlock);
317 lbh.setAction(LMConstants.ACTION.ADD);
318 TkServiceLocator.getLeaveBlockHistoryService().saveLeaveBlockHistory(lbh);
319
320 leaveBlocks.add(aLeaveBlock);
321 }
322 }
323
324 return balanceTransfer;
325 }
326 }
327
328 public BalanceTransferDao getBalanceTransferDao() {
329 return balanceTransferDao;
330 }
331
332 public void setBalanceTransferDao(BalanceTransferDao balanceTransferDao) {
333 this.balanceTransferDao = balanceTransferDao;
334 }
335
336 @Override
337 public void submitToWorkflow(BalanceTransfer balanceTransfer)
338 throws WorkflowException {
339
340
341 EntityNamePrincipalName principalName = null;
342 if (balanceTransfer.getPrincipalId() != null) {
343 principalName = KimApiServiceLocator.getIdentityService().getDefaultNamesForPrincipalId(balanceTransfer.getPrincipalId());
344 }
345
346 MaintenanceDocument document = KRADServiceLocatorWeb.getMaintenanceDocumentService().setupNewMaintenanceDocument(BalanceTransfer.class.getName(),
347 "BalanceTransferDocumentType",KRADConstants.MAINTENANCE_NEW_ACTION);
348
349 String personName = (principalName != null && principalName.getDefaultName() != null) ? principalName.getDefaultName().getCompositeName() : StringUtils.EMPTY;
350 String date = TKUtils.formatDate(new java.sql.Date(balanceTransfer.getEffectiveDate().getTime()));
351 document.getDocumentHeader().setDocumentDescription(personName + " (" + balanceTransfer.getPrincipalId() + ") - " + date);
352 Map<String,String[]> params = new HashMap<String,String[]>();
353
354 KRADServiceLocatorWeb.getMaintenanceDocumentService().setupMaintenanceObject(document, KRADConstants.MAINTENANCE_NEW_ACTION, params);
355 BalanceTransfer btObj = (BalanceTransfer) document.getNewMaintainableObject().getDataObject();
356
357 btObj.setAccrualCategoryRule(balanceTransfer.getAccrualCategoryRule());
358 btObj.setEffectiveDate(balanceTransfer.getEffectiveDate());
359 btObj.setForfeitedAmount(balanceTransfer.getForfeitedAmount());
360 btObj.setFromAccrualCategory(balanceTransfer.getFromAccrualCategory());
361 btObj.setPrincipalId(balanceTransfer.getPrincipalId());
362 btObj.setToAccrualCategory(balanceTransfer.getToAccrualCategory());
363 btObj.setTransferAmount(balanceTransfer.getTransferAmount());
364 btObj.setAmountTransferred(balanceTransfer.getAmountTransferred());
365 btObj.setSstoId(balanceTransfer.getSstoId());
366 btObj.setDocumentHeaderId(document.getDocumentHeader().getWorkflowDocument().getDocumentId());
367
368
369 KRADServiceLocatorWeb.getDocumentService().saveDocument(document);
370 document.getDocumentHeader().getWorkflowDocument().saveDocument("");
371
372 document.getDocumentHeader().getWorkflowDocument().route("");
373
374 }
375
376 @Override
377 public BalanceTransfer transferSsto(BalanceTransfer balanceTransfer) {
378 if(ObjectUtils.isNull(balanceTransfer))
379 throw new RuntimeException("did not supply a valid BalanceTransfer object.");
380 else {
381 List<LeaveBlock> sstoLbList = TkServiceLocator.getLeaveBlockService().getSSTOLeaveBlocks(balanceTransfer.getPrincipalId(), balanceTransfer.getSstoId(), balanceTransfer.getEffectiveDate());
382 String leaveDocId = "";
383 if(CollectionUtils.isNotEmpty(sstoLbList)) {
384 leaveDocId = sstoLbList.get(0).getDocumentId();
385 }
386 List<LeaveBlock> lbList = new ArrayList<LeaveBlock>();
387
388 LeaveBlock aLeaveBlock = new LeaveBlock();
389 aLeaveBlock.setPrincipalId(balanceTransfer.getPrincipalId());
390 aLeaveBlock.setLeaveDate(balanceTransfer.getEffectiveDate());
391 aLeaveBlock.setEarnCode(balanceTransfer.getCreditedAccrualCategory().getEarnCode());
392 aLeaveBlock.setAccrualCategory(balanceTransfer.getToAccrualCategory());
393 aLeaveBlock.setDescription("System Scheduled Time off Amount transferred");
394 aLeaveBlock.setLeaveAmount(balanceTransfer.getAmountTransferred());
395 aLeaveBlock.setAccrualGenerated(false);
396 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
397 aLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.REQUESTED);
398 aLeaveBlock.setBlockId(0L);
399 aLeaveBlock.setScheduleTimeOffId(balanceTransfer.getSstoId());
400 aLeaveBlock.setDocumentId(leaveDocId);
401
402 lbList.add(aLeaveBlock);
403 TkServiceLocator.getLeaveBlockService().saveLeaveBlocks(lbList);
404
405 balanceTransfer.setAccruedLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
406 return balanceTransfer;
407 }
408 }
409
410 @Override
411 public List<BalanceTransfer> getBalanceTransfers(String viewPrincipal,
412 Date beginPeriodDate, Date endPeriodDate) {
413
414 return balanceTransferDao.getBalanceTransfers(viewPrincipal, beginPeriodDate, endPeriodDate);
415 }
416
417 @Override
418 public void saveOrUpdate(BalanceTransfer balanceTransfer) {
419
420 balanceTransferDao.saveOrUpdate(balanceTransfer);
421 }
422 }