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.math.BigDecimal;
019 import java.util.HashMap;
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.ItemFields;
027 import org.kuali.kfs.module.purap.PurapConstants.ItemTypeCodes;
028 import org.kuali.kfs.module.purap.businessobject.PurApItem;
029 import org.kuali.kfs.module.purap.businessobject.PurchasingItemBase;
030 import org.kuali.kfs.sys.KFSKeyConstants;
031 import org.kuali.kfs.sys.KFSPropertyConstants;
032 import org.kuali.kfs.sys.businessobject.UnitOfMeasure;
033 import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent;
034 import org.kuali.kfs.vnd.businessobject.CommodityCode;
035 import org.kuali.rice.kns.service.BusinessObjectService;
036 import org.kuali.rice.kns.service.DataDictionaryService;
037 import org.kuali.rice.kns.util.GlobalVariables;
038 import org.kuali.rice.kns.util.ObjectUtils;
039
040 public class PurchasingImportItemValidation extends PurchasingAccountsPayableImportItemValidation {
041
042 private BusinessObjectService businessObjectService;
043 private DataDictionaryService dataDictionaryService;
044
045 public boolean validate(AttributedDocumentEvent event) {
046 boolean valid = true;
047 valid &= super.validate(event);
048 GlobalVariables.getMessageMap().addToErrorPath(PurapConstants.ITEM_TAB_ERROR_PROPERTY);
049
050 if (getItemForValidation().getItemType().isLineItemIndicator()) {
051 valid &= validateItemDescription(getItemForValidation());
052 }
053 valid &= validateItemUnitPrice(getItemForValidation());
054 valid &= validateUnitOfMeasureCodeExists(getItemForValidation());
055 valid &= validateCommodityCodes(getItemForValidation(), commodityCodeIsRequired());
056
057 GlobalVariables.getMessageMap().removeFromErrorPath(PurapConstants.ITEM_TAB_ERROR_PROPERTY);
058 return valid;
059 }
060
061 /**
062 * Validates whether the commodity code existed on the item, and if existed, whether the
063 * commodity code on the item existed in the database, and if so, whether the commodity
064 * code is active. Display error if any of these 3 conditions are not met.
065 *
066 * @param item The PurApItem containing the commodity code to be validated.
067 * @return boolean false if the validation fails and true otherwise.
068 */
069 protected boolean validateCommodityCodes(PurApItem item, boolean commodityCodeRequired) {
070 boolean valid = true;
071 String identifierString = item.getItemIdentifierString();
072 PurchasingItemBase purItem = (PurchasingItemBase) item;
073
074 //This validation is only needed if the commodityCodeRequired system parameter is true
075 if (commodityCodeRequired && StringUtils.isBlank(purItem.getPurchasingCommodityCode()) ) {
076 //This is the case where the commodity code is required but the item does not currently contain the commodity code.
077 valid = false;
078 String attributeLabel = dataDictionaryService.
079 getDataDictionary().getBusinessObjectEntry(CommodityCode.class.getName()).
080 getAttributeDefinition(PurapPropertyConstants.ITEM_COMMODITY_CODE).getLabel();
081 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_COMMODITY_CODE, KFSKeyConstants.ERROR_REQUIRED, attributeLabel + " in " + identifierString);
082 }
083 else if (StringUtils.isNotBlank(purItem.getPurchasingCommodityCode())) {
084 //Find out whether the commodity code has existed in the database
085 Map<String,String> fieldValues = new HashMap<String, String>();
086 fieldValues.put(PurapPropertyConstants.ITEM_COMMODITY_CODE, purItem.getPurchasingCommodityCode());
087 if (businessObjectService.countMatching(CommodityCode.class, fieldValues) != 1) {
088 //This is the case where the commodity code on the item does not exist in the database.
089 valid = false;
090 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_COMMODITY_CODE, PurapKeyConstants.PUR_COMMODITY_CODE_INVALID, " in " + identifierString);
091 }
092 else {
093 valid &= validateThatCommodityCodeIsActive(item);
094 }
095 }
096
097 return valid;
098 }
099
100 /**
101 * Checks that a description was entered for the item.
102 *
103 * @param item
104 * @return
105 */
106 public boolean validateItemDescription(PurApItem item) {
107 boolean valid = true;
108 if (StringUtils.isEmpty(item.getItemDescription())) {
109 valid = false;
110 String attributeLabel = dataDictionaryService.
111 getDataDictionary().getBusinessObjectEntry(item.getClass().getName()).
112 getAttributeDefinition(PurapPropertyConstants.ITEM_DESCRIPTION).getLabel();
113 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_DESCRIPTION, KFSKeyConstants.ERROR_REQUIRED, attributeLabel + " in " + item.getItemIdentifierString());
114 }
115 return valid;
116 }
117
118 /**
119 * Validates the unit price for all applicable item types. It validates that the unit price field was
120 * entered on the item, and that the price is in the right range for the item type.
121 *
122 * @param purDocument the purchasing document to be validated
123 * @return boolean false if there is any validation that fails.
124 */
125 public boolean validateItemUnitPrice(PurApItem item) {
126 boolean valid = true;
127 if (item.getItemType().isLineItemIndicator()) {
128 if (ObjectUtils.isNull(item.getItemUnitPrice())) {
129 valid = false;
130 String attributeLabel = dataDictionaryService.
131 getDataDictionary().getBusinessObjectEntry(item.getClass().getName()).
132 getAttributeDefinition(PurapPropertyConstants.ITEM_UNIT_PRICE).getLabel();
133 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_UNIT_PRICE, KFSKeyConstants.ERROR_REQUIRED, attributeLabel + " in " + item.getItemIdentifierString());
134 }
135 }
136
137 if (ObjectUtils.isNotNull(item.getItemUnitPrice())) {
138 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)))) {
139 // If the item type is not full order discount or trade in items, don't allow negative unit price.
140 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_UNIT_PRICE, PurapKeyConstants.ERROR_ITEM_AMOUNT_BELOW_ZERO, ItemFields.UNIT_COST, item.getItemIdentifierString());
141 valid = false;
142 }
143 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)))) {
144 // If the item type is full order discount or trade in items, its unit price must be negative.
145 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_UNIT_PRICE, PurapKeyConstants.ERROR_ITEM_AMOUNT_NOT_BELOW_ZERO, ItemFields.UNIT_COST, item.getItemIdentifierString());
146 valid = false;
147 }
148 }
149
150 return valid;
151 }
152
153 /**
154 * Validates that if the item type is quantity based, that the unit of measure code is valid.
155 * Looks for the UOM Code in the table. If it is not there, the code is invalid.
156 * This checking is needed only for imported items, since items added from new line could only
157 * choose an existing UOM from the drop-down list.
158 *
159 * @param item the item to be validated
160 * @return boolean false if the item type is quantity based and the unit of measure code is invalid.
161 */
162 protected boolean validateUnitOfMeasureCodeExists(PurApItem item) {
163 boolean valid = true;
164
165 if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) {
166 String uomCode = item.getItemUnitOfMeasureCode();
167 Map<String,String> fieldValues = new HashMap<String,String>();
168 fieldValues.put(KFSPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, uomCode);
169 if (businessObjectService.countMatching(UnitOfMeasure.class, fieldValues) != 1) {
170 String[] errorParams = { uomCode, "" + item.getItemLineNumber() };
171 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERRORS, PurapKeyConstants.ERROR_ITEMPARSER_INVALID_UOM_CODE, errorParams);
172 valid = false;
173 }
174 }
175
176 return valid;
177 }
178
179 /**
180 * Predicate to do a parameter lookup and tell us whether a commodity code is required.
181 * Override in child classes.
182 *
183 * @return True if a commodity code is required.
184 */
185 protected boolean commodityCodeIsRequired() {
186 return false;
187 }
188
189 protected boolean validateThatCommodityCodeIsActive(PurApItem item) {
190 if (!((PurchasingItemBase)item).getCommodityCode().isActive()) {
191 //This is the case where the commodity code on the item is not active.
192 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.ITEM_COMMODITY_CODE, PurapKeyConstants.PUR_COMMODITY_CODE_INACTIVE, " in " + item.getItemIdentifierString());
193 return false;
194 }
195 return true;
196 }
197
198 public BusinessObjectService getBusinessObjectService() {
199 return businessObjectService;
200 }
201
202 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
203 this.businessObjectService = businessObjectService;
204 }
205
206 public DataDictionaryService getDataDictionaryService() {
207 return dataDictionaryService;
208 }
209
210 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
211 this.dataDictionaryService = dataDictionaryService;
212 }
213
214 }