001/*
002 * Copyright 2005-2006 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 */
016package org.kuali.ole.fp.document.web.struts;
017
018import static org.kuali.ole.sys.OLEConstants.AuxiliaryVoucher.ACCRUAL_DOC_TYPE;
019import static org.kuali.ole.sys.OLEConstants.AuxiliaryVoucher.ADJUSTMENT_DOC_TYPE;
020import static org.kuali.ole.sys.OLEConstants.AuxiliaryVoucher.RECODE_DOC_TYPE;
021
022import java.sql.Date;
023import java.util.ArrayList;
024import java.util.Calendar;
025import java.util.List;
026
027import javax.servlet.http.HttpServletRequest;
028
029import org.apache.commons.collections.CollectionUtils;
030import org.apache.commons.collections.Predicate;
031import org.joda.time.DateTime;
032import org.kuali.ole.coa.businessobject.AccountingPeriod;
033import org.kuali.ole.coa.service.AccountingPeriodService;
034import org.kuali.ole.fp.document.AuxiliaryVoucherDocument;
035import org.kuali.ole.fp.document.validation.impl.AuxiliaryVoucherDocumentRuleConstants;
036import org.kuali.ole.sys.OLEConstants;
037import org.kuali.ole.sys.context.SpringContext;
038import org.kuali.ole.sys.service.UniversityDateService;
039import org.kuali.rice.core.api.datetime.DateTimeService;
040import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
041import org.kuali.rice.coreservice.framework.parameter.ParameterService;
042import org.kuali.rice.krad.document.Document;
043import org.kuali.rice.krad.util.ObjectUtils;
044
045/**
046 * Struts form so <code>{@link AuxiliaryVoucherDocument}</code> can be accessed and modified through UI.
047 */
048public class AuxiliaryVoucherForm extends VoucherForm {
049    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AuxiliaryVoucherForm.class);
050
051    protected String originalVoucherType = OLEConstants.AuxiliaryVoucher.ADJUSTMENT_DOC_TYPE; // keep this in sync with the default
052
053    // value set in the document business
054    // object
055
056    public AuxiliaryVoucherForm() {
057        super();
058    }
059
060    @Override
061    protected String getDefaultDocumentTypeName() {
062        return "OLE_AV";
063    }
064
065    /**
066     * Overrides the parent to call super.populate and then to call the two methods that are specific to loading the two select
067     * lists on the page. In addition, this also makes sure that the credit and debit amounts are filled in for situations where
068     * validation errors occur and the page reposts.
069     *
070     * @see org.kuali.rice.kns.web.struts.pojo.PojoForm#populate(javax.servlet.http.HttpServletRequest)
071     */
072    @Override
073    public void populate(HttpServletRequest request) {
074        // populate the drop downs
075        super.populate(request);
076        populateReversalDateForRendering();
077    }
078
079    /**
080     * @return Returns the serviceBillingDocument.
081     */
082    public AuxiliaryVoucherDocument getAuxiliaryVoucherDocument() {
083        return (AuxiliaryVoucherDocument) getDocument();
084    }
085
086    /**
087     * @param serviceBillingDocument The serviceBillingDocument to set.
088     */
089    public void setAuxiliaryVoucherDocument(AuxiliaryVoucherDocument auxiliaryVoucherDocument) {
090        setDocument(auxiliaryVoucherDocument);
091    }
092
093    /**
094     * Gets today's date and then sets the day of the month as 15th, irrespective of the current day of the month
095     * @return the modified reversal date
096     */
097    protected Date getAvReversalDate() {
098        Date documentReveralDate = getAuxiliaryVoucherDocument().getReversalDate();
099        if (ObjectUtils.isNotNull(documentReveralDate)) {
100            return documentReveralDate;
101        }
102
103        java.sql.Date avReversalDate = SpringContext.getBean(DateTimeService.class).getCurrentSqlDateMidnight();
104
105        Calendar cal = Calendar.getInstance();
106        cal.setTime(avReversalDate);
107
108        int thisMonth;
109
110        if (getAuxiliaryVoucherDocument().getAccountingPeriod().getUniversityFiscalPeriodCode().equals(OLEConstants.MONTH13)) {
111            thisMonth = cal.JULY;
112        }
113        else {
114            thisMonth = getAuxiliaryVoucherDocument().getAccountingPeriod().getMonth();
115        }
116
117        cal.set(Calendar.MONTH, (thisMonth));
118
119        //if today's day > 15 then set the month to next month.
120     //   if (cal.get(Calendar.DAY_OF_MONTH) > OLEConstants.AuxiliaryVoucher.ACCRUAL_DOC_DAY_OF_MONTH) {
121      //      cal.add(Calendar.MONTH, 1);
122      //  }
123
124        int reversalDateDefaultDayOfMonth = this.getReversalDateDefaultDayOfMonth();
125
126        cal.set(Calendar.DAY_OF_MONTH, reversalDateDefaultDayOfMonth);
127
128        long timeInMillis = cal.getTimeInMillis();
129        avReversalDate.setTime(timeInMillis);
130
131        return avReversalDate;
132    }
133
134    /**
135     * Handles special case display rules for displaying Reversal Date at UI layer
136     */
137    public void populateReversalDateForRendering() {
138        java.sql.Date today = getAvReversalDate();
139
140        if (getAuxiliaryVoucherDocument().getTypeCode().equals(ACCRUAL_DOC_TYPE)) {
141            getAuxiliaryVoucherDocument().setReversalDate(today);
142        }
143        else if (getAuxiliaryVoucherDocument().getTypeCode().equals(ADJUSTMENT_DOC_TYPE)) {
144            getAuxiliaryVoucherDocument().setReversalDate(null);
145        }
146        else if (getAuxiliaryVoucherDocument().getTypeCode().equals(RECODE_DOC_TYPE)) {
147            DateTime ts = new DateTime(getAuxiliaryVoucherDocument().getDocumentHeader().getWorkflowDocument().getDateCreated());
148            Date newts = new Date(ts.getMillis());
149
150            getAuxiliaryVoucherDocument().setReversalDate(newts);
151        }
152    }
153
154    /**
155     * This method returns the reversal date in the format MMM d, yyyy.
156     *
157     * @return String
158     */
159    @Override
160    public String getFormattedReversalDate() {
161        return formatReversalDate(getAuxiliaryVoucherDocument().getReversalDate());
162    }
163
164    /**
165     * @return String
166     */
167    public String getOriginalVoucherType() {
168        return originalVoucherType;
169    }
170
171    /**
172     * @param originalVoucherType
173     */
174    public void setOriginalVoucherType(String originalVoucherType) {
175        this.originalVoucherType = originalVoucherType;
176    }
177
178    /**
179     * Returns a formatted auxiliary voucher type: <Voucher Type Name> (<Voucher Type Code>)
180     *
181     * @return
182     */
183    public String getFormattedAuxiliaryVoucherType() {
184        String voucherTypeCode = getAuxiliaryVoucherDocument().getTypeCode();
185        String formattedVoucherType = new String();
186
187        if (OLEConstants.AuxiliaryVoucher.ACCRUAL_DOC_TYPE.equals(voucherTypeCode)) {
188            formattedVoucherType = OLEConstants.AuxiliaryVoucher.ACCRUAL_DOC_TYPE_NAME;
189        }
190        else if (OLEConstants.AuxiliaryVoucher.ADJUSTMENT_DOC_TYPE.equals(voucherTypeCode)) {
191            formattedVoucherType = OLEConstants.AuxiliaryVoucher.ADJUSTMENT_DOC_TYPE_NAME;
192        }
193        else if (OLEConstants.AuxiliaryVoucher.RECODE_DOC_TYPE.equals(voucherTypeCode)) {
194            formattedVoucherType = OLEConstants.AuxiliaryVoucher.RECODE_DOC_TYPE_NAME;
195        }
196        else {
197            throw new IllegalStateException("Invalid auxiliary voucher type code: " + voucherTypeCode);
198        }
199
200        return formattedVoucherType + " (" + voucherTypeCode + ")";
201    }
202
203    /**
204     * This method generates a proper list of valid accounting periods that the user can select from.
205     *
206     * @see org.kuali.ole.fp.document.web.struts.VoucherForm#populateAccountingPeriodListForRendering()
207     */
208    @Override
209    public void populateAccountingPeriodListForRendering() {
210        // grab the list of valid accounting periods
211        ArrayList accountingPeriods = new ArrayList(SpringContext.getBean(AccountingPeriodService.class).getOpenAccountingPeriods());
212        // now, validate further, based on the rules from AuxiliaryVoucherDocumentRule
213        ArrayList filteredAccountingPeriods = new ArrayList();
214        filteredAccountingPeriods.addAll(CollectionUtils.select(accountingPeriods, new OpenAuxiliaryVoucherPredicate(this.getDocument())));
215        // if our auxiliary voucher doc contains an accounting period already, make sure the collection has it too!
216        if (this.getDocument() instanceof AuxiliaryVoucherDocument) {
217            AuxiliaryVoucherDocument avDoc = (AuxiliaryVoucherDocument) this.getDocument();
218            if (avDoc != null && avDoc.getAccountingPeriod() != null && !filteredAccountingPeriods.contains(avDoc.getAccountingPeriod())) {
219                // this is most likely going to happen because the approver is trying
220                // to approve a document after the grace period of an accounting period
221                // or a fiscal year has switched over when the document was first created;
222                // as such, it's probably a good bet that the doc's accounting period
223                // belongs at the top of the list
224                filteredAccountingPeriods.add(0, avDoc.getAccountingPeriod());
225            }
226        }
227        // set into the form for rendering
228        setAccountingPeriods(filteredAccountingPeriods);
229        // set the chosen accounting period into the form
230        populateSelectedVoucherAccountingPeriod();
231    }
232
233    protected class OpenAuxiliaryVoucherPredicate implements Predicate {
234        protected ParameterService parameterService;
235        protected UniversityDateService dateService;
236        protected AccountingPeriodService acctPeriodService;
237        protected Document auxiliaryVoucherDocument;
238        protected AccountingPeriod currPeriod;
239        protected java.sql.Date currentDate;
240        protected Integer currentFiscalYear;
241
242        public OpenAuxiliaryVoucherPredicate(Document doc) {
243            this.parameterService = SpringContext.getBean(ParameterService.class);
244            this.dateService = SpringContext.getBean(UniversityDateService.class);
245            this.acctPeriodService = SpringContext.getBean(AccountingPeriodService.class);
246            this.auxiliaryVoucherDocument = doc;
247            this.currPeriod = acctPeriodService.getByDate(new java.sql.Date(new java.util.GregorianCalendar().getTimeInMillis()));
248            this.currentDate = new java.sql.Date(new java.util.Date().getTime());
249            this.currentFiscalYear = dateService.getCurrentFiscalYear();
250        }
251
252        @Override
253        public boolean evaluate(Object o) {
254            boolean result = false;
255            if (o instanceof AccountingPeriod) {
256                AccountingPeriod period = (AccountingPeriod) o;
257                result = /*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(AuxiliaryVoucherDocument.class, AuxiliaryVoucherDocumentRuleConstants.RESTRICTED_PERIOD_CODES, period.getUniversityFiscalPeriodCode()).evaluationSucceeds();
258                if (result) {
259                    result = (period.getUniversityFiscalYear().equals( currentFiscalYear ));
260                    if (result) {
261                        // did this accounting period end before now?
262                        result = acctPeriodService.compareAccountingPeriodsByDate(period, currPeriod) >= 0;
263                        if (!result) {
264                            // if yes, are we still in the grace period?
265                            result = getAuxiliaryVoucherDocument().calculateIfWithinGracePeriod(currentDate, period);
266                        }
267                    }
268                    else {
269                        // are we in current in the grace period of an ending accounting period of the previous fiscal year?
270                        result = getAuxiliaryVoucherDocument().calculateIfWithinGracePeriod(currentDate, period) && getAuxiliaryVoucherDocument().isEndOfPreviousFiscalYear(period);
271                    }
272                }
273            }
274            return result;
275        }
276    }
277
278    public List<String> getAccountingPeriodCompositeValueList() {
279        List<String> accountingPeriodCompositeValueList = new ArrayList<String>();
280        for (int i = 0; i < this.getAccountingPeriods().size(); i++) {
281            AccountingPeriod temp = (AccountingPeriod) this.getAccountingPeriods().get(i);
282            accountingPeriodCompositeValueList.add(temp.getUniversityFiscalPeriodCode() + temp.getUniversityFiscalYear());
283        }
284
285        return accountingPeriodCompositeValueList;
286    }
287
288    public List<String> getAccountingPeriodLabelList() {
289        List<String> accountingPeriodLabelList = new ArrayList<String>();
290        for (int i = 0; i < this.getAccountingPeriods().size(); i++) {
291            AccountingPeriod temp = (AccountingPeriod) this.getAccountingPeriods().get(i);
292            accountingPeriodLabelList.add(temp.getUniversityFiscalPeriodName());
293        }
294
295        return accountingPeriodLabelList;
296    }
297
298    public static final String REVERSAL_DATE_DEFAULT_DAY_OF_THE_MONTH_PARM_NAME = "REVERSAL_DATE_DEFAULT_DAY_OF_THE_MONTH";
299
300    /**
301     * get the reversal date default day of month defined as an application parameter
302     */
303    protected int getReversalDateDefaultDayOfMonth() {
304        ParameterService parameterService = SpringContext.getBean(ParameterService.class);
305        String defaultDayOfMonth = parameterService.getParameterValueAsString(AuxiliaryVoucherDocument.class, REVERSAL_DATE_DEFAULT_DAY_OF_THE_MONTH_PARM_NAME);
306
307        try {
308            Integer reversalDateDefaultDayOfMonth = Integer.parseInt(defaultDayOfMonth);
309
310            return reversalDateDefaultDayOfMonth;
311        }
312        catch(Exception e){
313            LOG.info("Invalid value was assigned to the paremeter: " + REVERSAL_DATE_DEFAULT_DAY_OF_THE_MONTH_PARM_NAME + ". The default value " + OLEConstants.AuxiliaryVoucher.ACCRUAL_DOC_DAY_OF_MONTH + " is applied.");
314        }
315
316        return OLEConstants.AuxiliaryVoucher.ACCRUAL_DOC_DAY_OF_MONTH;
317    }
318}