001/* 002 * Copyright 2008 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.module.purap.document.validation.impl; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.ole.module.purap.PurapConstants; 020import org.kuali.ole.module.purap.PurapConstants.PREQDocumentsStrings; 021import org.kuali.ole.module.purap.PurapKeyConstants; 022import org.kuali.ole.module.purap.PurapPropertyConstants; 023import org.kuali.ole.module.purap.businessobject.LineItemReceivingItem; 024import org.kuali.ole.module.purap.businessobject.PurapEnterableItem; 025import org.kuali.ole.module.purap.businessobject.ReceivingItem; 026import org.kuali.ole.module.purap.document.LineItemReceivingDocument; 027import org.kuali.ole.module.purap.document.ReceivingDocument; 028import org.kuali.ole.module.purap.document.service.ReceivingService; 029import org.kuali.ole.module.purap.document.validation.AddReceivingItemRule; 030import org.kuali.ole.module.purap.document.validation.ContinuePurapRule; 031import org.kuali.ole.sys.OLEKeyConstants; 032import org.kuali.ole.sys.OLEPropertyConstants; 033import org.kuali.ole.sys.businessobject.UnitOfMeasure; 034import org.kuali.ole.sys.context.SpringContext; 035import org.kuali.rice.kns.rules.DocumentRuleBase; 036import org.kuali.rice.kns.service.DataDictionaryService; 037import org.kuali.rice.kns.service.DictionaryValidationService; 038import org.kuali.rice.krad.document.Document; 039import org.kuali.rice.krad.document.TransactionalDocument; 040import org.kuali.rice.krad.service.BusinessObjectService; 041import org.kuali.rice.krad.util.GlobalVariables; 042import org.kuali.rice.krad.util.ObjectUtils; 043 044import java.util.HashMap; 045import java.util.List; 046import java.util.Map; 047 048public class LineItemReceivingDocumentRule extends DocumentRuleBase implements ContinuePurapRule, AddReceivingItemRule { 049 050 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LineItemReceivingDocumentRule.class); 051 052 @Override 053 protected boolean processCustomRouteDocumentBusinessRules(Document document) { 054 LOG.debug("Inside processCustomRouteDocumentBusinessRules of LineItemReceivingDocumentRule"); 055 boolean valid = true; 056 LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument) document; 057 if (LOG.isDebugEnabled()) 058 LOG.debug("LineItemReceivingDocument :" + lineItemReceivingDocument); 059 060 GlobalVariables.getMessageMap().clearErrorPath(); 061 GlobalVariables.getMessageMap().addToErrorPath(OLEPropertyConstants.DOCUMENT); 062 063 valid &= super.processCustomRouteDocumentBusinessRules(document); 064 valid &= canCreateLineItemReceivingDocument(lineItemReceivingDocument); 065 valid &= isAtLeastOneItemEntered(lineItemReceivingDocument); 066 valid &= validateItemUnitOfMeasure(lineItemReceivingDocument); 067 068 // makes sure all of the lines adhere to the rule that quantityDamaged and 069 // quantityReturned cannot (each) equal more than the quantityReceived 070 valid &= validateAllReceivingLinesHaveSaneQuantities(lineItemReceivingDocument); 071 if (LOG.isDebugEnabled()) 072 LOG.debug("isValid from LineItemReceivingDocumentRule :" + valid); 073 074 return valid; 075 } 076 077 /** 078 * TODO: move this up 079 * This method... 080 * 081 * @param receivingDocument 082 * @return 083 */ 084 protected boolean isAtLeastOneItemEntered(ReceivingDocument receivingDocument) { 085 if (LOG.isDebugEnabled()) { 086 LOG.debug("Inside isAtLeastOneItemEntered of LineItemReceivingDocumentRule"); 087 LOG.debug("Number of Items :" + receivingDocument.getItems().size()); 088 } 089 for (ReceivingItem item : (List<ReceivingItem>) receivingDocument.getItems()) { 090 if (((PurapEnterableItem) item).isConsideredEntered()) { 091 //if any item is entered return true 092 return true; 093 } 094 } 095 //if no items are entered return false 096 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_RECEIVING_LINEITEM_REQUIRED); 097 return false; 098 099 } 100 101 public boolean processContinuePurapBusinessRules(TransactionalDocument document) { 102 103 boolean valid = true; 104 LineItemReceivingDocument lineItemReceivingDocument = (LineItemReceivingDocument) document; 105 106 GlobalVariables.getMessageMap().clearErrorPath(); 107 GlobalVariables.getMessageMap().addToErrorPath(OLEPropertyConstants.DOCUMENT); 108 109 valid &= hasRequiredFieldsForContinue(lineItemReceivingDocument); 110 //only do this if valid 111 if (valid) { 112 valid &= canCreateLineItemReceivingDocument(lineItemReceivingDocument); 113 } 114 115 return valid; 116 } 117 118 /** 119 * Make sure the required fields on the init screen are filled in. 120 * 121 * @param lineItemReceivingDocument 122 * @return 123 */ 124 protected boolean hasRequiredFieldsForContinue(LineItemReceivingDocument lineItemReceivingDocument) { 125 126 boolean valid = true; 127 128 if (ObjectUtils.isNull(lineItemReceivingDocument.getPurchaseOrderIdentifier())) { 129 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, OLEKeyConstants.ERROR_REQUIRED, PREQDocumentsStrings.PURCHASE_ORDER_ID); 130 valid &= false; 131 } 132 133 if (ObjectUtils.isNull(lineItemReceivingDocument.getShipmentReceivedDate())) { 134 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.SHIPMENT_RECEIVED_DATE, OLEKeyConstants.ERROR_REQUIRED, PurapConstants.LineItemReceivingDocumentStrings.VENDOR_DATE); 135 valid &= false; 136 } 137 138 return valid; 139 } 140 141 /** 142 * Determines if it is valid to create a receiving line document. Only one 143 * receiving line document can be active at any time per purchase order document. 144 * 145 * @param lineItemReceivingDocument 146 * @return 147 */ 148 protected boolean canCreateLineItemReceivingDocument(LineItemReceivingDocument lineItemReceivingDocument) { 149 150 boolean valid = true; 151 152 if (SpringContext.getBean(ReceivingService.class).canCreateLineItemReceivingDocument(lineItemReceivingDocument.getPurchaseOrderIdentifier(), lineItemReceivingDocument.getDocumentNumber()) == false) { 153 valid &= false; 154 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_IDENTIFIER, PurapKeyConstants.ERROR_RECEIVING_LINE_DOCUMENT_ACTIVE_FOR_PO, lineItemReceivingDocument.getDocumentNumber(), lineItemReceivingDocument.getPurchaseOrderIdentifier().toString()); 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 protected boolean validateItemUnitOfMeasure(ReceivingDocument receivingDocument) { 164 boolean valid = true; 165 for (ReceivingItem item : (List<ReceivingItem>) receivingDocument.getItems()) { 166 // Validations for quantity based item type 167 if (item.getItemType().isQuantityBasedGeneralLedgerIndicator()) { 168 String uomCode = item.getItemUnitOfMeasureCode(); 169 if (StringUtils.isEmpty(uomCode)) { 170 valid = false; 171 String attributeLabel = SpringContext.getBean(DataDictionaryService.class).getDataDictionary().getBusinessObjectEntry(item.getClass().getName()).getAttributeDefinition(OLEPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE).getLabel(); 172 GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, OLEKeyConstants.ERROR_REQUIRED, attributeLabel + item.getItemUnitOfMeasureCode()); 173 } else { 174 // Find out whether the unit of measure code has existed in the database 175 Map<String, String> fieldValues = new HashMap<String, String>(); 176 fieldValues.put(OLEPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, item.getItemUnitOfMeasureCode()); 177 if (SpringContext.getBean(BusinessObjectService.class).countMatching(UnitOfMeasure.class, fieldValues) != 1) { 178 // This is the case where the unit of measure code on the item does not exist in the database. 179 valid = false; 180 GlobalVariables.getMessageMap().putError(OLEPropertyConstants.ITEM_UNIT_OF_MEASURE_CODE, PurapKeyConstants.PUR_ITEM_UNIT_OF_MEASURE_CODE_INVALID, item.getItemUnitOfMeasureCode()); 181 } 182 } 183 } 184 } 185 return valid; 186 } 187 188 /** 189 * @see org.kuali.ole.module.purap.document.validation.AddReceivingItemRule#processAddReceivingItemRules(org.kuali.ole.module.purap.document.ReceivingDocument, org.kuali.ole.module.purap.businessobject.ReceivingItem) 190 */ 191 public boolean processAddReceivingItemRules(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix) { 192 boolean valid = true; 193 194 valid &= SpringContext.getBean(DictionaryValidationService.class).isBusinessObjectValid(item, errorPathPrefix); 195 196 // test that the amount entered in the QuantityReturned and/or QuantityDamaged fields dont 197 // either equal more than the QuantityReceived. In other words, you can only return or mark as 198 // damaged those that are received. It doesnt make sense to receive 2 but return 3. 199 valid &= validateQuantityReturnedNotMoreThanReceived(document, item, errorPathPrefix, new Integer(0)); 200 valid &= validateQuantityDamagedNotMoreThanReceived(document, item, errorPathPrefix, new Integer(0)); 201 202 return valid; 203 } 204 205 protected boolean validateQuantityReturnedNotMoreThanReceived(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix, Integer lineNumber) { 206 if (item.getItemReturnedTotalQuantity() != null && item.getItemReceivedTotalQuantity() != null) { 207 if (item.getItemReturnedTotalQuantity().isGreaterThan(item.getItemReceivedTotalQuantity())) { 208 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_RECEIVING_LINE_QTYRETURNED_GT_QTYRECEIVED, (lineNumber.intValue() == 0 ? "Add Line" : lineNumber.toString())); 209 return false; 210 } 211 } 212 return true; 213 } 214 215 protected boolean validateQuantityDamagedNotMoreThanReceived(ReceivingDocument document, LineItemReceivingItem item, String errorPathPrefix, Integer lineNumber) { 216 if (item.getItemDamagedTotalQuantity() != null && item.getItemReceivedTotalQuantity() != null) { 217 if (item.getItemDamagedTotalQuantity().isGreaterThan(item.getItemReceivedTotalQuantity())) { 218 GlobalVariables.getMessageMap().putError(PurapConstants.ITEM_TAB_ERROR_PROPERTY, PurapKeyConstants.ERROR_RECEIVING_LINE_QTYDAMAGED_GT_QTYRECEIVED, (lineNumber.intValue() == 0 ? "Add Line" : lineNumber.toString())); 219 return false; 220 } 221 } 222 return true; 223 } 224 225 protected boolean validateAllReceivingLinesHaveSaneQuantities(ReceivingDocument document) { 226 GlobalVariables.getMessageMap().clearErrorPath(); 227 boolean valid = true; 228 for (int i = 0; i < document.getItems().size(); i++) { 229 LineItemReceivingItem item = (LineItemReceivingItem) document.getItems().get(i); 230 231 valid &= validateQuantityReturnedNotMoreThanReceived(document, item, "", new Integer(i + 1)); 232 valid &= validateQuantityDamagedNotMoreThanReceived(document, item, "", new Integer(i + 1)); 233 } 234 return valid; 235 } 236 237}