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.IdentifyForm;
020import com.echothree.control.user.search.common.result.SearchResultFactory;
021import com.echothree.model.control.core.common.CoreOptions;
022import com.echothree.model.control.core.common.CoreProperties;
023import com.echothree.model.control.core.common.transfer.ComponentVendorTransfer;
024import com.echothree.model.control.core.common.transfer.EntityInstanceTransfer;
025import com.echothree.model.control.core.common.transfer.EntityTypeTransfer;
026import com.echothree.model.control.core.server.control.EntityAliasControl;
027import com.echothree.model.control.core.server.control.EntityInstanceControl;
028import com.echothree.model.control.core.server.search.ComponentVendorSearchEvaluator;
029import com.echothree.model.control.core.server.search.EntityAliasTypeSearchEvaluator;
030import com.echothree.model.control.core.server.search.EntityAttributeGroupSearchEvaluator;
031import com.echothree.model.control.core.server.search.EntityAttributeSearchEvaluator;
032import com.echothree.model.control.core.server.search.EntityListItemSearchEvaluator;
033import com.echothree.model.control.core.server.search.EntityTypeSearchEvaluator;
034import com.echothree.model.control.customer.server.control.CustomerControl;
035import com.echothree.model.control.customer.server.search.CustomerSearchEvaluator;
036import com.echothree.model.control.employee.server.control.EmployeeControl;
037import com.echothree.model.control.employee.server.search.EmployeeSearchEvaluator;
038import com.echothree.model.control.item.server.control.ItemControl;
039import com.echothree.model.control.item.server.search.ItemSearchEvaluator;
040import com.echothree.model.control.party.server.control.PartyControl;
041import com.echothree.model.control.search.common.SearchKinds;
042import com.echothree.model.control.search.common.SearchTypes;
043import com.echothree.model.control.search.server.control.SearchControl;
044import com.echothree.model.control.search.server.logic.SearchLogic;
045import com.echothree.model.control.security.common.SecurityRoleGroups;
046import com.echothree.model.control.security.common.SecurityRoles;
047import com.echothree.model.control.security.server.logic.SecurityRoleLogic;
048import com.echothree.model.control.vendor.server.control.VendorControl;
049import com.echothree.model.control.vendor.server.search.VendorSearchEvaluator;
050import com.echothree.model.control.warehouse.server.control.WarehouseControl;
051import com.echothree.model.control.warehouse.server.search.WarehouseSearchEvaluator;
052import com.echothree.model.data.party.server.entity.Party;
053import com.echothree.model.data.search.server.entity.SearchKind;
054import com.echothree.model.data.search.server.entity.SearchType;
055import com.echothree.model.data.user.server.entity.UserVisit;
056import com.echothree.util.common.command.BaseResult;
057import com.echothree.util.common.string.NameResult;
058import com.echothree.util.common.validation.FieldDefinition;
059import com.echothree.util.common.validation.FieldType;
060import com.echothree.util.server.control.BaseSimpleCommand;
061import com.echothree.util.server.message.DummyExecutionErrorAccumulator;
062import com.echothree.util.server.persistence.EntityNamesUtils;
063import com.echothree.util.server.persistence.Session;
064import com.echothree.util.server.persistence.translator.EntityInstanceAndNames;
065import com.echothree.util.server.string.NameCleaner;
066import com.echothree.util.server.validation.fieldtype.EntityNameFieldType;
067import java.util.HashSet;
068import java.util.List;
069import java.util.Set;
070import javax.enterprise.context.Dependent;
071import javax.inject.Inject;
072
073@Dependent
074public class IdentifyCommand
075        extends BaseSimpleCommand<IdentifyForm> {
076    
077    private final static List<FieldDefinition> FORM_FIELD_DEFINITIONS;
078    
079    static {
080        FORM_FIELD_DEFINITIONS = List.of(
081                new FieldDefinition("Target", FieldType.STRING, true, null, null)
082        );
083    }
084    
085    /** Creates a new instance of IdentifyCommand */
086    public IdentifyCommand() {
087        super(null, FORM_FIELD_DEFINITIONS, true);
088    }
089
090    @Inject
091    EntityAliasControl entityAliasControl;
092
093    @Override
094    protected void setupSession() {
095        super.setupSession();
096
097        // Names are always included in the JumpResult, assembly of them is a little weird, so always disallow this option.
098        removeOption(CoreOptions.EntityInstanceIncludeNames);
099
100        // Ensure we're able to compare instances of and generate a HashCode for the EntityInstanceTransfers
101        removeFilteredTransferProperty(EntityInstanceTransfer.class, CoreProperties.ENTITY_TYPE);
102        removeFilteredTransferProperty(EntityTypeTransfer.class, CoreProperties.COMPONENT_VENDOR);
103        removeFilteredTransferProperty(EntityTypeTransfer.class, CoreProperties.ENTITY_TYPE_NAME);
104        removeFilteredTransferProperty(ComponentVendorTransfer.class, CoreProperties.COMPONENT_VENDOR_NAME);
105    }
106    
107    private EntityInstanceTransfer fillInEntityInstance(EntityInstanceAndNames entityInstanceAndNames) {
108        var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
109        var entityInstance = entityInstanceControl.getEntityInstanceTransfer(getUserVisit(), entityInstanceAndNames.getEntityInstance(), false, false, false, false);
110
111        entityInstance.setEntityNames(entityInstanceAndNames.getEntityNames());
112        
113        return entityInstance;
114    }
115    
116    private void checkSequenceTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
117        var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(this, party, target, true);
118        
119        if(entityInstanceAndNames != null) {
120            entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
121        }
122    }
123    
124    private void checkItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
125        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
126                SecurityRoleGroups.Item.name(), SecurityRoles.Search.name())) {
127            var itemControl = Session.getModelController(ItemControl.class);
128            var item = itemControl.getItemByNameThenAlias(target);
129
130            if(item != null) {
131                var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
132                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(item.getPrimaryKey());
133                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
134
135                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
136            }
137        }
138    }
139
140    private void checkCompanies(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
141        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
142                SecurityRoleGroups.Company.name(), SecurityRoles.Search.name())) {
143            var partyControl = Session.getModelController(PartyControl.class);
144            var partyCompany = partyControl.getPartyCompanyByName(target);
145
146            if(partyCompany != null) {
147                var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
148                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(partyCompany.getParty().getPrimaryKey());
149                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
150
151                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
152            }
153        }
154    }
155
156    private void checkDivisions(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
157        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
158                SecurityRoleGroups.Division.name(), SecurityRoles.Search.name())) {
159            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
160            var partyControl = Session.getModelController(PartyControl.class);
161            var partyDivisions = partyControl.getDivisionsByName(target);
162
163            partyDivisions.stream().map((partyDivision) -> entityInstanceControl.getEntityInstanceByBasePK(partyDivision.getParty().getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
164                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
165            });
166        }
167    }
168
169    private void checkDepartments(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
170        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
171                SecurityRoleGroups.Department.name(), SecurityRoles.Search.name())) {
172            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
173            var partyControl = Session.getModelController(PartyControl.class);
174            var partyDepartments = partyControl.getDepartmentsByName(target);
175
176            partyDepartments.stream().map((partyDepartment) -> entityInstanceControl.getEntityInstanceByBasePK(partyDepartment.getParty().getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
177                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
178            });
179        }
180    }
181
182    private void checkWarehouses(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
183        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
184                SecurityRoleGroups.Warehouse.name(), SecurityRoles.Search.name())) {
185            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
186            var warehouseControl = Session.getModelController(WarehouseControl.class);
187            var warehouse = warehouseControl.getWarehouseByName(target);
188
189            if(warehouse != null) {
190                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(warehouse.getParty().getPrimaryKey());
191                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
192
193                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
194            }
195        }
196    }
197
198    private void checkLocations(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
199        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
200                SecurityRoleGroups.Location.name(), SecurityRoles.Search.name())) {
201            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
202            var warehouseControl = Session.getModelController(WarehouseControl.class);
203            var locations = warehouseControl.getLocationsByName(target);
204
205            locations.stream().map((location) -> entityInstanceControl.getEntityInstanceByBasePK(location.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
206                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
207            });
208        }
209    }
210
211    private void checkEmployees(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
212        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
213                SecurityRoleGroups.Employee.name(), SecurityRoles.Search.name())) {
214            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
215            var employeeControl = Session.getModelController(EmployeeControl.class);
216            var partyEmployee = employeeControl.getPartyEmployeeByName(target);
217
218            if(partyEmployee != null) {
219                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(partyEmployee.getParty().getPrimaryKey());
220                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
221
222                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
223            }
224        }
225    }
226
227    private void checkCustomers(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
228        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
229                SecurityRoleGroups.Customer.name(), SecurityRoles.Search.name())) {
230            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
231            var customerControl = Session.getModelController(CustomerControl.class);
232            var customer = customerControl.getCustomerByName(target);
233
234            if(customer != null) {
235                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(customer.getParty().getPrimaryKey());
236                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
237
238                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
239            }
240        }
241    }
242
243    private void checkVendors(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
244        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
245                SecurityRoleGroups.Vendor.name(), SecurityRoles.Search.name())) {
246            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
247            var vendorControl = Session.getModelController(VendorControl.class);
248            var vendor = vendorControl.getVendorByName(target);
249
250            if(vendor != null) {
251                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(vendor.getParty().getPrimaryKey());
252                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
253
254                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
255            }
256        }
257    }
258
259    private void checkVendorItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
260        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
261                SecurityRoleGroups.VendorItem.name(), SecurityRoles.Search.name())) {
262            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
263            var vendorControl = Session.getModelController(VendorControl.class);
264            var vendorItems = vendorControl.getVendorItemsByVendorItemName(target);
265
266            vendorItems.stream().map((vendorItem) -> entityInstanceControl.getEntityInstanceByBasePK(vendorItem.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
267                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
268            });
269        }
270    }
271
272    private void checkComponentVendors(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
273        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
274                SecurityRoleGroups.ComponentVendor.name(), SecurityRoles.Search.name())) {
275            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
276            var componentVendor = componentControl.getComponentVendorByName(target);
277
278            if(componentVendor != null) {
279                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(componentVendor.getPrimaryKey());
280                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
281
282                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
283            }
284        }
285    }
286
287    private void checkEntityTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
288        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
289                SecurityRoleGroups.EntityType.name(), SecurityRoles.Search.name())) {
290            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
291            var entityTypes = entityTypeControl.getEntityTypesByName(target);
292
293            entityTypes.stream().map((entityType) -> entityInstanceControl.getEntityInstanceByBasePK(entityType.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
294                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
295            });
296        }
297    }
298
299    private void checkEntityAliasTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
300        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
301                SecurityRoleGroups.EntityAliasType.name(), SecurityRoles.Search.name())) {
302            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
303            var entityAliasTypes = entityAliasControl.getEntityAliasTypesByName(target);
304
305            entityAliasTypes.stream().map((entityAliasType) -> entityInstanceControl.getEntityInstanceByBasePK(entityAliasType.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
306                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
307            });
308        }
309    }
310
311    private void checkEntityAttributes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
312        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
313                SecurityRoleGroups.EntityAttribute.name(), SecurityRoles.Search.name())) {
314            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
315            var entityAttributes = coreControl.getEntityAttributesByName(target);
316
317            entityAttributes.stream().map((entityAttribute) -> entityInstanceControl.getEntityInstanceByBasePK(entityAttribute.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
318                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
319            });
320        }
321    }
322
323    private void checkEntityListItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
324        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
325                SecurityRoleGroups.EntityListItem.name(), SecurityRoles.Search.name())) {
326            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
327            var entityListItems = coreControl.getEntityListItemsByName(target);
328
329            entityListItems.stream().map((entityListItem) -> entityInstanceControl.getEntityInstanceByBasePK(entityListItem.getPrimaryKey())).map((entityInstance) -> EntityNamesUtils.getInstance().getEntityNames(entityInstance)).forEach((entityInstanceAndNames) -> {
330                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
331            });
332        }
333    }
334
335    private void checkEntityAttributeGroups(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
336        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
337                SecurityRoleGroups.EntityAttributeGroup.name(), SecurityRoles.Search.name())) {
338            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
339            var entityAttributeGroup = coreControl.getEntityAttributeGroupByName(target);
340
341            if(entityAttributeGroup != null) {
342                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(entityAttributeGroup.getPrimaryKey());
343                var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(entityInstance);
344
345                entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
346            }
347        }
348    }
349
350    private void executeCustomerSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
351            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
352            final String firstName, final String middleName, final String lastName, final String q) {
353        var customerSearchEvaluator = new CustomerSearchEvaluator(userVisit, searchType,
354                searchLogic.getDefaultSearchDefaultOperator(null),
355                searchLogic.getDefaultSearchSortOrder(null, searchKind),
356                searchLogic.getDefaultSearchSortDirection(null));
357
358        customerSearchEvaluator.setFirstName(firstName);
359        customerSearchEvaluator.setFirstNameSoundex(false);
360        customerSearchEvaluator.setMiddleName(middleName);
361        customerSearchEvaluator.setMiddleNameSoundex(false);
362        customerSearchEvaluator.setLastName(lastName);
363        customerSearchEvaluator.setLastNameSoundex(false);
364        customerSearchEvaluator.setQ(null, q);
365
366        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
367        // accumulating errors for this UC.
368        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
369        customerSearchEvaluator.execute(dummyExecutionErrorAccumulator);
370
371        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
372            addSearchResults(userVisit, searchType, entityInstances);
373        }
374    }
375
376    private void searchCustomers(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target,
377            final NameResult nameResult) {
378        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
379                SecurityRoleGroups.Customer.name(), SecurityRoles.Search.name())) {
380            var searchLogic = SearchLogic.getInstance();
381            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.CUSTOMER.name());
382
383            if(!hasExecutionErrors()) {
384                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
385
386                if(!hasExecutionErrors()) {
387                    var userVisit = getUserVisit();
388
389                    // First attempt using a first and/or last name isolated from target.
390                    executeCustomerSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
391                            nameResult.getFirstName(), nameResult.getMiddleName(), nameResult.getLastName(), null);
392                    // Then attempt searching for target using it as a query string.
393                    executeCustomerSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
394                            null, null, null, target);
395                }
396            }
397        }
398    }
399
400    private void executeEmployeeSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
401            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
402            final String firstName, final String middleName, final String lastName, final String q) {
403        var employeeSearchEvaluator = new EmployeeSearchEvaluator(userVisit, searchType,
404                searchLogic.getDefaultSearchDefaultOperator(null),
405                searchLogic.getDefaultSearchSortOrder(null, searchKind),
406                searchLogic.getDefaultSearchSortDirection(null));
407
408        employeeSearchEvaluator.setFirstName(firstName);
409        employeeSearchEvaluator.setFirstNameSoundex(false);
410        employeeSearchEvaluator.setMiddleName(middleName);
411        employeeSearchEvaluator.setMiddleNameSoundex(false);
412        employeeSearchEvaluator.setLastName(lastName);
413        employeeSearchEvaluator.setLastNameSoundex(false);
414        employeeSearchEvaluator.setQ(null, q);
415
416        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
417        // accumulating errors for this UC.
418        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
419        employeeSearchEvaluator.execute(dummyExecutionErrorAccumulator);
420
421        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
422            addSearchResults(userVisit, searchType, entityInstances);
423        }
424    }
425
426    private void searchEmployees(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target,
427            final NameResult nameResult) {
428        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
429                SecurityRoleGroups.Employee.name(), SecurityRoles.Search.name())) {
430            var searchLogic = SearchLogic.getInstance();
431            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.EMPLOYEE.name());
432
433            if(!hasExecutionErrors()) {
434                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
435
436                if(!hasExecutionErrors()) {
437                    var userVisit = getUserVisit();
438
439                    // First attempt using a first and/or last name isolated from target.
440                    executeEmployeeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
441                            nameResult.getFirstName(), nameResult.getMiddleName(), nameResult.getLastName(), null);
442                    // Then attempt searching for target using it as a query string.
443                    executeEmployeeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
444                            null, null, null, target);
445                }
446            }
447        }
448    }
449
450    private void executeVendorSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
451            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
452            final String firstName, final String middleName, final String lastName, final String q) {
453        var vendorSearchEvaluator = new VendorSearchEvaluator(userVisit, searchType,
454                searchLogic.getDefaultSearchDefaultOperator(null),
455                searchLogic.getDefaultSearchSortOrder(null, searchKind),
456                searchLogic.getDefaultSearchSortDirection(null));
457
458        vendorSearchEvaluator.setFirstName(firstName);
459        vendorSearchEvaluator.setFirstNameSoundex(false);
460        vendorSearchEvaluator.setMiddleName(middleName);
461        vendorSearchEvaluator.setMiddleNameSoundex(false);
462        vendorSearchEvaluator.setLastName(lastName);
463        vendorSearchEvaluator.setLastNameSoundex(false);
464        vendorSearchEvaluator.setQ(null, q);
465
466        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
467        // accumulating errors for this UC.
468        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
469        vendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
470
471        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
472            addSearchResults(userVisit, searchType, entityInstances);
473        }
474    }
475
476    private void searchVendors(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target,
477            final NameResult nameResult) {
478        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
479                SecurityRoleGroups.Vendor.name(), SecurityRoles.Search.name())) {
480            var searchLogic = SearchLogic.getInstance();
481            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.VENDOR.name());
482
483            if(!hasExecutionErrors()) {
484                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
485
486                if(!hasExecutionErrors()) {
487                    var userVisit = getUserVisit();
488
489                    // First attempt using a first and/or last name isolated from target.
490                    executeVendorSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
491                            nameResult.getFirstName(), nameResult.getMiddleName(), nameResult.getLastName(), null);
492                    // Then attempt searching for target using it as a query string.
493                    executeVendorSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
494                            null, null, null, target);
495                }
496            }
497        }
498    }
499
500    private void executeWarehouseSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
501            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType, final String q) {
502        var warehouseSearchEvaluator = new WarehouseSearchEvaluator(userVisit, searchType,
503                searchLogic.getDefaultSearchDefaultOperator(null),
504                searchLogic.getDefaultSearchSortOrder(null, searchKind),
505                searchLogic.getDefaultSearchSortDirection(null));
506
507        warehouseSearchEvaluator.setQ(null, q);
508
509        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
510        // accumulating errors for this UC.
511        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
512        warehouseSearchEvaluator.execute(dummyExecutionErrorAccumulator);
513
514        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
515            addSearchResults(userVisit, searchType, entityInstances);
516        }
517    }
518
519    private void searchWarehouses(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
520        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
521                SecurityRoleGroups.Warehouse.name(), SecurityRoles.Search.name())) {
522            var searchLogic = SearchLogic.getInstance();
523            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.WAREHOUSE.name());
524
525            if(!hasExecutionErrors()) {
526                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
527
528                if(!hasExecutionErrors()) {
529                    var userVisit = getUserVisit();
530
531                    // Attempt searching for target using it as a query string.
532                    executeWarehouseSearch(userVisit, entityInstances, searchLogic, searchKind, searchType,
533                            target);
534                }
535            }
536        }
537    }
538
539    private void executeItemSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
540            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
541            final String q) {
542        var itemSearchEvaluator = new ItemSearchEvaluator(userVisit, null, searchType,
543                searchLogic.getDefaultSearchDefaultOperator(null),
544                searchLogic.getDefaultSearchSortOrder(null, searchKind),
545                searchLogic.getDefaultSearchSortDirection(null),
546                null);
547
548        itemSearchEvaluator.setQ(null, q);
549
550        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
551        // accumulating errors for this UC.
552        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
553        itemSearchEvaluator.execute(dummyExecutionErrorAccumulator);
554
555        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
556            addSearchResults(userVisit, searchType, entityInstances);
557        }
558    }
559
560    private void searchItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
561        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
562                SecurityRoleGroups.Item.name(), SecurityRoles.Search.name())) {
563            var searchLogic = SearchLogic.getInstance();
564            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ITEM.name());
565
566            if(!hasExecutionErrors()) {
567                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
568
569                if(!hasExecutionErrors()) {
570                    var userVisit = getUserVisit();
571
572                    executeItemSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
573                }
574            }
575        }
576    }
577
578    private void executeComponentVendorSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
579            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
580            final String q) {
581        var componentVendorSearchEvaluator = new ComponentVendorSearchEvaluator(userVisit, null, searchType,
582                searchLogic.getDefaultSearchDefaultOperator(null),
583                searchLogic.getDefaultSearchSortOrder(null, searchKind),
584                searchLogic.getDefaultSearchSortDirection(null),
585                null);
586
587        componentVendorSearchEvaluator.setQ(null, q);
588
589        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
590        // accumulating errors for this UC.
591        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
592        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
593
594        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
595            addSearchResults(userVisit, searchType, entityInstances);
596        }
597    }
598
599    private void searchComponentVendors(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
600        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
601                SecurityRoleGroups.ComponentVendor.name(), SecurityRoles.Search.name())) {
602            var searchLogic = SearchLogic.getInstance();
603            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.COMPONENT_VENDOR.name());
604
605            if(!hasExecutionErrors()) {
606                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
607
608                if(!hasExecutionErrors()) {
609                    var userVisit = getUserVisit();
610
611                    executeComponentVendorSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
612                }
613            }
614        }
615    }
616
617    private void executeEntityTypeSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
618            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
619            final String q) {
620        var componentVendorSearchEvaluator = new EntityTypeSearchEvaluator(userVisit, null, searchType,
621                searchLogic.getDefaultSearchDefaultOperator(null),
622                searchLogic.getDefaultSearchSortOrder(null, searchKind),
623                searchLogic.getDefaultSearchSortDirection(null),
624                null);
625
626        componentVendorSearchEvaluator.setQ(null, q);
627
628        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
629        // accumulating errors for this UC.
630        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
631        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
632
633        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
634            addSearchResults(userVisit, searchType, entityInstances);
635        }
636    }
637
638    private void searchEntityTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
639        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
640                SecurityRoleGroups.EntityType.name(), SecurityRoles.Search.name())) {
641            var searchLogic = SearchLogic.getInstance();
642            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
643
644            if(!hasExecutionErrors()) {
645                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
646
647                if(!hasExecutionErrors()) {
648                    var userVisit = getUserVisit();
649
650                    executeEntityTypeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
651                }
652            }
653        }
654    }
655
656    private void executeEntityAliasTypeSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
657            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
658            final String q) {
659        var componentVendorSearchEvaluator = new EntityAliasTypeSearchEvaluator(userVisit, null, searchType,
660                searchLogic.getDefaultSearchDefaultOperator(null),
661                searchLogic.getDefaultSearchSortOrder(null, searchKind),
662                searchLogic.getDefaultSearchSortDirection(null),
663                null);
664
665        componentVendorSearchEvaluator.setQ(null, q);
666
667        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
668        // accumulating errors for this UC.
669        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
670        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
671
672        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
673            addSearchResults(userVisit, searchType, entityInstances);
674        }
675    }
676
677    private void searchEntityAliasTypes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
678        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
679                SecurityRoleGroups.EntityAliasType.name(), SecurityRoles.Search.name())) {
680            var searchLogic = SearchLogic.getInstance();
681            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
682
683            if(!hasExecutionErrors()) {
684                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
685
686                if(!hasExecutionErrors()) {
687                    var userVisit = getUserVisit();
688
689                    executeEntityAliasTypeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
690                }
691            }
692        }
693    }
694
695    private void executeEntityAttributeSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
696            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
697            final String q) {
698        var componentVendorSearchEvaluator = new EntityAttributeSearchEvaluator(userVisit, null, searchType,
699                searchLogic.getDefaultSearchDefaultOperator(null),
700                searchLogic.getDefaultSearchSortOrder(null, searchKind),
701                searchLogic.getDefaultSearchSortDirection(null),
702                null);
703
704        componentVendorSearchEvaluator.setQ(null, q);
705
706        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
707        // accumulating errors for this UC.
708        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
709        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
710
711        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
712            addSearchResults(userVisit, searchType, entityInstances);
713        }
714    }
715
716    private void searchEntityAttributes(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
717        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
718                SecurityRoleGroups.EntityAttribute.name(), SecurityRoles.Search.name())) {
719            var searchLogic = SearchLogic.getInstance();
720            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
721
722            if(!hasExecutionErrors()) {
723                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
724
725                if(!hasExecutionErrors()) {
726                    var userVisit = getUserVisit();
727
728                    executeEntityAttributeSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
729                }
730            }
731        }
732    }
733
734    private void executeEntityListItemSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
735            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
736            final String q) {
737        var componentVendorSearchEvaluator = new EntityListItemSearchEvaluator(userVisit, null, searchType,
738                searchLogic.getDefaultSearchDefaultOperator(null),
739                searchLogic.getDefaultSearchSortOrder(null, searchKind),
740                searchLogic.getDefaultSearchSortDirection(null),
741                null);
742
743        componentVendorSearchEvaluator.setQ(null, q);
744
745        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
746        // accumulating errors for this UC.
747        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
748        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
749
750        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
751            addSearchResults(userVisit, searchType, entityInstances);
752        }
753    }
754
755    private void searchEntityListItems(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
756        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
757                SecurityRoleGroups.EntityListItem.name(), SecurityRoles.Search.name())) {
758            var searchLogic = SearchLogic.getInstance();
759            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
760
761            if(!hasExecutionErrors()) {
762                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
763
764                if(!hasExecutionErrors()) {
765                    var userVisit = getUserVisit();
766
767                    executeEntityListItemSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
768                }
769            }
770        }
771    }
772
773    private void executeEntityAttributeGroupSearch(final UserVisit userVisit, final Set<EntityInstanceTransfer> entityInstances,
774            final SearchLogic searchLogic, final SearchKind searchKind, final SearchType searchType,
775            final String q) {
776        var componentVendorSearchEvaluator = new EntityAttributeGroupSearchEvaluator(userVisit, null, searchType,
777                searchLogic.getDefaultSearchDefaultOperator(null),
778                searchLogic.getDefaultSearchSortOrder(null, searchKind),
779                searchLogic.getDefaultSearchSortDirection(null),
780                null);
781
782        componentVendorSearchEvaluator.setQ(null, q);
783
784        // Avoid using the real ExecutionErrorAccumulator in order to avoid either throwing an Exception or
785        // accumulating errors for this UC.
786        var dummyExecutionErrorAccumulator = new DummyExecutionErrorAccumulator();
787        componentVendorSearchEvaluator.execute(dummyExecutionErrorAccumulator);
788
789        if(!dummyExecutionErrorAccumulator.hasExecutionErrors()) {
790            addSearchResults(userVisit, searchType, entityInstances);
791        }
792    }
793
794    private void searchEntityAttributeGroups(final Party party, final Set<EntityInstanceTransfer> entityInstances, final String target) {
795        if(SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(this, party,
796                SecurityRoleGroups.EntityAttributeGroup.name(), SecurityRoles.Search.name())) {
797            var searchLogic = SearchLogic.getInstance();
798            var searchKind = searchLogic.getSearchKindByName(this, SearchKinds.ENTITY_TYPE.name());
799
800            if(!hasExecutionErrors()) {
801                var searchType = searchLogic.getSearchTypeByName(this, searchKind, SearchTypes.IDENTIFY.name());
802
803                if(!hasExecutionErrors()) {
804                    var userVisit = getUserVisit();
805
806                    executeEntityAttributeGroupSearch(userVisit, entityInstances, searchLogic, searchKind, searchType, target);
807                }
808            }
809        }
810    }
811
812    // Add results from any of the BaseSearchEvaluators to the entityInstances.
813    private void addSearchResults(final UserVisit userVisit, final SearchType searchType,
814            final Set<EntityInstanceTransfer> entityInstances) {
815        var searchControl = Session.getModelController(SearchControl.class);
816        var userVisitSearch = SearchLogic.getInstance().getUserVisitSearch(null, userVisit, searchType);
817        var resultEntityInstances = searchControl.getUserVisitSearchEntityInstances(userVisitSearch);
818
819        for(var resultEntityInstance : resultEntityInstances) {
820            var entityInstanceAndNames = EntityNamesUtils.getInstance().getEntityNames(resultEntityInstance);
821
822            entityInstances.add(fillInEntityInstance(entityInstanceAndNames));
823        }
824    }
825
826    @Override
827    protected BaseResult execute() {
828        var result = SearchResultFactory.getIdentifyResult();
829        var entityInstances = new HashSet<EntityInstanceTransfer>();
830        var target = form.getTarget();
831        var party = getParty();
832
833        if(EntityNameFieldType.isValidName(target)) {
834            // Compile a list of all possible EntityInstances that the target may refer to.
835            checkSequenceTypes(party, entityInstances, target); // uses EEA
836            if(!hasExecutionErrors()) {
837                checkItems(party, entityInstances, target); // uses EEA
838            }
839            if(!hasExecutionErrors()) {
840                checkCompanies(party, entityInstances, target); // uses EEA
841            }
842            if(!hasExecutionErrors()) {
843                checkDivisions(party, entityInstances, target); // uses EEA
844            }
845            if(!hasExecutionErrors()) {
846                checkDepartments(party, entityInstances, target); // uses EEA
847            }
848            if(!hasExecutionErrors()) {
849                checkWarehouses(party, entityInstances, target); // uses EEA
850            }
851            if(!hasExecutionErrors()) {
852                checkLocations(party, entityInstances, target); // uses EEA
853            }
854            if(!hasExecutionErrors()) {
855                checkEmployees(party, entityInstances, target); // uses EEA
856            }
857            if(!hasExecutionErrors()) {
858                checkCustomers(party, entityInstances, target); // uses EEA
859            }
860            if(!hasExecutionErrors()) {
861                checkVendors(party, entityInstances, target); // uses EEA
862            }
863            if(!hasExecutionErrors()) {
864                checkVendorItems(party, entityInstances, target); // uses EEA
865            }
866            if(!hasExecutionErrors()) {
867                checkComponentVendors(party, entityInstances, target); // uses EEA
868            }
869            if(!hasExecutionErrors()) {
870                checkEntityTypes(party, entityInstances, target); // uses EEA
871            }
872            if(!hasExecutionErrors()) {
873                checkEntityAliasTypes(party, entityInstances, target); // uses EEA
874            }
875            if(!hasExecutionErrors()) {
876                checkEntityAttributes(party, entityInstances, target); // uses EEA
877            }
878            if(!hasExecutionErrors()) {
879                checkEntityListItems(party, entityInstances, target); // uses EEA
880            }
881            if(!hasExecutionErrors()) {
882                checkEntityAttributeGroups(party, entityInstances, target); // uses EEA
883            }
884        }
885
886        var nameResult = new NameCleaner().getCleansedName(target);
887        if(!hasExecutionErrors()) {
888            searchEmployees(party, entityInstances, target, nameResult); // uses EEA
889        }
890        if(!hasExecutionErrors()) {
891            searchCustomers(party, entityInstances, target, nameResult); // uses EEA
892        }
893        if(!hasExecutionErrors()) {
894            searchVendors(party, entityInstances, target, nameResult); // uses EEA
895        }
896        if(!hasExecutionErrors()) {
897            searchWarehouses(party, entityInstances, target); // uses EEA
898        }
899        if(!hasExecutionErrors()) {
900            searchItems(party, entityInstances, target); // uses EEA
901        }
902        if(!hasExecutionErrors()) {
903            searchComponentVendors(party, entityInstances, target); // uses EEA
904        }
905        if(!hasExecutionErrors()) {
906            searchEntityTypes(party, entityInstances, target); // uses EEA
907        }
908        if(!hasExecutionErrors()) {
909            searchEntityAliasTypes(party, entityInstances, target); // uses EEA
910        }
911        if(!hasExecutionErrors()) {
912            searchEntityAttributes(party, entityInstances, target); // uses EEA
913        }
914        if(!hasExecutionErrors()) {
915            searchEntityListItems(party, entityInstances, target); // uses EEA
916        }
917        if(!hasExecutionErrors()) {
918            searchEntityAttributeGroups(party, entityInstances, target); // uses EEA
919        }
920
921        result.setEntityInstances(entityInstances);
922        
923        return result;
924    }
925    
926}