001// -------------------------------------------------------------------------------- 002// Copyright 2002-2025 Echo Three, LLC 003// 004// Licensed under the Apache License, Version 2.0 (the "License"); 005// you may not use this file except in compliance with the License. 006// You may obtain a copy of the License at 007// 008// http://www.apache.org/licenses/LICENSE-2.0 009// 010// Unless required by applicable law or agreed to in writing, software 011// distributed under the License is distributed on an "AS IS" BASIS, 012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013// See the License for the specific language governing permissions and 014// limitations under the License. 015// -------------------------------------------------------------------------------- 016 017package com.echothree.control.user.search.server.command; 018 019import com.echothree.control.user.search.common.form.SearchCustomersForm; 020import com.echothree.control.user.search.common.result.SearchResultFactory; 021import com.echothree.model.control.customer.server.control.CustomerControl; 022import com.echothree.model.control.geo.server.control.GeoControl; 023import com.echothree.model.control.party.common.PartyTypes; 024import com.echothree.model.control.party.server.control.PartyControl; 025import com.echothree.model.control.search.common.SearchKinds; 026import com.echothree.model.control.search.server.control.SearchControl; 027import com.echothree.model.control.customer.server.search.CustomerSearchEvaluator; 028import com.echothree.model.control.search.server.logic.SearchLogic; 029import com.echothree.model.control.security.common.SecurityRoleGroups; 030import com.echothree.model.control.security.common.SecurityRoles; 031import com.echothree.model.data.party.server.entity.PartyAliasType; 032import com.echothree.model.data.user.common.pk.UserVisitPK; 033import com.echothree.util.common.message.ExecutionErrors; 034import com.echothree.util.common.string.StringUtils; 035import com.echothree.util.common.validation.FieldDefinition; 036import com.echothree.util.common.validation.FieldType; 037import com.echothree.util.common.command.BaseResult; 038import com.echothree.util.common.form.ValidationResult; 039import com.echothree.util.server.control.BaseSimpleCommand; 040import com.echothree.util.server.control.CommandSecurityDefinition; 041import com.echothree.util.server.control.PartyTypeDefinition; 042import com.echothree.util.server.control.SecurityRoleDefinition; 043import com.echothree.util.server.persistence.Session; 044import com.echothree.util.server.validation.Validator; 045import com.google.common.base.Splitter; 046import java.util.Arrays; 047import java.util.Collections; 048import java.util.List; 049import java.util.Locale; 050import java.util.regex.Pattern; 051import javax.enterprise.context.RequestScoped; 052 053@RequestScoped 054public class SearchCustomersCommand 055 extends BaseSimpleCommand<SearchCustomersForm> { 056 057 private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION; 058 private final static List<FieldDefinition> FORM_FIELD_DEFINITIONS; 059 private final static List<FieldDefinition> formAliasFieldDefinitions; 060 061 static { 062 COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(Collections.unmodifiableList(Arrays.asList( 063 new PartyTypeDefinition(PartyTypes.UTILITY.name(), null), 064 new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), Collections.unmodifiableList(Arrays.asList( 065 new SecurityRoleDefinition(SecurityRoleGroups.Customer.name(), SecurityRoles.Search.name()) 066 ))) 067 ))); 068 069 FORM_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList( 070 new FieldDefinition("SearchTypeName", FieldType.ENTITY_NAME, true, null, null), 071 new FieldDefinition("CustomerTypeName", FieldType.ENTITY_NAME, false, null, null), 072 new FieldDefinition("FirstName", FieldType.STRING, false, 1L, 20L), 073 new FieldDefinition("FirstNameSoundex", FieldType.BOOLEAN, false, null, null), 074 new FieldDefinition("MiddleName", FieldType.STRING, false, 1L, 20L), 075 new FieldDefinition("MiddleNameSoundex", FieldType.BOOLEAN, false, null, null), 076 new FieldDefinition("LastName", FieldType.STRING, false, 1L, 20L), 077 new FieldDefinition("LastNameSoundex", FieldType.BOOLEAN, false, null, null), 078 new FieldDefinition("Name", FieldType.STRING, false, null, null), 079 new FieldDefinition("CountryName", FieldType.ENTITY_NAME, false, null, null), 080 new FieldDefinition("AreaCode", FieldType.STRING, false, 1L, 5L), 081 new FieldDefinition("TelephoneNumber", FieldType.STRING, false, 1L, 25L), 082 new FieldDefinition("TelephoneExtension", FieldType.NUMBERS, false, 1L, 10L), 083 new FieldDefinition("EmailAddress", FieldType.EMAIL_ADDRESS, false, null, null), 084 new FieldDefinition("CustomerName", FieldType.ENTITY_NAME, false, null, null), 085 new FieldDefinition("PartyName", FieldType.ENTITY_NAME, false, null, null), 086 new FieldDefinition("PartyAliasTypeName", FieldType.ENTITY_NAME, false, null, null), 087 new FieldDefinition("Alias", FieldType.ENTITY_NAME, false, null, null), 088 new FieldDefinition("CreatedSince", FieldType.DATE_TIME, false, null, null), 089 new FieldDefinition("ModifiedSince", FieldType.DATE_TIME, false, null, null), 090 new FieldDefinition("Fields", FieldType.STRING, false, null, null) 091 )); 092 093 formAliasFieldDefinitions = Collections.unmodifiableList(Arrays.asList( 094 new FieldDefinition("Alias", FieldType.ENTITY_NAME, true, null, null) 095 )); 096 } 097 098 /** Creates a new instance of SearchCustomersCommand */ 099 public SearchCustomersCommand() { 100 super(COMMAND_SECURITY_DEFINITION, FORM_FIELD_DEFINITIONS, false); 101 } 102 103 @Override 104 protected ValidationResult validate() { 105 var validator = new Validator(this); 106 var validationResult = validator.validate(form, FORM_FIELD_DEFINITIONS); 107 108 if(!validationResult.getHasErrors()) { 109 var partyAliasTypeName = form.getPartyAliasTypeName(); 110 111 if(partyAliasTypeName != null) { 112 validationResult = validator.validate(form, formAliasFieldDefinitions); 113 } 114 } 115 116 return validationResult; 117 } 118 119 @Override 120 protected BaseResult execute() { 121 var searchControl = Session.getModelController(SearchControl.class); 122 var result = SearchResultFactory.getSearchCustomersResult(); 123 var searchKind = searchControl.getSearchKindByName(SearchKinds.CUSTOMER.name()); 124 125 if(searchKind != null) { 126 var searchTypeName = form.getSearchTypeName(); 127 var searchType = searchControl.getSearchTypeByName(searchKind, searchTypeName); 128 129 if(searchType != null) { 130 var customerControl = Session.getModelController(CustomerControl.class); 131 var customerTypeName = form.getCustomerTypeName(); 132 var customerType = customerTypeName == null? null: customerControl.getCustomerTypeByName(customerTypeName); 133 134 if(customerTypeName == null || customerType != null) { 135 var partyAliasTypeName = form.getPartyAliasTypeName(); 136 var alias = form.getAlias(); 137 PartyAliasType partyAliasType = null; 138 139 if(partyAliasTypeName != null) { 140 var partyControl = Session.getModelController(PartyControl.class); 141 var partyType = partyControl.getPartyTypeByName(PartyTypes.CUSTOMER.name()); 142 143 if(partyType != null) { 144 partyAliasType = partyControl.getPartyAliasTypeByName(partyType, partyAliasTypeName); 145 146 if(partyAliasType == null) { 147 addExecutionError(ExecutionErrors.UnknownPartyAliasTypeName.name(), PartyTypes.CUSTOMER.name(), partyAliasTypeName); 148 } 149 } else { 150 addExecutionError(ExecutionErrors.UnknownPartyTypeName.name(), PartyTypes.CUSTOMER.name()); 151 } 152 } 153 154 if(!hasExecutionErrors()) { 155 var geoControl = Session.getModelController(GeoControl.class); 156 var countryName = form.getCountryName(); 157 var countryAlias = countryName == null ? null : StringUtils.getInstance().cleanStringToName(countryName).toUpperCase(Locale.getDefault()); 158 var countryGeoCode = countryAlias == null ? null : geoControl.getCountryByAlias(countryAlias); 159 160 if(countryName == null || countryGeoCode != null) { 161 var geoCodeCountry = countryGeoCode == null ? null : geoControl.getGeoCodeCountry(countryGeoCode); 162 var areaCode = form.getAreaCode(); 163 var areaCodePattern = geoCodeCountry == null ? null : geoCodeCountry.getAreaCodePattern(); 164 var pattern = areaCodePattern == null ? null : Pattern.compile(areaCodePattern); 165 166 if(areaCode == null || (pattern == null || pattern.matcher(areaCode).matches())) { 167 var telephoneNumberPattern = countryGeoCode == null ? null : geoCodeCountry.getTelephoneNumberPattern(); 168 var telephoneNumber = form.getTelephoneNumber(); 169 170 pattern = telephoneNumberPattern == null ? null : Pattern.compile(telephoneNumberPattern); 171 172 if(telephoneNumber == null || (pattern == null || pattern.matcher(telephoneNumber).matches())) { 173 var searchLogic = SearchLogic.getInstance(); 174 var userVisit = getUserVisit(); 175 var customerSearchEvaluator = new CustomerSearchEvaluator(userVisit, searchType, 176 searchLogic.getDefaultSearchDefaultOperator(null), searchLogic.getDefaultSearchSortOrder(null, searchKind), 177 searchLogic.getDefaultSearchSortDirection(null)); 178 var createdSince = form.getCreatedSince(); 179 var modifiedSince = form.getModifiedSince(); 180 var fields = form.getFields(); 181 182 customerSearchEvaluator.setFirstName(form.getFirstName()); 183 customerSearchEvaluator.setFirstNameSoundex(Boolean.parseBoolean(form.getFirstNameSoundex())); 184 customerSearchEvaluator.setMiddleName(form.getMiddleName()); 185 customerSearchEvaluator.setMiddleNameSoundex(Boolean.parseBoolean(form.getMiddleNameSoundex())); 186 customerSearchEvaluator.setLastName(form.getLastName()); 187 customerSearchEvaluator.setLastNameSoundex(Boolean.parseBoolean(form.getLastNameSoundex())); 188 customerSearchEvaluator.setQ(this, form.getName()); 189 customerSearchEvaluator.setCountryGeoCode(countryGeoCode); 190 customerSearchEvaluator.setAreaCode(areaCode); 191 customerSearchEvaluator.setTelephoneNumber(telephoneNumber); 192 customerSearchEvaluator.setTelephoneExtension(form.getTelephoneExtension()); 193 customerSearchEvaluator.setEmailAddress(form.getEmailAddress()); 194 customerSearchEvaluator.setCustomerType(customerType); 195 customerSearchEvaluator.setPartyAliasType(partyAliasType); 196 customerSearchEvaluator.setAlias(alias); 197 customerSearchEvaluator.setCustomerName(form.getCustomerName()); 198 customerSearchEvaluator.setPartyName(form.getPartyName()); 199 customerSearchEvaluator.setCreatedSince(createdSince == null ? null : Long.valueOf(createdSince)); 200 customerSearchEvaluator.setModifiedSince(modifiedSince == null ? null : Long.valueOf(modifiedSince)); 201 customerSearchEvaluator.setFields(fields == null ? null : Splitter.on(':').trimResults().omitEmptyStrings().splitToList(fields).toArray(new String[0])); 202 203 if(!hasExecutionErrors()) { 204 result.setCount(customerSearchEvaluator.execute(this)); 205 } 206 } else { 207 addExecutionError(ExecutionErrors.InvalidTelephoneNumber.name(), telephoneNumber); 208 } 209 } else { 210 addExecutionError(ExecutionErrors.InvalidAreaCode.name(), areaCode); 211 } 212 } else { 213 addExecutionError(ExecutionErrors.UnknownCountryName.name(), countryName); 214 } 215 } 216 } else { 217 addExecutionError(ExecutionErrors.UnknownCustomerTypeName.name(), customerTypeName); 218 } 219 } else { 220 addExecutionError(ExecutionErrors.UnknownSearchTypeName.name(), SearchKinds.CUSTOMER.name(), searchTypeName); 221 } 222 } else { 223 addExecutionError(ExecutionErrors.UnknownSearchKindName.name(), SearchKinds.CUSTOMER.name()); 224 } 225 226 return result; 227 } 228}