001/* 002 * Copyright 2009 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 */ 016package org.kuali.ole.select.document.validation.impl; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.log4j.Logger; 020import org.kuali.ole.docstore.common.client.DocstoreClientLocator; 021import org.kuali.ole.module.purap.PurapConstants; 022import org.kuali.ole.module.purap.PurapConstants.ItemFields; 023import org.kuali.ole.module.purap.PurapConstants.ItemTypeCodes; 024import org.kuali.ole.module.purap.PurapKeyConstants; 025import org.kuali.ole.module.purap.PurapPropertyConstants; 026import org.kuali.ole.module.purap.businessobject.PurApItem; 027import org.kuali.ole.module.purap.businessobject.PurchasingItemBase; 028import org.kuali.ole.module.purap.document.validation.impl.PurchasingAccountsPayableAddItemValidation; 029import org.kuali.ole.select.bo.OLEDonor; 030import org.kuali.ole.select.businessobject.OlePurchaseOrderItem; 031import org.kuali.ole.select.businessobject.OleRequisitionItem; 032import org.kuali.ole.sys.OLEConstants; 033import org.kuali.ole.sys.OLEKeyConstants; 034import org.kuali.ole.sys.OLEPropertyConstants; 035import org.kuali.ole.sys.businessobject.UnitOfMeasure; 036import org.kuali.ole.sys.context.SpringContext; 037import org.kuali.ole.sys.document.validation.event.AttributedDocumentEvent; 038import org.kuali.ole.vnd.businessobject.CommodityCode; 039import org.kuali.rice.core.api.util.type.KualiDecimal; 040import org.kuali.rice.core.api.util.type.KualiInteger; 041import org.kuali.rice.kns.service.DataDictionaryService; 042import org.kuali.rice.krad.service.BusinessObjectService; 043import org.kuali.rice.krad.service.KRADServiceLocator; 044import org.kuali.rice.krad.util.GlobalVariables; 045import org.kuali.rice.krad.util.KRADConstants; 046import org.kuali.rice.krad.util.ObjectUtils; 047 048import java.math.BigDecimal; 049import java.util.HashMap; 050import java.util.Map; 051 052public class OlePurchasingAddItemValidation extends PurchasingAccountsPayableAddItemValidation { 053 054 private BusinessObjectService businessObjectService; 055 private DataDictionaryService dataDictionaryService; 056 private DocstoreClientLocator docstoreClientLocator; 057 private static final Logger LOG = Logger.getLogger(OlePurchasingAddItemValidation.class); 058 059 060 public DocstoreClientLocator getDocstoreClientLocator() { 061 if (docstoreClientLocator == null) { 062 docstoreClientLocator = SpringContext.getBean(DocstoreClientLocator.class); 063 } 064 return docstoreClientLocator; 065 } 066 067 public boolean validate(AttributedDocumentEvent event) { 068 boolean valid = true; 069 GlobalVariables.getMessageMap().addToErrorPath(PurapPropertyConstants.NEW_PURCHASING_ITEM_LINE); 070 //refresh itemType 071 PurApItem refreshedItem = getItemForValidation(); 072 refreshedItem.refreshReferenceObject("itemType"); 073 super.setItemForValidation(refreshedItem); 074 075 valid &= super.validate(event); 076 //valid &= validateItemUnitPrice(getItemForValidation()); 077 //valid &= validateUnitOfMeasure(getItemForValidation()); 078 if (getItemForValidation().getItemType().isLineItemIndicator()) { 079 valid &= validateItemDescription(getItemForValidation()); 080 valid &= validateItemLocation(getItemForValidation()); 081 valid &= validateCopiesAndPartsForEInstance(getItemForValidation()); 082 valid &= validateCommodityCodes(getItemForValidation(), commodityCodeIsRequired()); 083 } 084 GlobalVariables.getMessageMap().removeFromErrorPath(PurapPropertyConstants.NEW_PURCHASING_ITEM_LINE); 085 086 return valid; 087 } 088 089 /** 090 * Validates whether the commodity code existed on the item, and if existed, whether the 091 * commodity code on the item existed in the database, and if so, whether the commodity 092 * code is active. Display error if any of these 3 conditions are not met. 093 * 094 * @param item The PurApItem containing the commodity code to be validated. 095 * @return boolean false if the validation fails and true otherwise. 096 */ 097 protected boolean validateCommodityCodes(PurApItem item, boolean commodityCodeRequired) { 098 boolean valid = true; 099 String identifierString = item.getItemIdentifierString(); 100 PurchasingItemBase purItem = (PurchasingItemBase) item; 101 102 //This validation is only needed if the commodityCodeRequired system parameter is true 103 if (commodityCodeRequired && StringUtils.isBlank(purItem.getPurchasingCommodityCode())) { 104 //This is the case where the commodity code is required but the item does not currently contain the commodity code. 105 valid = false; 106 String attributeLabel = dataDictionaryService. 107 getDataDictionary().getBusinessObjectEntry(CommodityCode.class.getName()). 108 getAttributeDefinition(PurapPropertyConstants.ITEM_COMMODITY_CODE).getLabel(); 109 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_COMMODITY_CODE, OLEKeyConstants.ERROR_REQUIRED, attributeLabel + " in " + identifierString); 110 } else if (StringUtils.isNotBlank(purItem.getPurchasingCommodityCode())) { 111 //Find out whether the commodity code has existed in the database 112 Map<String, String> fieldValues = new HashMap<String, String>(); 113 fieldValues.put(PurapPropertyConstants.ITEM_COMMODITY_CODE, purItem.getPurchasingCommodityCode()); 114 if (businessObjectService.countMatching(CommodityCode.class, fieldValues) != 1) { 115 //This is the case where the commodity code on the item does not exist in the database. 116 valid = false; 117 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_COMMODITY_CODE, PurapKeyConstants.PUR_COMMODITY_CODE_INVALID, " in " + identifierString); 118 } else { 119 valid &= validateThatCommodityCodeIsActive(item); 120 } 121 } 122 123 return valid; 124 } 125 126 /** 127 * Validates the unit price for all applicable item types. It validates that the unit price field was 128 * entered on the item, and that the price is in the right range for the item type. 129 * 130 * @param purDocument the purchasing document to be validated 131 * @return boolean false if there is any validation that fails. 132 */ 133 public boolean validateItemUnitPrice(PurApItem item) { 134 boolean valid = true; 135 if (item.getItemType().isLineItemIndicator()) { 136 if (ObjectUtils.isNull(item.getItemUnitPrice())) { 137 valid = false; 138 String attributeLabel = dataDictionaryService. 139 getDataDictionary().getBusinessObjectEntry(item.getClass().getName()). 140 getAttributeDefinition(PurapPropertyConstants.ITEM_UNIT_PRICE).getLabel(); 141 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_UNIT_PRICE, OLEKeyConstants.ERROR_REQUIRED, attributeLabel + " in " + item.getItemIdentifierString()); 142 } 143 } 144 145 if (ObjectUtils.isNotNull(item.getItemUnitPrice())) { 146 if ((BigDecimal.ZERO.compareTo(item.getItemUnitPrice()) > 0) && ((!item.getItemTypeCode().equals(ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) && (!item.getItemTypeCode().equals(ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)))) { 147 // If the item type is not full order discount or trade in items, don't allow negative unit price. 148 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_UNIT_PRICE, PurapKeyConstants.ERROR_ITEM_AMOUNT_BELOW_ZERO, ItemFields.UNIT_COST, item.getItemIdentifierString()); 149 valid = false; 150 } else if ((BigDecimal.ZERO.compareTo(item.getItemUnitPrice()) < 0) && ((item.getItemTypeCode().equals(ItemTypeCodes.ITEM_TYPE_ORDER_DISCOUNT_CODE)) || (item.getItemTypeCode().equals(ItemTypeCodes.ITEM_TYPE_TRADE_IN_CODE)))) { 151 // If the item type is full order discount or trade in items, its unit price must be negative. 152 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_UNIT_PRICE, PurapKeyConstants.ERROR_ITEM_AMOUNT_NOT_BELOW_ZERO, ItemFields.UNIT_COST, item.getItemIdentifierString()); 153 valid = false; 154 } 155 } 156 157 return valid; 158 } 159 160 /** 161 * Validates that if the item type is quantity based, the unit of measure is required. 162 * 163 * @param item the item to be validated 164 * @return boolean false if the item type is quantity based and the unit of measure is empty. 165 */ 166 public boolean validateUnitOfMeasure(PurApItem item) { 167 boolean valid = true; 168 PurchasingItemBase purItem = (PurchasingItemBase) item; 169 // Validations for quantity based item type 170 if (purItem.getItemType().isQuantityBasedGeneralLedgerIndicator()) { 171 String uomCode = purItem.getItemUnitOfMeasureCode(); 172 if (StringUtils.isEmpty(uomCode)) { 173 valid = false; 174 String attributeLabel = dataDictionaryService. 175 getDataDictionary().getBusinessObjectEntry(item.getClass().getName()). 176 getAttributeDefinition(OLEPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE). 177 getLabel(); 178 GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, OLEKeyConstants.ERROR_REQUIRED, attributeLabel + " in " + item.getItemIdentifierString()); 179 } else { 180 //Find out whether the unit of measure code has existed in the database 181 Map<String, String> fieldValues = new HashMap<String, String>(); 182 fieldValues.put(OLEPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, purItem.getItemUnitOfMeasureCode()); 183 if (businessObjectService.countMatching(UnitOfMeasure.class, fieldValues) != 1) { 184 //This is the case where the unit of measure code on the item does not exist in the database. 185 valid = false; 186 GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, PurapKeyConstants.PUR_ITEM_UNIT_OF_MEASURE_CODE_INVALID, " in " + item.getItemIdentifierString()); 187 } 188 } 189 } 190 191 return valid; 192 } 193 194 /** 195 * Checks that a description was entered for the item. 196 * 197 * @param item 198 * @return 199 */ 200 public boolean validateItemDescription(PurApItem item) { 201 boolean valid = true; 202 if (StringUtils.isEmpty(item.getItemDescription())) { 203 valid = false; 204 String attributeLabel = dataDictionaryService. 205 getDataDictionary().getBusinessObjectEntry(item.getClass().getName()). 206 getAttributeDefinition(PurapPropertyConstants.ITEM_DESCRIPTION).getLabel(); 207 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_DESCRIPTION, OLEKeyConstants.ERROR_REQUIRED, attributeLabel + " in " + item.getItemIdentifierString()); 208 } 209 return valid; 210 } 211 212 213 /** 214 * Checks that a location was entered for the item for single copy. 215 * 216 * @param item 217 * @return 218 */ 219 public boolean validateItemLocation(PurApItem item) { 220 boolean valid = true; 221 if (item instanceof OleRequisitionItem) { 222 OleRequisitionItem oleRequisitionItem = (OleRequisitionItem) item; 223 valid = isValidLocation(oleRequisitionItem.getItemQuantity(), oleRequisitionItem.getItemNoOfParts(), oleRequisitionItem.getItemLocation()); 224 } else if (item instanceof OlePurchaseOrderItem) { 225 OlePurchaseOrderItem olePurchaseOrderItem = (OlePurchaseOrderItem) item; 226 valid = isValidLocation(olePurchaseOrderItem.getItemQuantity(), olePurchaseOrderItem.getItemNoOfParts(), olePurchaseOrderItem.getItemLocation()); 227 } 228 return valid; 229 } 230 231 private boolean isValidLocation(KualiDecimal noOfCopiesOrdered, KualiInteger noOfPartsOrdered, String itemLocation) { 232 boolean valid = true; 233 if (noOfCopiesOrdered != null && noOfPartsOrdered != null && (noOfCopiesOrdered.equals(new KualiDecimal(1)) 234 && noOfPartsOrdered.equals(new KualiInteger(1)))) { 235 if (itemLocation == null || itemLocation.isEmpty()) { 236 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, 237 OLEConstants.ITEM_LOCATION_REQUIRED, new String[]{}); 238 valid = false; 239 } 240 } 241 return valid; 242 } 243 244 public boolean validateCopiesAndPartsForEInstance(PurApItem item) { 245 boolean valid = true; 246 if (item instanceof OleRequisitionItem) { 247 OleRequisitionItem oleRequisitionItem = (OleRequisitionItem) item; 248 valid = isValidCopiesAndPartsForEInstance(oleRequisitionItem.getItemQuantity(), oleRequisitionItem.getItemNoOfParts(), oleRequisitionItem.getLinkToOrderOption()); 249 } else if (item instanceof OlePurchaseOrderItem) { 250 OlePurchaseOrderItem olePurchaseOrderItem = (OlePurchaseOrderItem) item; 251 valid = isValidCopiesAndPartsForEInstance(olePurchaseOrderItem.getItemQuantity(), olePurchaseOrderItem.getItemNoOfParts(), olePurchaseOrderItem.getLinkToOrderOption()); 252 } 253 return valid; 254 } 255 256 private boolean isValidCopiesAndPartsForEInstance(KualiDecimal noOfCopiesOrdered, KualiInteger noOfPartsOrdered, String linkToOrderOption) { 257 boolean valid = true; 258 if (StringUtils.isNotBlank(linkToOrderOption) && (linkToOrderOption.equals(OLEConstants.NB_ELECTRONIC) || linkToOrderOption.equals(OLEConstants.EB_ELECTRONIC)) && noOfCopiesOrdered != null && noOfPartsOrdered != null && (noOfCopiesOrdered.isGreaterThan(new KualiDecimal(1)) 259 || noOfPartsOrdered.isGreaterThan(new KualiInteger(1)))) { 260 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, 261 OLEConstants.ITEM_COPIESANDPARTS_SHOULDNOT_BE_GREATERTHAN_ONE_EINSTANCE, new String[]{}); 262 valid = false; 263 } 264 return valid; 265 } 266 267 /** 268 * Validates that if the item type is quantity based, the item quantity is required and if the item type is amount based, the 269 * quantity is not allowed. 270 * 271 * @param item the item to be validated 272 * @return boolean false if there's any validation that fails. 273 */ 274 public boolean validateItemQuantity(PurApItem item) { 275 boolean valid = true; 276 PurchasingItemBase purItem = (PurchasingItemBase) item; 277 if (purItem.getItemType().isQuantityBasedGeneralLedgerIndicator() && (ObjectUtils.isNull(purItem.getItemQuantity()))) { 278 valid = false; 279 String attributeLabel = dataDictionaryService. 280 getDataDictionary().getBusinessObjectEntry(item.getClass().getName()). 281 getAttributeDefinition(PurapPropertyConstants.ITEM_QUANTITY).getLabel(); 282 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.QUANTITY, OLEKeyConstants.ERROR_REQUIRED, attributeLabel + " in " + item.getItemIdentifierString()); 283 } else if (purItem.getItemType().isAmountBasedGeneralLedgerIndicator() && ObjectUtils.isNotNull(purItem.getItemQuantity())) { 284 valid = false; 285 String attributeLabel = dataDictionaryService. 286 getDataDictionary().getBusinessObjectEntry(item.getClass().getName()). 287 getAttributeDefinition(PurapPropertyConstants.ITEM_QUANTITY).getLabel(); 288 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.QUANTITY, PurapKeyConstants.ERROR_ITEM_QUANTITY_NOT_ALLOWED, attributeLabel + " in " + item.getItemIdentifierString()); 289 } 290 291 return valid; 292 } 293 294 /** 295 * Predicate to do a parameter lookup and tell us whether a commodity code is required. 296 * Override in child classes. 297 * 298 * @return True if a commodity code is required. 299 */ 300 protected boolean commodityCodeIsRequired() { 301 return false; 302 } 303 304 protected boolean validateThatCommodityCodeIsActive(PurApItem item) { 305 if (!((PurchasingItemBase) item).getCommodityCode().isActive()) { 306 //This is the case where the commodity code on the item is not active. 307 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_COMMODITY_CODE, PurapKeyConstants.PUR_COMMODITY_CODE_INACTIVE, " in " + item.getItemIdentifierString()); 308 return false; 309 } 310 return true; 311 } 312 313 public BusinessObjectService getBusinessObjectService() { 314 return businessObjectService; 315 } 316 317 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 318 this.businessObjectService = businessObjectService; 319 } 320 321 public DataDictionaryService getDataDictionaryService() { 322 return dataDictionaryService; 323 } 324 325 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) { 326 this.dataDictionaryService = dataDictionaryService; 327 } 328 329}