При разработке и переносе данных в платформе 1С:Предприятие 7.7 программисты часто сталкиваются с ситуацией, когда метод НайтиПоНаименованию возвращает 0 (элемент не найден), хотя нужная позиция номенклатуры гарантированно существует в информационной базе. Разберем по шагам, почему возникает такое поведение платформы и как правильно организовать поиск элементов справочника.
Проанализируем синтаксис встроенного метода справочника в 1С 7.7:
НайтиПоНаименованию(<Наименование>, <Режим>, <ФлагПоиска>)
Рассмотрим назначение каждого параметра подробнее:
1 (значение по умолчанию) — поиск осуществляется только внутри текущего родителя (установленной группы). Если родитель явно не задан методом ИспользоватьРодителя(), поиск будет производиться исключительно в корне справочника среди элементов первого уровня. Элементы, вложенные в любые папки и подпапки, найдены не будут.0 — поиск выполняется по всей иерархии справочника, независимо от вложенности и групп.0 (значение по умолчанию) — поиск по начальным символам наименования.1 — поиск строго по точному совпадению всей строки.Таким образом, при вызове метода только с одним параметром Спр.НайтиПоНаименованию(СтрокаПоиска) платформа ищет элемент исключительно в корне справочника. Если товар лежит в любой группе номенклатуры, метод возвращает 0.
Чтобы найти элемент в иерархическом справочнике по всей базе, необходимо явно передать второй параметр со значением 0. Также для исключения случайных совпадений по первым буквам рекомендуется устанавливать третий параметр в значение 1 (точное соответствие).
Посмотрим на пример правильного кода:
СпрНом = СоздатьОбъект("Справочник.Номенклатура");
ИскомоеНазвание = СокрЛП(Таб.ТовНаим);
// 0 - поиск по всему справочнику, 1 - точное совпадение
Если СпрНом.НайтиПоНаименованию(ИскомоеНазвание, 0, 1) = 1 Тогда
// После успешного позиционирования обращение к реквизитам выполняется напрямую
Таб.СтавкаНДС = СпрНом.СтавкаНДС;
Иначе
Сообщить("Номенклатура не найдена: " + ИскомоеНазвание, "!");
КонецЕсли;
Обратите внимание: после успешного выполнения поиска объект справочника уже спозиционирован на найденной записи. Конструкция Спр.ТекущийЭлемент().СтавкаНДС является избыточной — правильнее и быстрее обращаться к реквизитам напрямую через переменную объекта: Спр.СтавкаНДС.
Если поиск с параметром 0 по-прежнему возвращает неудачу, проверим следующие нюансы строковых данных:
160. Стандартная функция СокрЛП удаляет только обычные пробелы (код 32). Для очистки выполним предварительную замену: СтрЗаменить(ИскомаяСтрока, Симв(160), " ").НайтиПоНаименованию ищет только по стандартному реквизиту Наименование. Если из внешнего источника передается длинное описание, в конфигурациях 1С 7.7 оно обычно хранится в отдельном реквизите ПолнНаименование. Для поиска по дополнительным реквизитам используется метод НайтиПоРеквизиту.Рассмотрим другие проверенные способы сопоставления номенклатуры в 1С 7.7 в зависимости от стоящей задачи:
НайтиПоРеквизиту:
СпрНом = СоздатьОбъект("Справочник.Номенклатура");
// 0 - поиск по всему справочнику
Если СпрНом.НайтиПоРеквизиту("Артикул", ИскомыйАртикул, 0) = 1 Тогда
Таб.СтавкаНДС = СпрНом.СтавкаНДС;
КонецЕсли;
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса =
"//{{ЗАПРОС(ПоискТовара)
|Товар = Справочник.Номенклатура.ТекущийЭлемент;
|Ставка = Справочник.Номенклатура.СтавкаНДС;
|Группировка Товар без групп;
|Условие(Товар.Наименование = ИскомоеНазвание);
|"//}}ЗАПРОС
;
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
Если Запрос.Группировка(1) = 1 Тогда
Таб.СтавкаНДС = Запрос.Ставка;
КонецЕсли;
КонецЕсли;
НайтиПоНаименованию внутри цикла замедляет работу из-за постоянных обращений к базе. Для ускорения выгрузим весь справочник в память один раз перед циклом:
ТЗНоменклатура = СоздатьОбъект("ТаблицаЗначений");
СпрНом = СоздатьОбъект("Справочник.Номенклатура");
СпрНом.ВыгрузитьТаблицу(ТЗНоменклатура);
// Внутри цикла загрузки строк:
НомСтроки = 0;
Если ТЗНоменклатура.НайтиЗначение(ИскомоеНазвание, НомСтроки, "Наименование") = 1 Тогда
ТЗНоменклатура.ПолучитьСтрокуПоНомеру(НомСтроки);
Таб.СтавкаНДС = ТЗНоменклатура.СтавкаНДС;
КонецЕсли;