Как проверить заполнение табличной части до записи документа в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки в среде 1С:Предприятие одной из наиболее частых задач является контроль качества вводимых данных. Особую сложность для начинающих разработчиков представляет проверка табличных частей, когда необходимо не просто запретить запись пустого документа, а указать пользователю на конкретную строку и колонку, где допущена ошибка. Рассмотрим подробно, как реализовать такую проверку до момента записи документа в базу данных, проанализируем различные подходы и выберем наиболее эффективные инструменты.

Постановка задачи и анализ контекста

Представим ситуацию, описанную в теме: у нас есть табличная часть с перечнем номенклатуры. Нам необходимо убедиться, что для каждой позиции заполнена цена. Если цена отсутствует, система должна прервать процесс записи и выдать информативное сообщение. Важное условие — проверка должна происходить до записи, чтобы не засорять базу данных неполными или некорректными объектами.

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

Способ 1. Использование системного механизма ОбработкаПроверкиЗаполнения

Это «золотой стандарт» платформы 1С для валидации данных. Данное событие вызывается на сервере автоматически при нажатии пользователем кнопки «Провести и закрыть» или «Записать», но строго до начала транзакции записи.

Разберем, как реализовать этот механизм в модуле объекта (быстро подготовить каркас поможет Консоль кода + ИИ-помощник):


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

КонецПроцедуры

Проанализируем этот код. Параметр Отказ — это ключевой рычаг управления. Если мы присвоим ему значение Истина, платформа прервет выполнение операции записи. Объект СообщениеПользователю позволяет не просто вывести текст, но и подсветить красным цветом ту самую ячейку Цена, в которой обнаружена ошибка. Это значительно повышает удобство работы пользователя (UX).

Способ 2. Проверка в событии формы ПередЗаписью

Иногда логика проверки требует данных, которые есть только на форме, или сложного взаимодействия с интерфейсом. В этом случае мы используем событие ПередЗаписью в модуле формы. Однако здесь важно понимать разницу между клиентским и серверным контекстом.

Выясним причину использования клиентской проверки: она экономит ресурсы сервера, не отправляя данные на запись, если заведомо известно, что они некорректны. Рассмотрим пример реализации:


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

Важно: Проверка на форме не заменяет проверку в модуле объекта, так как документ может быть записан программно (из другой обработки), минуя форму. Поэтому критически важные проверки всегда дублируйте в модуле объекта.

Способ 3. Интерактивная проверка при изменении (Lazy Validation)

Как обсуждалось на форуме, можно проверять данные в момент их ввода в событии ПриИзменении. Это позволяет пользователю сразу увидеть ошибку, не дожидаясь нажатия кнопки записи. Посмотрим на пример кода для реквизита номенклатуры:


&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
    
    ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
    
    Если ТекущаяСтрока <> Неопределено Тогда
        // Вызываем серверную функцию для получения цены
        ЦенаТовара = ПолучитьЦенуНаСервере(ТекущаяСтрока.Номенклатура, Объект.Дата);
        
        Если ЦенаТовара = 0 Тогда
            // Предупреждаем пользователя, но не блокируем работу
            ПоказатьПредупреждение(, "Внимание: для данной номенклатуры не задана цена в прайс-листе!");
        Иначе
            ТекущаяСтрока.Цена = ЦенаТовара;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Этот подход хорош тем, что он проактивен. Однако, как верно заметили участники дискуссии, избыточные походы на сервер при каждом изменении могут замедлить работу при плохом интернет-соединении. Используйте этот метод разумно, комбинируя его с финальной проверкой в ОбработкаПроверкиЗаполнения.

Работа со ссылкой нового документа

Рассмотрим нюанс, упомянутый в 10-м сообщении форума. Если ваша процедура проверки (например, ПослеВнесенияЗаказовНаСервер) требует наличия ссылки на документ (например, для записи в связанные регистры или передачи в запросы), а документ еще не записан, используйте метод УстановитьСсылкуНового().

Проанализируем ситуацию: платформа позволяет заранее зарезервировать УникальныйИдентификатор для объекта. Это делается следующим образом:


// В модуле формы или при создании объекта
СсылкаНаБудущийДокумент = Документы.ЗаказПокупателя.ПолучитьСсылку();
ЭтотОбъект.УстановитьСсылкуНового(СсылкаНаБудущийДокумент);

Теперь, даже если документ физически не записан в таблицу SQL, свойство Объект.Ссылка уже будет содержать валидный идентификатор, который можно использовать в алгоритмах проверки заполнения.

Оптимизация проверки при большом количестве строк

Если в вашем документе тысячи строк, перебор в цикле Для Каждого может вызвать зависание интерфейса. В таких случаях мы рекомендуем использовать временные таблицы и запросы.

Разберем по шагам алгоритм быстрой проверки:

  1. Выгружаем табличную часть объекта в таблицу значений.
  2. Передаем эту таблицу в запрос как параметр.
  3. В запросе выбираем строки, где Цена = 0.
  4. Если результат запроса не пустой — выводим список ошибок.

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ТчТовары.НомерСтроки КАК НомерСтроки,
    |   ТчТовары.Номенклатура.Наименование КАК НоменклатураНаименование
    |ПОМЕСТИТЬ ВТ_Товары
    |ИЗ
    |   &ТчТовары КАК ТчТовары
    |;
    |ВЫБРАТЬ
    |   ВТ_Товары.НомерСтроки,
    |   ВТ_Товары.НоменклатураНаименование
    |ИЗ
    |   ВТ_Товары КАК ВТ_Товары
    |ГДЕ
    |   ВТ_Товары.Цена = 0";

Запрос.УстановитьПараметр("ТчТовары", Товары.Выгрузить());
РезультатЗапроса = Запрос.Выполнить();
// Далее обработка результата...

Такой подход работает значительно быстрее на больших объемах данных, так как оптимизация поиска пустых значений перекладывается на движок СУБД.

Подведем итоги

Для качественной реализации проверки заполнения данных в 1С следует придерживаться комплексного подхода:

  1. Свойства метаданных: Для простых полей всегда устанавливайте свойство «Проверка заполнения» в значение «Выдавать ошибку».
  2. Модуль объекта: Основную логику проверки (особенно зависимую от условий, например, «если товар — услуга, то цена может быть нулевой») размещайте в ОбработкаПроверкиЗаполнения.
  3. Пользовательский интерфейс: Используйте объект СообщениеПользователю для точной адресации ошибки в конкретную строку табличной части.
  4. Производительность: При работе с ТЧ объемом более 500 строк отдавайте предпочтение проверкам через временные таблицы в запросах.

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

← На главную