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