1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.kpme.tklm.leave.payout.service;
17
18 import java.math.BigDecimal;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.commons.lang.StringUtils;
25 import org.apache.log4j.Logger;
26 import org.joda.time.LocalDate;
27 import org.kuali.kpme.core.accrualcategory.AccrualCategory;
28 import org.kuali.kpme.core.accrualcategory.rule.AccrualCategoryRule;
29 import org.kuali.kpme.core.cache.CacheUtils;
30 import org.kuali.kpme.core.service.HrServiceLocator;
31 import org.kuali.kpme.core.util.HrConstants;
32 import org.kuali.kpme.core.util.TKUtils;
33 import org.kuali.kpme.tklm.common.LMConstants;
34 import org.kuali.kpme.tklm.common.TkConstants;
35 import org.kuali.kpme.tklm.leave.block.LeaveBlock;
36 import org.kuali.kpme.tklm.leave.block.LeaveBlockHistory;
37 import org.kuali.kpme.tklm.leave.override.EmployeeOverride;
38 import org.kuali.kpme.tklm.leave.payout.LeavePayout;
39 import org.kuali.kpme.tklm.leave.payout.dao.LeavePayoutDao;
40 import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
41 import org.kuali.rice.kew.api.exception.WorkflowException;
42 import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
43 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
44 import org.kuali.rice.krad.document.Document;
45 import org.kuali.rice.krad.maintenance.MaintenanceDocument;
46 import org.kuali.rice.krad.service.KRADServiceLocator;
47 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
48 import org.kuali.rice.krad.util.GlobalVariables;
49 import org.kuali.rice.krad.util.KRADConstants;
50 import org.kuali.rice.krad.util.ObjectUtils;
51
52 public class LeavePayoutServiceImpl implements LeavePayoutService {
53
54 private LeavePayoutDao leavePayoutDao;
55 private static final Logger LOG = Logger.getLogger(LeavePayoutServiceImpl.class);
56
57 @Override
58 public List<LeavePayout> getAllLeavePayoutsForPrincipalId(
59 String principalId) {
60 return leavePayoutDao.getAllLeavePayoutsForPrincipalId(principalId);
61 }
62
63 @Override
64 public List<LeavePayout> getAllLeavePayoutsForPrincipalIdAsOfDate(
65 String principalId, LocalDate effectiveDate) {
66 return leavePayoutDao.getAllLeavePayoutsForPrincipalIdAsOfDate(principalId,effectiveDate);
67 }
68
69 @Override
70 public List<LeavePayout> getAllLeavePayoutsByEffectiveDate(
71 LocalDate effectiveDate) {
72 return leavePayoutDao.getAllLeavePayoutsByEffectiveDate(effectiveDate);
73 }
74
75 @Override
76 public LeavePayout getLeavePayoutById(String lmLeavePayoutId) {
77 return leavePayoutDao.getLeavePayoutById(lmLeavePayoutId);
78 }
79
80 public LeavePayoutDao getLeavePayoutDao() {
81 return leavePayoutDao;
82 }
83
84 public void setLeavePayoutDao(LeavePayoutDao leavePayoutDao) {
85 this.leavePayoutDao = leavePayoutDao;
86 }
87
88 @Override
89 public LeavePayout initializePayout(String principalId,
90 String accrualCategoryRule, BigDecimal accruedBalance,
91 LocalDate effectiveDate) {
92
93
94
95 LeavePayout leavePayout = null;
96 AccrualCategoryRule accrualRule = HrServiceLocator.getAccrualCategoryRuleService().getAccrualCategoryRule(accrualCategoryRule);
97
98 if(ObjectUtils.isNotNull(accrualRule) && ObjectUtils.isNotNull(accruedBalance)) {
99 leavePayout = new LeavePayout();
100
101
102
103
104
105 AccrualCategory fromAccrualCategory = HrServiceLocator.getAccrualCategoryService().getAccrualCategory(accrualRule.getLmAccrualCategoryId());
106 BigDecimal fullTimeEngagement = HrServiceLocator.getJobService().getFteSumForAllActiveLeaveEligibleJobs(principalId, effectiveDate);
107
108
109
110 BigDecimal maxBalance = accrualRule.getMaxBalance();
111 BigDecimal adjustedMaxBalance = maxBalance.multiply(fullTimeEngagement).setScale(2);
112
113 BigDecimal maxPayoutAmount = null;
114 BigDecimal adjustedMaxPayoutAmount = null;
115 if(ObjectUtils.isNotNull(accrualRule.getMaxPayoutAmount())) {
116 maxPayoutAmount = new BigDecimal(accrualRule.getMaxPayoutAmount());
117 adjustedMaxPayoutAmount = maxPayoutAmount.multiply(fullTimeEngagement).setScale(2);
118 }
119 else {
120
121 maxPayoutAmount = new BigDecimal(Long.MAX_VALUE);
122 adjustedMaxPayoutAmount = maxPayoutAmount;
123 }
124
125 BigDecimal maxCarryOver = null;
126 BigDecimal adjustedMaxCarryOver = null;
127 if(ObjectUtils.isNotNull(accrualRule.getMaxCarryOver())) {
128 maxCarryOver = new BigDecimal(accrualRule.getMaxCarryOver());
129 adjustedMaxCarryOver = maxCarryOver.multiply(fullTimeEngagement).setScale(2);
130 }
131 else {
132
133 maxCarryOver = new BigDecimal(Long.MAX_VALUE);
134 adjustedMaxCarryOver = maxCarryOver;
135 }
136
137 EmployeeOverride maxBalanceOverride = LmServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, fromAccrualCategory.getLeavePlan(), fromAccrualCategory.getAccrualCategory(), "MB", effectiveDate);
138 EmployeeOverride maxPayoutAmountOverride = LmServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, fromAccrualCategory.getLeavePlan(), fromAccrualCategory.getAccrualCategory(), "MPA", effectiveDate);
139 EmployeeOverride maxAnnualCarryOverOverride = LmServiceLocator.getEmployeeOverrideService().getEmployeeOverride(principalId, fromAccrualCategory.getLeavePlan(), fromAccrualCategory.getAccrualCategory(), "MAC", effectiveDate);
140
141 if(maxBalanceOverride != null)
142 adjustedMaxBalance = new BigDecimal(maxBalanceOverride.getOverrideValue());
143 if(maxPayoutAmountOverride != null)
144 adjustedMaxPayoutAmount = new BigDecimal(maxPayoutAmountOverride.getOverrideValue());
145 if(maxAnnualCarryOverOverride != null)
146 adjustedMaxCarryOver = new BigDecimal(maxAnnualCarryOverOverride.getOverrideValue());
147
148
149 BigDecimal transferAmount = accruedBalance.subtract(adjustedMaxBalance);
150 if(transferAmount.compareTo(adjustedMaxPayoutAmount) > 0) {
151
152
153
154
155 BigDecimal forfeiture = transferAmount.subtract(adjustedMaxPayoutAmount).setScale(2);
156 forfeiture = forfeiture.stripTrailingZeros();
157 leavePayout.setForfeitedAmount(forfeiture);
158 leavePayout.setPayoutAmount(adjustedMaxPayoutAmount);
159 }
160 else {
161 leavePayout.setPayoutAmount(transferAmount);
162 leavePayout.setForfeitedAmount(BigDecimal.ZERO);
163 }
164
165 assert(adjustedMaxBalance.compareTo(accruedBalance.subtract(leavePayout.getPayoutAmount().add(leavePayout.getForfeitedAmount()))) == 0);
166
167
168 if(StringUtils.equals(accrualRule.getMaxBalanceActionFrequency(),HrConstants.MAX_BAL_ACTION_FREQ.YEAR_END)) {
169 if(ObjectUtils.isNotNull(maxCarryOver)) {
170
171 if(ObjectUtils.isNull(adjustedMaxCarryOver))
172 adjustedMaxCarryOver = maxCarryOver.multiply(fullTimeEngagement).setScale(2);
173
174
175
176 if(adjustedMaxBalance.compareTo(adjustedMaxCarryOver) > 0) {
177 BigDecimal carryOverDiff = adjustedMaxBalance.subtract(adjustedMaxCarryOver);
178
179 if(StringUtils.equals(accrualRule.getActionAtMaxBalance(),HrConstants.ACTION_AT_MAX_BALANCE.LOSE)){
180
181 leavePayout.setForfeitedAmount(leavePayout.getForfeitedAmount().add(carryOverDiff));
182 }
183 else {
184
185 BigDecimal potentialPayoutAmount = leavePayout.getPayoutAmount().add(carryOverDiff);
186
187
188 if(potentialPayoutAmount.compareTo(adjustedMaxPayoutAmount) <= 0) {
189
190 leavePayout.setPayoutAmount(leavePayout.getPayoutAmount().add(carryOverDiff));
191 }
192 else {
193
194 BigDecimal carryOverExcess = potentialPayoutAmount.subtract(adjustedMaxPayoutAmount);
195
196 leavePayout.setForfeitedAmount(leavePayout.getForfeitedAmount().add(carryOverExcess));
197
198 leavePayout.setPayoutAmount(leavePayout.getPayoutAmount().add(carryOverDiff.subtract(carryOverExcess)));
199
200 assert(adjustedMaxCarryOver.compareTo(accruedBalance.subtract(leavePayout.getPayoutAmount().add(leavePayout.getForfeitedAmount()))) == 0);
201 }
202 }
203 }
204
205 }
206 }
207
208 leavePayout.setEffectiveLocalDate(effectiveDate);
209 leavePayout.setAccrualCategoryRule(accrualCategoryRule);
210 leavePayout.setFromAccrualCategory(fromAccrualCategory.getAccrualCategory());
211 leavePayout.setPrincipalId(principalId);
212 leavePayout.setEarnCode(accrualRule.getMaxPayoutEarnCode());
213
214 }
215 return leavePayout;
216 }
217
218 @Override
219 public LeavePayout payout(LeavePayout leavePayout) {
220 if(ObjectUtils.isNull(leavePayout)) {
221
222 LOG.error("did not supply a valid LeavePayout object.");
223 return null;
224 } else {
225 List<LeaveBlock> leaveBlocks = new ArrayList<LeaveBlock>();
226 BigDecimal transferAmount = leavePayout.getPayoutAmount();
227 LeaveBlock aLeaveBlock = null;
228
229 if(ObjectUtils.isNotNull(transferAmount)) {
230 if(transferAmount.compareTo(BigDecimal.ZERO) > 0) {
231
232 aLeaveBlock = new LeaveBlock();
233
234 aLeaveBlock.setPrincipalId(leavePayout.getPrincipalId());
235 aLeaveBlock.setLeaveDate(leavePayout.getEffectiveDate());
236 aLeaveBlock.setEarnCode(leavePayout.getEarnCode());
237 aLeaveBlock.setAccrualCategory(leavePayout.getEarnCodeObj().getAccrualCategory());
238 aLeaveBlock.setDescription("Amount payed out");
239 aLeaveBlock.setLeaveAmount(leavePayout.getPayoutAmount());
240 aLeaveBlock.setAccrualGenerated(true);
241 aLeaveBlock.setTransactionDocId(leavePayout.getDocumentHeaderId());
242 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_PAYOUT);
243 aLeaveBlock.setRequestStatus(HrConstants.REQUEST_STATUS.REQUESTED);
244 aLeaveBlock.setDocumentId(leavePayout.getLeaveCalendarDocumentId());
245 aLeaveBlock.setBlockId(0L);
246
247
248
249
250 aLeaveBlock = LmServiceLocator.getLeaveBlockService().saveLeaveBlock(aLeaveBlock, GlobalVariables.getUserSession().getPrincipalId());
251
252 leavePayout.setPayoutLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
253
254
255 aLeaveBlock = new LeaveBlock();
256 aLeaveBlock.setPrincipalId(leavePayout.getPrincipalId());
257 aLeaveBlock.setLeaveDate(leavePayout.getEffectiveDate());
258 aLeaveBlock.setEarnCode(leavePayout.getFromAccrualCategoryObj().getEarnCode());
259 aLeaveBlock.setAccrualCategory(leavePayout.getFromAccrualCategory());
260 aLeaveBlock.setDescription("Payout amount");
261 aLeaveBlock.setLeaveAmount(leavePayout.getPayoutAmount().negate());
262 aLeaveBlock.setAccrualGenerated(true);
263 aLeaveBlock.setTransactionDocId(leavePayout.getDocumentHeaderId());
264 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_PAYOUT);
265 aLeaveBlock.setRequestStatus(HrConstants.REQUEST_STATUS.REQUESTED);
266 aLeaveBlock.setDocumentId(leavePayout.getLeaveCalendarDocumentId());
267 aLeaveBlock.setBlockId(0L);
268
269
270
271
272 aLeaveBlock = LmServiceLocator.getLeaveBlockService().saveLeaveBlock(aLeaveBlock, GlobalVariables.getUserSession().getPrincipalId());
273
274 leavePayout.setPayoutFromLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
275 }
276 }
277
278 BigDecimal forfeitedAmount = leavePayout.getForfeitedAmount();
279 if(ObjectUtils.isNotNull(forfeitedAmount)) {
280
281 if(forfeitedAmount.compareTo(BigDecimal.ZERO) > 0) {
282
283 aLeaveBlock = new LeaveBlock();
284 aLeaveBlock.setPrincipalId(leavePayout.getPrincipalId());
285 aLeaveBlock.setLeaveDate(leavePayout.getEffectiveDate());
286 aLeaveBlock.setEarnCode(leavePayout.getFromAccrualCategoryObj().getEarnCode());
287 aLeaveBlock.setAccrualCategory(leavePayout.getFromAccrualCategory());
288 aLeaveBlock.setDescription(LMConstants.PAYOUT_FORFEIT_LB_DESCRIPTION);
289 aLeaveBlock.setLeaveAmount(forfeitedAmount.negate());
290 aLeaveBlock.setAccrualGenerated(true);
291 aLeaveBlock.setTransactionDocId(leavePayout.getDocumentHeaderId());
292 aLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.LEAVE_PAYOUT);
293 aLeaveBlock.setRequestStatus(HrConstants.REQUEST_STATUS.REQUESTED);
294 aLeaveBlock.setDocumentId(leavePayout.getLeaveCalendarDocumentId());
295 aLeaveBlock.setBlockId(0L);
296
297
298
299
300 aLeaveBlock = LmServiceLocator.getLeaveBlockService().saveLeaveBlock(aLeaveBlock, GlobalVariables.getUserSession().getPrincipalId());
301
302 leavePayout.setForfeitedLeaveBlockId(aLeaveBlock.getLmLeaveBlockId());
303 }
304 }
305 return leavePayout;
306 }
307 }
308
309 @Override
310 public void submitToWorkflow(LeavePayout leavePayout)
311 throws WorkflowException {
312
313
314
315
316
317 MaintenanceDocument document = (MaintenanceDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument("LeavePayoutDocumentType");
318 document.getDocumentHeader().setDocumentDescription(TKUtils.getDocumentDescription(leavePayout.getPrincipalId(), leavePayout.getEffectiveLocalDate()));
319 Map<String,String[]> params = new HashMap<String,String[]>();
320
321 KRADServiceLocatorWeb.getMaintenanceDocumentService().setupMaintenanceObject(document, KRADConstants.MAINTENANCE_NEW_ACTION, params);
322
323 LeavePayout lpObj = (LeavePayout) document.getNewMaintainableObject().getDataObject();
324
325 lpObj.setAccrualCategoryRule(leavePayout.getAccrualCategoryRule());
326 lpObj.setEffectiveDate(leavePayout.getEffectiveDate());
327 lpObj.setLeaveCalendarDocumentId(leavePayout.getLeaveCalendarDocumentId());
328 lpObj.setForfeitedAmount(leavePayout.getForfeitedAmount());
329 lpObj.setFromAccrualCategory(leavePayout.getFromAccrualCategory());
330 lpObj.setPrincipalId(leavePayout.getPrincipalId());
331 lpObj.setEarnCode(leavePayout.getEarnCode());
332 lpObj.setPayoutAmount(leavePayout.getPayoutAmount());
333 lpObj.setDocumentHeaderId(document.getDocumentHeader().getWorkflowDocument().getDocumentId());
334
335
336 KRADServiceLocatorWeb.getDocumentService().saveDocument(document);
337 document.getDocumentHeader().getWorkflowDocument().saveDocument("");
338
339 document.getDocumentHeader().getWorkflowDocument().route("");
340 }
341
342 @Override
343 public List<LeavePayout> getLeavePayouts(String viewPrincipal,
344 LocalDate beginPeriodDate, LocalDate endPeriodDate) {
345 return leavePayoutDao.getLeavePayouts(viewPrincipal, beginPeriodDate, endPeriodDate);
346 }
347
348 @Override
349 public void saveOrUpdate(LeavePayout payout) {
350 leavePayoutDao.saveOrUpdate(payout);
351 }
352
353 @Override
354 public List<LeavePayout> getLeavePayouts(String principalId, String fromAccrualCategory, String payoutAmount, String earnCode, String forfeitedAmount, LocalDate fromEffdt, LocalDate toEffdt) {
355 return leavePayoutDao.getLeavePayouts(principalId, fromAccrualCategory, payoutAmount, earnCode, forfeitedAmount, fromEffdt, toEffdt);
356 }
357 }