001// -------------------------------------------------------------------------------- 002// Copyright 2002-2026 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.validation.Validator; 044import com.google.common.base.Splitter; 045import java.util.List; 046import java.util.Locale; 047import java.util.regex.Pattern; 048import javax.enterprise.context.Dependent; 049import javax.inject.Inject; 050 051@Dependent 052public class SearchCustomersCommand 053 extends BaseSimpleCommand<SearchCustomersForm> { 054 055 private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION; 056 private final static List<FieldDefinition> FORM_FIELD_DEFINITIONS; 057 private final static List<FieldDefinition> formAliasFieldDefinitions; 058 059 static { 060 COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of( 061 new PartyTypeDefinition(PartyTypes.UTILITY.name(), null), 062 new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of( 063 new SecurityRoleDefinition(SecurityRoleGroups.Customer.name(), SecurityRoles.Search.name()) 064 )) 065 )); 066 067 FORM_FIELD_DEFINITIONS = List.of( 068 new FieldDefinition("SearchTypeName", FieldType.ENTITY_NAME, true, null, null), 069 new FieldDefinition("CustomerTypeName", FieldType.ENTITY_NAME, false, null, null), 070 new FieldDefinition("FirstName", FieldType.STRING, false, 1L, 20L), 071 new FieldDefinition("FirstNameSoundex", FieldType.BOOLEAN, false, null, null), 072 new FieldDefinition("MiddleName", FieldType.STRING, false, 1L, 20L), 073 new FieldDefinition("MiddleNameSoundex", FieldType.BOOLEAN, false, null, null), 074 new FieldDefinition("LastName", FieldType.STRING, false, 1L, 20L), 075 new FieldDefinition("LastNameSoundex", FieldType.BOOLEAN, false, null, null), 076 new FieldDefinition("Name", FieldType.STRING, false, null, null), 077 new FieldDefinition("CountryName", FieldType.ENTITY_NAME, false, null, null), 078 new FieldDefinition("AreaCode", FieldType.STRING, false, 1L, 5L), 079 new FieldDefinition("TelephoneNumber", FieldType.STRING, false, 1L, 25L), 080 new FieldDefinition("TelephoneExtension", FieldType.NUMBERS, false, 1L, 10L), 081 new FieldDefinition("EmailAddress", FieldType.EMAIL_ADDRESS, false, null, null), 082 new FieldDefinition("CustomerName", FieldType.ENTITY_NAME, false, null, null), 083 new FieldDefinition("PartyName", FieldType.ENTITY_NAME, false, null, null), 084 new FieldDefinition("PartyAliasTypeName", FieldType.ENTITY_NAME, false, null, null), 085 new FieldDefinition("Alias", FieldType.ENTITY_NAME, false, null, null), 086 new FieldDefinition("CreatedSince", FieldType.DATE_TIME, false, null, null), 087 new FieldDefinition("ModifiedSince", FieldType.DATE_TIME, false, null, null), 088 new FieldDefinition("Fields", FieldType.STRING, false, null, null) 089 ); 090 091 formAliasFieldDefinitions = List.of( 092 new FieldDefinition("Alias", FieldType.ENTITY_NAME, true, null, null) 093 ); 094 } 095 096 @Inject 097 CustomerControl customerControl; 098 099 @Inject 100 GeoControl geoControl; 101 102 @Inject 103 PartyControl partyControl; 104 105 @Inject 106 SearchControl searchControl; 107 108 @Inject 109 SearchLogic searchLogic; 110 111 /** Creates a new instance of SearchCustomersCommand */ 112 public SearchCustomersCommand() { 113 super(COMMAND_SECURITY_DEFINITION, FORM_FIELD_DEFINITIONS, false); 114 } 115 116 @Override 117 protected ValidationResult validate() { 118 var validator = new Validator(this); 119 var validationResult = validator.validate(form, FORM_FIELD_DEFINITIONS); 120 121 if(!validationResult.getHasErrors()) { 122 var partyAliasTypeName = form.getPartyAliasTypeName(); 123 124 if(partyAliasTypeName != null) { 125 validationResult = validator.validate(form, formAliasFieldDefinitions); 126 } 127 } 128 129 return validationResult; 130 } 131 132 @Override 133 protected BaseResult execute() { 134 var result = SearchResultFactory.getSearchCustomersResult(); 135 var searchKind = searchControl.getSearchKindByName(SearchKinds.CUSTOMER.name()); 136 137 if(searchKind != null) { 138 var searchTypeName = form.getSearchTypeName(); 139 var searchType = searchControl.getSearchTypeByName(searchKind, searchTypeName); 140 141 if(searchType != null) { 142 var customerTypeName = form.getCustomerTypeName(); 143 var customerType = customerTypeName == null? null: customerControl.getCustomerTypeByName(customerTypeName); 144 145 if(customerTypeName == null || customerType != null) { 146 var partyAliasTypeName = form.getPartyAliasTypeName(); 147 var alias = form.getAlias(); 148 PartyAliasType partyAliasType = null; 149 150 if(partyAliasTypeName != null) { 151 var partyType = partyControl.getPartyTypeByName(PartyTypes.CUSTOMER.name()); 152 153 if(partyType != null) { 154 partyAliasType = partyControl.getPartyAliasTypeByName(partyType, partyAliasTypeName); 155 156 if(partyAliasType == null) { 157 addExecutionError(ExecutionErrors.UnknownPartyAliasTypeName.name(), PartyTypes.CUSTOMER.name(), partyAliasTypeName); 158 } 159 } else { 160 addExecutionError(ExecutionErrors.UnknownPartyTypeName.name(), PartyTypes.CUSTOMER.name()); 161 } 162 } 163 164 if(!hasExecutionErrors()) { 165 var countryName = form.getCountryName(); 166 var countryAlias = countryName == null ? null : StringUtils.getInstance().cleanStringToName(countryName).toUpperCase(Locale.getDefault()); 167 var countryGeoCode = countryAlias == null ? null : geoControl.getCountryByAlias(countryAlias); 168 169 if(countryName == null || countryGeoCode != null) { 170 var geoCodeCountry = countryGeoCode == null ? null : geoControl.getGeoCodeCountry(countryGeoCode); 171 var areaCode = form.getAreaCode(); 172 var areaCodePattern = geoCodeCountry == null ? null : geoCodeCountry.getAreaCodePattern(); 173 var pattern = areaCodePattern == null ? null : Pattern.compile(areaCodePattern); 174 175 if(areaCode == null || (pattern == null || pattern.matcher(areaCode).matches())) { 176 var telephoneNumberPattern = countryGeoCode == null ? null : geoCodeCountry.getTelephoneNumberPattern(); 177 var telephoneNumber = form.getTelephoneNumber(); 178 179 pattern = telephoneNumberPattern == null ? null : Pattern.compile(telephoneNumberPattern); 180 181 if(telephoneNumber == null || (pattern == null || pattern.matcher(telephoneNumber).matches())) { 182 var userVisit = getUserVisit(); 183 var customerSearchEvaluator = new CustomerSearchEvaluator(userVisit, searchType, 184 searchLogic.getDefaultSearchDefaultOperator(null), searchLogic.getDefaultSearchSortOrder(null, searchKind), 185 searchLogic.getDefaultSearchSortDirection(null)); 186 var createdSince = form.getCreatedSince(); 187 var modifiedSince = form.getModifiedSince(); 188 var fields = form.getFields(); 189 190 customerSearchEvaluator.setFirstName(form.getFirstName()); 191 customerSearchEvaluator.setFirstNameSoundex(Boolean.parseBoolean(form.getFirstNameSoundex())); 192 customerSearchEvaluator.setMiddleName(form.getMiddleName()); 193 customerSearchEvaluator.setMiddleNameSoundex(Boolean.parseBoolean(form.getMiddleNameSoundex())); 194 customerSearchEvaluator.setLastName(form.getLastName()); 195 customerSearchEvaluator.setLastNameSoundex(Boolean.parseBoolean(form.getLastNameSoundex())); 196 customerSearchEvaluator.setQ(this, form.getName()); 197 customerSearchEvaluator.setCountryGeoCode(countryGeoCode); 198 customerSearchEvaluator.setAreaCode(areaCode); 199 customerSearchEvaluator.setTelephoneNumber(telephoneNumber); 200 customerSearchEvaluator.setTelephoneExtension(form.getTelephoneExtension()); 201 customerSearchEvaluator.setEmailAddress(form.getEmailAddress()); 202 customerSearchEvaluator.setCustomerType(customerType); 203 customerSearchEvaluator.setPartyAliasType(partyAliasType); 204 customerSearchEvaluator.setAlias(alias); 205 customerSearchEvaluator.setCustomerName(form.getCustomerName()); 206 customerSearchEvaluator.setPartyName(form.getPartyName()); 207 customerSearchEvaluator.setCreatedSince(createdSince == null ? null : Long.valueOf(createdSince)); 208 customerSearchEvaluator.setModifiedSince(modifiedSince == null ? null : Long.valueOf(modifiedSince)); 209 customerSearchEvaluator.setFields(fields == null ? null : Splitter.on(':').trimResults().omitEmptyStrings().splitToList(fields).toArray(new String[0])); 210 211 if(!hasExecutionErrors()) { 212 result.setCount(customerSearchEvaluator.execute(this)); 213 } 214 } else { 215 addExecutionError(ExecutionErrors.InvalidTelephoneNumber.name(), telephoneNumber); 216 } 217 } else { 218 addExecutionError(ExecutionErrors.InvalidAreaCode.name(), areaCode); 219 } 220 } else { 221 addExecutionError(ExecutionErrors.UnknownCountryName.name(), countryName); 222 } 223 } 224 } else { 225 addExecutionError(ExecutionErrors.UnknownCustomerTypeName.name(), customerTypeName); 226 } 227 } else { 228 addExecutionError(ExecutionErrors.UnknownSearchTypeName.name(), SearchKinds.CUSTOMER.name(), searchTypeName); 229 } 230 } else { 231 addExecutionError(ExecutionErrors.UnknownSearchKindName.name(), SearchKinds.CUSTOMER.name()); 232 } 233 234 return result; 235 } 236}