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 }