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 }