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