При интеграции с внешними системами (телефонией, мессенджерами, сайтом или кассовым оборудованием) разработчики часто сталкиваются с задачей быстрого поиска физического лица или покупателя по входящему номеру телефона. Нередко простой запрос к справочнику не возвращает записей, даже если в карточке контакта номер отображается корректно. Разберем по шагам, почему типовой запрос дает сбой, где фактически хранятся телефоны в конфигурации «1С:Розница» и как правильно реализовать поиск.
Рассмотрим типичные причины, из-за которых запрос к контактным данным завершается неудачей:
КонтактнаяИнформация. Обращение вида ФизическиеЛица.КонтактнаяИнформация.НомерТелефонаБезКодов в секции ГДЕ некорректно, так как запрос должен адресоваться напрямую к таблице Справочник.ФизическиеЛица.КонтактнаяИнформация.НомерТелефонаБезКодов. По стандартам разработки данный реквизит содержит исключительно номер абонента без кода страны, префикса и кода города (например, для номера +7 (999) 123-45-67 в реквизит записывается только 1234567). Попытка сопоставить это поле с 10- или 11-значным номером приведет к пустому результату. Кроме того, если контакт вводился вручную без использования специализированной формы ввода телефона, этот реквизит может вовсе оставаться незаполненным.ФизическиеЛица используется преимущественно для учета сотрудников (кассиров, администраторов). Покупатели розничной сети чаще всего хранятся в справочнике Контрагенты (с признаком ЮрФизЛицо = ФизЛицо) либо их телефоны привязаны к справочнику ИнформационныеКарты (карты лояльности).+7, с восьмеркой, с дефисами или скобками. Попытка поиска через точное равенство = без очистки строки от спецсимволов обычно не дает результата.Проанализируем наиболее распространенный и практичный вариант решения: очистим входящую строку от лишних символов, выделим значащую часть номера (последние 10 цифр) и выполним запрос к табличной части КонтактнаяИнформация с условием по оператору ПОДОБНО.
// 1. Нормализация входного номера телефона
ОчищенныйНомер = СокрЛП(ВходящийТелефон);
ОчищенныйНомер = СтрЗаменить(ОчищенныйНомер, "-", "");
ОчищенныйНомер = СтрЗаменить(ОчищенныйНомер, " ", "");
ОчищенныйНомер = СтрЗаменить(ОчищенныйНомер, "(", "");
ОчищенныйНомер = СтрЗаменить(ОчищенныйНомер, ")", "");
ОчищенныйНомер = СтрЗаменить(ОчищенныйНомер, "+", "");
ОчищенныйНомер = СтрЗаменить(ОчищенныйНомер, Символы.НПП, "");
// Берем последние 10 цифр номера (без префикса страны)
МаскаПоиска = "%" + Прав(ОчищенныйНомер, 10) + "%";
// 2. Выполнение запроса к табличной части
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ФизическиеЛицаКИ.Ссылка КАК Ссылка
|ИЗ
| Справочник.ФизическиеЛица.КонтактнаяИнформация КАК ФизическиеЛицаКИ
|ГДЕ
| ФизическиеЛицаКИ.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон)
| И ФизическиеЛицаКИ.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.ТелефонФизическогоЛица)
| И ФизическиеЛицаКИ.Представление ПОДОБНО &МаскаПоиска";
Запрос.УстановитьПараметр("МаскаПоиска", МаскаПоиска);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка найденной ссылки
СсылкаНаФизЛицо = Выборка.Ссылка;
КонецЦикла;
Обратим внимание на ключевые моменты этого кода:
Тип с проверкой на Перечисление.ТипыКонтактнойИнформации.Телефон, чтобы исключить адреса электронной почты и почтовые адреса.Вид позволяет ограничить область поиска нужным видом контактной информации (например, ТелефонФизическогоЛица).Прав(ОчищенныйНомер, 10) отсекает различия в префиксах (+7, 8, 7), а спецсимволы % обеспечивают совпадение вне зависимости от наличия пробелов или скобок в поле Представление.В актуальных версиях Библиотеки стандартных подсистем (БСП) в табличную часть КонтактнаяИнформация добавлен реквизит НомерТелефона. В него записываются только цифры полного телефонного номера с кодом страны и города, без пробелов, тире и скобок. Если база данных заполнена корректно через типовые диалоги ввода, поиск по этому реквизиту работает точнее и быстрее:
ОчищенныйНомер = СокрЛП(ВходящийТелефон);
// Удаляем символы форматирования
СимволыДляУдаления = "- ()+";
Для Сч = 1 По СтрДлина(СимволыДляУдаления) Цикл
ОчищенныйНомер = СтрЗаменить(ОчищенныйНомер, Сред(СимволыДляУдаления, Сч, 1), "");
КонецЦикла;
// Ищем совпадение по 10 цифрам в конце строки
МаскаПоиска = "%" + Прав(ОчищенныйНомер, 10);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КИ.Ссылка КАК Ссылка
|ИЗ
| Справочник.ФизическиеЛица.КонтактнаяИнформация КАК КИ
|ГДЕ
| КИ.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон)
| И КИ.НомерТелефона ПОДОБНО &МаскаПоиска";
Запрос.УстановитьПараметр("МаскаПоиска", МаскаПоиска);
РезультатЗапроса = Запрос.Выполнить();
Если поиск среди физических лиц не дал результатов, проверим справочник Контрагенты и карты лояльности. В розничной торговле покупатели фиксируются именно там:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| КонтрагентыКИ.Ссылка КАК Покупатель
|ИЗ
| Справочник.Контрагенты.КонтактнаяИнформация КАК КонтрагентыКИ
|ГДЕ
| КонтрагентыКИ.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон)
| И КонтрагентыКИ.Представление ПОДОБНО &МаскаПоиска";
Запрос.УстановитьПараметр("МаскаПоиска", "%" + Прав(ОчищенныйНомер, 10) + "%");
Результат = Запрос.Выполнить();
Если в конфигурации ведется учет дисконтных карт, номер телефона покупателя часто хранится в реквизитах справочника ИнформационныеКарты или связанных с ними регистрах сведений. В таких случаях поиск следует направить на соответствующую таблицу карт лояльности.
В конфигурациях 1С для разбора и обработки контактных данных предусмотрен общий модуль УправлениеКонтактнойИнформацией:
УправлениеКонтактнойИнформацией.СведенияОТелефоне(КонтактнаяИнформация) позволяет разобрать строку или JSON-структуру записи на составляющие: код страны, код города, номер абонента и добавочный номер.УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъектов(...) возвращает готовую таблицу значений с контактными данными переданного массива ссылок.Взаимодействия.ПолучитьВсеКонтактыПоТелефону(...) для сквозного поиска объектов по всей базе.При внедрении поиска обратим внимание на важные архитектурные нюансы:
ПОДОБНО с маской "%...". Поиск с символом процента в начале строки исключает использование индексов СУБД (B-tree) и приводит к полному сканированию таблицы (Full Table Scan). Если база насчитывает сотни тысяч контрагентов, для высоконагруженных сценариев (например, всплывающее окно при входящем звонке) рекомендуется задействовать полнотекстовый поиск 1С через объект ПолнотекстовыйПоиск либо создать отдельный независимый регистр сведений, хранящий очищенный номер телефона и ссылку на объект.УстановитьПривилегированныйРежим(Истина).