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.persistence.Session; 044import com.echothree.util.server.validation.Validator; 045import com.google.common.base.Splitter; 046import java.util.List; 047import java.util.Locale; 048import java.util.regex.Pattern; 049import javax.enterprise.context.Dependent; 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 /** Creates a new instance of SearchCustomersCommand */ 097 public SearchCustomersCommand() { 098 super(COMMAND_SECURITY_DEFINITION, FORM_FIELD_DEFINITIONS, false); 099 } 100 101 @Override 102 protected ValidationResult validate() { 103 var validator = new Validator(this); 104 var validationResult = validator.validate(form, FORM_FIELD_DEFINITIONS); 105 106 if(!validationResult.getHasErrors()) { 107 var partyAliasTypeName = form.getPartyAliasTypeName(); 108 109 if(partyAliasTypeName != null) { 110 validationResult = validator.validate(form, formAliasFieldDefinitions); 111 } 112 } 113 114 return validationResult; 115 } 116 117 @Override 118 protected BaseResult execute() { 119 var searchControl = Session.getModelController(SearchControl.class); 120 var result = SearchResultFactory.getSearchCustomersResult(); 121 var searchKind = searchControl.getSearchKindByName(SearchKinds.CUSTOMER.name()); 122 123 if(searchKind != null) { 124 var searchTypeName = form.getSearchTypeName(); 125 var searchType = searchControl.getSearchTypeByName(searchKind, searchTypeName); 126 127 if(searchType != null) { 128 var customerControl = Session.getModelController(CustomerControl.class); 129 var customerTypeName = form.getCustomerTypeName(); 130 var customerType = customerTypeName == null? null: customerControl.getCustomerTypeByName(customerTypeName); 131 132 if(customerTypeName == null || customerType != null) { 133 var partyAliasTypeName = form.getPartyAliasTypeName(); 134 var alias = form.getAlias(); 135 PartyAliasType partyAliasType = null; 136 137 if(partyAliasTypeName != null) { 138 var partyControl = Session.getModelController(PartyControl.class); 139 var partyType = partyControl.getPartyTypeByName(PartyTypes.CUSTOMER.name()); 140 141 if(partyType != null) { 142 partyAliasType = partyControl.getPartyAliasTypeByName(partyType, partyAliasTypeName); 143 144 if(partyAliasType == null) { 145 addExecutionError(ExecutionErrors.UnknownPartyAliasTypeName.name(), PartyTypes.CUSTOMER.name(), partyAliasTypeName); 146 } 147 } else { 148 addExecutionError(ExecutionErrors.UnknownPartyTypeName.name(), PartyTypes.CUSTOMER.name()); 149 } 150 } 151 152 if(!hasExecutionErrors()) { 153 var geoControl = Session.getModelController(GeoControl.class); 154 var countryName = form.getCountryName(); 155 var countryAlias = countryName == null ? null : StringUtils.getInstance().cleanStringToName(countryName).toUpperCase(Locale.getDefault()); 156 var countryGeoCode = countryAlias == null ? null : geoControl.getCountryByAlias(countryAlias); 157 158 if(countryName == null || countryGeoCode != null) { 159 var geoCodeCountry = countryGeoCode == null ? null : geoControl.getGeoCodeCountry(countryGeoCode); 160 var areaCode = form.getAreaCode(); 161 var areaCodePattern = geoCodeCountry == null ? null : geoCodeCountry.getAreaCodePattern(); 162 var pattern = areaCodePattern == null ? null : Pattern.compile(areaCodePattern); 163 164 if(areaCode == null || (pattern == null || pattern.matcher(areaCode).matches())) { 165 var telephoneNumberPattern = countryGeoCode == null ? null : geoCodeCountry.getTelephoneNumberPattern(); 166 var telephoneNumber = form.getTelephoneNumber(); 167 168 pattern = telephoneNumberPattern == null ? null : Pattern.compile(telephoneNumberPattern); 169 170 if(telephoneNumber == null || (pattern == null || pattern.matcher(telephoneNumber).matches())) { 171 var searchLogic = SearchLogic.getInstance(); 172 var userVisit = getUserVisit(); 173 var customerSearchEvaluator = new CustomerSearchEvaluator(userVisit, searchType, 174 searchLogic.getDefaultSearchDefaultOperator(null), searchLogic.getDefaultSearchSortOrder(null, searchKind), 175 searchLogic.getDefaultSearchSortDirection(null)); 176 var createdSince = form.getCreatedSince(); 177 var modifiedSince = form.getModifiedSince(); 178 var fields = form.getFields(); 179 180 customerSearchEvaluator.setFirstName(form.getFirstName()); 181 customerSearchEvaluator.setFirstNameSoundex(Boolean.parseBoolean(form.getFirstNameSoundex())); 182 customerSearchEvaluator.setMiddleName(form.getMiddleName()); 183 customerSearchEvaluator.setMiddleNameSoundex(Boolean.parseBoolean(form.getMiddleNameSoundex())); 184 customerSearchEvaluator.setLastName(form.getLastName()); 185 customerSearchEvaluator.setLastNameSoundex(Boolean.parseBoolean(form.getLastNameSoundex())); 186 customerSearchEvaluator.setQ(this, form.getName()); 187 customerSearchEvaluator.setCountryGeoCode(countryGeoCode); 188 customerSearchEvaluator.setAreaCode(areaCode); 189 customerSearchEvaluator.setTelephoneNumber(telephoneNumber); 190 customerSearchEvaluator.setTelephoneExtension(form.getTelephoneExtension()); 191 customerSearchEvaluator.setEmailAddress(form.getEmailAddress()); 192 customerSearchEvaluator.setCustomerType(customerType); 193 customerSearchEvaluator.setPartyAliasType(partyAliasType); 194 customerSearchEvaluator.setAlias(alias); 195 customerSearchEvaluator.setCustomerName(form.getCustomerName()); 196 customerSearchEvaluator.setPartyName(form.getPartyName()); 197 customerSearchEvaluator.setCreatedSince(createdSince == null ? null : Long.valueOf(createdSince)); 198 customerSearchEvaluator.setModifiedSince(modifiedSince == null ? null : Long.valueOf(modifiedSince)); 199 customerSearchEvaluator.setFields(fields == null ? null : Splitter.on(':').trimResults().omitEmptyStrings().splitToList(fields).toArray(new String[0])); 200 201 if(!hasExecutionErrors()) { 202 result.setCount(customerSearchEvaluator.execute(this)); 203 } 204 } else { 205 addExecutionError(ExecutionErrors.InvalidTelephoneNumber.name(), telephoneNumber); 206 } 207 } else { 208 addExecutionError(ExecutionErrors.InvalidAreaCode.name(), areaCode); 209 } 210 } else { 211 addExecutionError(ExecutionErrors.UnknownCountryName.name(), countryName); 212 } 213 } 214 } else { 215 addExecutionError(ExecutionErrors.UnknownCustomerTypeName.name(), customerTypeName); 216 } 217 } else { 218 addExecutionError(ExecutionErrors.UnknownSearchTypeName.name(), SearchKinds.CUSTOMER.name(), searchTypeName); 219 } 220 } else { 221 addExecutionError(ExecutionErrors.UnknownSearchKindName.name(), SearchKinds.CUSTOMER.name()); 222 } 223 224 return result; 225 } 226}