View Javadoc
1   /*
2    * Copyright 2009 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.select.document.validation.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.log4j.Logger;
20  import org.kuali.ole.docstore.common.client.DocstoreClientLocator;
21  import org.kuali.ole.module.purap.PurapConstants;
22  import org.kuali.ole.module.purap.PurapConstants.ItemFields;
23  import org.kuali.ole.module.purap.PurapConstants.ItemTypeCodes;
24  import org.kuali.ole.module.purap.PurapKeyConstants;
25  import org.kuali.ole.module.purap.PurapPropertyConstants;
26  import org.kuali.ole.module.purap.businessobject.PurApItem;
27  import org.kuali.ole.module.purap.businessobject.PurchasingItemBase;
28  import org.kuali.ole.module.purap.document.validation.impl.PurchasingAccountsPayableAddItemValidation;
29  import org.kuali.ole.select.bo.OLEDonor;
30  import org.kuali.ole.select.businessobject.OlePurchaseOrderItem;
31  import org.kuali.ole.select.businessobject.OleRequisitionItem;
32  import org.kuali.ole.sys.OLEConstants;
33  import org.kuali.ole.sys.OLEKeyConstants;
34  import org.kuali.ole.sys.OLEPropertyConstants;
35  import org.kuali.ole.sys.businessobject.UnitOfMeasure;
36  import org.kuali.ole.sys.context.SpringContext;
37  import org.kuali.ole.sys.document.validation.event.AttributedDocumentEvent;
38  import org.kuali.ole.vnd.businessobject.CommodityCode;
39  import org.kuali.rice.core.api.util.type.KualiDecimal;
40  import org.kuali.rice.core.api.util.type.KualiInteger;
41  import org.kuali.rice.kns.service.DataDictionaryService;
42  import org.kuali.rice.krad.service.BusinessObjectService;
43  import org.kuali.rice.krad.service.KRADServiceLocator;
44  import org.kuali.rice.krad.util.GlobalVariables;
45  import org.kuali.rice.krad.util.KRADConstants;
46  import org.kuali.rice.krad.util.ObjectUtils;
47  
48  import java.math.BigDecimal;
49  import java.util.HashMap;
50  import java.util.Map;
51  
52  public class OlePurchasingAddItemValidation extends PurchasingAccountsPayableAddItemValidation {
53  
54      private BusinessObjectService businessObjectService;
55      private DataDictionaryService dataDictionaryService;
56      private DocstoreClientLocator docstoreClientLocator;
57      private static final Logger LOG = Logger.getLogger(OlePurchasingAddItemValidation.class);
58  
59  
60      public DocstoreClientLocator getDocstoreClientLocator() {
61          if (docstoreClientLocator == null) {
62              docstoreClientLocator = SpringContext.getBean(DocstoreClientLocator.class);
63          }
64          return docstoreClientLocator;
65      }
66  
67      public boolean validate(AttributedDocumentEvent event) {
68          boolean valid = true;
69          GlobalVariables.getMessageMap().addToErrorPath(PurapPropertyConstants.NEW_PURCHASING_ITEM_LINE);
70          //refresh itemType
71          PurApItem refreshedItem = getItemForValidation();
72          refreshedItem.refreshReferenceObject("itemType");
73          super.setItemForValidation(refreshedItem);
74  
75          valid &= super.validate(event);
76          //valid &= validateItemUnitPrice(getItemForValidation());
77          //valid &= validateUnitOfMeasure(getItemForValidation());
78          if (getItemForValidation().getItemType().isLineItemIndicator()) {
79              valid &= validateItemDescription(getItemForValidation());
80              valid &= validateItemLocation(getItemForValidation());
81              valid &= validateCopiesAndPartsForEInstance(getItemForValidation());
82              valid &= validateCommodityCodes(getItemForValidation(), commodityCodeIsRequired());
83          }
84          GlobalVariables.getMessageMap().removeFromErrorPath(PurapPropertyConstants.NEW_PURCHASING_ITEM_LINE);
85  
86          return valid;
87      }
88  
89      /**
90       * Validates whether the commodity code existed on the item, and if existed, whether the
91       * commodity code on the item existed in the database, and if so, whether the commodity
92       * code is active. Display error if any of these 3 conditions are not met.
93       *
94       * @param item The PurApItem containing the commodity code to be validated.
95       * @return boolean false if the validation fails and true otherwise.
96       */
97      protected boolean validateCommodityCodes(PurApItem item, boolean commodityCodeRequired) {
98          boolean valid = true;
99          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 }