Как организовать проверку заполнения характеристики номенклатуры при работе с таблицей значений

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В процессе разработки механизмов сопоставления данных (например, при импорте номенклатуры от контрагента) часто возникает задача обязательной проверки заполнения характеристик. Если в нашей базе для конкретной позиции номенклатуры ведется учет по характеристикам, система не должна позволять переходить к следующему этапу обработки или сохранять данные, пока характеристика не будет выбрана. Рассмотрим, как реализовать такую проверку программно, проанализируем различные подходы и выберем наиболее оптимальный с точки зрения производительности.

Базовый алгоритм проверки в цикле

Представим ситуацию: у нас есть таблица значений ТаблицаСопоставления, в которой пользователь сопоставляет номенклатуру контрагента с нашей собственной. При смене страницы или перед выполнением итоговой операции нам нужно убедиться, что для каждой строки, где выбрана наша номенклатура, также указана характеристика (если она предусмотрена для этого товара). Проанализируем простейший вариант реализации этой логики.

Разберем пример кода, который перебирает строки таблицы и обращается к вспомогательной функции для поиска записей в справочнике характеристик:


Для Каждого СтрокаТаблицы Из ТаблицаСопоставления Цикл
    // Проверяем, заполнена ли основная номенклатура в строке
    Если ЗначениеЗаполнено(СтрокаТаблицы.Номенклатура) Тогда
        
        // Вызываем функцию проверки наличия характеристик для данной номенклатуры
        Если ЕстьХарактеристики(СтрокаТаблицы.Номенклатура) И НЕ ЗначениеЗаполнено(СтрокаТаблицы.ХарактеристикаНоменклатуры) Тогда
            Сообщить("В строке №" + СтрокаТаблицы.НПП + " ведется учет по характеристике номенклатуры! Пожалуйста, заполните её.");
            // Здесь можно добавить Возврат или Прервать, если критично остановить процесс
        КонецЕсли;
        
    КонецЕсли;
КонецЦикла;

Функция ЕстьХарактеристики в данном случае выполняет поиск хотя бы одной записи в подчиненном справочнике ХарактеристикиНоменклатуры, где владельцем является текущая номенклатура. Рассмотрим её устройство:


Функция ЕстьХарактеристики(Номенклатура)
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |	ХарактеристикиНоменклатуры.Ссылка
    |ИЗ
    |	Справочник.ХарактеристикиНоменклатуры КАК ХарактеристикиНоменклатуры
    |ГДЕ
    |	ХарактеристикиНоменклатуры.Владелец = &Владелец";
    
    Запрос.УстановитьПараметр("Владелец", Номенклатура);
    РезультатЗапроса = Запрос.Выполнить();
    
    Если РезультатЗапроса.Пустой() Тогда
        Возврат Ложь;
    Иначе
        Возврат Истина;
    КонецЕсли;
КонецФункции

Оптимизация производительности: почему запрос в цикле — это плохо

Проанализируем приведенный выше код. С технической точки зрения он рабочий, но имеет существенный недостаток: запрос в цикле. Если в таблице сопоставления будет 100, 500 или 1000 строк, система выполнит соответствующее количество обращений к базе данных. Это приведет к заметным "тормозам" интерфейса при смене страницы.

Для оптимизации процесса рекомендуется использовать один из двух подходов:

  1. Использование флага в номенклатуре. В типовых конфигурациях (УТ 10.3, УПП) в справочнике Номенклатура уже есть реквизит ВестиУчетПоХарактеристикам. Проверка этого булевого значения происходит мгновенно, так как данные о номенклатуре обычно уже подгружены в кэш.
  2. Предварительная выборка данных. Перед началом цикла можно собрать всю номенклатуру из таблицы в массив и одним запросом получить список тех позиций, для которых включен учет характеристик.

Посмотрим, как изменить алгоритм, используя встроенный реквизит конфигурации (актуально для УПП и УТ 10.3):


Для Каждого СтрокаТЧ Из ТаблицаСопоставления Цикл
    // Проверяем заполнение номенклатуры и встроенный флаг ведения учета по характеристикам
    Если ЗначениеЗаполнено(СтрокаТЧ.Номенклатура) 
        И СтрокаТЧ.Номенклатура.ВестиУчетПоХарактеристикам 
        И НЕ ЗначениеЗаполнено(СтрокаТЧ.Характеристика) Тогда
        
        Сообщить("Ошибка в строке " + СтрокаТЧ.НомерСтроки + ": не указана характеристика!");
    КонецЕсли;
КонецЦикла;

Индивидуальные и общие характеристики

Выясним важный нюанс, касающийся структуры метаданных 1С. В современных конфигурациях (УТ 11, ERP, КА 2) характеристики могут быть индивидуальными для каждой номенклатуры или общими для вида номенклатуры.

Если ваша конфигурация использует общие характеристики, то запрос из первого примера (поиск по владельцу-номенклатуре) не сработает, так как владельцем характеристик будет выступать ВидНоменклатуры. В этом случае правильнее проверять настройки самого вида номенклатуры:


// Пример для УТ 11 / ERP
Если СтрокаТЧ.Номенклатура.ВидНоменклатуры.ИспользоватьХарактеристики Тогда
    Если НЕ ЗначениеЗаполнено(СтрокаТЧ.Характеристика) Тогда
        // Вывод сообщения об ошибке
    КонецЕсли;
КонецЕсли;

Улучшение взаимодействия с пользователем

Использование метода Сообщить() не всегда удобно, так как пользователь должен сам искать строку с ошибкой. В управляемых формах (платформа 8.3) рекомендуется использовать объект СообщениеПользователю. Это позволит "привязать" текст ошибки к конкретной ячейке таблицы.

Рассмотрим пример реализации качественного информирования:


ИндексСтроки = 0;
Для Каждого СтрокаТЧ Из Объект.ТаблицаСопоставления Цикл
    Если ЗначениеЗаполнено(СтрокаТЧ.Номенклатура) И НужнаХарактеристика(СтрокаТЧ.Номенклатура) Тогда
        Если НЕ ЗначениеЗаполнено(СтрокаТЧ.Характеристика) Тогда
            Сообщение = Новый СообщениеПользователю;
            Сообщение.Текст = "Необходимо заполнить характеристику для номенклатуры " + СтрокаТЧ.Номенклатура;
            // Указываем путь к данным, чтобы пользователь мог кликнуть на сообщение
            Сообщение.Поле = "Объект.ТаблицаСопоставления[" + ИндексСтроки + "].Характеристика";
            Сообщение.УстановитьДанные(Объект);
            Сообщение.Сообщить();
        КонецЕсли;
    КонецЕсли;
    ИндексСтроки = ИндексСтроки + 1;
КонецЦикла;

Когда вызывать проверку?

Проанализируем подходящие события формы для вызова описанного кода:

Подведем итог: наиболее эффективным методом является проверка флага ВестиУчетПоХарактеристикам (или аналогичного) непосредственно в объекте Номенклатура или её виде. Это исключает лишние запросы к базе данных и делает работу интерфейса быстрой и отзывчивой. Использование СообщениеПользователю делает ваш инструмент профессиональным и удобным для конечного пользователя.

← На главную