1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.hr.lm.leavecalendar.validation;
17
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.joda.time.DateTime;
21 import org.joda.time.DateTimeConstants;
22 import org.kuali.hr.lm.LMConstants;
23 import org.kuali.hr.lm.accrual.AccrualCategory;
24 import org.kuali.hr.lm.employeeoverride.EmployeeOverride;
25 import org.kuali.hr.lm.leave.web.LeaveCalendarWSForm;
26 import org.kuali.hr.lm.leaveSummary.LeaveSummary;
27 import org.kuali.hr.lm.leaveSummary.LeaveSummaryRow;
28 import org.kuali.hr.lm.leaveblock.LeaveBlock;
29 import org.kuali.hr.time.calendar.CalendarEntries;
30 import org.kuali.hr.time.earncode.EarnCode;
31 import org.kuali.hr.time.earncodegroup.EarnCodeGroup;
32 import org.kuali.hr.time.service.base.TkServiceLocator;
33 import org.kuali.hr.time.util.TKContext;
34 import org.kuali.hr.time.util.TKUtils;
35 import org.kuali.hr.time.util.TkConstants;
36
37 import java.math.BigDecimal;
38 import java.sql.Date;
39 import java.util.*;
40
41 import org.kuali.rice.kew.api.KewApiServiceLocator;
42 import org.kuali.rice.kew.api.document.DocumentStatus;
43 import org.kuali.rice.krad.util.ObjectUtils;
44
45 public class LeaveCalendarValidationUtil {
46
47
48 public static List<String> validateLeaveAccrualRuleMaxUsage(LeaveCalendarWSForm lcf) {
49 LeaveBlock updatedLeaveBlock = null;
50 if(lcf.getLeaveBlockId() != null) {
51 updatedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(lcf.getLeaveBlockId());
52 }
53 return validateLeaveAccrualRuleMaxUsage(lcf.getLeaveSummary(), lcf.getSelectedEarnCode(), lcf.getStartDate(),
54 lcf.getEndDate(), lcf.getLeaveAmount(), updatedLeaveBlock);
55 }
56
57 public static List<String> validateLeaveAccrualRuleMaxUsage(LeaveSummary ls, String selectedEarnCode, String leaveStartDateString,
58 String leaveEndDateString, BigDecimal leaveAmount, LeaveBlock updatedLeaveBlock) {
59 List<String> errors = new ArrayList<String>();
60 String principalId = TKContext.getTargetPrincipalId();
61 long daysSpan = TKUtils.getDaysBetween(TKUtils.formatDateString(leaveStartDateString), TKUtils.formatDateString(leaveEndDateString));
62 if(ls != null && CollectionUtils.isNotEmpty(ls.getLeaveSummaryRows())) {
63 BigDecimal oldLeaveAmount = null;
64 boolean earnCodeChanged = false;
65 if(updatedLeaveBlock != null) {
66 if(!updatedLeaveBlock.getEarnCode().equals(selectedEarnCode)) {
67 earnCodeChanged = true;
68 }
69 if(!updatedLeaveBlock.getLeaveAmount().equals(leaveAmount)) {
70 oldLeaveAmount = updatedLeaveBlock.getLeaveAmount();
71 }
72 }
73 Date aDate = TKUtils.formatDateString(leaveEndDateString);
74 EarnCode earnCodeObj = TkServiceLocator.getEarnCodeService().getEarnCode(selectedEarnCode, aDate);
75 if(earnCodeObj != null) {
76 AccrualCategory accrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(earnCodeObj.getAccrualCategory(), aDate);
77 if(accrualCategory != null) {
78 List<LeaveSummaryRow> rows = ls.getLeaveSummaryRows();
79 for(LeaveSummaryRow aRow : rows) {
80 if(aRow.getAccrualCategory().equals(accrualCategory.getAccrualCategory())) {
81
82 List<EmployeeOverride> employeeOverrides = TkServiceLocator.getEmployeeOverrideService().getEmployeeOverrides(principalId,TKUtils.formatDateString(leaveEndDateString));
83 String leavePlan = accrualCategory.getLeavePlan();
84 BigDecimal maxUsage = aRow.getUsageLimit();
85 for(EmployeeOverride eo : employeeOverrides) {
86 if(eo.getLeavePlan().equals(leavePlan) && eo.getAccrualCategory().equals(aRow.getAccrualCategory())) {
87 if(eo.getOverrideType().equals("MU") && eo.isActive()) {
88 if(eo.getOverrideValue()!=null && !eo.getOverrideValue().equals(""))
89 maxUsage = new BigDecimal(eo.getOverrideValue());
90 else
91 maxUsage = null;
92 }
93 }
94 }
95 BigDecimal ytdUsage = aRow.getYtdApprovedUsage();
96 BigDecimal pendingLeaveBalance = aRow.getPendingLeaveRequests();
97 BigDecimal desiredUsage = new BigDecimal(0);
98 if(pendingLeaveBalance!=null) {
99 if(oldLeaveAmount!=null) {
100
101 if(!earnCodeChanged ||
102 updatedLeaveBlock.getAccrualCategory().equals(accrualCategory.getAccrualCategory())) {
103 pendingLeaveBalance = pendingLeaveBalance.subtract(oldLeaveAmount.abs());
104 }
105 }
106
107 desiredUsage = desiredUsage.add(pendingLeaveBalance);
108 }
109
110 desiredUsage = desiredUsage.add(leaveAmount.multiply(new BigDecimal(daysSpan+1)));
111
112 if(ytdUsage!=null) {
113 desiredUsage = desiredUsage.add(ytdUsage);
114 }
115 if(maxUsage!=null) {
116 if(desiredUsage.compareTo(maxUsage) > 0 ) {
117 errors.add("This leave request would exceed the usage limit for " + aRow.getAccrualCategory());
118 }
119 }
120 }
121 }
122 }
123 }
124 }
125 return errors;
126 }
127
128
129
130 public static Map<String, Set<String>> validatePendingTransactions(String principalId, Date fromDate, Date toDate) {
131 Map<String, Set<String>> allMessages = new HashMap<String, Set<String>>();
132
133 Set<String> actionMessages = new HashSet<String>();
134 Set<String> infoMessages = new HashSet<String>();
135 Set<String> warningMessages = new HashSet<String>();
136
137 allMessages.put("actionMessages", actionMessages);
138 allMessages.put("infoMessages", infoMessages);
139 allMessages.put("warningMessages", warningMessages);
140 List<LeaveBlock> leaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(principalId, fromDate, toDate, LMConstants.LEAVE_BLOCK_TYPE.BALANCE_TRANSFER);
141 Set<String> workflowDocIds = new HashSet<String>();
142 for(LeaveBlock lb : leaveBlocks) {
143 if(lb.getTransactionalDocId() != null)
144 workflowDocIds.add(lb.getTransactionalDocId());
145 else
146 if(lb.getDescription().contains("Forfeited balance transfer amount"))
147 allMessages.get("infoMessages").add("A max balance action that forfeited accrued leave occurred on this calendar");
148 }
149 for(String workflowDocId : workflowDocIds) {
150 DocumentStatus status = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(workflowDocId);
151
152 if(StringUtils.equals(status.getCode(), TkConstants.ROUTE_STATUS.FINAL)) {
153 allMessages.get("infoMessages").add("A transfer action occurred on this calendar");
154 }
155 else if(StringUtils.equals(status.getCode(), TkConstants.ROUTE_STATUS.ENROUTE)) {
156 allMessages.get("actionMessages").add("A pending balance transfer exists on this calendar. It must be finalized before this calendar can be approved");
157 }
158 else
159 allMessages.get("warningMessages").add("A balance transfer document exists for this calendar with status neither final or enroute");
160 }
161
162 leaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksWithType(principalId, fromDate, toDate, LMConstants.LEAVE_BLOCK_TYPE.LEAVE_PAYOUT);
163 workflowDocIds = new HashSet<String>();
164 for(LeaveBlock lb : leaveBlocks) {
165 if(lb.getTransactionalDocId() != null)
166 workflowDocIds.add(lb.getTransactionalDocId());
167 }
168 for(String workflowDocId : workflowDocIds) {
169 DocumentStatus status = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(workflowDocId);
170
171 if(StringUtils.equals(status.getCode(), TkConstants.ROUTE_STATUS.FINAL)) {
172 allMessages.get("infoMessages").add("A payout action occurred on this calendar");
173 }
174 else if(StringUtils.equals(status.getCode(), TkConstants.ROUTE_STATUS.ENROUTE)) {
175 allMessages.get("actionMessages").add("A pending payout exists on this calendar. It must be finalized before this calendar can be approved");
176 }
177 else
178 allMessages.get("warningMessages").add("A payout document exists for this calendar with status neither final or enroute");
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233 return allMessages;
234 }
235
236
237 public static Map<String, Set<String>> getWarningMessagesForLeaveBlocks(List<LeaveBlock> leaveBlocks) {
238
239 Map<String, Set<String>> allMessages = new HashMap<String, Set<String>>();
240
241 Set<String> actionMessages = new HashSet<String>();
242 Set<String> infoMessages = new HashSet<String>();
243 Set<String> warningMessages = new HashSet<String>();
244
245 if (CollectionUtils.isNotEmpty(leaveBlocks)) {
246 for(LeaveBlock lb : leaveBlocks) {
247 EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(lb.getEarnCode(), lb.getLeaveDate());
248 if(ec != null) {
249 EarnCodeGroup eg = TkServiceLocator.getEarnCodeGroupService().getEarnCodeGroupForEarnCode(lb.getEarnCode(), lb.getLeaveDate());
250 if(eg != null && !StringUtils.isEmpty(eg.getWarningText())) {
251 warningMessages.add(eg.getWarningText());
252 }
253 }
254 }
255 }
256 allMessages.put("actionMessages", actionMessages);
257 allMessages.put("infoMessages", infoMessages);
258 allMessages.put("warningMessages", warningMessages);
259
260
261 return allMessages;
262 }
263
264 public static List<String> validateAvailableLeaveBalance(LeaveCalendarWSForm lcf) {
265 LeaveBlock updatedLeaveBlock = null;
266 if(lcf.getLeaveBlockId() != null) {
267 updatedLeaveBlock = TkServiceLocator.getLeaveBlockService().getLeaveBlock(lcf.getLeaveBlockId());
268 }
269 return validateAvailableLeaveBalanceForUsage(lcf.getSelectedEarnCode(), lcf.getStartDate(), lcf.getEndDate(), lcf.getLeaveAmount(), updatedLeaveBlock);
270 }
271
272 public static List<String> validateAvailableLeaveBalanceForUsage(String earnCode, String leaveStartDateString, String leaveEndDateString,
273 BigDecimal leaveAmount, LeaveBlock updatedLeaveBlock) {
274 List<String> errors = new ArrayList<String>();
275 boolean earnCodeChanged = false;
276 BigDecimal oldAmount = null;
277
278 if(updatedLeaveBlock != null) {
279 if(!updatedLeaveBlock.getEarnCode().equals(earnCode)) {
280 earnCodeChanged = true;
281 }
282 if(!updatedLeaveBlock.getLeaveAmount().equals(leaveAmount)) {
283 oldAmount = updatedLeaveBlock.getLeaveAmount();
284 }
285 }
286 Date startDate = TKUtils.formatDateString(leaveStartDateString);
287 Date endDate = TKUtils.formatDateString(leaveEndDateString);
288 long daysSpan = TKUtils.getDaysBetween(startDate,endDate);
289 EarnCode earnCodeObj = TkServiceLocator.getEarnCodeService().getEarnCode(earnCode, endDate);
290 if(earnCodeObj != null && earnCodeObj.getAllowNegativeAccrualBalance().equals("N")) {
291 AccrualCategory accrualCategory = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(earnCodeObj.getAccrualCategory(), endDate);
292 if(accrualCategory != null) {
293 java.util.Date nextIntervalDate = TkServiceLocator.getAccrualService().getNextAccrualIntervalDate(accrualCategory.getAccrualEarnInterval(), endDate);
294
295 java.util.Date usageEndDate = nextIntervalDate;
296 if(nextIntervalDate.compareTo(endDate) > 0) {
297 Calendar aCal = Calendar.getInstance();
298 aCal.setTime(nextIntervalDate);
299 aCal.add(Calendar.DAY_OF_YEAR, -1);
300 usageEndDate = aCal.getTime();
301 }
302
303
304 if(accrualCategory.getAccrualEarnInterval().equals(LMConstants.ACCRUAL_EARN_INTERVAL_CODE.NO_ACCRUAL)) {
305 Calendar aCal = Calendar.getInstance();
306 aCal.setTime(endDate);
307 aCal.set(Calendar.MONTH, Calendar.DECEMBER);
308 aCal.set(Calendar.DAY_OF_MONTH, 31);
309 nextIntervalDate = aCal.getTime();
310 usageEndDate = nextIntervalDate;
311 }
312 BigDecimal availableBalance = TkServiceLocator.getLeaveSummaryService()
313 .getLeaveBalanceForAccrCatUpToDate(TKContext.getTargetPrincipalId(), startDate, endDate, accrualCategory.getAccrualCategory(), usageEndDate);
314
315 if(oldAmount!=null) {
316 if(!earnCodeChanged ||
317 updatedLeaveBlock.getAccrualCategory().equals(accrualCategory.getAccrualCategory())) {
318 availableBalance = availableBalance.add(oldAmount.abs());
319 }
320 }
321
322 BigDecimal desiredUsage = leaveAmount.multiply(new BigDecimal(daysSpan+1));
323 if(desiredUsage.compareTo(availableBalance) > 0 ) {
324 errors.add("Requested leave amount " + desiredUsage.toString() + " is greater than available leave balance " + availableBalance.toString());
325 }
326 }
327 }
328
329 return errors;
330 }
331
332
333 public static List<String> validateSpanningWeeks(LeaveCalendarWSForm lcf) {
334 boolean spanningWeeks = lcf.getSpanningWeeks().equalsIgnoreCase("y");
335 DateTime startTemp = new DateTime(TKUtils.convertDateStringToTimestamp(lcf.getStartDate()).getTime());
336 DateTime endTemp = new DateTime(TKUtils.convertDateStringToTimestamp(lcf.getEndDate()).getTime());
337
338 List<String> errors = new ArrayList<String>();
339 boolean valid = true;
340 while ((startTemp.isBefore(endTemp) || startTemp.isEqual(endTemp)) && valid) {
341 if (!spanningWeeks &&
342 (startTemp.getDayOfWeek() == DateTimeConstants.SATURDAY || startTemp.getDayOfWeek() == DateTimeConstants.SUNDAY)) {
343 valid = false;
344 }
345 startTemp = startTemp.plusDays(1);
346 }
347 if (!valid) {
348 errors.add("Weekend day is selected, but include weekends checkbox is not checked");
349 }
350 return errors;
351 }
352 }