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