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