/*
* 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.purap.document.validation.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.kuali.kfs.module.purap.PurapConstants;
import org.kuali.kfs.module.purap.PurapKeyConstants;
import org.kuali.kfs.module.purap.PurapPropertyConstants;
import org.kuali.kfs.module.purap.PurapConstants.PREQDocumentsStrings;
import org.kuali.kfs.module.purap.businessobject.LineItemReceivingItem;
import org.kuali.kfs.module.purap.businessobject.PurapEnterableItem;
import org.kuali.kfs.module.purap.businessobject.ReceivingItem;
import org.kuali.kfs.module.purap.document.LineItemReceivingDocument;
import org.kuali.kfs.module.purap.document.ReceivingDocument;
import org.kuali.kfs.module.purap.document.service.ReceivingService;
import org.kuali.kfs.module.purap.document.validation.AddReceivingItemRule;
import org.kuali.kfs.module.purap.document.validation.ContinuePurapRule;
import org.kuali.kfs.sys.KFSKeyConstants;
import org.kuali.kfs.sys.KFSPropertyConstants;
import org.kuali.kfs.sys.businessobject.UnitOfMeasure;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.rice.kns.rules.DocumentRuleBase;
import org.kuali.rice.kns.service.DataDictionaryService;
import org.kuali.rice.kns.service.DictionaryValidationService;
import org.kuali.rice.krad.document.Document;
import org.kuali.rice.krad.document.TransactionalDocument;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.ObjectUtils;
public class LineItemReceivingDocumentRule extends DocumentRuleBase implements ContinuePurapRule, AddReceivingItemRule{
@Override
protected boolean processCustomRouteDocumentBusinessRules(Document document) {
boolean valid = true;
LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument)document;
GlobalVariables.getMessageMap().clearErrorPath();
GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.DOCUMENT);
valid &= super.processCustomRouteDocumentBusinessRules(document);
valid &= canCreateLineItemReceivingDocument(lineItemReceivingDocument);
valid &= isAtLeastOneItemEntered(lineItemReceivingDocument);
valid &= validateItemUnitOfMeasure(lineItemReceivingDocument);
// makes sure all of the lines adhere to the rule that quantityDamaged and
// quantityReturned cannot (each) equal more than the quantityReceived
valid &= validateAllReceivingLinesHaveSaneQuantities(lineItemReceivingDocument);
return valid;
}
/**
* TODO: move this up
* This method...
* @param receivingDocument
* @return
*/
protected boolean isAtLeastOneItemEntered(ReceivingDocument receivingDocument){
for (ReceivingItem item : (List<ReceivingItem>) receivingDocument.getItems()) {
if (((PurapEnterableItem)item).isConsideredEntered()) {
//if any item is entered return true
return true;
}
}
//if no items are entered return false
GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_RECEIVING_LINEITEM_REQUIRED);
return false;
}
public boolean processContinuePurapBusinessRules(TransactionalDocument document) {
boolean valid = true;
LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument)document;
GlobalVariables.getMessageMap().clearErrorPath();
GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.DOCUMENT);
valid &= hasRequiredFieldsForContinue(lineItemReceivingDocument);
//only do this if valid
if(valid){
valid &= canCreateLineItemReceivingDocument(lineItemReceivingDocument);
}
return valid;
}
/**
* Make sure the required fields on the init screen are filled in.
*
* @param lineItemReceivingDocument
* @return
*/
protected boolean hasRequiredFieldsForContinue(LineItemReceivingDocument lineItemReceivingDocument){
boolean valid = true;
if (ObjectUtils.isNull(lineItemReceivingDocument.getPurchaseOrderIdentifier())) {
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, KFSKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.PURCHASE_ORDER_ID);
valid &= false;
}
if (ObjectUtils.isNull(lineItemReceivingDocument.getShipmentReceivedDate())) {
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.SHIPMENT_RECEIVED_DATE, KFSKeyConstants.ERROR_REQUIRED, PurapConstants.LineItemReceivingDocumentStrings.VENDOR_DATE);
valid &= false;
}
return valid;
}
/**
* Determines if it is valid to create a receiving line document. Only one
* receiving line document can be active at any time per purchase order document.
*
* @param lineItemReceivingDocument
* @return
*/
protected boolean canCreateLineItemReceivingDocument(LineItemReceivingDocument lineItemReceivingDocument){
boolean valid = true;
if( SpringContext.getBean(ReceivingService.class).canCreateLineItemReceivingDocument(lineItemReceivingDocument.getPurchaseOrderIdentifier(), lineItemReceivingDocument.getDocumentNumber()) == false){
valid &= false;
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_RECEIVING_LINE_DOCUMENT_ACTIVE_FOR_PO, lineItemReceivingDocument.getDocumentNumber(), lineItemReceivingDocument.getPurchaseOrderIdentifier().toString());
}
return valid;
}
/**
* Validates that if the item type is quantity based, the unit of measure is required.
*/
protected boolean validateItemUnitOfMeasure(ReceivingDocument receivingDocument) {
boolean valid = true;
for (ReceivingItem item : (List<ReceivingItem>) receivingDocument.getItems()) {
// Validations for quantity based item type
if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
String uomCode = item.getItemUnitOfMeasureCode();
if (StringUtils.isEmpty(uomCode)) {
valid = false;
String attributeLabel = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(item.getClass().getName()).getAttributeDefinition(KFSPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE).getLabel();
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, KFSKeyConstants.ERROR_REQUIRED, attributeLabel + item.getItemUnitOfMeasureCode());
}
else {
// Find out whether the unit of measure code has existed in the database
Map<String, String> fieldValues = new HashMap<String, String>();
fieldValues.put(KFSPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, item.getItemUnitOfMeasureCode());
if (SpringContext.getBean(BusinessObjectService.class).countMatching(UnitOfMeasure.class, fieldValues) != 1) {
// This is the case where the unit of measure code on the item does not exist in the database.
valid = false;
GlobalVariables.getMessageMap().putError(KFSPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, PurapKeyConstants.PUR_ITEM_UNIT_OF_MEASURE_CODE_INVALID, item.getItemUnitOfMeasureCode());
}
}
}
}
return valid;
}
/**
* @see org.kuali.kfs.module.purap.document.validation.AddReceivingItemRule#processAddReceivingItemRules(org.kuali.kfs.module.purap.document.ReceivingDocument, org.kuali.kfs.module.purap.businessobject.ReceivingItem)
*/
public boolean processAddReceivingItemRules(ReceivingDocument document, LineItemReceivingItem item,String errorPathPrefix) {
boolean valid = true;
valid &= SpringContext.getBean(DictionaryValidationService.class).isBusinessObjectValid(item,errorPathPrefix);
// test that the amount entered in the QuantityReturned and/or QuantityDamaged fields dont
// either equal more than the QuantityReceived. In other words, you can only return or mark as
// damaged those that are received. It doesnt make sense to receive 2 but return 3.
valid &= validateQuantityReturnedNotMoreThanReceived(document, item, errorPathPrefix, new Integer(0));
valid &= validateQuantityDamagedNotMoreThanReceived(document, item, errorPathPrefix, new Integer(0));
return valid;
}
protected boolean validateQuantityReturnedNotMoreThanReceived(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix, Integer lineNumber) {
if (item.getItemReturnedTotalQuantity() != null && item.getItemReceivedTotalQuantity() != null) {
if (item.getItemReturnedTotalQuantity().isGreaterThan(item.getItemReceivedTotalQuantity())) {
GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_RECEIVING_LINE_QTYRETURNED_GT_QTYRECEIVED, (lineNumber.intValue() == 0 ? "Add Line" : lineNumber.toString()));
return false;
}
}
return true;
}
protected boolean validateQuantityDamagedNotMoreThanReceived(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix, Integer lineNumber) {
if (item.getItemDamagedTotalQuantity() != null && item.getItemReceivedTotalQuantity() != null) {
if (item.getItemDamagedTotalQuantity().isGreaterThan(item.getItemReceivedTotalQuantity())) {
GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_RECEIVING_LINE_QTYDAMAGED_GT_QTYRECEIVED, (lineNumber.intValue() == 0 ? "Add Line" : lineNumber.toString()));
return false;
}
}
return true;
}
protected boolean validateAllReceivingLinesHaveSaneQuantities(ReceivingDocument document) {
GlobalVariables.getMessageMap().clearErrorPath();
boolean valid = true;
for (int i = 0; i < document.getItems().size(); i++) {
LineItemReceivingItem item = (LineItemReceivingItem) document.getItems().get(i);
valid &= validateQuantityReturnedNotMoreThanReceived(document, item, "", new Integer(i + 1));
valid &= validateQuantityDamagedNotMoreThanReceived(document, item, "", new Integer(i + 1));
}
return valid;
}
}