1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.fp.document.service.impl;
17
18 import java.math.BigDecimal;
19 import java.sql.Date;
20 import java.sql.Timestamp;
21 import java.text.ParseException;
22 import java.util.Calendar;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import org.kuali.ole.fp.businessobject.TravelMileageRate;
27 import org.kuali.ole.fp.document.dataaccess.TravelMileageRateDao;
28 import org.kuali.ole.fp.document.service.DisbursementVoucherTravelService;
29 import org.kuali.ole.sys.service.NonTransactional;
30 import org.kuali.ole.sys.util.KfsDateUtils;
31 import org.kuali.rice.core.api.datetime.DateTimeService;
32 import org.kuali.rice.core.api.util.type.KualiDecimal;
33
34
35
36
37
38
39 @NonTransactional
40 public class DisbursementVoucherTravelServiceImpl implements DisbursementVoucherTravelService {
41 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DisbursementVoucherTravelServiceImpl.class);
42
43 private TravelMileageRateDao travelMileageRateDao;
44 private DateTimeService dateTimeService;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public KualiDecimal calculatePerDiemAmount(Timestamp startDateTime, Timestamp endDateTime, KualiDecimal rate) {
75 KualiDecimal perDiemAmount = KualiDecimal.ZERO;
76 KualiDecimal perDiemRate = new KualiDecimal(rate.doubleValue());
77
78
79 if (perDiemAmount == null || startDateTime == null || endDateTime == null) {
80 LOG.error("Per diem amount, Start date/time, and End date/time must all be given.");
81 throw new RuntimeException("Per diem amount, Start date/time, and End date/time must all be given.");
82 }
83
84
85 if (endDateTime.compareTo(startDateTime) <= 0) {
86 LOG.error("End date/time must be after start date/time.");
87 throw new RuntimeException("End date/time must be after start date/time.");
88 }
89
90 Calendar startCalendar = Calendar.getInstance();
91 startCalendar.setTime(startDateTime);
92
93 Calendar endCalendar = Calendar.getInstance();
94 endCalendar.setTime(endDateTime);
95
96 double diffDays = KfsDateUtils.getDifferenceInDays(startDateTime, endDateTime);
97 double diffHours = KfsDateUtils.getDifferenceInHours(startDateTime, endDateTime);
98
99
100 if (diffDays == 0) {
101
102 if (diffHours > 12) {
103
104 perDiemAmount = perDiemRate.divide(new KualiDecimal(2));
105
106
107 if (timeInPerDiemPeriod(endCalendar, 19, 0, 23, 59)) {
108 perDiemAmount = perDiemAmount.add(perDiemRate.divide(new KualiDecimal(4)));
109 }
110 }
111 }
112
113
114 else {
115
116 if (diffHours >= 7.5) {
117
118 perDiemAmount = perDiemRate.multiply(new KualiDecimal(diffDays - 1));
119
120
121 if (timeInPerDiemPeriod(startCalendar, 0, 0, 11, 59)) {
122 perDiemAmount = perDiemAmount.add(perDiemRate);
123 }
124 else if (timeInPerDiemPeriod(startCalendar, 12, 0, 17, 59)) {
125 perDiemAmount = perDiemAmount.add(perDiemRate.divide(new KualiDecimal(2)));
126 }
127 else if (timeInPerDiemPeriod(startCalendar, 18, 0, 23, 59)) {
128 perDiemAmount = perDiemAmount.add(perDiemRate.divide(new KualiDecimal(4)));
129 }
130
131
132 if (timeInPerDiemPeriod(endCalendar, 0, 1, 6, 0)) {
133 perDiemAmount = perDiemAmount.add(perDiemRate.divide(new KualiDecimal(4)));
134 }
135 else if (timeInPerDiemPeriod(endCalendar, 6, 1, 12, 0)) {
136 perDiemAmount = perDiemAmount.add(perDiemRate.divide(new KualiDecimal(2)));
137 }
138 else if (timeInPerDiemPeriod(endCalendar, 12, 01, 23, 59)) {
139 perDiemAmount = perDiemAmount.add(perDiemRate);
140 }
141 }
142 }
143
144 return perDiemAmount;
145 }
146
147
148
149
150
151
152
153
154
155
156
157 protected boolean timeInPerDiemPeriod(Calendar cal, int periodStartHour, int periodStartMinute, int periodEndHour, int periodEndMinute) {
158 int hour = cal.get(Calendar.HOUR_OF_DAY);
159 int minute = cal.get(Calendar.MINUTE);
160
161 return (((hour > periodStartHour) || (hour == periodStartHour && minute >= periodStartMinute)) && ((hour < periodEndHour) || (hour == periodEndHour && minute <= periodEndMinute)));
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 public KualiDecimal calculateMileageAmount(Integer totalMileage, Timestamp travelStartDate) {
179 KualiDecimal mileageAmount = KualiDecimal.ZERO;
180
181 if (totalMileage == null || travelStartDate == null) {
182 LOG.error("Total Mileage and Travel Start Date must be given.");
183 throw new RuntimeException("Total Mileage and Travel Start Date must be given.");
184 }
185
186
187 Date effectiveDate = null;
188 try {
189 effectiveDate = dateTimeService.convertToSqlDate(travelStartDate);
190 }
191 catch (ParseException e) {
192 LOG.error("Unable to parse travel start date into sql date " + e.getMessage());
193 throw new RuntimeException("Unable to parse travel start date into sql date " + e.getMessage());
194 }
195
196
197 List mileageRates = (List) travelMileageRateDao.retrieveMostEffectiveMileageRates(effectiveDate);
198
199 if (mileageRates == null || mileageRates.isEmpty()) {
200 LOG.error("Unable to retreive mileage rates.");
201 throw new RuntimeException("Unable to retreive mileage rates.");
202 }
203
204 int mileage = totalMileage.intValue();
205 int mileageRemaining = mileage;
206
207
208
209
210
211 for (Iterator iter = mileageRates.iterator(); iter.hasNext();) {
212 TravelMileageRate rate = (TravelMileageRate) iter.next();
213 int mileageLimitAmount = rate.getMileageLimitAmount().intValue();
214 if (mileageRemaining > mileageLimitAmount) {
215 BigDecimal numMiles = new BigDecimal(mileageRemaining - mileageLimitAmount);
216 BigDecimal rateForMiles = numMiles.multiply(rate.getMileageRate()).setScale(KualiDecimal.SCALE, KualiDecimal.ROUND_BEHAVIOR);
217 mileageAmount = mileageAmount.add(new KualiDecimal(rateForMiles));
218 mileageRemaining = mileageLimitAmount;
219 }
220
221 }
222
223 return mileageAmount;
224 }
225
226
227
228
229
230 public TravelMileageRateDao getTravelMileageRateDao() {
231 return travelMileageRateDao;
232 }
233
234
235
236
237
238 public void setTravelMileageRateDao(TravelMileageRateDao travelMileageRateDao) {
239 this.travelMileageRateDao = travelMileageRateDao;
240 }
241
242
243
244
245
246 public DateTimeService getDateTimeService() {
247 return dateTimeService;
248 }
249
250
251
252
253
254 public void setDateTimeService(DateTimeService dateTimeService) {
255 this.dateTimeService = dateTimeService;
256 }
257 }