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