1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.hr.time.accrual.service;
17
18 import java.math.BigDecimal;
19 import java.sql.Date;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.LinkedHashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.apache.commons.lang.StringUtils;
27 import org.joda.time.DateTime;
28 import org.kuali.hr.lm.LMConstants;
29 import org.kuali.hr.lm.accrual.AccrualCategory;
30 import org.kuali.hr.lm.accrual.AccrualCategoryRule;
31 import org.kuali.hr.time.accrual.TimeOffAccrual;
32 import org.kuali.hr.time.accrual.dao.TimeOffAccrualDao;
33 import org.kuali.hr.time.earncode.EarnCode;
34 import org.kuali.hr.time.principal.PrincipalHRAttributes;
35 import org.kuali.hr.time.service.base.TkServiceLocator;
36 import org.kuali.hr.time.timeblock.TimeBlock;
37 import org.kuali.hr.time.timesheet.TimesheetDocument;
38 import org.kuali.hr.time.util.TkConstants;
39
40 public class TimeOffAccrualServiceImpl implements TimeOffAccrualService {
41
42 public static final String ACCRUAL_CATEGORY_KEY = "accrualCategory";
43 public static final String ACCRUAL_RATE_KEY = "accrualRate";
44 public static final String ACCRUAL_NAME_KEY = "accrualName";
45 public static final String YEARLY_CARRYOVER_KEY = "yearlyCarryover";
46 public static final String HOURS_ACCRUED_KEY = "hoursAccrued";
47 public static final String HOURS_TAKEN_KEY = "hoursTaken";
48 public static final String HOURS_ADJUST_KEY = "hoursAdjust";
49 public static final String TOTAL_HOURS_KEY = "totalHours";
50 public static final String EFF_DATE_KEY = "effdt";
51
52 private TimeOffAccrualDao timeOffAccrualDao;
53
54 public void setTimeOffAccrualDao(TimeOffAccrualDao timeOffAccrualDao) {
55 this.timeOffAccrualDao = timeOffAccrualDao;
56 }
57
58 @Override
59 public List<TimeOffAccrual> getTimeOffAccruals(String principalId, Date asOfDate) {
60 return timeOffAccrualDao.getActiveTimeOffAccruals(principalId, asOfDate);
61 }
62
63 @Override
64 public List<Map<String, Object>> getTimeOffAccrualsCalc(String principalId, Date asOfDate) {
65 List<Map<String, Object>> timeOffAccrualsCalc = new ArrayList<Map<String, Object>>();
66 Map<String,String> accrualCatToDescr = new HashMap<String, String>();
67 String accrualRate = "";
68
69 for (TimeOffAccrual timeOffAccrual : getTimeOffAccruals(principalId, asOfDate)) {
70 String accrualCatDescr = accrualCatToDescr.get(timeOffAccrual.getAccrualCategory());
71
72 if (StringUtils.isBlank(accrualCatDescr)){
73 AccrualCategory accrualCat = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(timeOffAccrual.getAccrualCategory(), asOfDate);
74 if (accrualCat != null) {
75 accrualCatDescr = accrualCat.getDescr();
76 accrualCatToDescr.put(accrualCat.getAccrualCategory(), accrualCatDescr);
77
78 DateTime currentDate = new DateTime();
79 List<AccrualCategoryRule> accrualCategoryRules = accrualCat.getAccrualCategoryRules();
80
81 PrincipalHRAttributes principalHRAttributes = TkServiceLocator.getPrincipalHRAttributeService().getPrincipalCalendar(principalId, asOfDate);
82 if (principalHRAttributes == null) {
83 throw new RuntimeException("Cannot find principal hr attributes for " + principalId);
84 }
85 Date serviceDate = principalHRAttributes.getServiceDate();
86 if (serviceDate == null) {
87 throw new RuntimeException("Cannot find service date on principal hr attribute for " + principalId);
88 }
89 DateTime jodaServiceDate = new DateTime(serviceDate);
90
91 Long serviceUnits= new Long(0);
92
93 for(AccrualCategoryRule accrualCategoryRule : accrualCategoryRules){
94 String serviceUnitOfTime = accrualCategoryRule.getServiceUnitOfTime();
95
96 if ( serviceUnitOfTime.equals(LMConstants.SERVICE_TIME_YEAR)){
97 serviceUnits = new Long(currentDate.getYear() - jodaServiceDate.getYear()) + 1;
98 }
99 if ( serviceUnitOfTime.equals(LMConstants.SERVICE_TIME_MONTHS)){
100 serviceUnits = new Long(currentDate.getYear() - jodaServiceDate.getYear()) * 12 +
101 new Long(currentDate.getMonthOfYear() - jodaServiceDate.getMonthOfYear()) ;
102 }
103
104 if ( serviceUnits >= accrualCategoryRule.getStart() && serviceUnits < accrualCategoryRule.getEnd()){
105 accrualRate = accrualCategoryRule.getAccrualRate().toString() + " " + accrualCat.getUnitOfTime();
106 break;
107 }
108 }
109 }
110 }
111 Map<String, Object> output = new LinkedHashMap<String, Object>();
112 output.put(ACCRUAL_CATEGORY_KEY, accrualCatDescr + "("+timeOffAccrual.getAccrualCategory()+")");
113 output.put(ACCRUAL_RATE_KEY, accrualRate);
114 output.put(ACCRUAL_NAME_KEY, timeOffAccrual.getAccrualCategory());
115 output.put(YEARLY_CARRYOVER_KEY, timeOffAccrual.getYearlyCarryover());
116 output.put(HOURS_ACCRUED_KEY, timeOffAccrual.getHoursAccrued());
117 output.put(HOURS_TAKEN_KEY, timeOffAccrual.getHoursTaken());
118 output.put(HOURS_ADJUST_KEY, timeOffAccrual.getHoursAdjust());
119 BigDecimal totalHours = timeOffAccrual.getYearlyCarryover().add(timeOffAccrual.getHoursAccrued().subtract(timeOffAccrual.getHoursTaken()).add(timeOffAccrual.getHoursAdjust()));
120 output.put(TOTAL_HOURS_KEY, totalHours);
121 output.put(EFF_DATE_KEY, timeOffAccrual.getEffectiveDate());
122
123
124
125 timeOffAccrualsCalc.add(output);
126 }
127
128 return timeOffAccrualsCalc;
129 }
130
131 public List<String> validateAccrualHoursLimit(TimesheetDocument timesheetDocument) {
132 String pId = "";
133 if (timesheetDocument != null) {
134 pId = timesheetDocument.getPrincipalId();
135 }
136
137 return validateAccrualHoursLimit(pId, timesheetDocument.getTimeBlocks(), timesheetDocument.getAsOfDate());
138
139 }
140
141 public List<String> validateAccrualHoursLimit(String pId, List<TimeBlock> tbList, Date asOfDate) {
142 List<String> warningMessages = new ArrayList<String>();
143
144 List<Map<String, Object>> calcList = this.getTimeOffAccrualsCalc(pId, asOfDate);
145
146 if (tbList.isEmpty()) {
147 return warningMessages;
148 }
149 List<String> accruals = new ArrayList<String>();
150 for (Map<String, Object> aMap : calcList) {
151 accruals.add((String) aMap.get(ACCRUAL_CATEGORY_KEY));
152 }
153 for (Map<String, Object> aMap : calcList) {
154 String accrualCategory = (String) aMap.get(ACCRUAL_NAME_KEY);
155 List<TimeBlock> warningTbs = new ArrayList<TimeBlock>();
156 BigDecimal totalForAccrCate = this.totalForAccrCate(accrualCategory, tbList, warningTbs);
157
158 if(totalForAccrCate.compareTo(BigDecimal.ZERO)==0){
159 continue;
160 }
161 BigDecimal balanceHrs = (((BigDecimal)aMap.get(YEARLY_CARRYOVER_KEY)).add((BigDecimal)aMap.get(HOURS_ACCRUED_KEY)).subtract((BigDecimal)aMap.get(HOURS_TAKEN_KEY)).add((BigDecimal)aMap.get(HOURS_ADJUST_KEY)));
162
163 if (totalForAccrCate.compareTo(balanceHrs) == 1) {
164 String msg = "Warning: Total hours entered (" + totalForAccrCate.toString() + ") for Accrual Category \"" + (String) aMap.get(ACCRUAL_CATEGORY_KEY) + "\" has exceeded balance (" + balanceHrs.toString() + "). Problem Time Blocks are:<br/>";
165 for(TimeBlock tb : warningTbs) {
166 msg += "Earn code: " + tb.getEarnCode()+ " Hours: " + tb.getHours().toString() + " on Date " + (tb.getBeginTimeDisplay() != null ? tb.getBeginTimeDisplay().toString(TkConstants.DT_BASIC_DATE_FORMAT) : "") + "<br/>";
167 }
168 warningMessages.add(msg);
169
170 }
171 }
172 return warningMessages;
173 }
174 public List<String> validateAccrualHoursLimitByEarnCode(TimesheetDocument timesheetDocument, String earnCode) {
175 List<String> warningMessages = new ArrayList<String>();
176 String pId = "";
177 if (timesheetDocument != null) {
178 pId = timesheetDocument.getPrincipalId();
179 }
180 List<Map<String, Object>> calcList = this.getTimeOffAccrualsCalc(pId, timesheetDocument.getAsOfDate());
181
182 List<TimeBlock> tbList = timesheetDocument.getTimeBlocks();
183 if (tbList.isEmpty()) {
184 return warningMessages;
185 }
186 List<String> accruals = new ArrayList<String>();
187 for (Map<String, Object> aMap : calcList) {
188 accruals.add((String) aMap.get(ACCRUAL_CATEGORY_KEY));
189 }
190
191 List<AccrualCategory> accrualCategories = TkServiceLocator.getAccrualCategoryService().getActiveAccrualCategories(timesheetDocument.getAsOfDate());
192
193 for(AccrualCategory accrualCategory : accrualCategories){
194 if(!accruals.contains(accrualCategory.getAccrualCategory()) && !StringUtils.equals(TkConstants.HOLIDAY_EARN_CODE, accrualCategory.getAccrualCategory())){
195 Map<String, Object> accrualData = new LinkedHashMap<String, Object>();
196 accrualData.put(ACCRUAL_CATEGORY_KEY, accrualCategory.getAccrualCategory());
197 accrualData.put(YEARLY_CARRYOVER_KEY, new BigDecimal(0.00));
198 accrualData.put(HOURS_ACCRUED_KEY, new BigDecimal(0.00));
199 accrualData.put(HOURS_TAKEN_KEY, new BigDecimal(0.00));
200 accrualData.put(HOURS_ADJUST_KEY, new BigDecimal(0.00));
201 calcList.add(accrualData);
202 }
203 }
204 for (Map<String, Object> aMap : calcList) {
205 String accrualCategory = (String) aMap.get(ACCRUAL_CATEGORY_KEY);
206 List<TimeBlock> warningTbs = new ArrayList<TimeBlock>();
207 BigDecimal totalForAccrCate = this.totalForAccrCate(accrualCategory, tbList, warningTbs);
208 BigDecimal balanceHrs = (((BigDecimal)aMap.get(YEARLY_CARRYOVER_KEY)).add((BigDecimal)aMap.get(HOURS_ACCRUED_KEY)).subtract((BigDecimal)aMap.get(HOURS_TAKEN_KEY)).add((BigDecimal)aMap.get(HOURS_ADJUST_KEY)));
209
210 if (totalForAccrCate.compareTo(balanceHrs) == 1) {
211 if (accrualCategory.equals(earnCode)) {
212 String msg = "Warning: Total hours entered (" + totalForAccrCate.toString() + ") for Accrual Category \"" + (String) aMap.get(ACCRUAL_CATEGORY_KEY) + "\" has exceeded balance (" + balanceHrs.toString() + "). Problem Time Blocks are: ";
213 for(TimeBlock tb : warningTbs) {
214 msg += "Earn code: " + tb.getEarnCode()+ " Hours: " + tb.getHours().toString() + " on Date " + (tb.getBeginTimeDisplay() != null ? tb.getBeginTimeDisplay().toString(TkConstants.DT_BASIC_DATE_FORMAT) : "") + " ";
215 }
216
217 warningMessages.add(msg);
218 }
219
220 }
221 }
222 return warningMessages;
223 }
224
225 public BigDecimal totalForAccrCate(String accrualCategory, List<TimeBlock> tbList, List<TimeBlock> warningTbs) {
226 BigDecimal total = BigDecimal.ZERO;
227 for (TimeBlock tb : tbList) {
228 String earnCode = tb.getEarnCode();
229 Date asOfDate = new java.sql.Date(tb.getBeginTimestamp().getTime());
230 EarnCode ec = TkServiceLocator.getEarnCodeService().getEarnCode(earnCode, asOfDate);
231 String accrCate = "";
232 if (ec != null) {
233 accrCate = ec.getAccrualCategory();
234 if (accrCate != null) {
235 if (accrCate.equals(accrualCategory)) {
236 total = total.add(tb.getHours());
237 warningTbs.add(tb);
238 }
239 }
240 }
241 }
242 return total;
243 }
244
245 @Override
246 public TimeOffAccrual getTimeOffAccrual(Long laTimeOffAccrualId) {
247 return timeOffAccrualDao.getTimeOffAccrual(laTimeOffAccrualId);
248 }
249
250 @Override
251 public int getTimeOffAccrualCount(String accrualCategory, Date effectiveDate, String principalId, String lmAccrualId) {
252 return timeOffAccrualDao.getTimeOffAccrualCount(accrualCategory, effectiveDate, principalId, lmAccrualId);
253 }
254
255 @Override
256 public List<TimeOffAccrual> getTimeOffAccruals(String principalId, String accrualCategory){
257 return timeOffAccrualDao.getTimeOffAccruals(principalId, accrualCategory);
258 }
259 }