001 /*
002 * Copyright 2011 The Kuali Foundation.
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.kfs.module.endow.document.service.impl;
017
018 import java.sql.Date;
019 import java.util.Calendar;
020 import java.util.HashMap;
021 import java.util.Map;
022
023 import org.apache.commons.lang.StringUtils;
024 import org.kuali.kfs.module.endow.EndowConstants;
025 import org.kuali.kfs.module.endow.businessobject.FrequencyCode;
026 import org.kuali.kfs.module.endow.document.service.FrequencyCodeService;
027 import org.kuali.kfs.module.endow.document.service.KEMService;
028 import org.kuali.rice.kns.service.BusinessObjectService;
029 import org.kuali.rice.kns.service.DateTimeService;
030
031 public class FrequencyCodeServiceImpl implements FrequencyCodeService {
032
033 protected BusinessObjectService businessObjectService;
034 protected DateTimeService dateTimeService;
035 protected KEMService kemService;
036
037 /**
038 * @see org.kuali.kfs.module.endow.document.service.FrequencyCodeService#getByPrimaryKey(java.lang.String)
039 */
040 public FrequencyCode getByPrimaryKey(String code) {
041 FrequencyCode frequencyCode = null;
042 if (StringUtils.isNotBlank(code)) {
043 Map criteria = new HashMap();
044 criteria.put("code", code);
045
046 frequencyCode = (FrequencyCode) businessObjectService.findByPrimaryKey(FrequencyCode.class, criteria);
047 }
048
049 return frequencyCode;
050 }
051
052 /**
053 * @see org.kuali.kfs.module.endow.document.service.FrequencyCodeService#calculateProcessDate(String)
054 */
055 public Date calculateProcessDate(String frequencyCode) {
056 Date currentDate = kemService.getCurrentDate();
057
058 String frequencyType = frequencyCode.substring(0, 1);
059
060 if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.DAILY)) {
061 return currentDate;
062 }
063
064 if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.WEEKLY)) {
065 String dayOfWeek = frequencyCode.substring(1, 4).toUpperCase();
066 return calculateNextWeeklyDate(dayOfWeek, currentDate);
067 }
068
069 if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.SEMI_MONTHLY)) {
070 String dayOfSemiMonthly = frequencyCode.substring(1, 3);
071 return calculateNextSemiMonthlyDate(dayOfSemiMonthly, currentDate);
072 }
073
074 if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.MONTHLY)) {
075 String dayOfMonth = frequencyCode.substring(1, 3);
076 return calculateNextMonthlyDate(dayOfMonth, currentDate);
077 }
078
079 if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.QUARTERLY) ||
080 frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.SEMI_ANNUALLY) ||
081 frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.ANNUALLY)) {
082 String month = frequencyCode.substring(1, 2);
083 String dayOfMonth = frequencyCode.substring(2, 4);
084 return calculateNextQuarterlyOrSemiAnnuallyOrAnnuallyProcessDate(month, dayOfMonth, frequencyType, currentDate);
085 }
086
087 return currentDate;
088 }
089
090 /**
091 * Method to calculate the next processing week date based on the frequency type
092 * adds the appropriate number of days to the current date
093 * @param dayOfWeek
094 * @return next processing date
095 */
096 protected Date calculateNextWeeklyDate(String dayOfWeekFromFrequencyCode, Date currentDate) {
097 Calendar calendar = Calendar.getInstance();
098 calendar.setTime(currentDate);
099
100 int daysToAdd = 0;
101 int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); // today's day of the week
102 int maximumDaysInWeek = calendar.getActualMaximum(Calendar.DAY_OF_WEEK);
103
104 if (dayOfWeekFromFrequencyCode.equalsIgnoreCase(EndowConstants.FrequencyWeekDays.MONDAY)) {
105 if (dayOfWeek < Calendar.MONDAY)
106 daysToAdd = Calendar.MONDAY - dayOfWeek;
107 else
108 daysToAdd = maximumDaysInWeek - dayOfWeek + Calendar.MONDAY;
109 } else if (dayOfWeekFromFrequencyCode.equalsIgnoreCase(EndowConstants.FrequencyWeekDays.TUESDAY)) {
110 if (dayOfWeek < Calendar.TUESDAY)
111 daysToAdd = Calendar.TUESDAY - dayOfWeek;
112 else
113 daysToAdd = maximumDaysInWeek - dayOfWeek + Calendar.TUESDAY;
114 } else if (dayOfWeekFromFrequencyCode.equalsIgnoreCase(EndowConstants.FrequencyWeekDays.WEDNESDAY)) {
115 if (dayOfWeek < Calendar.WEDNESDAY)
116 daysToAdd = Calendar.WEDNESDAY - dayOfWeek;
117 else
118 daysToAdd = maximumDaysInWeek - dayOfWeek + Calendar.WEDNESDAY;
119 } else if (dayOfWeekFromFrequencyCode.equalsIgnoreCase(EndowConstants.FrequencyWeekDays.THURSDAY)) {
120 if (dayOfWeek < Calendar.THURSDAY)
121 daysToAdd = Calendar.THURSDAY - dayOfWeek;
122 else
123 daysToAdd = maximumDaysInWeek - dayOfWeek + Calendar.THURSDAY;
124 } else if (dayOfWeekFromFrequencyCode.equalsIgnoreCase(EndowConstants.FrequencyWeekDays.FRIDAY)) {
125 if (dayOfWeek < Calendar.FRIDAY)
126 daysToAdd = Calendar.FRIDAY - dayOfWeek;
127 else
128 daysToAdd = maximumDaysInWeek - dayOfWeek + Calendar.FRIDAY;
129 }
130
131 calendar.add(Calendar.DAY_OF_MONTH, daysToAdd);
132
133 return new java.sql.Date(calendar.getTimeInMillis());
134 }
135
136 /**
137 * Method to calculate the next processing semi-monthly date based on the frequency type
138 * Sets the day of the month and then returns the processing date
139 * @param dayOfSemiMonthly
140 * @return next processing date
141 */
142 protected Date calculateNextSemiMonthlyDate(String dayOfSemiMonthly, Date currentDate) {
143 Calendar calendar = Calendar.getInstance();
144 calendar.setTime(currentDate);
145
146 int dayOfMonthToSet = Integer.parseInt(dayOfSemiMonthly);
147 int dayOfMonthNextToSet = dayOfMonthToSet + 15;
148
149 calendar.set(Calendar.DAY_OF_MONTH, dayOfMonthToSet);
150
151 if (new java.sql.Date(calendar.getTimeInMillis()).before(currentDate)) {
152 calendar.add(Calendar.DAY_OF_MONTH, dayOfMonthNextToSet);
153 }
154 if (new java.sql.Date(calendar.getTimeInMillis()).before(currentDate)) {
155 calendar.set(Calendar.DAY_OF_MONTH, dayOfMonthToSet);
156 calendar.add(Calendar.MONTH, 1);
157 }
158
159 return new java.sql.Date(calendar.getTimeInMillis());
160 }
161
162 /**
163 * Method to calculate the next processing monthly date based on the frequency type
164 * Sets the day in the calendar based on day part of the frequency code.
165 * @param dayOfMonth
166 * @return next processing date
167 */
168 protected Date calculateNextMonthlyDate(String dayOfMonth, Date currentDate) {
169 int dayInMonthToSet;
170
171 Calendar calendar = Calendar.getInstance();
172 calendar.setTime(currentDate);
173 setCalendarWithDays(calendar, dayOfMonth);
174 while (new java.sql.Date(calendar.getTimeInMillis()).before(currentDate)) {
175 calendar.add(Calendar.MONTH, 1);
176 }
177
178 return new java.sql.Date(calendar.getTimeInMillis());
179 }
180
181 /**
182 * Method to calculate the next processing quarterly or semi-annually or annually date based on the frequency type
183 * Sets the day in the calendar based on day part of the frequency code.
184 * @param frequencyType frequency code for quarterly, month, dayOfMonth
185 * @return next processing date
186 */
187 protected Date calculateNextQuarterlyOrSemiAnnuallyOrAnnuallyProcessDate(String month, String dayOfMonth, String frequencyType, Date currentDate) {
188 Calendar calendar = Calendar.getInstance();
189 calendar.setTime(currentDate);
190 calendar = setCaledarWithMonth(month, currentDate);
191 setCalendarWithDays(calendar, dayOfMonth);
192
193 if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.QUARTERLY)) {
194 while (new java.sql.Date(calendar.getTimeInMillis()).before(currentDate)) {
195 calendar.add(Calendar.MONTH, 3);
196 setCalendarWithDays(calendar, dayOfMonth);
197 }
198 }
199 if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.SEMI_ANNUALLY)) {
200 while (new java.sql.Date(calendar.getTimeInMillis()).before(currentDate)) {
201 calendar.add(Calendar.MONTH, 6);
202 setCalendarWithDays(calendar, dayOfMonth);
203 }
204 }
205 if (frequencyType.equalsIgnoreCase(EndowConstants.FrequencyTypes.ANNUALLY)) {
206 while (new java.sql.Date(calendar.getTimeInMillis()).before(currentDate)) {
207 calendar.add(Calendar.MONTH, 12);
208 setCalendarWithDays(calendar, dayOfMonth);
209 }
210 }
211
212 return new java.sql.Date(calendar.getTimeInMillis());
213 }
214
215 /**
216 * This method will check the current month and set the calendar to that month
217 * @param month month to set the calendar
218 * @return calendar calendar is set to the month selected
219 */
220 protected Calendar setCaledarWithMonth(String month, Date currentDate) {
221 Calendar calendar = Calendar.getInstance();
222 calendar.setTime(currentDate);
223 int calendarMonth = 1;
224
225 if (EndowConstants.FrequencyMonths.JANUARY.equalsIgnoreCase(month)) {
226 calendarMonth = Calendar.JANUARY;
227 } else if (EndowConstants.FrequencyMonths.FEBRUARY.equalsIgnoreCase(month)) {
228 calendarMonth = Calendar.FEBRUARY;
229 } else if (EndowConstants.FrequencyMonths.MARCH.equalsIgnoreCase(month)) {
230 calendarMonth = Calendar.MARCH;
231 } else if (EndowConstants.FrequencyMonths.APRIL.equalsIgnoreCase(month)) {
232 calendarMonth = Calendar.APRIL;
233 } else if (EndowConstants.FrequencyMonths.MAY.equalsIgnoreCase(month)) {
234 calendarMonth = Calendar.MAY;
235 } else if (EndowConstants.FrequencyMonths.JUNE.equalsIgnoreCase(month)) {
236 calendarMonth = Calendar.JUNE;
237 } else if (EndowConstants.FrequencyMonths.JULY.equalsIgnoreCase(month)) {
238 calendarMonth = Calendar.JULY;
239 } else if (EndowConstants.FrequencyMonths.AUGUST.equalsIgnoreCase(month)) {
240 calendarMonth = Calendar.AUGUST;
241 } else if (EndowConstants.FrequencyMonths.SEPTEMBER.equalsIgnoreCase(month)) {
242 calendarMonth = Calendar.SEPTEMBER;
243 } else if (EndowConstants.FrequencyMonths.OCTOBER.equalsIgnoreCase(month)) {
244 calendarMonth = Calendar.OCTOBER;
245 } else if (EndowConstants.FrequencyMonths.NOVEMBER.equalsIgnoreCase(month)) {
246 calendarMonth = Calendar.NOVEMBER;
247 } else if (EndowConstants.FrequencyMonths.DECEMBER.equalsIgnoreCase(month)) {
248 calendarMonth = Calendar.DECEMBER;
249 }
250
251 calendar.set(Calendar.MONTH, calendarMonth);
252
253 return calendar;
254 }
255
256 /**
257 * This method will check the current month and set the calendar to that month
258 * @param month, dayOfMonth month to set the calendar, dayOfMonth day of the month to set to
259 * @return calendar calendar is set to the month selected
260 */
261 protected void setCalendarWithDays(Calendar calendar, String dayOfMonth) {
262 int dayInMonthToSet;
263 int calendarMonth = calendar.get(Calendar.MONTH);
264
265 if (StringUtils.equalsIgnoreCase(dayOfMonth, EndowConstants.FrequencyMonthly.MONTH_END)) { // month end for the month so need to get max days...
266 dayInMonthToSet = checkMaximumDaysInMonth(calendar.get(Calendar.MONTH));
267 } else {
268 dayInMonthToSet = Integer.parseInt(dayOfMonth);
269
270 if (dayInMonthToSet > 29 && calendarMonth == Calendar.FEBRUARY) {
271 dayInMonthToSet = checkMaximumDaysInFebruary();
272 } else if (dayInMonthToSet > 30 && (calendarMonth == Calendar.APRIL || calendarMonth == Calendar.JUNE ||
273 calendarMonth == Calendar.SEPTEMBER || calendarMonth == Calendar.NOVEMBER)) {
274 dayInMonthToSet = 30;
275 dayInMonthToSet = checkMaximumDaysInMonth(calendarMonth);
276 }
277 }
278
279 calendar.set(Calendar.DAY_OF_MONTH, dayInMonthToSet);
280 }
281
282 /**
283 * This method will check and return either maximum days in the month as 28 or 29 for leap year.
284 * It first sets the month to February and then checks the maximum days..
285 * @return maxDays Maximum number of days in the month of February for calendar.
286 */
287 protected int checkMaximumDaysInFebruary() {
288 int maxDays;
289 Calendar februaryMonthlyDateCalendar = Calendar.getInstance();
290 februaryMonthlyDateCalendar.set(Calendar.MONTH, Calendar.FEBRUARY);
291 maxDays = februaryMonthlyDateCalendar.getActualMaximum(Calendar.DAY_OF_MONTH);
292
293 return maxDays;
294 }
295
296 /**
297 * This method will check and return maximum days in a month.
298 * @param monthNumber The number of the month to test for maximum days..
299 * @return maxDays Maximum number of days in the month of February for calendar.
300 */
301 protected int checkMaximumDaysInMonth(int monthNumber) {
302 int maxDays;
303
304 Calendar calendar = Calendar.getInstance();
305 calendar.set(Calendar.MONTH, monthNumber);
306 maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
307
308 return maxDays;
309 }
310
311 /**
312 * This method gets the businessObjectService.
313 *
314 * @return businessObjectService
315 */
316 protected BusinessObjectService getBusinessObjectService() {
317 return businessObjectService;
318 }
319
320 /**
321 * This method sets the businessObjectService
322 *
323 * @param businessObjectService
324 */
325 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
326 this.businessObjectService = businessObjectService;
327 }
328
329 public void setDateTimeService(DateTimeService dateTimeService) {
330 this.dateTimeService = dateTimeService;
331 }
332
333 protected DateTimeService getDateTimeService() {
334 return dateTimeService;
335 }
336
337 protected KEMService getKemService() {
338 return kemService;
339 }
340
341 public void setKemService(KEMService kemService) {
342 this.kemService = kemService;
343 }
344
345 }