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