/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.ar.document.validation.impl; import static org.kuali.kfs.sys.document.validation.impl.AccountingDocumentRuleBaseConstants.ERROR_PATH.DOCUMENT_ERROR_PREFIX; import java.sql.Timestamp; import org.kuali.kfs.module.ar.ArConstants; import org.kuali.kfs.module.ar.ArKeyConstants; import org.kuali.kfs.module.ar.ArPropertyConstants; import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument; import org.kuali.kfs.sys.document.validation.GenericValidation; import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent; import org.kuali.rice.core.api.datetime.DateTimeService; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; public class CustomerInvoiceDueDateValidation extends GenericValidation { private CustomerInvoiceDocument customerInvoiceDocument; private DateTimeService dateTimeService; private ParameterService parameterService; @Override public boolean validate(AttributedDocumentEvent event) { Timestamp dueDateTimestamp = new Timestamp(customerInvoiceDocument.getInvoiceDueDate().getTime()); Timestamp billingDateTimestamp = new Timestamp(dateTimeService.getCurrentDate().getTime()); // test only for initial state and not for correction if (ObjectUtils.isNull((customerInvoiceDocument.getFinancialSystemDocumentHeader().getFinancialDocumentInErrorNumber())) && (dueDateTimestamp.before(billingDateTimestamp) || dueDateTimestamp.equals(billingDateTimestamp))) { 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); return false; } else { long diffInDays = getDifferenceInDays(billingDateTimestamp, dueDateTimestamp); //KfsDateUtils.getDifferenceInDays(billingDateTimestamp, dueDateTimestamp); int maxNumOfDaysAfterCurrentDateForInvoiceDueDate = Integer.parseInt(parameterService.getParameterValueAsString(CustomerInvoiceDocument.class, ArConstants.MAXIMUM_NUMBER_OF_DAYS_AFTER_CURRENT_DATE_FOR_INVOICE_DUE_DATE)); if (diffInDays >= maxNumOfDaysAfterCurrentDateForInvoiceDueDate) { 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 + ""); return false; } } return true; } /** * * This method calculates the difference in days between the two timestamps provided. * * This method is used instead of KfsDateUtils.getDifferenceInDays() because there is a rounding issue within the timestamp that exists which must be dealt with to * 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 * numbers. * * The approach used within KfsDateUtils does not offer enough accuracy to calculate the difference consistently and accurately. * * @param t1 * @param t2 * @return The difference in days between the two given timestamps. */ public static long getDifferenceInDays (Timestamp t1, Timestamp t2) { // Make sure the result is always > 0 if (t1.compareTo (t2) < 0) { Timestamp tmp = t1; t1 = t2; t2 = tmp; } // Timestamps mix milli and nanoseconds in the API, so we have to separate the two long diffSeconds = (t1.getTime () / 1000) - (t2.getTime () / 1000); // For normals dates, we have millisecond precision int nano1 = ((int) t1.getTime () % 1000) * 1000000; nano1 = t1.getNanos (); int nano2 = ((int) t2.getTime () % 1000) * 1000000; nano2 = t2.getNanos (); int diffNanos = nano1 - nano2; if (diffNanos < 0) { // Borrow one second diffSeconds --; diffNanos += 1000000000; } // mix nanos and millis again Timestamp result = new Timestamp ((diffSeconds * 1000) + (diffNanos / 1000000)); // setNanos() with a value of in the millisecond range doesn't affect the value of the time field // while milliseconds in the time field will modify nanos! Damn, this API is a *mess* result.setNanos (diffNanos); return result.getDate(); } public CustomerInvoiceDocument getCustomerInvoiceDocument() { return customerInvoiceDocument; } public void setCustomerInvoiceDocument(CustomerInvoiceDocument customerInvoiceDocument) { this.customerInvoiceDocument = customerInvoiceDocument; } public DateTimeService getDateTimeService() { return dateTimeService; } public void setDateTimeService(DateTimeService dateTimeService) { this.dateTimeService = dateTimeService; } public ParameterService getParameterService() { return parameterService; } public void setParameterService(ParameterService parameterService) { this.parameterService = parameterService; } }