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