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