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 static org.kuali.kfs.sys.document.validation.impl.AccountingDocumentRuleBaseConstants.ERROR_PATH.DOCUMENT_ERROR_PREFIX;
019    
020    import java.sql.Timestamp;
021    
022    import org.kuali.kfs.module.ar.ArConstants;
023    import org.kuali.kfs.module.ar.ArKeyConstants;
024    import org.kuali.kfs.module.ar.ArPropertyConstants;
025    import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
026    import org.kuali.kfs.sys.document.validation.GenericValidation;
027    import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent;
028    import org.kuali.rice.kns.service.DateTimeService;
029    import org.kuali.rice.kns.service.ParameterService;
030    import org.kuali.rice.kns.util.DateUtils;
031    import org.kuali.rice.kns.util.GlobalVariables;
032    
033    public class CustomerInvoiceDueDateValidation extends GenericValidation {
034        
035        private CustomerInvoiceDocument customerInvoiceDocument;
036        private DateTimeService dateTimeService;
037        private ParameterService parameterService;
038        
039        public boolean validate(AttributedDocumentEvent event) {
040            
041            Timestamp dueDateTimestamp = new Timestamp(customerInvoiceDocument.getInvoiceDueDate().getTime());
042            Timestamp billingDateTimestamp = new Timestamp(dateTimeService.getCurrentDate().getTime());
043            
044            if (dueDateTimestamp.before(billingDateTimestamp) || dueDateTimestamp.equals(billingDateTimestamp)) {
045                GlobalVariables.getMessageMap().putError(DOCUMENT_ERROR_PREFIX + ArPropertyConstants.CustomerInvoiceDocumentFields.INVOICE_DUE_DATE, ArKeyConstants.ERROR_CUSTOMER_INVOICE_DOCUMENT_INVALID_INVOICE_DUE_DATE_BEFORE_OR_EQUAL_TO_BILLING_DATE);
046                return false;
047            }
048            else {
049                long diffInDays = getDifferenceInDays(billingDateTimestamp, dueDateTimestamp); //DateUtils.getDifferenceInDays(billingDateTimestamp, dueDateTimestamp);
050                int maxNumOfDaysAfterCurrentDateForInvoiceDueDate = Integer.parseInt(parameterService.getParameterValue(CustomerInvoiceDocument.class, ArConstants.MAXIMUM_NUMBER_OF_DAYS_AFTER_CURRENT_DATE_FOR_INVOICE_DUE_DATE));
051                if (diffInDays >= maxNumOfDaysAfterCurrentDateForInvoiceDueDate) {
052                    GlobalVariables.getMessageMap().putError(DOCUMENT_ERROR_PREFIX + ArPropertyConstants.CustomerInvoiceDocumentFields.INVOICE_DUE_DATE, ArKeyConstants.ERROR_CUSTOMER_INVOICE_DOCUMENT_INVALID_INVOICE_DUE_DATE_MORE_THAN_X_DAYS, maxNumOfDaysAfterCurrentDateForInvoiceDueDate + "");
053                    return false;
054                }
055    
056            }
057            
058            return true;
059        }
060    
061        /**
062         * 
063         * This method calculates the difference in days between the two timestamps provided.
064         * 
065         * This method is used instead of DateUtils.getDifferenceInDays() because there is a rounding issue within the timestamp that exists which must be dealt with to 
066         * prevent improper calculations.  This issue is similar to the problems that exist with adding and subtracting doubles and the inherently bad way that Java handles
067         * numbers.  
068         * 
069         * The approach used within DateUtils does not offer enough accuracy to calculate the difference consistently and accurately.
070         * 
071         * @param t1
072         * @param t2
073         * @return The difference in days between the two given timestamps.  
074         */
075        public static long getDifferenceInDays (Timestamp t1, Timestamp t2) {
076            // Make sure the result is always > 0
077            if (t1.compareTo (t2) < 0) {
078                Timestamp tmp = t1;
079                t1 = t2;
080                t2 = tmp;
081            }
082    
083            // Timestamps mix milli and nanoseconds in the API, so we have to separate the two
084            long diffSeconds = (t1.getTime () / 1000) - (t2.getTime () / 1000);
085            // For normals dates, we have millisecond precision
086            int nano1 = ((int) t1.getTime () % 1000) * 1000000;
087            nano1 = t1.getNanos ();
088            int nano2 = ((int) t2.getTime () % 1000) * 1000000;
089            nano2 = t2.getNanos ();
090    
091            int diffNanos = nano1 - nano2;
092            if (diffNanos < 0) {
093                // Borrow one second
094                diffSeconds --;
095                diffNanos += 1000000000;
096            }
097    
098            // mix nanos and millis again
099            Timestamp result = new Timestamp ((diffSeconds * 1000) + (diffNanos / 1000000));
100            // setNanos() with a value of in the millisecond range doesn't affect the value of the time field
101            // while milliseconds in the time field will modify nanos! Damn, this API is a *mess*
102            result.setNanos (diffNanos);
103            return result.getDate();
104        }
105        
106        public CustomerInvoiceDocument getCustomerInvoiceDocument() {
107            return customerInvoiceDocument;
108        }
109    
110        public void setCustomerInvoiceDocument(CustomerInvoiceDocument customerInvoiceDocument) {
111            this.customerInvoiceDocument = customerInvoiceDocument;
112        }
113    
114        public DateTimeService getDateTimeService() {
115            return dateTimeService;
116        }
117    
118        public void setDateTimeService(DateTimeService dateTimeService) {
119            this.dateTimeService = dateTimeService;
120        }
121        
122        public ParameterService getParameterService() {
123            return parameterService;
124        }
125    
126        public void setParameterService(ParameterService parameterService) {
127            this.parameterService = parameterService;
128        }
129    }