/*
* 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 java.sql.Date;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
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.businessobject.InvoiceRecurrence;
import org.kuali.kfs.module.ar.document.CustomerInvoiceDocument;
import org.kuali.kfs.module.ar.document.service.InvoiceRecurrenceDocumentService;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.util.KfsDateUtils;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kew.api.WorkflowDocument;
import org.kuali.rice.kew.api.exception.WorkflowException;
import org.kuali.rice.kns.document.MaintenanceDocument;
import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.service.DocumentService;
import org.kuali.rice.krad.util.ObjectUtils;
public class InvoiceRecurrenceRule extends MaintenanceDocumentRuleBase {
protected static Logger LOG = org.apache.log4j.Logger.getLogger(InvoiceRecurrenceRule.class);
protected InvoiceRecurrence oldInvoiceRecurrence;
protected InvoiceRecurrence newInvoiceRecurrence;
protected DateTimeService dateTimeService;
@Override
public void setupConvenienceObjects() {
oldInvoiceRecurrence = (InvoiceRecurrence) super.getOldBo();
newInvoiceRecurrence = (InvoiceRecurrence) super.getNewBo();
}
@Override
protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
boolean success;
java.sql.Date today = getDateTimeService().getCurrentSqlDateMidnight();
Date currentDate = getDateTimeService().getCurrentSqlDate();
success = checkIfInvoiceIsApproved(newInvoiceRecurrence.getInvoiceNumber());
/*
success &= checkIfRecurrenceMaintenanceAlreadyExists(newInvoiceRecurrence);
success &= validateDocumentRecurrenceBeginDate(newInvoiceRecurrence);
*/
success &= validateDocumentRecurrenceEndDate(newInvoiceRecurrence.getDocumentRecurrenceBeginDate(),
newInvoiceRecurrence.getDocumentRecurrenceEndDate());
success &= validateIfBothEndDateAndTotalRecurrenceNumberAreEntered(newInvoiceRecurrence.getDocumentRecurrenceBeginDate(),
newInvoiceRecurrence.getDocumentRecurrenceEndDate(),
newInvoiceRecurrence.getDocumentTotalRecurrenceNumber(),
newInvoiceRecurrence.getDocumentRecurrenceIntervalCode());
success &= validateEndDateOrTotalNumberofRecurrences(newInvoiceRecurrence.getDocumentRecurrenceEndDate(),
newInvoiceRecurrence.getDocumentTotalRecurrenceNumber());
success &= validateMaximumNumberOfRecurrences(newInvoiceRecurrence.getDocumentTotalRecurrenceNumber(),
newInvoiceRecurrence.getDocumentRecurrenceIntervalCode());
return success;
}
@Override
protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) {
// always return true even if there are business rule failures.
processCustomRouteDocumentBusinessRules(document);
return true;
}
/**
* Check if an Invoice Recurrence Maintenance document already exists.
*/
protected boolean checkIfRecurrenceMaintenanceAlreadyExists(InvoiceRecurrence newInvoiceRecurrence) {
boolean success = true;
Map<String, String> criteria = new HashMap<String, String>();
criteria.put("invoiceNumber", newInvoiceRecurrence.getInvoiceNumber());
InvoiceRecurrence invoiceRecurrence = SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(InvoiceRecurrence.class, criteria);
if (ObjectUtils.isNotNull(invoiceRecurrence) && !(oldInvoiceRecurrence.equals(invoiceRecurrence))) {
putFieldError(ArPropertyConstants.INVOICE_NUMBER, ArKeyConstants.ERROR_MAINTENANCE_DOCUMENT_ALREADY_EXISTS);
success = false;
}
return success;
}
/**
* Validate if the invoice has an approved status.
*/
protected boolean checkIfInvoiceIsApproved(String recurrenceInvoiceNumber) {
boolean success = true;
if (ObjectUtils.isNull(recurrenceInvoiceNumber)) {
return success;
}
CustomerInvoiceDocument customerInvoiceDocument = null;
if (!SpringContext.getBean(DocumentService.class).documentExists(recurrenceInvoiceNumber)) {
putFieldError(ArPropertyConstants.INVOICE_NUMBER, ArKeyConstants.ERROR_INVOICE_DOES_NOT_EXIST);
success = false;
}
else {
try {
customerInvoiceDocument = (CustomerInvoiceDocument)SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(recurrenceInvoiceNumber);
} catch (WorkflowException e){
}
if (ObjectUtils.isNotNull(customerInvoiceDocument)) {
WorkflowDocument workflowDocument = customerInvoiceDocument.getDocumentHeader().getWorkflowDocument();
if (!(workflowDocument.isApproved())) {
putFieldError(ArPropertyConstants.INVOICE_NUMBER, ArKeyConstants.ERROR_RECURRING_INVOICE_NUMBER_MUST_BE_APPROVED);
success = false;
}
}
}
return success;
}
/**
* Validate Begin Date.
*/
protected boolean validateDocumentRecurrenceBeginDate(InvoiceRecurrence newInvoiceRecurrence) {
boolean success = true;
if (ObjectUtils.isNull(newInvoiceRecurrence.getDocumentRecurrenceBeginDate())) {
return success;
}
Timestamp currentDate = new Timestamp(getDateTimeService().getCurrentDate().getTime());
Timestamp beginDateTimestamp = new Timestamp(newInvoiceRecurrence.getDocumentRecurrenceBeginDate().getTime());
if (beginDateTimestamp.before(currentDate) || beginDateTimestamp.equals(currentDate)) {
putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_BEGIN_DATE, ArKeyConstants.ERROR_INVOICE_RECURRENCE_BEGIN_DATE_EARLIER_THAN_TODAY);
return false;
}
return success;
}
/**
* Validate End Date.
*/
public boolean validateDocumentRecurrenceEndDate(Date newInvoiceRecurrenceBeginDate, Date newInvoiceRecurrenceEndDate) {
boolean success = true;
if (!SpringContext.getBean(InvoiceRecurrenceDocumentService.class).isValidRecurrenceEndDate(newInvoiceRecurrenceBeginDate, newInvoiceRecurrenceEndDate)) {
putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_END_DATE, ArKeyConstants.ERROR_END_DATE_EARLIER_THAN_BEGIN_DATE);
return false;
}
return success;
}
/**
* This method checks that End Date and Total Recurrence Number are valid when both are entered.
*
* @param document the maintenance document
* @return
*/
protected boolean validateIfBothEndDateAndTotalRecurrenceNumberAreEntered(Date recurrenceBeginDate, Date recurrenceEndDate, Integer totalRecurrenceNumber, String recurrenceIntervalCode) {
if (ObjectUtils.isNull(recurrenceBeginDate) ||
ObjectUtils.isNull(recurrenceIntervalCode) ||
ObjectUtils.isNull(recurrenceEndDate) ||
ObjectUtils.isNull(totalRecurrenceNumber)) {
return true;
}
Calendar beginCalendar = Calendar.getInstance();
beginCalendar.setTime(recurrenceBeginDate);
Date beginDate = recurrenceBeginDate;
Calendar endCalendar = Calendar.getInstance();
endCalendar.setTime(recurrenceEndDate);
Date endDate = recurrenceEndDate;
Calendar nextCalendar = Calendar.getInstance();
Date nextDate = beginDate;
int totalRecurrences = 0;
int addCounter = 0;
String intervalCode = recurrenceIntervalCode;
if (intervalCode.equals("M")) {
addCounter = 1;
}
if (intervalCode.equals("Q")) {
addCounter = 3;
}
/* perform this loop while begin_date is less than or equal to end_date */
while (!(beginDate.after(endDate))){
beginCalendar.setTime(beginDate);
beginCalendar.add(Calendar.MONTH, addCounter);
beginDate = KfsDateUtils.convertToSqlDate(beginCalendar.getTime());
totalRecurrences++;
nextDate = beginDate;
nextCalendar.setTime(nextDate);
nextCalendar.add(Calendar.MONTH, addCounter);
nextDate = KfsDateUtils.convertToSqlDate(nextCalendar.getTime());
if (endDate.after(beginDate) && endDate.before(nextDate)) {
totalRecurrences++;
break;
}
}
if (totalRecurrences != totalRecurrenceNumber.intValue()) {
putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_END_DATE, ArKeyConstants.ERROR_END_DATE_AND_TOTAL_NUMBER_OF_RECURRENCES_NOT_VALID);
return false;
}
return true;
}
/**
* Validate that either End Date or Total Number of Recurrences must be entered.
*/
protected boolean validateEndDateOrTotalNumberofRecurrences(Date recurrenceEndDate, Integer totalRecurrenceNumber) {
boolean success = true;
if (ObjectUtils.isNull(recurrenceEndDate) && ObjectUtils.isNull(totalRecurrenceNumber)) {
putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_END_DATE, ArKeyConstants.ERROR_END_DATE_OR_TOTAL_NUMBER_OF_RECURRENCES);
return false;
}
return success;
}
/**
* Total number of recurrences may not be greater than the number defined in system parameter MAXIMUM_RECURRENCES_BY_INTERVAL.
*/
protected boolean validateMaximumNumberOfRecurrences(Integer totalRecurrenceNumber, String recurrenceIntervalCode) {
if (ObjectUtils.isNull(recurrenceIntervalCode) ||
ObjectUtils.isNull(totalRecurrenceNumber)) {
return true;
}
boolean success = true;
Integer maximumRecurrencesByInterval;
if (ObjectUtils.isNotNull(recurrenceIntervalCode)) {
List<String> maximumRecurrences = new ArrayList<String>( SpringContext.getBean(ParameterService.class).getSubParameterValuesAsString(InvoiceRecurrence.class, ArConstants.MAXIMUM_RECURRENCES_BY_INTERVAL, recurrenceIntervalCode) );
if (maximumRecurrences.size() > 0 && StringUtils.isNotBlank(maximumRecurrences.get(0))) {
maximumRecurrencesByInterval = Integer.valueOf(maximumRecurrences.get(0));
if (totalRecurrenceNumber > maximumRecurrencesByInterval) {
putFieldError(ArPropertyConstants.InvoiceRecurrenceFields.INVOICE_RECURRENCE_TOTAL_RECURRENCE_NUMBER, ArKeyConstants.ERROR_TOTAL_NUMBER_OF_RECURRENCES_GREATER_THAN_ALLOWED, maximumRecurrences.get(0));
return false;
}
}
}
return success;
}
}