Как правильно вызвать процедуру из модуля объекта в управляемой форме 1С 8.3 и организовать проверку заполнения реквизитов?

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

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

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

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

Способ 1: Прямой вызов экспортной процедуры через преобразование контекста

Если руководитель настаивает на хранении логики именно в модуле объекта, нам необходимо вызвать её из модуля формы. На управляемых формах данные хранятся в типе ДанныеФормыСтруктура (переменная Объект), который «не знает» о методах модуля объекта. Чтобы получить доступ к этим методам, нужно выполнить преобразование на сервере.

Рассмотрим по шагам, как реализовать этот вызов. Сначала в Модуле объекта создадим экспортную процедуру (обязательно с ключевым словом Экспорт):


Процедура ВыполнитьПроверкуВидовМестХранения() Экспорт
    // Проверяем логику: если отправитель - ПунктОтпуска, то получатель - Склад или ПунктОтпуска
    Если ВидОтправителя = ПредопределенноеЗначение("Перечисление.ВидыМестХраненияЛС.ПунктОтпуска") Тогда
        Если НЕ (ВидПолучателя = ПредопределенноеЗначение("Перечисление.ВидыМестХраненияЛС.Склад") 
            ИЛИ ВидПолучателя = ПредопределенноеЗначение("Перечисление.ВидыМестХраненияЛС.ПунктОтпуска")) Тогда
            
            // Вместо Сообщить лучше выбросить исключение или вернуть статус
            ВызватьИсключение "Неверно заполнен вид получателя для данного отправителя!";
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Теперь в Модуле формы вызовем эту процедуру. Помним, что преобразование контекста — операция «тяжелая», поэтому её следует выполнять только на сервере:


&НаСервере
Процедура ВызватьПроверкуИзОбъектаНаСервере()
    // Конвертируем данные формы в реальный объект документа
    ДокОбъект = РеквизитФормыВЗначение("Объект");
    
    // Вызываем экспортную процедуру модуля объекта
    ДокОбъект.ВыполнитьПроверкуВидовМестХранения();
    
    // Если нужно, чтобы изменения в объекте (если они были) вернулись на форму:
    // ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецПроцедуры

&НаКлиенте
Процедура ВидПолучателяПриИзменении(Элемент)
    ВызватьПроверкуИзОбъектаНаСервере();
КонецПроцедуры

Способ 2: Оптимальное решение через Общий модуль

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

Создадим общий модуль (например, РаботаСДокументамиСервер) с включенными свойствами «Сервер» и «Вызов сервера». Разместим там логику:


Функция ПроверитьКорректностьМестХранения(ВидОтправителя, ВидПолучателя) Экспорт
    Если ВидОтправителя = ПредопределенноеЗначение("Перечисление.ВидыМестХраненияЛС.ПунктОтпуска") Тогда
        Возврат (ВидПолучателя = ПредопределенноеЗначение("Перечисление.ВидыМестХраненияЛС.Склад") 
                ИЛИ ВидПолучателя = ПредопределенноеЗначение("Перечисление.ВидыМестХраненияЛС.ПунктОтпуска"));
    КонецЕсли;
    Возврат Истина;
КонецФункции

Теперь эту функцию можно использовать в модуле формы для оперативной очистки поля:


&НаКлиенте
Процедура ПроверитьЗаполнениеВидов()
    Если НЕ РаботаСДокументамиСервер.ПроверитьКорректностьМестХранения(Объект.ВидОтправителя, Объект.ВидПолучателя) Тогда
        Объект.ВидПолучателя = ПредопределенноеЗначение("Перечисление.ВидыМестХраненияЛС.ПустаяСсылка");
        Состояние("Ошибка заполнения: выбран недопустимый получатель!");
    КонецЕсли;
КонецПроцедуры

Разбор ошибок: Почему возникают проблемы с «ВыбранноеЗначение»

Посмотрим на ошибки автора в Сообщении 14. Попытка вызвать процедуру ВидОтправителяОбработкаВыбора из события ПриИзменении приводит к ошибке Переменная не определена. Это происходит потому, что у каждого события свой набор параметров. У ПриИзменении есть только параметр Элемент, а у ОбработкаВыбора есть еще ВыбранноеЗначение и СтандартнаяОбработка.

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

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

Для того чтобы документ нельзя было записать с ошибками (требование начальника), в Модуле объекта следует использовать предопределенный обработчик ОбработкаПроверкиЗаполнения. Рассмотрим пример:


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

Дополнительные рекомендации по улучшению интерфейса

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

  1. Используйте событие НачалоВыбора для поля ВидПолучателя.
  2. Программно сформируйте массив доступных значений на основе текущего значения ВидОтправителя.
  3. Установите этот массив в параметры выбора или непосредственно в список выбора элемента формы.

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

← На главную