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.purap.document.validation.impl; 017 018 import java.util.HashMap; 019 import java.util.List; 020 import java.util.Map; 021 022 import org.apache.commons.lang.StringUtils; 023 import org.kuali.kfs.module.purap.PurapConstants; 024 import org.kuali.kfs.module.purap.PurapKeyConstants; 025 import org.kuali.kfs.module.purap.PurapPropertyConstants; 026 import org.kuali.kfs.module.purap.PurapConstants.PREQDocumentsStrings; 027 import org.kuali.kfs.module.purap.businessobject.LineItemReceivingItem; 028 import org.kuali.kfs.module.purap.businessobject.PurapEnterableItem; 029 import org.kuali.kfs.module.purap.businessobject.ReceivingItem; 030 import org.kuali.kfs.module.purap.document.LineItemReceivingDocument; 031 import org.kuali.kfs.module.purap.document.ReceivingDocument; 032 import org.kuali.kfs.module.purap.document.service.ReceivingService; 033 import org.kuali.kfs.module.purap.document.validation.AddReceivingItemRule; 034 import org.kuali.kfs.module.purap.document.validation.ContinuePurapRule; 035 import org.kuali.kfs.sys.KFSKeyConstants; 036 import org.kuali.kfs.sys.KFSPropertyConstants; 037 import org.kuali.kfs.sys.businessobject.UnitOfMeasure; 038 import org.kuali.kfs.sys.context.SpringContext; 039 import org.kuali.rice.kns.document.Document; 040 import org.kuali.rice.kns.document.TransactionalDocument; 041 import org.kuali.rice.kns.rules.DocumentRuleBase; 042 import org.kuali.rice.kns.service.BusinessObjectService; 043 import org.kuali.rice.kns.service.DataDictionaryService; 044 import org.kuali.rice.kns.service.DictionaryValidationService; 045 import org.kuali.rice.kns.util.GlobalVariables; 046 import org.kuali.rice.kns.util.ObjectUtils; 047 048 public class LineItemReceivingDocumentRule extends DocumentRuleBase implements ContinuePurapRule, AddReceivingItemRule{ 049 050 @Override 051 protected boolean processCustomRouteDocumentBusinessRules(Document document) { 052 boolean valid = true; 053 LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument)document; 054 055 GlobalVariables.getMessageMap().clearErrorPath(); 056 GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.DOCUMENT); 057 058 valid &= super.processCustomRouteDocumentBusinessRules(document); 059 valid &= canCreateLineItemReceivingDocument(lineItemReceivingDocument); 060 valid &= isAtLeastOneItemEntered(lineItemReceivingDocument); 061 valid &= validateItemUnitOfMeasure(lineItemReceivingDocument); 062 063 // makes sure all of the lines adhere to the rule that quantityDamaged and 064 // quantityReturned cannot (each) equal more than the quantityReceived 065 valid &= validateAllReceivingLinesHaveSaneQuantities(lineItemReceivingDocument); 066 067 return valid; 068 } 069 /** 070 * TODO: move this up 071 * This method... 072 * @param receivingDocument 073 * @return 074 */ 075 protected boolean isAtLeastOneItemEntered(ReceivingDocument receivingDocument){ 076 for (ReceivingItem item : (List<ReceivingItem>) receivingDocument.getItems()) { 077 if (((PurapEnterableItem)item).isConsideredEntered()) { 078 //if any item is entered return true 079 return true; 080 } 081 } 082 //if no items are entered return false 083 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_RECEIVING_LINEITEM_REQUIRED); 084 return false; 085 086 } 087 088 public boolean processContinuePurapBusinessRules(TransactionalDocument document) { 089 090 boolean valid = true; 091 LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument)document; 092 093 GlobalVariables.getMessageMap().clearErrorPath(); 094 GlobalVariables.getMessageMap().addToErrorPath(KFSPropertyConstants.DOCUMENT); 095 096 valid &= hasRequiredFieldsForContinue(lineItemReceivingDocument); 097 //only do this if valid 098 if(valid){ 099 valid &= canCreateLineItemReceivingDocument(lineItemReceivingDocument); 100 } 101 102 return valid; 103 } 104 105 /** 106 * Make sure the required fields on the init screen are filled in. 107 * 108 * @param lineItemReceivingDocument 109 * @return 110 */ 111 protected boolean hasRequiredFieldsForContinue(LineItemReceivingDocument lineItemReceivingDocument){ 112 113 boolean valid = true; 114 115 if (ObjectUtils.isNull(lineItemReceivingDocument.getPurchaseOrderIdentifier())) { 116 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, KFSKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.PURCHASE_ORDER_ID); 117 valid &= false; 118 } 119 120 if (ObjectUtils.isNull(lineItemReceivingDocument.getShipmentReceivedDate())) { 121 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.SHIPMENT_RECEIVED_DATE, KFSKeyConstants.ERROR_REQUIRED, PurapConstants.LineItemReceivingDocumentStrings.VENDOR_DATE); 122 valid &= false; 123 } 124 125 return valid; 126 } 127 128 /** 129 * Determines if it is valid to create a receiving line document. Only one 130 * receiving line document can be active at any time per purchase order document. 131 * 132 * @param lineItemReceivingDocument 133 * @return 134 */ 135 protected boolean canCreateLineItemReceivingDocument(LineItemReceivingDocument lineItemReceivingDocument){ 136 137 boolean valid = true; 138 139 if( SpringContext.getBean(ReceivingService.class).canCreateLineItemReceivingDocument(lineItemReceivingDocument.getPurchaseOrderIdentifier(), lineItemReceivingDocument.getDocumentNumber()) == false){ 140 valid &= false; 141 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_RECEIVING_LINE_DOCUMENT_ACTIVE_FOR_PO, lineItemReceivingDocument.getDocumentNumber(), lineItemReceivingDocument.getPurchaseOrderIdentifier().toString()); 142 } 143 144 return valid; 145 } 146 147 /** 148 * Validates that if the item type is quantity based, the unit of measure is required. 149 */ 150 protected boolean validateItemUnitOfMeasure(ReceivingDocument receivingDocument) { 151 boolean valid = true; 152 for (ReceivingItem item : (List<ReceivingItem>) receivingDocument.getItems()) { 153 // Validations for quantity based item type 154 if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) { 155 String uomCode = item.getItemUnitOfMeasureCode(); 156 if (StringUtils.isEmpty(uomCode)) { 157 valid = false; 158 String attributeLabel = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(item.getClass().getName()).getAttributeDefinition(KFSPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE).getLabel(); 159 GlobalVariables.getMessageMap().putError(KFSPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, KFSKeyConstants.ERROR_REQUIRED, attributeLabel + item.getItemUnitOfMeasureCode()); 160 } 161 else { 162 // Find out whether the unit of measure code has existed in the database 163 Map<String, String> fieldValues = new HashMap<String, String>(); 164 fieldValues.put(KFSPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, item.getItemUnitOfMeasureCode()); 165 if (SpringContext.getBean(BusinessObjectService.class).countMatching(UnitOfMeasure.class, fieldValues) != 1) { 166 // This is the case where the unit of measure code on the item does not exist in the database. 167 valid = false; 168 GlobalVariables.getMessageMap().putError(KFSPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, PurapKeyConstants.PUR_ITEM_UNIT_OF_MEASURE_CODE_INVALID, item.getItemUnitOfMeasureCode()); 169 } 170 } 171 } 172 } 173 return valid; 174 } 175 176 /** 177 * @see org.kuali.kfs.module.purap.document.validation.AddReceivingItemRule#processAddReceivingItemRules(org.kuali.kfs.module.purap.document.ReceivingDocument, org.kuali.kfs.module.purap.businessobject.ReceivingItem) 178 */ 179 public boolean processAddReceivingItemRules(ReceivingDocument document, LineItemReceivingItem item,String errorPathPrefix) { 180 boolean valid = true; 181 182 valid &= SpringContext.getBean(DictionaryValidationService.class).isBusinessObjectValid(item,errorPathPrefix); 183 184 // test that the amount entered in the QuantityReturned and/or QuantityDamaged fields dont 185 // either equal more than the QuantityReceived. In other words, you can only return or mark as 186 // damaged those that are received. It doesnt make sense to receive 2 but return 3. 187 valid &= validateQuantityReturnedNotMoreThanReceived(document, item, errorPathPrefix, new Integer(0)); 188 valid &= validateQuantityDamagedNotMoreThanReceived(document, item, errorPathPrefix, new Integer(0)); 189 190 return valid; 191 } 192 193 protected boolean validateQuantityReturnedNotMoreThanReceived(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix, Integer lineNumber) { 194 if (item.getItemReturnedTotalQuantity() != null && item.getItemReceivedTotalQuantity() != null) { 195 if (item.getItemReturnedTotalQuantity().isGreaterThan(item.getItemReceivedTotalQuantity())) { 196 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_RECEIVING_LINE_QTYRETURNED_GT_QTYRECEIVED, (lineNumber.intValue() == 0 ? "Add Line" : lineNumber.toString())); 197 return false; 198 } 199 } 200 return true; 201 } 202 203 protected boolean validateQuantityDamagedNotMoreThanReceived(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix, Integer lineNumber) { 204 if (item.getItemDamagedTotalQuantity() != null && item.getItemReceivedTotalQuantity() != null) { 205 if (item.getItemDamagedTotalQuantity().isGreaterThan(item.getItemReceivedTotalQuantity())) { 206 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_RECEIVING_LINE_QTYDAMAGED_GT_QTYRECEIVED, (lineNumber.intValue() == 0 ? "Add Line" : lineNumber.toString())); 207 return false; 208 } 209 } 210 return true; 211 } 212 213 protected boolean validateAllReceivingLinesHaveSaneQuantities(ReceivingDocument document) { 214 GlobalVariables.getMessageMap().clearErrorPath(); 215 boolean valid = true; 216 for (int i = 0; i < document.getItems().size(); i++) { 217 LineItemReceivingItem item = (LineItemReceivingItem) document.getItems().get(i); 218 219 valid &= validateQuantityReturnedNotMoreThanReceived(document, item, "", new Integer(i + 1)); 220 valid &= validateQuantityDamagedNotMoreThanReceived(document, item, "", new Integer(i + 1)); 221 } 222 return valid; 223 } 224 225 }