View Javadoc

1   /*
2    * Copyright 2007 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.vnd.document.validation.impl;
17  
18  import java.lang.reflect.Field;
19  import java.util.ArrayList;
20  import java.util.Date;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.apache.commons.lang.StringUtils;
29  import org.kuali.ole.coa.businessobject.Chart;
30  import org.kuali.ole.coa.businessobject.Organization;
31  import org.kuali.ole.module.purap.businessobject.Carrier;
32  import org.kuali.ole.module.purap.document.PaymentRequestDocument;
33  import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
34  import org.kuali.ole.select.service.OleForiegnVendorPhoneNumberService;
35  import org.kuali.ole.sys.OLEConstants;
36  import org.kuali.ole.sys.OLEKeyConstants;
37  import org.kuali.ole.sys.OLEPropertyConstants;
38  import org.kuali.ole.sys.context.SpringContext;
39  import org.kuali.ole.sys.service.PostalCodeValidationService;
40  import org.kuali.ole.vnd.VendorConstants;
41  import org.kuali.ole.vnd.VendorKeyConstants;
42  import org.kuali.ole.vnd.VendorParameterConstants;
43  import org.kuali.ole.vnd.VendorPropertyConstants;
44  import org.kuali.ole.vnd.businessobject.AddressType;
45  import org.kuali.ole.vnd.businessobject.OwnershipType;
46  import org.kuali.ole.vnd.businessobject.VendorAddress;
47  import org.kuali.ole.vnd.businessobject.VendorAlias;
48  import org.kuali.ole.vnd.businessobject.VendorCommodityCode;
49  import org.kuali.ole.vnd.businessobject.VendorContact;
50  import org.kuali.ole.vnd.businessobject.VendorContract;
51  import org.kuali.ole.vnd.businessobject.VendorContractOrganization;
52  import org.kuali.ole.vnd.businessobject.VendorCustomerNumber;
53  import org.kuali.ole.vnd.businessobject.VendorDefaultAddress;
54  import org.kuali.ole.vnd.businessobject.VendorDetail;
55  import org.kuali.ole.vnd.businessobject.VendorHeader;
56  import org.kuali.ole.vnd.businessobject.VendorPhoneNumber;
57  import org.kuali.ole.vnd.businessobject.VendorTransmissionFormatDetail;
58  import org.kuali.ole.vnd.businessobject.VendorType;
59  import org.kuali.ole.vnd.document.service.VendorService;
60  import org.kuali.ole.vnd.service.PhoneNumberService;
61  import org.kuali.ole.vnd.service.TaxNumberService;
62  import org.kuali.rice.core.api.datetime.DateTimeService;
63  import org.kuali.rice.core.api.parameter.ParameterEvaluatorService;
64  import org.kuali.rice.core.api.util.type.KualiDecimal;
65  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
66  import org.kuali.rice.kns.document.MaintenanceDocument;
67  import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
68  import org.kuali.rice.kns.service.DataDictionaryService;
69  import org.kuali.rice.krad.bo.PersistableBusinessObject;
70  import org.kuali.rice.krad.service.BusinessObjectService;
71  import org.kuali.rice.krad.service.PersistenceService;
72  import org.kuali.rice.krad.util.ErrorMessage;
73  import org.kuali.rice.krad.util.GlobalVariables;
74  import org.kuali.rice.krad.util.ObjectUtils;
75  import org.springframework.util.AutoPopulatingList;
76  
77  /**
78   * Business rules applicable to VendorDetail document.
79   */
80  public class VendorRule extends MaintenanceDocumentRuleBase {
81  
82      private VendorDetail oldVendor;
83      private VendorDetail newVendor;
84  
85  
86      /**
87       * Overrides the setupBaseConvenienceObjects from the superclass because we cannot use the setupBaseConvenienceObjects from the
88       * superclass. The reason we cannot use the superclass method is because it calls the updateNonUpdateableReferences for
89       * everything and we cannot do that for parent vendors, because we want to update vendor header information only on parent
90       * vendors, so the saving of the vendor header is done manually. If we call the updateNonUpdateableReferences, it is going to
91       * overwrite any changes that the user might have done in the vendor header with the existing values in the database.
92       *
93       * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#setupBaseConvenienceObjects(org.kuali.rice.kns.document.MaintenanceDocument)
94       */
95      @Override
96      public void setupBaseConvenienceObjects(MaintenanceDocument document) {
97          oldVendor = (VendorDetail) document.getOldMaintainableObject().getBusinessObject();
98          newVendor = (VendorDetail) document.getNewMaintainableObject().getBusinessObject();
99          super.setNewBo(newVendor);
100         setupConvenienceObjects();
101     }
102 
103     /**
104      * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#setupConvenienceObjects()
105      */
106     @Override
107     public void setupConvenienceObjects() {
108         // setup oldVendor convenience objects, make sure all possible sub-objects are populated
109         refreshSubObjects(oldVendor);
110 
111         // setup newVendor convenience objects, make sure all possible sub-objects are populated
112         refreshSubObjects(newVendor);
113     }
114 
115 
116     /**
117      * Refreshes the references of vendor detail and its sub objects
118      *
119      * @param vendor VendorDetail document
120      */
121     void refreshSubObjects(VendorDetail vendor) {
122         if (vendor == null) {
123             return;
124         }
125 
126         // If this is a division vendor, we need to do a refreshNonUpdateableReferences
127         // and also refreshes the vendor header, since the user aren't supposed to
128         // make any updates of vendor header's attributes while editing a division vendor
129         if (!vendor.isVendorParentIndicator()) {
130             vendor.refreshNonUpdateableReferences();
131             vendor.getVendorHeader().refreshNonUpdateableReferences();
132 
133         }
134         else {
135             // Retrieve the references objects of the vendor header of this vendor.
136             List<String> headerFieldNames = getObjectReferencesListFromBOClass(VendorHeader.class);
137             vendor.getVendorHeader().refreshNonUpdateableReferences();
138             SpringContext.getBean(PersistenceService.class).retrieveReferenceObjects(vendor.getVendorHeader(), headerFieldNames);
139 
140             // We still need to retrieve all the other references of this vendor in addition to
141             // vendor header. Since this is a parent vendor, whose vendor header saving is handled manually,
142             // we have already retrieved references for vendor header's attributes above, so we should
143             // exclude retrieving reference objects of vendor header.
144             List<String> detailFieldNames = getObjectReferencesListFromBOClass(vendor.getClass());
145             detailFieldNames.remove(VendorConstants.VENDOR_HEADER_ATTR);
146             SpringContext.getBean(PersistenceService.class).retrieveReferenceObjects(vendor, detailFieldNames);
147         }
148 
149         // refresh addresses
150         if (vendor.getVendorAddresses() != null) {
151             for (VendorAddress address : vendor.getVendorAddresses()) {
152                 address.refreshNonUpdateableReferences();
153                 if (address.getVendorDefaultAddresses() != null) {
154                     for (VendorDefaultAddress defaultAddress : address.getVendorDefaultAddresses()) {
155                         defaultAddress.refreshNonUpdateableReferences();
156                     }
157                 }
158             }
159         }
160         // refresh contacts
161         if (vendor.getVendorContacts() != null) {
162             for (VendorContact contact : vendor.getVendorContacts()) {
163                 contact.refreshNonUpdateableReferences();
164             }
165         }
166         // refresh contracts
167         if (vendor.getVendorContracts() != null) {
168             for (VendorContract contract : vendor.getVendorContracts()) {
169                 contract.refreshNonUpdateableReferences();
170             }
171         }
172     }
173 
174     /**
175      * This is currently used as a helper to get a list of object references (e.g. vendorType, vendorOwnershipType, etc) from a
176      * BusinessObject (e.g. VendorHeader, VendorDetail, etc) class dynamically. Feel free to enhance it, refactor it or move it to a
177      * superclass or elsewhere as you see appropriate.
178      *
179      * @param theClass The Class name of the object whose objects references list are extracted
180      * @return List a List of attributes of the class
181      */
182     private List getObjectReferencesListFromBOClass(Class theClass) {
183         List<String> results = new ArrayList();
184         for (Field theField : theClass.getDeclaredFields()) {
185             // only get persistable business object references
186             if ( PersistableBusinessObject.class.isAssignableFrom( theField.getType() ) ) {
187                     results.add(theField.getName());
188                 }
189             }
190         return results;
191     }
192 
193     /**
194      * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomApproveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
195      */
196     @Override
197     protected boolean processCustomApproveDocumentBusinessRules(MaintenanceDocument document) {
198         boolean valid = processValidation(document);
199         return valid & super.processCustomApproveDocumentBusinessRules(document);
200     }
201 
202     /**
203      * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
204      */
205     @Override
206     protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
207         boolean valid = processValidation(document);
208         return valid & super.processCustomRouteDocumentBusinessRules(document);
209     }
210 
211     /**
212      * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
213      */
214     @Override
215     protected boolean processCustomSaveDocumentBusinessRules(MaintenanceDocument document) {
216         boolean valid = true;
217         return valid & super.processCustomSaveDocumentBusinessRules(document);
218     }
219 
220     /**
221      * Validates VendorDetail and its VendorContracts.
222      *
223      * @param document MaintenanceDocument instance
224      * @return boolean false or true
225      */
226     private boolean processValidation(MaintenanceDocument document) {
227         boolean valid = true;
228 
229         valid &= processVendorValidation(document);
230         valid &= processContactValidation(document);
231         if (ObjectUtils.isNotNull(newVendor.getVendorHeader().getVendorType())) {
232             valid &= processAddressValidation(document);
233             valid &= processContractValidation(document);
234             valid &= processCommodityCodeValidation(document);
235         }
236 
237         return valid;
238     }
239 
240     /**
241      * Validates VendorDetail document.
242      *
243      * @param document MaintenanceDocument instance
244      * @return boolean false or true
245      */
246     boolean processVendorValidation(MaintenanceDocument document) {
247         boolean valid = true;
248         VendorDetail vendorDetail = (VendorDetail) document.getNewMaintainableObject().getBusinessObject();
249         valid &= validateTaxTypeAndTaxNumberBlankness(vendorDetail);
250         valid &= validateParentVendorTaxNumber(vendorDetail);
251         valid &= validateOwnershipTypeAllowed(vendorDetail);
252         valid &= validateTaxNumberFromTaxNumberService(vendorDetail);
253         valid &= validateRestrictedReasonRequiredness(vendorDetail);
254         valid &= validateInactiveReasonRequiredness(vendorDetail);
255         valid &= validatePreInactiveIndicator(vendorDetail);
256 
257         if (ObjectUtils.isNotNull(vendorDetail.getVendorHeader().getVendorType())) {
258             valid &= validateTaxNumberRequiredness(vendorDetail);
259         }
260 
261         valid &= validateVendorNames(vendorDetail);
262         valid &= validateVendorSoldToNumber(vendorDetail);
263         valid &= validateMinimumOrderAmount(vendorDetail);
264         valid &= validateOwnershipCategory(vendorDetail);
265         valid &= validateVendorWithholdingTaxDates(vendorDetail);
266         valid &= validateVendorW8BenOrW9ReceivedIndicator(vendorDetail);
267         valid &= validateSearchAliases(vendorDetail);
268         valid &= validateContracts(vendorDetail);
269         return valid;
270     }
271 
272     private boolean validateContracts(VendorDetail vendorDetail) {
273         boolean success = true;
274         int vendorPos = 0;
275         List<VendorContract> vendorContracts = vendorDetail.getVendorContracts();
276         for (VendorContract vendorContract : vendorContracts) {
277             List<VendorContractOrganization> organizations = vendorContract.getVendorContractOrganizations();
278             List<VendorContractOrganization> organizationCopy = new ArrayList<VendorContractOrganization>(organizations);
279             for (VendorContractOrganization organization :organizations ) {
280                  String chartCode = organization.getChartOfAccountsCode();
281                  String organizationCode = organization.getOrganizationCode();
282                  if (StringUtils.isNotEmpty(chartCode) && StringUtils.isNotEmpty(organizationCode)) {
283                      int counter = 0;
284                      int organizationPos = 0;
285                      for (VendorContractOrganization org : organizationCopy) {
286                          if (chartCode.equalsIgnoreCase(org.getChartOfAccountsCode()) && organizationCode.equalsIgnoreCase(org.getOrganizationCode())) {
287                              if (counter++ != 0) {
288                                  organizationCopy.remove(organization);
289                                  putFieldError(VendorPropertyConstants.VENDOR_CONTRACT + "[" + vendorPos + "]." +
290                                          VendorPropertyConstants.VENDOR_CONTRACT_ORGANIZATION + "[" + organizationPos + "]." +
291                                          VendorPropertyConstants.VENDOR_CUSTOMER_NUMBER_CHART_OF_ACCOUNTS_CODE,
292                                          VendorKeyConstants.ERROR_DUPLICATE_ENTRY_NOT_ALLOWED,chartCode + " " + organizationCode );
293                                  success = false;
294                                  break;
295                              }
296                          }
297                      }
298                      organizationPos++;
299                  }
300                  vendorPos++;
301             }
302         }
303         return success;
304     }
305 
306 
307     private boolean validateSearchAliases(VendorDetail vendorDetail) {
308         boolean success = true;
309         List<VendorAlias> searchAliases = vendorDetail.getVendorAliases();
310         List<VendorAlias> aliasList = new ArrayList<VendorAlias>(searchAliases);
311         int pos = 0;
312         for (VendorAlias searchAlias : searchAliases) {
313                 String aliasName = searchAlias.getVendorAliasName();
314                if (aliasName != null) {
315                    int counter = 0;
316                    for (VendorAlias alias : aliasList) {
317                        if (aliasName.equals(alias.getVendorAliasName())) {
318                            if (counter++ != 0) {
319                                putFieldError(VendorPropertyConstants.VENDOR_SEARCH_ALIASES + "[" + pos + "]." + VendorPropertyConstants.VENDOR_ALIAS_NAME, VendorKeyConstants.ERROR_DUPLICATE_ENTRY_NOT_ALLOWED,aliasName);
320                                aliasList.remove(searchAlias);
321                                success = false;
322                                break;
323                            }
324                        }
325                    }
326                 }
327                pos++;
328         }
329         return success;
330     }
331 
332     /**
333      * Validates that if the vendor has reference or associated with purchase order document or payment request document.
334      * @param vendorDetail the VendorDetail object to be validated.
335      * @return boolean false if the vendor has reference with purchase order document or payment request document.
336      */
337     boolean validatePreInactiveIndicator(VendorDetail vendorDetail) {
338         boolean activeIndicator = vendorDetail.isActiveIndicator();
339         if(!activeIndicator){
340             Map vendorHeaderIdMap = new HashMap();
341             vendorHeaderIdMap.put("VNDR_HDR_GNRTD_ID", vendorDetail.getVendorHeaderGeneratedIdentifier());
342             BusinessObjectService
343                 businessObjectService = SpringContext.getBean(BusinessObjectService.class);
344             List<PurchaseOrderDocument> vendorPurchaseOrderDocumentList = (List) businessObjectService.findMatching(PurchaseOrderDocument.class, vendorHeaderIdMap);
345             boolean statusFlag = false;
346             for(int i=0;i<vendorPurchaseOrderDocumentList.size();i++){
347                 PurchaseOrderDocument purchaseOrderDocument =vendorPurchaseOrderDocumentList.get(i);
348                 String status = purchaseOrderDocument.getApplicationDocumentStatus();
349                // if(status.equalsIgnoreCase(VendorPropertyConstants.PO_STATUS_CLOSED)){
350                     statusFlag = true;
351                // }
352             }
353 
354             if(!statusFlag){
355                 if(vendorPurchaseOrderDocumentList.size() > 0){
356 
357                     putFieldError(VendorPropertyConstants.VENDOR_INACTIVE_REFERENCE, VendorKeyConstants.ERROR_INACTIVE_REFERENCE);
358                     return false;
359                 }
360                 List<PurchaseOrderDocument> vendorPaymentRequestDocumentList = (List) businessObjectService.findMatching(PaymentRequestDocument.class, vendorHeaderIdMap);
361                 if(vendorPaymentRequestDocumentList.size() > 0){
362                     putFieldError(VendorPropertyConstants.VENDOR_INACTIVE_REFERENCE, VendorKeyConstants.ERROR_INACTIVE_REFERENCE);
363                     return false;
364                 }
365             }
366         }
367        return true;
368     }
369 
370     /**
371      * Validates that if the vendor is set to be inactive, the inactive reason is required.
372      *
373      * @param vendorDetail the VendorDetail object to be validated
374      * @return boolean false if the vendor is inactive and the inactive reason is empty or if the vendor is active and the inactive reason is not empty
375      */
376     boolean validateInactiveReasonRequiredness(VendorDetail vendorDetail) {
377         boolean activeIndicator = vendorDetail.isActiveIndicator();
378         boolean emptyInactiveReason = StringUtils.isEmpty(vendorDetail.getVendorInactiveReasonCode());
379 
380         // return false if the vendor is inactive and the inactive reason is empty
381         if (!activeIndicator && emptyInactiveReason) {
382             putFieldError(VendorPropertyConstants.VENDOR_INACTIVE_REASON, VendorKeyConstants.ERROR_INACTIVE_REASON_REQUIRED);
383             return false;
384         }
385         // return false if the vendor is active and the inactive reason is not empty
386         if (activeIndicator && !emptyInactiveReason) {
387             putFieldError(VendorPropertyConstants.VENDOR_INACTIVE_REASON, VendorKeyConstants.ERROR_INACTIVE_REASON_NOT_ALLOWED);
388             return false;
389         }
390         return true;
391     }
392 
393     /**
394      * Validates that if the vendor is not foreign and if the vendor type's tax number required indicator is true, then the tax
395      * number is required. If the vendor foreign indicator is true, then the tax number is not required regardless of its vendor
396      * type.
397      *
398      * @param vendorDetail the VendorDetail object to be validated
399      * @return boolean false if there is no tax number and the indicator is true.
400      */
401     boolean validateTaxNumberRequiredness(VendorDetail vendorDetail) {
402         if (!vendorDetail.getVendorHeader().getVendorForeignIndicator() && vendorDetail.getVendorHeader().getVendorType().isVendorTaxNumberRequiredIndicator() && StringUtils.isBlank(vendorDetail.getVendorHeader().getVendorTaxNumber())) {
403             if (vendorDetail.isVendorParentIndicator()) {
404                 putFieldError(VendorPropertyConstants.VENDOR_TAX_NUMBER, VendorKeyConstants.ERROR_VENDOR_TYPE_REQUIRES_TAX_NUMBER, vendorDetail.getVendorHeader().getVendorType().getVendorTypeDescription());
405             }
406             else {
407                 putFieldError(VendorPropertyConstants.VENDOR_TAX_NUMBER, VendorKeyConstants.ERROR_VENDOR_PARENT_NEEDS_CHANGED);
408             }
409             return false;
410         }
411         return true;
412     }
413 
414     /**
415      * Validates that, if the vendor is set to be restricted, the restricted reason is required.
416      *
417      * @param vendorDetail The VendorDetail object to be validated
418      * @return boolean false if the vendor is restricted and the restricted reason is empty
419      */
420     boolean validateRestrictedReasonRequiredness(VendorDetail vendorDetail) {
421         if (ObjectUtils.isNotNull(vendorDetail.getVendorRestrictedIndicator()) && vendorDetail.getVendorRestrictedIndicator() && StringUtils.isEmpty(vendorDetail.getVendorRestrictedReasonText())) {
422             putFieldError(VendorPropertyConstants.VENDOR_RESTRICTED_REASON_TEXT, VendorKeyConstants.ERROR_RESTRICTED_REASON_REQUIRED);
423             return false;
424         }
425         return true;
426     }
427 
428     /**
429      * Validates that if vendor is parent, then tax # and tax type combo should be unique by checking for the existence of vendor(s)
430      * with the same tax # and tax type in the existing vendor header table. Ideally we're also supposed to check for pending
431      * vendors, but at the moment, the pending vendors are under research investigation, so we're only checking the existing vendors
432      * for now. If the vendor is a parent and the validation fails, display the actual error message. If the vendor is not a parent
433      * and the validation fails, display the error message that the parent of this vendor needs to be changed, please contact
434      * Purchasing Dept. While checking for the existence of vendors with the same tax # and tax type, exclude the vendors with the
435      * same id. KULPURAP-302: Allow a duplication of a tax number in vendor header if there are only "inactive" header records with
436      * the duplicate record
437      *
438      * @param vendorDetail the VendorDetail object to be validated
439      * @return boolean true if the vendorDetail passes the unique tax # and tax type validation.
440      */
441    boolean validateParentVendorTaxNumber(VendorDetail vendorDetail) {
442         boolean valid = true;
443         boolean isParent = vendorDetail.isVendorParentIndicator();
444         Map criteria = new HashMap();
445         criteria.put(VendorPropertyConstants.VENDOR_TAX_TYPE_CODE, vendorDetail.getVendorHeader().getVendorTaxTypeCode());
446         criteria.put(VendorPropertyConstants.VENDOR_TAX_NUMBER, vendorDetail.getVendorHeader().getVendorTaxNumber());
447         criteria.put(OLEPropertyConstants.ACTIVE_INDICATOR, true);
448         Map negativeCriteria = new HashMap();
449         int existingVendor = 0;
450         // If this is editing an existing vendor, we have to include the current vendor's
451         // header generated id in the negative criteria so that the current vendor is
452         // excluded from the search
453         if (ObjectUtils.isNotNull(vendorDetail.getVendorHeaderGeneratedIdentifier())) {
454             negativeCriteria.put(VendorPropertyConstants.VENDOR_HEADER_GENERATED_ID, vendorDetail.getVendorHeaderGeneratedIdentifier());
455             existingVendor = getBoService().countMatching(VendorDetail.class, criteria, negativeCriteria);
456         }
457         else {
458             // If this is creating a new vendor, we can't include the header generated id
459             // in the negative criteria because it's null, so we'll only look for existing
460             // vendors with the same tax # and tax type regardless of the vendor header generated id.
461             existingVendor = getBoService().countMatching(VendorDetail.class, criteria);
462         }
463         if (existingVendor > 0) {
464             if (isParent) {
465                 putFieldError(VendorPropertyConstants.VENDOR_TAX_NUMBER, VendorKeyConstants.ERROR_VENDOR_TAX_TYPE_AND_NUMBER_COMBO_EXISTS);
466             }
467             else {
468                 putFieldError(VendorPropertyConstants.VENDOR_TAX_NUMBER, VendorKeyConstants.ERROR_VENDOR_PARENT_NEEDS_CHANGED);
469             }
470             valid &= false;
471         }
472         return valid;
473     }
474 
475     /**
476      * Validates that the following business rules are satisfied: 1. Tax type cannot be blank if the tax # is not blank. 2. Tax type
477      * cannot be set if the tax # is blank. If the vendor is a parent and the validation fails, we'll display an error message
478      * indicating that the tax type cannot be blank if the tax # is not blank or that the tax type cannot be set if the tax # is
479      * blank. If the vendor is not a parent and the validation fails, we'll display an error message indicating that the parent of
480      * this vendor needs to be changed, please contact Purchasing Dept.
481      *
482      * @param vendorDetail the VendorDetail object to be validated
483      * @return boolean true if the vendor Detail passes the validation and false otherwise.
484      */
485     boolean validateTaxTypeAndTaxNumberBlankness(VendorDetail vendorDetail) {
486         boolean valid = true;
487         boolean isParent = vendorDetail.isVendorParentIndicator();
488         if (!StringUtils.isBlank(vendorDetail.getVendorHeader().getVendorTaxNumber()) && (StringUtils.isBlank(vendorDetail.getVendorHeader().getVendorTaxTypeCode()))) {
489             if (isParent) {
490                 putFieldError(VendorPropertyConstants.VENDOR_TAX_TYPE_CODE, VendorKeyConstants.ERROR_VENDOR_TAX_TYPE_CANNOT_BE_BLANK);
491             }
492             valid &= false;
493         }
494         else if (StringUtils.isBlank(vendorDetail.getVendorHeader().getVendorTaxNumber()) && !StringUtils.isBlank(vendorDetail.getVendorHeader().getVendorTaxTypeCode())) {
495             if (isParent) {
496                 putFieldError(VendorPropertyConstants.VENDOR_TAX_TYPE_CODE, VendorKeyConstants.ERROR_VENDOR_TAX_TYPE_CANNOT_BE_SET);
497             }
498             valid &= false;
499         }
500 
501         if (!valid && !isParent) {
502             putFieldError(VendorPropertyConstants.VENDOR_TAX_TYPE_CODE, VendorKeyConstants.ERROR_VENDOR_PARENT_NEEDS_CHANGED);
503         }
504 
505         return valid;
506     }
507 
508 
509     /**
510      * Validates the vendorName, vendorFirstName and vendorLastName fields according to these business rules: 1. At least one of the
511      * three vendor name fields must be filled in. 2. Both of the two ways of entering vendor name (One vendor name field vs
512      * VendorFirstName/VendorLastName) cannot be used 3. If either the vendor first name or the vendor last name have been entered,
513      * the other must be entered.
514      *
515      * @param vendorDetail The VendorDetail object to be validated
516      * @return boolean true if the vendorDetail passes this validation and false otherwise.
517      */
518     protected boolean validateVendorNames(VendorDetail vendorDetail) {
519         boolean valid = true;
520         if (StringUtils.isBlank(vendorDetail.getVendorName())) {
521             // At least one of the three vendor name fields must be filled in.
522             if (StringUtils.isBlank(vendorDetail.getVendorFirstName()) && StringUtils.isBlank(vendorDetail.getVendorLastName())) {
523 
524                 putFieldError(VendorPropertyConstants.VENDOR_NAME, VendorKeyConstants.ERROR_VENDOR_NAME_REQUIRED);
525                 valid &= false;
526             }
527             // If either the vendor first name or the vendor last name have been entered, the other must be entered.
528             else if (StringUtils.isBlank(vendorDetail.getVendorFirstName()) || StringUtils.isBlank(vendorDetail.getVendorLastName())) {
529 
530                 putFieldError(VendorPropertyConstants.VENDOR_NAME, VendorKeyConstants.ERROR_VENDOR_BOTH_NAME_REQUIRED);
531                 valid &= false;
532             }
533             else {
534                 String vendorName = vendorDetail.getVendorLastName() + VendorConstants.NAME_DELIM + vendorDetail.getVendorFirstName();
535                 if (vendorName.length() > VendorConstants.MAX_VENDOR_NAME_LENGTH) {
536                     putFieldError(VendorPropertyConstants.VENDOR_LAST_NAME, VendorKeyConstants.ERROR_VENDOR_NAME_TOO_LONG);
537                     valid &= false;
538                 }
539 
540             }
541         }
542         else {
543             // Both of the two ways of entering vendor name (One vendor name field vs VendorFirstName/VendorLastName) cannot be used
544             if (!StringUtils.isBlank(vendorDetail.getVendorFirstName()) || !StringUtils.isBlank(vendorDetail.getVendorLastName())) {
545 
546                 putFieldError(VendorPropertyConstants.VENDOR_NAME, VendorKeyConstants.ERROR_VENDOR_NAME_INVALID);
547                 valid &= false;
548             }
549         }
550         return valid;
551     }
552 
553     /**
554      * Validates the vendorSoldToNumber field to ensure that it's a valid existing vendor number;
555      * and if so set vendorSoldToName accordingly.
556      *
557      * @param document - the maintenanceDocument being evaluated
558      * @return boolean true if the vendorDetail in the document contains valid vendorSoldToNumber.
559      */
560     protected boolean validateVendorSoldToNumber(VendorDetail vendorDetail) {
561         boolean valid = true;
562         String vendorSoldToNumber = vendorDetail.getVendorSoldToNumber();
563 
564         // if vendor number is empty, clear all vendorSoldTo fields
565         if (StringUtils.isEmpty(vendorSoldToNumber)) {
566             vendorDetail.setSoldToVendorDetail(null);
567             vendorDetail.setVendorSoldToGeneratedIdentifier(null);
568             vendorDetail.setVendorSoldToAssignedIdentifier(null);
569             vendorDetail.setVendorSoldToNumber(null);
570             vendorDetail.setVendorSoldToName(null);
571             return valid;
572         }
573 
574         VendorDetail vendorSoldTo = SpringContext.getBean(VendorService.class).getVendorDetail(vendorSoldToNumber);
575         if (vendorSoldTo != null) {
576             // if vendor number is valid, set all vendorSoldTo fields
577             vendorDetail.setSoldToVendorDetail(vendorSoldTo);
578             vendorDetail.setVendorSoldToGeneratedIdentifier(vendorSoldTo.getVendorHeaderGeneratedIdentifier());
579             vendorDetail.setVendorSoldToAssignedIdentifier(vendorSoldTo.getVendorDetailAssignedIdentifier());
580             vendorDetail.setVendorSoldToName(vendorSoldTo.getVendorName());
581         }
582         else {
583             // otherwise clear vendorSoldToName
584             vendorDetail.setSoldToVendorDetail(null);
585             vendorDetail.setVendorSoldToName(null);
586             valid = false;
587             putFieldError(VendorPropertyConstants.VENDOR_SOLD_TO_NUMBER, VendorKeyConstants.VENDOR_SOLD_TO_NUMBER_INVALID);
588         }
589 
590         return valid;
591     }
592 
593     /**
594      * Validates the ownership type codes that aren't allowed for the tax type of the vendor. The rules are : 1. If tax type is
595      * "SSN", then check the ownership type against the allowed types for "SSN" in the Rules table. 2. If tax type is "FEIN", then
596      * check the ownership type against the allowed types for "FEIN" in the Rules table. If the vendor is a parent and the
597      * validation fails, display the actual error message. If the vendor is not a parent and the validation fails, display the error
598      * message that the parent of this vendor needs to be changed, please contact Purchasing Dept.
599      *
600      * @param vendorDetail The VendorDetail object to be validated
601      * @return boolean true if the ownership type is allowed and FALSE otherwise.
602      */
603     private boolean validateOwnershipTypeAllowed(VendorDetail vendorDetail) {
604         boolean valid = true;
605         boolean isParent = vendorDetail.isVendorParentIndicator();
606         String ownershipTypeCode = vendorDetail.getVendorHeader().getVendorOwnershipCode();
607         String taxTypeCode = vendorDetail.getVendorHeader().getVendorTaxTypeCode();
608         if (StringUtils.isNotEmpty(ownershipTypeCode) && StringUtils.isNotEmpty(taxTypeCode)) {
609             if (VendorConstants.TAX_TYPE_FEIN.equals(taxTypeCode)) {
610                 if (!/*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(VendorDetail.class, VendorParameterConstants.FEIN_ALLOWED_OWNERSHIP_TYPES, ownershipTypeCode).evaluationSucceeds()) {
611                     valid &= false;
612                 }
613             }
614             else if (VendorConstants.TAX_TYPE_SSN.equals(taxTypeCode)) {
615                 if (!/*REFACTORME*/SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(VendorDetail.class, VendorParameterConstants.SSN_ALLOWED_OWNERSHIP_TYPES, ownershipTypeCode).evaluationSucceeds()) {
616                     valid &= false;
617                 }
618             }
619         }
620         if (!valid && isParent) {
621             putFieldError(VendorPropertyConstants.VENDOR_OWNERSHIP_CODE, VendorKeyConstants.ERROR_OWNERSHIP_TYPE_CODE_NOT_ALLOWED, new String[] { vendorDetail.getVendorHeader().getVendorOwnership().getVendorOwnershipDescription(), taxTypeCode });
622         }
623         else if (!valid && !isParent) {
624             putFieldError(VendorPropertyConstants.VENDOR_OWNERSHIP_CODE, VendorKeyConstants.ERROR_VENDOR_PARENT_NEEDS_CHANGED);
625         }
626         return valid;
627     }
628 
629 
630     /**
631      * Validates that the minimum order amount is less than the maximum allowed amount.
632      *
633      * @param vendorDetail The VendorDetail object to be validated
634      * @return booelan true if the vendorMinimumOrderAmount is less than the maximum allowed amount.
635      */
636     private boolean validateMinimumOrderAmount(VendorDetail vendorDetail) {
637         boolean valid = true;
638         KualiDecimal minimumOrderAmount = vendorDetail.getVendorMinimumOrderAmount();
639         if (ObjectUtils.isNotNull(minimumOrderAmount)) {
640             KualiDecimal VENDOR_MIN_ORDER_AMOUNT = new KualiDecimal(SpringContext.getBean(ParameterService.class).getParameterValueAsString(VendorDetail.class, VendorParameterConstants.VENDOR_MIN_ORDER_AMOUNT));
641             if (ObjectUtils.isNotNull(VENDOR_MIN_ORDER_AMOUNT) && (VENDOR_MIN_ORDER_AMOUNT.compareTo(minimumOrderAmount) < 1) || (minimumOrderAmount.isNegative())) {
642                 putFieldError(VendorPropertyConstants.VENDOR_MIN_ORDER_AMOUNT, VendorKeyConstants.ERROR_VENDOR_MAX_MIN_ORDER_AMOUNT, VENDOR_MIN_ORDER_AMOUNT.toString());
643                 valid &= false;
644             }
645         }
646         return valid;
647     }
648 
649     /**
650      * Validates that if the ownership category allowed indicator is false, the vendor does not have ownership category. It will
651      * return false if the vendor contains ownership category. If the vendor is a parent and the validation fails, display the
652      * actual error message. If the vendor is not a parent and the validation fails, display the error message that the parent of
653      * this vendor needs to be changed, please contact Purchasing Dept.
654      *
655      * @param vendorDetail The VendorDetail to be validated
656      * @return boolean true if the vendor does not contain ownership category and false otherwise
657      */
658     private boolean validateOwnershipCategory(VendorDetail vendorDetail) {
659         boolean valid = true;
660         boolean isParent = vendorDetail.isVendorParentIndicator();
661         OwnershipType ot = vendorDetail.getVendorHeader().getVendorOwnership();
662         if (ot != null && !ot.getVendorOwnershipCategoryAllowedIndicator()) {
663             if (ObjectUtils.isNotNull(vendorDetail.getVendorHeader().getVendorOwnershipCategory())) {
664                 valid &= false;
665             }
666         }
667         if (!valid && isParent) {
668             putFieldError(VendorPropertyConstants.VENDOR_OWNERSHIP_CATEGORY_CODE, VendorKeyConstants.ERROR_OWNERSHIP_CATEGORY_CODE_NOT_ALLOWED, new String[] { vendorDetail.getVendorHeader().getVendorOwnershipCategory().getVendorOwnershipCategoryDescription(), vendorDetail.getVendorHeader().getVendorOwnership().getVendorOwnershipDescription() });
669         }
670         else if (!valid && !isParent) {
671             putFieldError(VendorPropertyConstants.VENDOR_OWNERSHIP_CODE, VendorKeyConstants.ERROR_VENDOR_PARENT_NEEDS_CHANGED);
672         }
673         return valid;
674     }
675 
676     /**
677      * Calls the methods in TaxNumberService to validate the tax number for these business rules: 1. Tax number must be 9 digits and
678      * cannot be all zeros (but can be blank). 2. First three digits of a SSN cannot be 000. 3. First three digits of a SSN cannot
679      * be 666. 4. Middle two digits of a SSN cannot be 00. 5. Last four digits of a SSN cannot be 0000. 6. First two digits of a
680      * FEIN cannot be 00. 7. Check system parameters for not allowed tax numbers
681      *
682      * @param vendorDetail The VendorDetail object to be validated
683      * @return boolean true if the tax number is a valid tax number and false otherwise.
684      */
685     private boolean validateTaxNumberFromTaxNumberService(VendorDetail vendorDetail) {
686         boolean valid = true;
687         boolean isParent = vendorDetail.isVendorParentIndicator();
688         String taxNumber = vendorDetail.getVendorHeader().getVendorTaxNumber();
689         String taxType = vendorDetail.getVendorHeader().getVendorTaxTypeCode();
690         if (!StringUtils.isEmpty(taxType) && !StringUtils.isEmpty(taxNumber)) {
691             valid = SpringContext.getBean(TaxNumberService.class).isValidTaxNumber(taxNumber, taxType);
692             if (!valid && isParent) {
693                 putFieldError(VendorPropertyConstants.VENDOR_TAX_NUMBER, VendorKeyConstants.ERROR_TAX_NUMBER_INVALID);
694             }
695             valid = SpringContext.getBean(TaxNumberService.class).isAllowedTaxNumber(taxNumber);
696             if (!valid && isParent) {
697                 putFieldError(VendorPropertyConstants.VENDOR_TAX_NUMBER, VendorKeyConstants.ERROR_TAX_NUMBER_NOT_ALLOWED);
698             }
699         }
700         if (!valid && !isParent) {
701             putFieldError(VendorPropertyConstants.VENDOR_TAX_NUMBER, VendorKeyConstants.ERROR_VENDOR_PARENT_NEEDS_CHANGED);
702         }
703 
704         return valid;
705     }
706 
707     /**
708      * Validates commodity code related rules.
709      *
710      * @param document MaintenanceDocument
711      * @return boolean false or true
712      */
713     boolean processCommodityCodeValidation(MaintenanceDocument document) {
714         boolean valid = true;
715         List<VendorCommodityCode> vendorCommodities = newVendor.getVendorCommodities();
716         boolean commodityCodeRequired = newVendor.getVendorHeader().getVendorType().isCommodityRequiredIndicator();
717         if (commodityCodeRequired) {
718             if (vendorCommodities.size() == 0) {
719                 //display error that the commodity code is required for this type of vendor.
720                 String propertyName = "add." + VendorPropertyConstants.VENDOR_COMMODITIES_CODE_PURCHASING_COMMODITY_CODE;
721                 putFieldError(propertyName, VendorKeyConstants.ERROR_VENDOR_COMMODITY_CODE_IS_REQUIRED_FOR_THIS_VENDOR_TYPE);
722                 valid = false;
723             }
724             //We only need to validate the default indicator if there is at least
725             //one commodity code for the vendor.
726             else if (vendorCommodities.size() > 0) {
727                 valid &= validateCommodityCodeDefaultIndicator(vendorCommodities);
728             }
729         }
730         else if (vendorCommodities.size() > 0) {
731             //If the commodity code is not required, but the vendor contains at least one commodity code,
732             //we have to check that there is only one commodity code with default indicator = Y.
733             int defaultCount = 0;
734             for (int i=0; i < vendorCommodities.size(); i++) {
735                 VendorCommodityCode vcc = vendorCommodities.get(i);
736                 if (vcc.isCommodityDefaultIndicator()) {
737                     defaultCount ++;
738                     if (defaultCount > 1) {
739                         valid = false;
740                         String propertyName = VendorPropertyConstants.VENDOR_COMMODITIES_CODE + "[" + i + "]." + VendorPropertyConstants.VENDOR_COMMODITIES_DEFAULT_INDICATOR;
741                         putFieldError(propertyName, VendorKeyConstants.ERROR_VENDOR_COMMODITY_CODE_REQUIRE_ONE_DEFAULT_IND);
742                         break;
743                     }
744                 }
745             }
746         }
747 
748         return valid;
749     }
750 
751     /**
752      * Validates that there is one and only one default indicator selected
753      * for commodity code if the vendor contains at least one commodity code.
754      *
755      * @param vendorCommodities the list of VendorCommodityCode to be validated
756      * @return boolean true or false
757      */
758     private boolean validateCommodityCodeDefaultIndicator(List<VendorCommodityCode> vendorCommodities) {
759         boolean valid = true;
760 
761         boolean foundDefaultIndicator = false;
762         for (int i=0; i < vendorCommodities.size(); i++) {
763             VendorCommodityCode vcc = vendorCommodities.get(i);
764             if (vcc.isCommodityDefaultIndicator()) {
765                 if (!foundDefaultIndicator) {
766                     foundDefaultIndicator = true;
767                 }
768                 else {
769                     //display error that there can only be 1 commodity code with default indicator = true.
770                     String propertyName = VendorPropertyConstants.VENDOR_COMMODITIES_CODE + "[" + i + "]." + VendorPropertyConstants.VENDOR_COMMODITIES_DEFAULT_INDICATOR;
771                     putFieldError(propertyName, VendorKeyConstants.ERROR_VENDOR_COMMODITY_CODE_REQUIRE_ONE_DEFAULT_IND);
772                     valid = false;
773                 }
774             }
775         }
776         if (!foundDefaultIndicator && vendorCommodities.size() > 0) {
777             //display error that there must be one commodity code selected as the default commodity code for the vendor.
778             String propertyName = VendorPropertyConstants.VENDOR_COMMODITIES_CODE + "[0]." + VendorPropertyConstants.VENDOR_COMMODITIES_DEFAULT_INDICATOR;
779             putFieldError(propertyName, VendorKeyConstants.ERROR_VENDOR_COMMODITY_CODE_REQUIRE_ONE_DEFAULT_IND);
780             valid = false;
781         }
782         return valid;
783     }
784 
785     /**
786      * Validates vendor address fields.
787      *
788      * @param document MaintenanceDocument
789      * @return boolean false or true
790      */
791     boolean processAddressValidation(MaintenanceDocument document) {
792         boolean valid = true;
793         boolean validAddressType = false;
794 
795         List<VendorAddress> addresses = newVendor.getVendorAddresses();
796         String vendorTypeCode = newVendor.getVendorHeader().getVendorTypeCode();
797         String vendorAddressTypeRequiredCode = newVendor.getVendorHeader().getVendorType().getVendorAddressTypeRequiredCode();
798 
799         for (int i = 0; i < addresses.size(); i++) {
800             VendorAddress address = addresses.get(i);
801             String errorPath = MAINTAINABLE_ERROR_PREFIX + VendorPropertyConstants.VENDOR_ADDRESS + "[" + i + "]";
802             GlobalVariables.getMessageMap().clearErrorPath();
803             GlobalVariables.getMessageMap().addToErrorPath(errorPath);
804 
805             this.getDictionaryValidationService().validateBusinessObject(address);
806             if (GlobalVariables.getMessageMap().hasErrors()) {
807                 valid = false;
808             }
809 
810             if (address.getVendorAddressTypeCode().equals(vendorAddressTypeRequiredCode)) {
811                 validAddressType = true;
812             }
813 
814 
815             valid &= checkFaxNumber(address);
816 
817             valid &= checkAddressCountryEmptyStateZip(address);
818 
819             GlobalVariables.getMessageMap().clearErrorPath();
820         }
821 
822         List<VendorPhoneNumber> phoneNumbers = newVendor.getVendorPhoneNumbers();
823         for(int j=0;j<phoneNumbers.size();j++){
824             VendorPhoneNumber phoneNumber = phoneNumbers.get(j);
825             String errorPath = MAINTAINABLE_ERROR_PREFIX + VendorPropertyConstants.VENDOR_PHONE_NUMBERS + "[" + j + "]";
826             GlobalVariables.getMessageMap().clearErrorPath();
827             GlobalVariables.getMessageMap().addToErrorPath(errorPath);
828             this.getDictionaryValidationService().validateBusinessObject(phoneNumber);
829             valid &= checkPhoneNumber(phoneNumber);
830         }
831 
832         // validate Address Type
833         String vendorAddressTabPrefix = OLEConstants.ADD_PREFIX + "." + VendorPropertyConstants.VENDOR_ADDRESS + ".";
834         if (!StringUtils.isBlank(vendorTypeCode) && !StringUtils.isBlank(vendorAddressTypeRequiredCode) && !validAddressType) {
835             String[] parameters = new String[] { vendorTypeCode, vendorAddressTypeRequiredCode };
836             putFieldError(vendorAddressTabPrefix + VendorPropertyConstants.VENDOR_ADDRESS_TYPE_CODE, VendorKeyConstants.ERROR_ADDRESS_TYPE, parameters);
837             String addressLine1Label = SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(VendorAddress.class, VendorPropertyConstants.VENDOR_ADDRESS_LINE_1);
838             String addressCityLabel = SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(VendorAddress.class, VendorPropertyConstants.VENDOR_ADDRESS_CITY);
839             String addressCountryLabel = SpringContext.getBean(DataDictionaryService.class).getAttributeLabel(VendorAddress.class, VendorPropertyConstants.VENDOR_ADDRESS_COUNTRY);
840             putFieldError(vendorAddressTabPrefix + VendorPropertyConstants.VENDOR_ADDRESS_LINE_1, OLEKeyConstants.ERROR_REQUIRED, addressLine1Label);
841             putFieldError(vendorAddressTabPrefix + VendorPropertyConstants.VENDOR_ADDRESS_CITY, OLEKeyConstants.ERROR_REQUIRED, addressCityLabel);
842             putFieldError(vendorAddressTabPrefix + VendorPropertyConstants.VENDOR_ADDRESS_COUNTRY, OLEKeyConstants.ERROR_REQUIRED, addressCountryLabel);
843             valid = false;
844         }
845 
846         valid &= validateDefaultAddressCampus(newVendor);
847 
848         // Check to see if all divisions have one desired address for this vendor type
849         Map fieldValues = new HashMap();
850         fieldValues.put(VendorPropertyConstants.VENDOR_HEADER_GENERATED_ID, newVendor.getVendorHeaderGeneratedIdentifier());
851         // Find all the addresses for this vendor and its divisions:
852         List<VendorAddress> vendorDivisionAddresses = new ArrayList(SpringContext.getBean(BusinessObjectService.class).findMatchingOrderBy(VendorAddress.class, fieldValues, VendorPropertyConstants.VENDOR_DETAIL_ASSIGNED_ID, true));
853 
854         // This set stores the vendorDetailedAssignedIds for the vendor divisions which is
855         // bascically the division numbers 0, 1, 2, ...
856         HashSet<Integer> vendorDetailedIds = new HashSet();
857         // This set stores the vendor division numbers of the ones which have one address of the desired type
858         HashSet<Integer> vendorDivisionsIdsWithDesiredAddressType = new HashSet();
859 
860         for (VendorAddress vendorDivisionAddress : vendorDivisionAddresses) {
861             // We need to exclude the first one Since we already checked for this in valid AddressType above.
862             if (vendorDivisionAddress.getVendorDetailAssignedIdentifier() != 0) {
863                 vendorDetailedIds.add(vendorDivisionAddress.getVendorDetailAssignedIdentifier());
864                 if (vendorDivisionAddress.getVendorAddressTypeCode().equalsIgnoreCase(vendorAddressTypeRequiredCode)) {
865                     vendorDivisionsIdsWithDesiredAddressType.add(vendorDivisionAddress.getVendorDetailAssignedIdentifier());
866                 }
867             }
868         }
869 
870         // If the number of divisions with the desired address type is less than the number of divisions for his vendor
871         if (vendorDivisionsIdsWithDesiredAddressType.size() < vendorDetailedIds.size()) {
872             Iterator itr = vendorDetailedIds.iterator();
873             Integer value;
874             String vendorId;
875 
876             while (itr.hasNext()) {
877                 value = (Integer) itr.next();
878                 if (!vendorDivisionsIdsWithDesiredAddressType.contains(value)) {
879                     vendorId = newVendor.getVendorHeaderGeneratedIdentifier().toString() + '-' + value.toString();
880                     String[] parameters = new String[] { vendorId, vendorTypeCode, vendorAddressTypeRequiredCode };
881 
882                     //divisions without the desired address type should only be an warning
883                     GlobalVariables.getMessageMap().putWarningWithoutFullErrorPath(MAINTAINABLE_ERROR_PREFIX + vendorAddressTabPrefix + VendorPropertyConstants.VENDOR_ADDRESS_TYPE_CODE, VendorKeyConstants.ERROR_ADDRESS_TYPE_DIVISIONS, parameters);
884                 }
885             }
886         }
887 
888         return valid;
889     }
890 
891     /**
892      * Validates that if US is selected for the country then the state and zip cannot be empty. Also,
893      * zip format validation is added if US is selected.
894      *
895      * @param addresses VendorAddress which is being validated
896      * @return boolean false if the country is United States and there is no state or zip code
897      */
898     boolean checkAddressCountryEmptyStateZip(VendorAddress address) {
899         //GlobalVariables.getMessageMap().clearErrorPath();
900         //GlobalVariables.getMessageMap().addToErrorPath(OLEPropertyConstants.DOCUMENT + "." + OLEPropertyConstants.NEW_MAINTAINABLE_OBJECT + "." + VendorPropertyConstants.VENDOR_ADDRESS);
901         boolean valid = SpringContext.getBean(PostalCodeValidationService.class).validateAddress(address.getVendorCountryCode(), address.getVendorStateCode(), address.getVendorZipCode(), VendorPropertyConstants.VENDOR_ADDRESS_STATE, VendorPropertyConstants.VENDOR_ADDRESS_ZIP);
902         //GlobalVariables.getMessageMap().clearErrorPath();
903 		return valid;
904     }
905 
906     /**
907      * Checks if the "allow default indicator" is true or false for this address.
908      *
909      * @param addresses VendorAddress which is being validated
910      * @return boolean false or true
911      */
912 
913     boolean findAllowDefaultAddressIndicatorHelper(VendorAddress vendorAddress) {
914 
915         AddressType addressType = new AddressType();
916 
917         addressType = vendorAddress.getVendorAddressType();
918         if (ObjectUtils.isNull(addressType)) {
919             return false;
920         }
921         // Retrieving the Default Address Indicator for this Address Type:
922         return addressType.getVendorDefaultIndicator();
923 
924     }
925 
926     /**
927      * If add button is selected on Default Address, checks if the allow default indicator is set to false for this address type
928      * then it does not allow user to select a default address for this address and if it is true then it allows only one campus to
929      * be default for this address.
930      *
931      * @param vendorDetail VendorDetail document
932      * @param addedDefaultAddress VendorDefaultAddress which is being added
933      * @param parent The VendorAddress which we are adding a default address to it
934      * @return boolean false or true
935      */
936     boolean checkDefaultAddressCampus(VendorDetail vendorDetail, VendorDefaultAddress addedDefaultAddress, VendorAddress parent) {
937         VendorAddress vendorAddress = parent;
938         if (ObjectUtils.isNull(vendorAddress)) {
939             return false;
940         }
941 
942         int j = vendorDetail.getVendorAddresses().indexOf(vendorAddress);
943         String errorPath = MAINTAINABLE_ERROR_PREFIX + VendorPropertyConstants.VENDOR_ADDRESS + "[" + j + "]";
944         GlobalVariables.getMessageMap().addToErrorPath(errorPath);
945 
946         // Retrieving the Default Address Indicator for this Address Type:
947         boolean allowDefaultAddressIndicator = findAllowDefaultAddressIndicatorHelper(vendorAddress);
948         String addedAddressCampusCode = addedDefaultAddress.getVendorCampusCode();
949         String addedAddressTypeCode = vendorAddress.getVendorAddressTypeCode();
950 
951         // if the selected address type does not allow defaults, then the user should not be allowed to
952         // select the default indicator or add any campuses to the address
953         if (allowDefaultAddressIndicator == false) {
954             String[] parameters = new String[] { addedAddressTypeCode };
955             GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_DEFAULT_ADDRESS + "[" + 0 + "]." + VendorPropertyConstants.VENDOR_DEFAULT_ADDRESS_CAMPUS, VendorKeyConstants.ERROR_ADDRESS_DEFAULT_CAMPUS_NOT_ALLOWED, parameters);
956             return false;
957         }
958 
959         List<VendorDefaultAddress> vendorDefaultAddresses = vendorAddress.getVendorDefaultAddresses();
960         for (int i = 0; i < vendorDefaultAddresses.size(); i++) {
961             VendorDefaultAddress vendorDefaultAddress = vendorDefaultAddresses.get(i);
962             if (vendorDefaultAddress.getVendorCampusCode().equalsIgnoreCase(addedAddressCampusCode)) {
963                 String[] parameters = new String[] { addedAddressCampusCode, addedAddressTypeCode };
964                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_DEFAULT_ADDRESS + "[" + i + "]." + VendorPropertyConstants.VENDOR_DEFAULT_ADDRESS_CAMPUS, VendorKeyConstants.ERROR_ADDRESS_DEFAULT_CAMPUS, parameters);
965                 return false;
966             }
967         }
968 
969         return true;
970     }
971 
972     /**
973      * Checks if the allow default indicator is set to false for this address the default indicator cannot be set to true/yes. If
974      * "allow default indicator" is set to true/yes for address type, one address must have the default indicator set (no more, no
975      * less) and only one campus to be set as default for this address.
976      *
977      * @param vendorDetail VendorDetail document
978      * @return boolean false or true
979      */
980 
981     boolean validateDefaultAddressCampus(VendorDetail vendorDetail) {
982         List<VendorAddress> vendorAddresses = vendorDetail.getVendorAddresses();
983         String addressTypeCode;
984         String addressTypeDesc;
985         String campusCode;
986         boolean valid = true;
987         boolean previousValue = false;
988 
989         // This is a HashMap to store the default Address Type Codes and their associated default Indicator
990         HashMap addressTypeCodeDefaultIndicator = new HashMap();
991 
992         // This is a HashMap to store Address Type Codes and Address Campus Codes for Default Addresses
993         HashMap addressTypeDefaultCampus = new HashMap();
994 
995         // This is a HashSet for storing only the Address Type Codes which have at least one default Indicator set to true
996         HashSet addressTypesHavingDefaultTrue = new HashSet();
997 
998         int i = 0;
999         for (VendorAddress address : vendorAddresses) {
1000             addressTypeCode = address.getVendorAddressTypeCode();
1001             addressTypeDesc = address.getVendorAddressType().getVendorAddressTypeDescription();
1002             String errorPath = MAINTAINABLE_ERROR_PREFIX + VendorPropertyConstants.VENDOR_ADDRESS + "[" + i + "]";
1003             GlobalVariables.getMessageMap().addToErrorPath(errorPath);
1004             String[] parameters = new String[] { addressTypeCode };
1005 
1006             // If "allow default indicator" is set to true/yes for address type, one address must have the default indicator set (no
1007             // more, no less).
1008             // For example, if a vendor contains three PO type addresses and the PO address type is set to allow defaults in the
1009             // address type table,
1010             // then only one of these PO addresses can have the default indicator set to true/yes.
1011 
1012             if (findAllowDefaultAddressIndicatorHelper(address)) {
1013                 if (address.isVendorDefaultAddressIndicator()) {
1014                     addressTypesHavingDefaultTrue.add(addressTypeCode);
1015                 }
1016                 if (!addressTypeCodeDefaultIndicator.isEmpty() && addressTypeCodeDefaultIndicator.containsKey(addressTypeCode)) {
1017                     previousValue = ((Boolean) addressTypeCodeDefaultIndicator.get(addressTypeCode)).booleanValue();
1018                 }
1019 
1020                 if (addressTypeCodeDefaultIndicator.put(addressTypeCode, address.isVendorDefaultAddressIndicator()) != null && previousValue && address.isVendorDefaultAddressIndicator()) {
1021                     GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_DEFAULT_ADDRESS_INDICATOR, VendorKeyConstants.ERROR_ADDRESS_DEFAULT_INDICATOR,addressTypeDesc );
1022                     valid = false;
1023                 }
1024 
1025             }
1026             // If "allow default indicator" is set to false/no for address type, the default indicator cannot be set to true/yes.
1027             else {
1028                 if (address.isVendorDefaultAddressIndicator()) {
1029                     GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_DEFAULT_ADDRESS_INDICATOR, VendorKeyConstants.ERROR_ADDRESS_DEFAULT_ADDRESS_NOT_ALLOWED, parameters);
1030                     valid = false;
1031                 }
1032 
1033             }
1034 
1035             List<VendorDefaultAddress> vendorDefaultAddresses = address.getVendorDefaultAddresses();
1036 
1037             // If "allow default indicator" is set to true/yes for address type, a campus can only be set on one of each type of
1038             // Address.
1039             // For example, Bloomington can not be included in the campus list for two PO type addresses.
1040             // Each campus can only have one default address.
1041             int j = 0;
1042             for (VendorDefaultAddress defaultAddress : vendorDefaultAddresses) {
1043                 campusCode = (String) addressTypeDefaultCampus.put(addressTypeCode, defaultAddress.getVendorCampusCode());
1044                 if (StringUtils.isNotBlank(campusCode) && campusCode.equalsIgnoreCase(defaultAddress.getVendorCampusCode())) {
1045                     String[] newParameters = new String[] { defaultAddress.getVendorCampusCode(), addressTypeCode };
1046                     GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_DEFAULT_ADDRESS + "[" + j + "]." + VendorPropertyConstants.VENDOR_DEFAULT_ADDRESS_CAMPUS, VendorKeyConstants.ERROR_ADDRESS_DEFAULT_CAMPUS, newParameters);
1047                     valid = false;
1048                 }
1049                 j++;
1050             }
1051             i++;
1052             GlobalVariables.getMessageMap().removeFromErrorPath(errorPath);
1053         }
1054 
1055         // If "allow default indicator" is set to true/yes for address type, one address must have the default indicator set to true
1056         if (!addressTypeCodeDefaultIndicator.isEmpty()) {
1057             Set<String> addressTypes = addressTypeCodeDefaultIndicator.keySet();
1058 
1059             for (String addressType : addressTypes) {
1060                 if (!addressTypesHavingDefaultTrue.contains(addressType)) {
1061 
1062                     int addressIndex = 0;
1063                     for (VendorAddress address : vendorAddresses) {
1064                         String[] parameters = new String[] { address.getVendorAddressType().getVendorAddressTypeDescription() };
1065                         String propertyName = VendorPropertyConstants.VENDOR_ADDRESS + "[" + addressIndex + "]." + VendorPropertyConstants.VENDOR_DEFAULT_ADDRESS_INDICATOR;
1066                         if (address.getVendorAddressType().getVendorAddressTypeCode().equalsIgnoreCase(addressType)) {
1067                             putFieldError(propertyName, VendorKeyConstants.ERROR_ADDRESS_DEFAULT_INDICATOR, parameters);
1068                             break;
1069                         }
1070                         addressIndex++;
1071                     }
1072                     valid = false;
1073                 }
1074 
1075             }
1076         }
1077 
1078         return valid;
1079     }
1080 
1081 
1082     /**
1083      * Validates that the Vendor Fax Number is a valid phone number.
1084      *
1085      * @param addresses VendorAddress instance
1086      * @return boolean false or true
1087      */
1088     boolean checkFaxNumber(VendorAddress address) {
1089         boolean valid = true;
1090         String faxNumber = address.getVendorFaxNumber();
1091         boolean foriegnVendor=false;
1092         if (newVendor.getVendorHeader() != null) {
1093             if (newVendor.getVendorHeader().getVendorForeignIndicator() != null) {
1094                 foriegnVendor = newVendor.getVendorHeader().getVendorForeignIndicator();
1095             }
1096         }
1097 
1098         if(foriegnVendor) {
1099 
1100             if(StringUtils.isNotEmpty(faxNumber) && !SpringContext.getBean(OleForiegnVendorPhoneNumberService.class).isValidForiegnVendorPhoneNumber(faxNumber)){
1101                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_FAX_NUMBER, VendorKeyConstants.ERROR_FORIEGN_VENDOR_FAX_NUMBER);
1102                 valid &= false;
1103             }
1104         }
1105         else {
1106             if (StringUtils.isNotEmpty(faxNumber) && !SpringContext.getBean(PhoneNumberService.class).isValidPhoneNumber(faxNumber)) {
1107                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_FAX_NUMBER, VendorKeyConstants.ERROR_FAX_NUMBER);
1108                 valid &= false;
1109             }
1110         }
1111         return valid;
1112     }
1113 
1114     boolean checkPhoneNumber(VendorPhoneNumber vendorPhoneNumber){
1115         boolean valid = true;
1116         String phoneNumber = vendorPhoneNumber.getVendorPhoneNumber();
1117         boolean foriegnVendor=false;
1118         if (newVendor.getVendorHeader() != null) {
1119             if (newVendor.getVendorHeader().getVendorForeignIndicator() != null) {
1120                 foriegnVendor = newVendor.getVendorHeader().getVendorForeignIndicator();
1121             }
1122         }
1123         if(foriegnVendor) {
1124 
1125             if(StringUtils.isNotEmpty(phoneNumber) && !SpringContext.getBean(OleForiegnVendorPhoneNumberService.class).isValidForiegnVendorPhoneNumber(phoneNumber)){
1126                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_PHONE_NUMBER, VendorKeyConstants.ERROR_FORIEGN_VENDOR_PHONE_NUMBER);
1127                 valid &= false;
1128             }
1129         }
1130         else {
1131             if (StringUtils.isNotEmpty(phoneNumber) && !SpringContext.getBean(PhoneNumberService.class).isValidPhoneNumber(phoneNumber)) {
1132                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_PHONE_NUMBER, VendorKeyConstants.ERROR_PHONE_NUMBER);
1133                 valid &= false;
1134             }
1135         }
1136         return valid;
1137     }
1138 
1139     /**
1140      * A stub method as placeholder for future Contact Validation
1141      *
1142      * @param document MaintenanceDocument instance
1143      * @return boolean false or true
1144      */
1145     private boolean processContactValidation(MaintenanceDocument document) {
1146         boolean valid = true;
1147         int i = 0;
1148         for (VendorContact contact : newVendor.getVendorContacts()) {
1149             String errorPath = MAINTAINABLE_ERROR_PREFIX + VendorPropertyConstants.VENDOR_CONTACT + "[" + i + "]";
1150             GlobalVariables.getMessageMap().addToErrorPath(errorPath);
1151 
1152             this.getDictionaryValidationService().validateBusinessObject(contact);
1153             Map<String, AutoPopulatingList<ErrorMessage>> errors = GlobalVariables.getMessageMap().getErrorMessages();
1154             if ((errors != null ) && (!errors.isEmpty())) {
1155                 valid = false;
1156             }
1157             i++;
1158             GlobalVariables.getMessageMap().clearErrorPath();
1159         }
1160         return valid;
1161     }
1162 
1163     /**
1164      * Validates vendor customer numbers
1165      *
1166      * @param document MaintenanceDocument instance
1167      * @return boolean false or true
1168      */
1169     private boolean processCustomerNumberValidation(MaintenanceDocument document) {
1170         boolean valid = true;
1171 
1172         List<VendorCustomerNumber> customerNumbers = newVendor.getVendorCustomerNumbers();
1173         for (VendorCustomerNumber customerNumber : customerNumbers) {
1174             valid &= validateVendorCustomerNumber(customerNumber);
1175         }
1176         return valid;
1177     }
1178 
1179     /**
1180      * Validates vendor customer number. The chart and org must exist in the database.
1181      *
1182      * @param customerNumber VendorCustomerNumber
1183      * @return boolean false or true
1184      */
1185     boolean validateVendorCustomerNumber(VendorCustomerNumber customerNumber) {
1186         boolean valid = true;
1187 
1188         // The chart and org must exist in the database.
1189         String chartOfAccountsCode = customerNumber.getChartOfAccountsCode();
1190         String orgCode = customerNumber.getVendorOrganizationCode();
1191         String carrierCode = customerNumber.getVendorStandardDeliveryCarrier();
1192         if (!StringUtils.isBlank(chartOfAccountsCode) && !StringUtils.isBlank(orgCode)) {
1193             Map chartOrgMap = new HashMap();
1194             chartOrgMap.put("chartOfAccountsCode", chartOfAccountsCode);
1195             if (SpringContext.getBean(BusinessObjectService.class).countMatching(Chart.class, chartOrgMap) < 1) {
1196                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CUSTOMER_NUMBER_CHART_OF_ACCOUNTS_CODE, OLEKeyConstants.ERROR_EXISTENCE, chartOfAccountsCode);
1197                 valid &= false;
1198             }
1199             chartOrgMap.put("organizationCode", orgCode);
1200             if (SpringContext.getBean(BusinessObjectService.class).countMatching(Organization.class, chartOrgMap) < 1) {
1201                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CUSTOMER_NUMBER_ORGANIZATION_CODE, OLEKeyConstants.ERROR_EXISTENCE, orgCode);
1202                 valid &= false;
1203             }
1204 
1205         }
1206         if (!StringUtils.isBlank(carrierCode)) {
1207             Map carrierMap = new HashMap();
1208             carrierMap.put("carrierCode", carrierCode);
1209             if (SpringContext.getBean(BusinessObjectService.class).countMatching(Carrier.class, carrierMap) < 1) {
1210                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CARRIER_CODE, OLEKeyConstants.ERROR_EXISTENCE, carrierCode);
1211                 valid &= false;
1212             }
1213         }
1214 
1215         return valid;
1216     }
1217 
1218    /* boolean validateVendorAlias(VendorAlias vendorAlias){
1219         boolean valid = true;
1220         String aliasName = vendorAlias.getVendorAliasName();
1221         if (!StringUtils.isBlank(aliasName)) {
1222             Map vendorAliasMap = new HashMap();
1223             vendorAliasMap.put("aliasType", aliasName);
1224          if (SpringContext.getBean(BusinessObjectService.class).countMatching(AliasType.class, vendorAliasMap) < 1) {
1225                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_ALIAS_NAME, OLEKeyConstants.ERROR_EXISTENCE, aliasName);
1226                 valid &= false;
1227             }
1228             Integer aliasId = vendorAlias.getVendorAliasTypeId()!=null?vendorAlias.getVendorAliasTypeId():0;
1229             if(aliasId == 0){
1230                 String aliasCode = String.valueOf(aliasId);
1231                 GlobalVariables.getMessageMap().putError("aliasTypeId", OLEKeyConstants.ERROR_REQUIRED, "Please select any search Alias Name from Lookup.Alias code");
1232                 valid &= false;
1233             }
1234         }
1235         return valid;
1236     }*/
1237 
1238     /**
1239      * Validates vendor contract. If the vendorContractAllowedIndicator is false, it cannot have vendor contracts, then return false
1240      *
1241      * @param document MaintenanceDocument
1242      * @return boolean false or true
1243      */
1244     private boolean processContractValidation(MaintenanceDocument document) {
1245         boolean valid = true;
1246         List<VendorContract> contracts = newVendor.getVendorContracts();
1247         if (ObjectUtils.isNull(contracts)) {
1248             return valid;
1249         }
1250 
1251         // If the vendorContractAllowedIndicator is false, it cannot have vendor contracts, return false;
1252         if (contracts.size() > 0 && !newVendor.getVendorHeader().getVendorType().isVendorContractAllowedIndicator()) {
1253             valid = false;
1254             String errorPath = MAINTAINABLE_ERROR_PREFIX + VendorPropertyConstants.VENDOR_CONTRACT + "[0]";
1255             GlobalVariables.getMessageMap().addToErrorPath(errorPath);
1256             GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_NAME, VendorKeyConstants.ERROR_VENDOR_CONTRACT_NOT_ALLOWED);
1257             GlobalVariables.getMessageMap().removeFromErrorPath(errorPath);
1258             return valid;
1259         }
1260 
1261         for (int i = 0; i < contracts.size(); i++) {
1262             VendorContract contract = contracts.get(i);
1263 
1264             String errorPath = MAINTAINABLE_ERROR_PREFIX + VendorPropertyConstants.VENDOR_CONTRACT + "[" + i + "]";
1265             GlobalVariables.getMessageMap().addToErrorPath(errorPath);
1266 
1267             valid &= validateVendorContractPOLimitAndExcludeFlagCombination(contract);
1268             valid &= validateVendorContractBeginEndDates(contract);
1269             valid &= processContractB2BValidation(document, contract, i);
1270 
1271             GlobalVariables.getMessageMap().removeFromErrorPath(errorPath);
1272         }
1273 
1274 
1275         return valid;
1276     }
1277 
1278     /**
1279      * Validates that the proper combination of Exclude Indicator and APO Amount is present on a vendor contract. Do not perform
1280      * this validation on Contract add line as the user cannot currently enter the sub-collection of contract-orgs so we should not
1281      * force this until the document is submitted. The rules are : 1. Must enter a Default APO Limit or at least one organization
1282      * with an APO Amount. 2. If the Exclude Indicator for an organization is N, an organization APO Amount is required. 3. If the
1283      * Exclude Indicator for an organization is Y, the organization APO Amount is not allowed.
1284      *
1285      * @param contract VendorContract
1286      * @return boolean true if the proper combination of Exclude Indicator and APO Amount is present, otherwise flase.
1287      */
1288     boolean validateVendorContractPOLimitAndExcludeFlagCombination(VendorContract contract) {
1289         boolean valid = true;
1290         boolean NoOrgHasApoLimit = true;
1291 
1292         List<VendorContractOrganization> organizations = contract.getVendorContractOrganizations();
1293         if (ObjectUtils.isNotNull(organizations)) {
1294             int organizationCounter = 0;
1295             for (VendorContractOrganization organization : organizations) {
1296                 if (ObjectUtils.isNotNull(organization.getVendorContractPurchaseOrderLimitAmount())) {
1297                     NoOrgHasApoLimit = false;
1298                 }
1299                 valid &= validateVendorContractOrganization(organization);
1300                 organizationCounter++;
1301             }
1302         }
1303         if (NoOrgHasApoLimit && ObjectUtils.isNull(contract.getOrganizationAutomaticPurchaseOrderLimit())) {
1304             // Rule #1 in the above java doc has been violated.
1305             GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_DEFAULT_APO_LIMIT, VendorKeyConstants.ERROR_VENDOR_CONTRACT_NO_APO_LIMIT);
1306             valid &= false;
1307         }
1308         return valid;
1309     }
1310 
1311     /**
1312      * Validates that: 1. If the VendorContractBeginningDate is entered then the VendorContractEndDate is also entered, and vice
1313      * versa. 2. If both dates are entered, the VendorContractBeginningDate is before the VendorContractEndDate. The date fields are
1314      * required so we should know that we have valid dates.
1315      *
1316      * @param contract VendorContract
1317      * @return boolean true if the beginning date is before the end date, false if only one date is entered or the beginning date is
1318      *         after the end date.
1319      */
1320     boolean validateVendorContractBeginEndDates(VendorContract contract) {
1321         boolean valid = true;
1322 
1323         if (ObjectUtils.isNotNull(contract.getVendorContractBeginningDate()) && ObjectUtils.isNull(contract.getVendorContractEndDate())) {
1324             GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_END_DATE, VendorKeyConstants.ERROR_VENDOR_CONTRACT_BEGIN_DATE_NO_END_DATE);
1325             valid &= false;
1326         }
1327         else {
1328             if (ObjectUtils.isNull(contract.getVendorContractBeginningDate()) && ObjectUtils.isNotNull(contract.getVendorContractEndDate())) {
1329                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_BEGIN_DATE, VendorKeyConstants.ERROR_VENDOR_CONTRACT_END_DATE_NO_BEGIN_DATE);
1330                 valid &= false;
1331             }
1332         }
1333         if (valid && ObjectUtils.isNotNull(contract.getVendorContractBeginningDate()) && ObjectUtils.isNotNull(contract.getVendorContractEndDate())) {
1334             if (contract.getVendorContractBeginningDate().after(contract.getVendorContractEndDate())) {
1335                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_BEGIN_DATE, VendorKeyConstants.ERROR_VENDOR_CONTRACT_BEGIN_DATE_AFTER_END);
1336                 valid &= false;
1337             }
1338         }
1339 
1340         return valid;
1341     }
1342 
1343     /**
1344      * Validates a vendor contract organization. The rules are : 1. If the Exclude Indicator for the organization is N, an
1345      * organization APO Amount is required. 2. If the Exclude Indicator for the organization is Y, an organization APO Amount is not
1346      * allowed. 3. The chart and org for the organization must exist in the database.
1347      *
1348      * @param organization VendorContractOrganization
1349      * @return boolean true if these three rules are passed, otherwise false.
1350      */
1351     boolean validateVendorContractOrganization(VendorContractOrganization organization) {
1352         boolean valid = true;
1353 
1354         boolean isExcluded = organization.isVendorContractExcludeIndicator();
1355         if (isExcluded) {
1356             if (ObjectUtils.isNotNull(organization.getVendorContractPurchaseOrderLimitAmount())) {
1357                 // Rule #2 in the above java doc has been violated.
1358                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_ORGANIZATION_APO_LIMIT, VendorKeyConstants.ERROR_VENDOR_CONTRACT_ORG_EXCLUDED_WITH_APO_LIMIT);
1359                 valid &= false;
1360             }
1361         }
1362         else { // isExcluded = false
1363             if (ObjectUtils.isNull(organization.getVendorContractPurchaseOrderLimitAmount())) {
1364                 // Rule #1 in the above java doc has been violated.
1365                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_ORGANIZATION_APO_LIMIT, VendorKeyConstants.ERROR_VENDOR_CONTRACT_ORG_NOT_EXCLUDED_NO_APO_LIMIT);
1366                 valid &= false;
1367             }
1368         }
1369 
1370         // The chart and org must exist in the database.
1371         String chartOfAccountsCode = organization.getChartOfAccountsCode();
1372         String orgCode = organization.getOrganizationCode();
1373         if (!StringUtils.isBlank(chartOfAccountsCode) && !StringUtils.isBlank(orgCode)) {
1374             Map chartOrgMap = new HashMap();
1375             chartOrgMap.put("chartOfAccountsCode", chartOfAccountsCode);
1376             if (SpringContext.getBean(BusinessObjectService.class).countMatching(Chart.class, chartOrgMap) < 1) {
1377                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_CHART_OF_ACCOUNTS_CODE, OLEKeyConstants.ERROR_EXISTENCE, chartOfAccountsCode);
1378                 valid &= false;
1379             }
1380             chartOrgMap.put("organizationCode", orgCode);
1381             if (SpringContext.getBean(BusinessObjectService.class).countMatching(Organization.class, chartOrgMap) < 1) {
1382                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_ORGANIZATION_CODE, OLEKeyConstants.ERROR_EXISTENCE, orgCode);
1383                 valid &= false;
1384             }
1385         }
1386 
1387         return valid;
1388     }
1389 
1390     /**
1391      * Validates vendor contracts against single B2B restriction on a vendor/campus basis. Only one B2B contract allowed per vendor/campus
1392      *
1393      * @param document MaintenanceDocument
1394      * @return boolean false or true
1395      */
1396     private boolean processContractB2BValidation(MaintenanceDocument document, VendorContract contract, int contractPos) {
1397         boolean valid = true;
1398         List<Integer> indexOfB2BContracts = new ArrayList();
1399         //list of contracts already associated with vendor
1400         List<VendorContract> contracts = newVendor.getVendorContracts();
1401         if (ObjectUtils.isNull(contracts)) {
1402             return valid;
1403         }
1404         //find all b2b contracts for comparison
1405         if(contractPos == -1){
1406             if(contract.getVendorB2bIndicator()){
1407                 for (int i = 0; i < contracts.size(); i++) {
1408                     VendorContract vndrContract = contracts.get(i);
1409                     if(vndrContract.getVendorB2bIndicator()){
1410                         //check for duplicate campus; vendor is implicitly the same
1411                         if(contract.getVendorCampusCode().equals(vndrContract.getVendorCampusCode())){
1412                             valid &= false;
1413                             GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_B2B_INDICATOR, VendorKeyConstants.ERROR_VENDOR_CONTRACT_B2B_LIMIT_EXCEEDED, contract.getVendorCampusCode());
1414                         }
1415                     }
1416                 }
1417             }
1418         } else
1419         {
1420             if(contract.getVendorB2bIndicator()){
1421                 for (int i = 0; i < contracts.size(); i++) {
1422                     VendorContract vndrContract = contracts.get(i);
1423                     if(vndrContract.getVendorB2bIndicator()){
1424                         //make sure we're not checking contracts against themselves
1425                         if(i != contractPos){
1426                             //check for duplicate campus; vendor is implicitly the same
1427                             if(contract.getVendorCampusCode().equals(vndrContract.getVendorCampusCode())){
1428                                 valid &= false;
1429                                 String [] errorArray = new String []{contract.getVendorContractName(), contract.getVendorCampusCode()};
1430                                 GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_CONTRACT_B2B_INDICATOR, VendorKeyConstants.ERROR_VENDOR_CONTRACT_B2B_LIMIT_EXCEEDED_DB, errorArray);
1431                             }
1432                         }
1433                     }
1434                 }
1435             }
1436         }
1437        return valid;
1438     }
1439 
1440     /**
1441      * Validates business rules for VendorDetail document collection add lines. Add lines are the initial lines on a collections,
1442      * i.e. the ones next to the "Add" button
1443      *
1444      * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomAddCollectionLineBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument,
1445      *      java.lang.String, org.kuali.rice.krad.bo.PersistableBusinessObject)
1446      */
1447     @Override
1448     public boolean processCustomAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName, PersistableBusinessObject bo) {
1449         boolean success = true;
1450 
1451         // this incoming bo needs to be refreshed because it doesn't have its subobjects setup
1452         bo.refreshNonUpdateableReferences();
1453 
1454         if (bo instanceof VendorAddress) {
1455             VendorAddress address = (VendorAddress) bo;
1456             success &= checkAddressCountryEmptyStateZip(address);
1457             VendorDetail vendorDetail = (VendorDetail) document.getNewMaintainableObject().getBusinessObject();
1458         }
1459         if (bo instanceof VendorContract) {
1460             VendorContract contract = (VendorContract) bo;
1461             success &= validateVendorContractBeginEndDates(contract);
1462             success &= processContractB2BValidation(document,contract, -1);
1463         }
1464         if (bo instanceof VendorContractOrganization) {
1465             VendorContractOrganization contractOrg = (VendorContractOrganization) bo;
1466             success &= validateVendorContractOrganization(contractOrg);
1467         }
1468         if (bo instanceof VendorCustomerNumber) {
1469             VendorCustomerNumber customerNumber = (VendorCustomerNumber) bo;
1470             success &= validateVendorCustomerNumber(customerNumber);
1471         }
1472       /*  if (bo instanceof VendorAlias) {
1473             VendorAlias vendorAlias = (VendorAlias) bo;
1474             success &= validateVendorAlias(vendorAlias);
1475         }*/
1476 
1477         if (bo instanceof VendorTransmissionFormatDetail) {
1478             VendorDetail newVendorDetail  = (VendorDetail) document.getNewMaintainableObject().getBusinessObject();
1479             newVendorDetail.refreshNonUpdateableReferences();
1480             VendorTransmissionFormatDetail vendorTransmissionFormatDetail = (VendorTransmissionFormatDetail) bo;
1481             success &= validateVendorTransmissionFormatDetail(vendorTransmissionFormatDetail,newVendorDetail);
1482         }
1483 
1484         if (bo instanceof VendorDefaultAddress) {
1485             VendorDefaultAddress defaultAddress = (VendorDefaultAddress) bo;
1486             String parentName = StringUtils.substringBeforeLast(collectionName, ".");
1487             VendorAddress parent = (VendorAddress) ObjectUtils.getPropertyValue(this.getNewBo(), parentName);
1488             VendorDetail vendorDetail = (VendorDetail) document.getNewMaintainableObject().getBusinessObject();
1489             success &= checkDefaultAddressCampus(vendorDetail, defaultAddress, parent);
1490         }
1491 
1492         return success;
1493     }
1494 
1495 
1496       boolean validateVendorTransmissionFormatDetail(VendorTransmissionFormatDetail vendorTransmissionFormatDetail,VendorDetail vendorDetail){
1497        boolean valid = true;
1498        boolean preferredTransmissionFlag = false;
1499        int oldPreferredTransmissionFlagCount = 0;
1500        boolean newVendorPreferredTransmissionFormat = vendorTransmissionFormatDetail.isVendorPreferredTransmissionFormat();
1501           for (VendorTransmissionFormatDetail oldVendorTransmissionFormatDetail : vendorDetail.getVendorTransmissionFormat()) {
1502               oldVendorTransmissionFormatDetail.refreshNonUpdateableReferences();
1503               if(oldVendorTransmissionFormatDetail.isVendorPreferredTransmissionFormat()){
1504                 preferredTransmissionFlag = true;
1505                 oldPreferredTransmissionFlagCount = oldPreferredTransmissionFlagCount + 1;
1506              }
1507           }
1508          if(oldPreferredTransmissionFlagCount > 1){
1509              GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_PREFERRED_TRANSMISSION, OLEKeyConstants.ERROR_DUPLICATE_PREFERRED_FORMAT, "preferred transmission format");
1510              valid &= false;
1511          }
1512          if(newVendorPreferredTransmissionFormat && preferredTransmissionFlag){
1513             GlobalVariables.getMessageMap().putError(VendorPropertyConstants.VENDOR_PREFERRED_TRANSMISSION, OLEKeyConstants.ERROR_DUPLICATE_PREFERRED_FORMAT, "preferred transmission format");
1514             valid &= false;
1515          }
1516 
1517        return valid;
1518     }
1519 
1520     /**
1521      * Validates the rule that if a document has a federal witholding tax begin date and end date, the begin date should come before
1522      * the end date.
1523      *
1524      * @param vdDocument VendorDetail
1525      * @return boolean false or true
1526      */
1527     private boolean validateVendorWithholdingTaxDates(VendorDetail vdDocument) {
1528         boolean valid = true;
1529         DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
1530 
1531         Date beginDate = vdDocument.getVendorHeader().getVendorFederalWithholdingTaxBeginningDate();
1532         Date endDate = vdDocument.getVendorHeader().getVendorFederalWithholdingTaxEndDate();
1533         if (ObjectUtils.isNotNull(beginDate) && ObjectUtils.isNotNull(endDate)) {
1534             if (dateTimeService.dateDiff(beginDate, endDate, false) <= 0) {
1535                 putFieldError(VendorPropertyConstants.VENDOR_FEDERAL_WITHOLDING_TAX_BEGINNING_DATE, VendorKeyConstants.ERROR_VENDOR_TAX_BEGIN_DATE_AFTER_END);
1536                 valid &= false;
1537             }
1538         }
1539         return valid;
1540 
1541     }
1542 
1543     /**
1544      * Validates the rule that both w9 received and w-8ben cannot be set to yes
1545      *
1546      * @param vdDocument VendorDetail
1547      * @return boolean false or true
1548      */
1549     private boolean validateVendorW8BenOrW9ReceivedIndicator(VendorDetail vdDocument) {
1550         boolean valid = true;
1551 
1552         if (ObjectUtils.isNotNull(vdDocument.getVendorHeader().getVendorW9ReceivedIndicator()) && ObjectUtils.isNotNull(vdDocument.getVendorHeader().getVendorW8BenReceivedIndicator()) && vdDocument.getVendorHeader().getVendorW9ReceivedIndicator() && vdDocument.getVendorHeader().getVendorW8BenReceivedIndicator()) {
1553             putFieldError(VendorPropertyConstants.VENDOR_W9_RECEIVED_INDICATOR, VendorKeyConstants.ERROR_VENDOR_W9_AND_W8_RECEIVED_INDICATOR_BOTH_TRUE);
1554             valid &= false;
1555         }
1556         return valid;
1557 
1558     }
1559 
1560     /**
1561      * Overrides the method in MaintenanceDocumentRuleBase to give error message to the user when
1562      * the user tries to add a vendor contract when the vendor type of the vendor does not allow
1563      * contract.
1564      *
1565      * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processAddCollectionLineBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument, java.lang.String, org.kuali.rice.krad.bo.PersistableBusinessObject)
1566      */
1567     @Override
1568     public boolean processAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName, PersistableBusinessObject bo) {
1569         if (collectionName.equals(VendorPropertyConstants.VENDOR_CONTRACT)) {
1570             VendorDetail vendorDetail = (VendorDetail)document.getDocumentBusinessObject();
1571             vendorDetail.getVendorHeader().refreshReferenceObject("vendorType");
1572             VendorType vendorType = vendorDetail.getVendorHeader().getVendorType();
1573             if (!vendorType.isVendorContractAllowedIndicator()) {
1574                 String propertyName = "add." + collectionName + "." + VendorPropertyConstants.VENDOR_CONTRACT_NAME;
1575                 putFieldError(propertyName, VendorKeyConstants.ERROR_VENDOR_CONTRACT_NOT_ALLOWED);
1576                 return false;
1577             }
1578         }
1579         return super.processAddCollectionLineBusinessRules(document, collectionName, bo);
1580     }
1581 }