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