Как добавить реквизит табличной части внешней обработки в проверку заполнения?

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

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

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

---

Анализ исходной проблемы и ошибок в коде

Рассмотрим ситуацию, с которой столкнулся автор темы. В обработчике модуля объекта ОбработкаПроверкиЗаполнения он пытается динамически добавлять реквизит табличной части в проверку:


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

В данном фрагменте кода кроются сразу две серьезные методологические ошибки, из-за которых программа отказывается работать.

Ошибка первая: Нарушение контекста (попытка работы с формой на сервере).
Обратите внимание на конструкцию ЭлементыФормы.ТаблСостояний... в коде. Процедура ОбработкаПроверкиЗаполнения располагается в Модуле объекта внешней обработки. Этот модуль компилируется и выполняется исключительно на стороне сервера. Объектная модель на сервере ничего не знает о существовании интерфейсных элементов, таких как ЭлементыФормы (в обычных формах) или Элементы (в управляемых формах). Попытка обращения к ним вызовет критическую ошибку выполнения «Переменная не определена».

Ошибка вторая: Ограничение декларативной проверки табличных частей.
Когда мы добавляем в массив ПроверяемыеРеквизиты путь к реквизиту табличной части в формате "ИмяТабличнойЧасти.ИмяРеквизита", платформа 1С воспринимает это как директиву: «Проверить заполнение этого реквизита абсолютно во всех строках данной табличной части».
Но у автора условие накладывается выборочно (например, только для определенной номенклатуры в первой строке). Если мы воспользуемся стандартным массивом, то система начнет требовать заполнения реквизита СостояниеВходногоКонтроля во всех строках без исключения, что нарушает бизнес-логику процесса.

---

Вариант решения №1: Стандартная проверка для всех строк (без условий)

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

Для этого выполним следующие шаги:

  1. Откроем внешнюю обработку в конфигураторе.
  2. Перейдем на вкладку «Реквизиты», развернем нужную табличную часть и выберем целевой реквизит.
  3. В палитре свойств реквизита найдем свойство «Проверка заполнения» и установим его в значение «Выдавать ошибку».

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

Если же эту проверку нужно включать или отключать динамически, мы можем управлять ей в процедуре ОбработкаПроверкиЗаполнения:


Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    
    // Если определенное условие выполняется, то включаем проверку для всей колонки ТЧ
    Если НужнаПроверкаТаблицы Тогда
        ПроверяемыеРеквизиты.Добавить("Маршрутки.СостояниеВходногоКонтроля");
    Иначе
        // Если проверка не нужна, удаляем реквизит из массива проверяемых
        ИндексРеквизита = ПроверяемыеРеквизиты.Найти("Маршрутки.СостояниеВходногоКонтроля");
        Если ИндексРеквизита <> Неопределено Тогда
            ПроверяемыеРеквизиты.Удалить(ИндексРеквизита);
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

---

Вариант решения №2: Выборочная программная проверка строк (Рекомендуемый метод)

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

Рассмотрим по шагам, как реализовать этот алгоритм, избежав ошибок контекста формы.

Шаг 1. Передача контекста из формы в модуль объекта

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

В коде формы (например, в процедуре при нажатии кнопки «Записать» или «Выполнить») перед вызовом проверки напишем следующий код:


&НаКлиенте
Процедура ЗаписатьДанные(Команда)
    ВыполнитьЗаписьНаСервере();
КонецПроцедуры

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

Шаг 2. Реализация выборочной проверки в модуле объекта

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


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

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

---

Преимущества ручной проверки строк

Использование ручного обхода и объекта СообщениеПользователю дает ряд существенных преимуществ:

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

← На главную