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.ar.document.validation.impl;
017    
018    import java.sql.Date;
019    import java.sql.Timestamp;
020    import java.util.Calendar;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    import org.apache.commons.lang.StringUtils;
026    import org.apache.log4j.Logger;
027    import org.kuali.kfs.module.ar.ArConstants;
028    import org.kuali.kfs.module.ar.ArKeyConstants;
029    import org.kuali.kfs.module.ar.ArPropertyConstants;
030    import org.kuali.kfs.module.ar.businessobject.InvoiceRecurrence;
031    import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
032    import org.kuali.kfs.module.ar.document.service.InvoiceRecurrenceDocumentService;
033    import org.kuali.kfs.sys.context.SpringContext;
034    import org.kuali.rice.kew.exception.WorkflowException;
035    import org.kuali.rice.kns.document.MaintenanceDocument;
036    import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
037    import org.kuali.rice.kns.service.BusinessObjectService;
038    import org.kuali.rice.kns.service.DateTimeService;
039    import org.kuali.rice.kns.service.DocumentService;
040    import org.kuali.rice.kns.service.ParameterService;
041    import org.kuali.rice.kns.util.DateUtils;
042    import org.kuali.rice.kns.util.ObjectUtils;
043    import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
044    
045    public class InvoiceRecurrenceRule extends MaintenanceDocumentRuleBase {
046        protected static Logger LOG = org.apache.log4j.Logger.getLogger(InvoiceRecurrenceRule.class);
047        protected InvoiceRecurrence oldInvoiceRecurrence;
048        protected InvoiceRecurrence newInvoiceRecurrence;
049        
050        protected DateTimeService dateTimeService;
051    
052        @Override
053        public void setupConvenienceObjects() {
054            oldInvoiceRecurrence = (InvoiceRecurrence) super.getOldBo();
055            newInvoiceRecurrence = (InvoiceRecurrence) super.getNewBo();
056        }
057        
058        @Override
059        protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
060    
061            boolean success;
062            java.sql.Date today = getDateTimeService().getCurrentSqlDateMidnight();
063            Date currentDate = getDateTimeService().getCurrentSqlDate();
064    
065           
066            success = checkIfInvoiceIsApproved(newInvoiceRecurrence.getInvoiceNumber());
067    /*
068            success &= checkIfRecurrenceMaintenanceAlreadyExists(newInvoiceRecurrence);
069            success &= validateDocumentRecurrenceBeginDate(newInvoiceRecurrence);
070    */
071            success &= validateDocumentRecurrenceEndDate(newInvoiceRecurrence.getDocumentRecurrenceBeginDate(), 
072                                                         newInvoiceRecurrence.getDocumentRecurrenceEndDate());
073            success &= validateIfBothEndDateAndTotalRecurrenceNumberAreEntered(newInvoiceRecurrence.getDocumentRecurrenceBeginDate(), 
074                                                                               newInvoiceRecurrence.getDocumentRecurrenceEndDate(),
075                                                                               newInvoiceRecurrence.getDocumentTotalRecurrenceNumber(),
076                                                                               newInvoiceRecurrence.getDocumentRecurrenceIntervalCode());
077            success &= validateEndDateOrTotalNumberofRecurrences(newInvoiceRecurrence.getDocumentRecurrenceEndDate(),
078                                                                 newInvoiceRecurrence.getDocumentTotalRecurrenceNumber());   
079            success &= validateMaximumNumberOfRecurrences(newInvoiceRecurrence.getDocumentTotalRecurrenceNumber(),
080                                                          newInvoiceRecurrence.getDocumentRecurrenceIntervalCode());
081            return success;
082        }
083    
084        @Override
085        protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) {
086            // always return true even if there are business rule failures.
087            processCustomRouteDocumentBusinessRules(document);
088            return true;
089        }
090    
091        /**
092         * Check if an Invoice Recurrence Maintenance document already exists.
093         */
094        protected boolean checkIfRecurrenceMaintenanceAlreadyExists(InvoiceRecurrence newInvoiceRecurrence) {
095            boolean success = true;
096            Map<String, String> criteria = new HashMap<String, String>();
097            criteria.put("invoiceNumber", newInvoiceRecurrence.getInvoiceNumber());
098            InvoiceRecurrence invoiceRecurrence = (InvoiceRecurrence) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(InvoiceRecurrence.class, criteria);
099            if (ObjectUtils.isNotNull(invoiceRecurrence) && !(oldInvoiceRecurrence.equals(invoiceRecurrence))) {
100                putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.RECURRING_INVOICE_NUMBER, ArKeyConstants.ERROR_MAINTENANCE_DOCUMENT_ALREADY_EXISTS);
101                success = false;
102            }
103            return success;
104        }
105        /**
106         * Validate if the invoice has an approved status.
107         */
108        protected boolean checkIfInvoiceIsApproved(String recurrenceInvoiceNumber) {
109            boolean success = true;
110            
111            if (ObjectUtils.isNull(recurrenceInvoiceNumber)) {
112                return success;
113            }
114            
115            CustomerInvoiceDocument customerInvoiceDocument = null;
116            if (!SpringContext.getBean(DocumentService.class).documentExists(recurrenceInvoiceNumber)) {
117                putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.RECURRING_INVOICE_NUMBER, ArKeyConstants.ERROR_INVOICE_DOES_NOT_EXIST);
118                success = false;
119            }
120            else {
121                try {
122                    customerInvoiceDocument = (CustomerInvoiceDocument)SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(recurrenceInvoiceNumber);
123                } catch (WorkflowException e){
124                }
125                if (ObjectUtils.isNotNull(customerInvoiceDocument)) {
126                    KualiWorkflowDocument workflowDocument = customerInvoiceDocument.getDocumentHeader().getWorkflowDocument();
127                    if (!(workflowDocument.stateIsApproved())) {
128                        putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.RECURRING_INVOICE_NUMBER, ArKeyConstants.ERROR_RECURRING_INVOICE_NUMBER_MUST_BE_APPROVED);
129                        success = false;
130                    }
131                }
132            }
133            return success;
134        }
135        /**
136         * Validate Begin Date.
137         */
138        protected boolean validateDocumentRecurrenceBeginDate(InvoiceRecurrence newInvoiceRecurrence) {
139            boolean success = true;
140            if (ObjectUtils.isNull(newInvoiceRecurrence.getDocumentRecurrenceBeginDate())) {
141                return success;
142            }
143            Timestamp currentDate = new Timestamp(getDateTimeService().getCurrentDate().getTime());
144            Timestamp beginDateTimestamp = new Timestamp(newInvoiceRecurrence.getDocumentRecurrenceBeginDate().getTime());
145            if (beginDateTimestamp.before(currentDate) || beginDateTimestamp.equals(currentDate)) {
146                putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_BEGIN_DATE, ArKeyConstants.ERROR_INVOICE_RECURRENCE_BEGIN_DATE_EARLIER_THAN_TODAY);
147                return false;
148            }
149            return success;
150        }
151        /**
152         * Validate End Date.
153         */
154        public boolean validateDocumentRecurrenceEndDate(Date newInvoiceRecurrenceBeginDate, Date newInvoiceRecurrenceEndDate) {
155            boolean success = true;
156            if (!SpringContext.getBean(InvoiceRecurrenceDocumentService.class).isValidRecurrenceEndDate(newInvoiceRecurrenceBeginDate, newInvoiceRecurrenceEndDate)) {
157                putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_END_DATE, ArKeyConstants.ERROR_END_DATE_EARLIER_THAN_BEGIN_DATE);
158                return false;
159            }
160            return success;
161        }
162        /**
163         * This method checks that End Date and Total Recurrence Number are valid when both are entered.
164         * 
165         * @param document the maintenance document
166         * @return
167         */
168        protected boolean validateIfBothEndDateAndTotalRecurrenceNumberAreEntered(Date recurrenceBeginDate, Date recurrenceEndDate, Integer totalRecurrenceNumber, String recurrenceIntervalCode) {
169    
170            if (ObjectUtils.isNull(recurrenceBeginDate) || 
171                ObjectUtils.isNull(recurrenceIntervalCode) ||
172                ObjectUtils.isNull(recurrenceEndDate) ||
173                ObjectUtils.isNull(totalRecurrenceNumber)) {
174                return true;
175            }
176    
177            Calendar beginCalendar = Calendar.getInstance();
178            beginCalendar.setTime(recurrenceBeginDate);
179            Date beginDate = recurrenceBeginDate;
180            Calendar endCalendar = Calendar.getInstance();
181            endCalendar.setTime(recurrenceEndDate);
182            Date endDate = recurrenceEndDate;
183            Calendar nextCalendar = Calendar.getInstance();
184            Date nextDate = beginDate;
185                    
186            int totalRecurrences = 0;
187            int addCounter = 0;
188            String intervalCode = recurrenceIntervalCode;
189            if (intervalCode.equals("M")) {
190                addCounter = 1;
191            }
192            if (intervalCode.equals("Q")) {
193                addCounter = 3;
194            }
195            /* perform this loop while begin_date is less than or equal to end_date */
196            while (!(beginDate.after(endDate))){
197                beginCalendar.setTime(beginDate);
198                beginCalendar.add(Calendar.MONTH, addCounter);
199                beginDate = DateUtils.convertToSqlDate(beginCalendar.getTime());
200                totalRecurrences++;
201    
202                nextDate = beginDate;
203                nextCalendar.setTime(nextDate);
204                nextCalendar.add(Calendar.MONTH, addCounter);
205                nextDate = DateUtils.convertToSqlDate(nextCalendar.getTime());
206                if (endDate.after(beginDate) && endDate.before(nextDate)) {
207                    totalRecurrences++;
208                    break;
209                }
210            }
211            if (totalRecurrences != totalRecurrenceNumber.intValue()) {
212                putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_END_DATE, ArKeyConstants.ERROR_END_DATE_AND_TOTAL_NUMBER_OF_RECURRENCES_NOT_VALID);
213                return false;
214            }
215            
216            return true;
217        }
218        /**
219         * Validate that either End Date or Total Number of Recurrences must be entered.
220         */
221        protected boolean validateEndDateOrTotalNumberofRecurrences(Date recurrenceEndDate, Integer totalRecurrenceNumber) {
222            boolean success = true;
223            if (ObjectUtils.isNull(recurrenceEndDate) && ObjectUtils.isNull(totalRecurrenceNumber)) {
224                putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_END_DATE, ArKeyConstants.ERROR_END_DATE_OR_TOTAL_NUMBER_OF_RECURRENCES);
225                return false;
226            }
227            return success;
228        }
229    
230        /**
231         * Total number of recurrences may not be greater than the number defined in system parameter MAXIMUM_RECURRENCES_BY_INTERVAL.
232         */ 
233        protected boolean validateMaximumNumberOfRecurrences(Integer totalRecurrenceNumber, String recurrenceIntervalCode) {
234    
235            if (ObjectUtils.isNull(recurrenceIntervalCode) ||
236                ObjectUtils.isNull(totalRecurrenceNumber)) {
237                return true;
238            }
239            boolean success = true;
240            Integer maximumRecurrencesByInterval;
241            if (ObjectUtils.isNotNull(recurrenceIntervalCode)) {
242                List<String> maximumRecurrences = SpringContext.getBean(ParameterService.class).getParameterValues(InvoiceRecurrence.class, ArConstants.MAXIMUM_RECURRENCES_BY_INTERVAL, recurrenceIntervalCode);
243                if (maximumRecurrences.size() > 0 && StringUtils.isNotBlank(maximumRecurrences.get(0))) {
244                    maximumRecurrencesByInterval = Integer.valueOf(maximumRecurrences.get(0));
245                    if (totalRecurrenceNumber > maximumRecurrencesByInterval) {
246                        putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_TOTAL_RECURRENCE_NUMBER, ArKeyConstants.ERROR_TOTAL_NUMBER_OF_RECURRENCES_GREATER_THAN_ALLOWED, maximumRecurrences.get(0));
247                        return false;
248                    }
249                }
250            }
251            return success;
252        }
253    
254    }