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.coa.batch.dataaccess.impl;
017    
018    import java.sql.Date;
019    import java.util.Collection;
020    import java.util.GregorianCalendar;
021    import java.util.regex.Matcher;
022    import java.util.regex.Pattern;
023    
024    import org.apache.commons.lang.StringUtils;
025    import org.apache.ojb.broker.query.Criteria;
026    import org.apache.ojb.broker.query.QueryByCriteria;
027    import org.kuali.kfs.coa.businessobject.AccountingPeriod;
028    import org.kuali.kfs.sys.KFSPropertyConstants;
029    import org.kuali.kfs.sys.batch.dataaccess.impl.FiscalYearMakerImpl;
030    import org.kuali.rice.kns.bo.PersistableBusinessObject;
031    
032    /**
033     * Performs custom population of accounting periods records for a new year being created in the fiscal year maker process
034     */
035    public class AccountingPeriodFiscalYearMakerImpl extends FiscalYearMakerImpl {
036        
037        public AccountingPeriodFiscalYearMakerImpl() {
038            super();
039            
040            super.setAllowOverrideTargetYear(false);
041        }
042    
043        /**
044         * Updates the year on the fiscal period name and sets status to open for next year records
045         * 
046         * @see org.kuali.kfs.coa.batch.dataaccess.impl.FiscalYearMakerHelperImpl#changeForNewYear(java.lang.Integer,
047         *      org.kuali.rice.kns.bo.PersistableBusinessObject)
048         */
049        @Override
050        public void changeForNewYear(Integer baseFiscalYear, PersistableBusinessObject currentRecord) {
051            super.changeForNewYear(baseFiscalYear, currentRecord);
052    
053            AccountingPeriod accountingPeriod = (AccountingPeriod) currentRecord;
054    
055            // update fiscal period name which contains the fiscal year
056            String fiscalPeriodName = accountingPeriod.getUniversityFiscalPeriodName();
057    
058            String oldCalendarStartYear = new Integer(accountingPeriod.getUniversityFiscalYear() - 2).toString();
059            String oldCalendarEndYear = new Integer(accountingPeriod.getUniversityFiscalYear() - 1).toString();
060    
061            String newCalendarStartYear = new Integer(accountingPeriod.getUniversityFiscalYear() - 1).toString();
062            String newCalendarEndYear = new Integer(accountingPeriod.getUniversityFiscalYear()).toString();
063    
064            // replace 4 digit year in name if found, else replace 2 digit
065            if (StringUtils.contains(fiscalPeriodName, oldCalendarEndYear)) {
066                fiscalPeriodName = StringUtils.replace(fiscalPeriodName, oldCalendarEndYear, newCalendarEndYear);
067            }
068            else if (StringUtils.contains(fiscalPeriodName, oldCalendarStartYear)) {
069                fiscalPeriodName = StringUtils.replace(fiscalPeriodName, oldCalendarStartYear, newCalendarStartYear);
070            }
071            else {
072                fiscalPeriodName = updateTwoDigitYear(newCalendarEndYear.substring(2, 4), oldCalendarEndYear.substring(2, 4), fiscalPeriodName);
073                fiscalPeriodName = updateTwoDigitYear(newCalendarStartYear.substring(2, 4), oldCalendarStartYear.substring(2, 4), fiscalPeriodName);
074            }
075    
076            accountingPeriod.setUniversityFiscalPeriodName(fiscalPeriodName);
077    
078            // increment period end date by one year
079            accountingPeriod.setUniversityFiscalPeriodEndDate(addYearToDate(accountingPeriod.getUniversityFiscalPeriodEndDate()));
080    
081            // set status to closed
082            accountingPeriod.setActive(false);
083        }
084    
085        /**
086         * Retrieves all Accounting Period records for the first copied fiscal year and make active
087         * 
088         * @see org.kuali.kfs.coa.batch.dataaccess.impl.FiscalYearMakerHelperImpl#performCustomProcessing(java.lang.Integer)
089         */
090        @Override
091        public void performCustomProcessing(Integer baseFiscalYear, boolean firstCopyYear) {
092            if (!firstCopyYear) {
093                return;
094            }
095            
096            Criteria criteriaId = new Criteria();
097            criteriaId.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, baseFiscalYear + 1);
098    
099            QueryByCriteria queryId = new QueryByCriteria(AccountingPeriod.class, criteriaId);
100    
101            Collection<AccountingPeriod> accountingPeriods = getPersistenceBrokerTemplate().getCollectionByQuery(queryId);
102            for (AccountingPeriod accountingPeriod : accountingPeriods) {
103                accountingPeriod.setActive(true);
104                getPersistenceBrokerTemplate().store(accountingPeriod);
105            }
106        }
107    
108        /**
109         * Adds one year to the given date
110         * 
111         * @param inDate date to increment
112         * @return Date incoming date plus one year
113         */
114        protected java.sql.Date addYearToDate(Date inDate) {
115            GregorianCalendar currentCalendarDate = new GregorianCalendar();
116            currentCalendarDate.clear();
117    
118            currentCalendarDate.setTimeInMillis(inDate.getTime());
119            currentCalendarDate.add(GregorianCalendar.YEAR, 1);
120    
121            return new Date(currentCalendarDate.getTimeInMillis());
122        }
123    
124        /**
125         * this routine is provided to update string fields which contain two-digit years that need to be updated for display. it is
126         * very specific, but it's necessary. "two-digit year" means the two numeric characters preceded by a non-numeric character.
127         * 
128         * @param newYear
129         * @param oldYear
130         * @param currentString
131         * @return the updated string for a two digit year
132         */
133        protected String updateTwoDigitYear(String newYear, String oldYear, String currentString) {
134            // group 1 is the bounded by the outermost set of parentheses
135            // group 2 is the first inner set
136            // group 3 is the second inner set--a two-digit year at the beginning of the line
137            String regExpString = "(([^0-9]{1}" + oldYear + ")|^(" + oldYear + "))";
138            Pattern pattern = Pattern.compile(regExpString);
139            Matcher matcher = pattern.matcher(currentString);
140    
141            // start looking for a match
142            boolean matched = matcher.find();
143            if (!matched) {
144                // just return if nothing is found
145                return currentString;
146            }
147    
148            // we found something
149            // we have to process it
150            String returnString = currentString;
151            StringBuffer outString = new StringBuffer();
152            // is there a match at the beginning of the line (a match with group 3)?
153            if (matcher.group(3) != null) {
154                // there is a two-digit-year string at the beginning of the line
155                // we want to replace it
156                matcher.appendReplacement(outString, newYear);
157                // find the next match if there is one
158                matched = matcher.find();
159            }
160    
161            while (matched) {
162                // the new string will no longer match with group 3
163                // if there is still a match, it will be with group 2
164                // now we have to prefix the new year string with the same
165                // non-numeric character as the next match (hyphen, space, whatever)
166                String newYearString = matcher.group(2).substring(0, 1) + newYear;
167                matcher.appendReplacement(outString, newYearString);
168                matched = matcher.find();
169            }
170    
171            // dump whatever detritus is left into the new string
172            matcher.appendTail(outString);
173    
174            return outString.toString();
175        }
176    
177    }