Как исправить ошибку «Данная команда не может выполняться в формуле элемента диалога» при записи справочника в 1С 7.7?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При разработке обработок загрузки данных из внешних источников (например, из файлов Microsoft Excel) разработчики периодически сталкиваются с ошибкой выполнения: «Данная команда не может выполняться в формуле элемента диалога!». Ошибка обычно возникает в момент, когда обработка открывает форму нового элемента справочника и пытается программно вызвать метод Записать() внутри предопределенной процедуры ПриОткрытии().

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

Причины возникновения ошибки

Проанализируем механику работы экранных форм в 1С 7.7, чтобы понять источник проблемы:

  1. Ограничение контекста инициализации диалога: во время выполнения обработчиков ПриОткрытии() или ВводНового() визуальный диалог элемента еще не построен до конца. Платформа находится в фазе инициализации интерфейса и жестко блокирует вызовы методов фиксации данных диалога, таких как Записать(). Любая попытка сохранить форму на этом этапе трактуется платформой как некорректная команда, выполняемая в контексте формулы диалога.
  2. Ошибочный ручной вызов предопределенных событий: вызов функций ПриЗаписи() и ПриЗакрытии() напрямую из кода не запускает системные механизмы транзакции или штатного закрытия окна. Это просто исполнение пользовательских процедур с такими именами. Метод Записать() при этом пытается принудительно перевести форму в сохраненное состояние, что недопустимо.
  3. Разница в поведении справочников и документов: у документов в модуле формы существует специализированный метод ЗаписатьВФорме(), а также специфическая логика работы транзакций при открытии. У справочников метод ЗаписатьВФорме() отсутствует, а интерактивная запись жестко привязана к штатным системным кнопкам диалога.

Основное решение: отказ от открытия форм и создание объектов через программную модель

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

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

  1. Создаем новый элемент через объектную переменную Справочник.Номенклатура.
  2. Заполняем базовые реквизиты (наименование, артикул и прочие поля).
  3. Записываем элемент в базу, чтобы он получил уникальный идентификатор и ссылку.
  4. Создаем подчиненный элемент в справочнике единиц измерения, привязав его к владельцу через ИспользоватьВладельца().
  5. Записываем единицу измерения, после чего возвращаемся к номенклатуре, подставляем созданную единицу в качестве базовой и выполняем повторное сохранение.

Посмотрим на пример реализации данного алгоритма:


// Создаем объект номенклатуры
СпрН = СоздатьОбъект("Справочник.Номенклатура");
СпрН.Новый();
СпрН.Наименование     = СокрЛП(ОкноExcel.Cells(Сч, 3).Value);
СпрН.ПолнНаименование = СпрН.Наименование;
СпрН.Артикул          = СокрЛП(ОкноExcel.Cells(Сч, 2).Value);

// Первичная запись для получения ссылки в базе данных
СпрН.Записать();

// Создаем подчиненную единицу измерения
СпрЕд = СоздатьОбъект("Справочник.Единицы");
СпрЕд.ИспользоватьВладельца(СпрН.ТекущийЭлемент());
СпрЕд.Новый();

// Заполняем реквизиты единицы (например, штуки)
СпрЕд.Наименование = "шт";
СпрЕд.Коэффициент  = 1;
// Если в конфигурации используется классификатор ОКЕИ:
// СпрЕд.ОКЕИ = Константа.БазоваяЕдиницаШтука; 

СпрЕд.Записать();

// Привязываем созданную единицу к реквизитам товара
СпрН.БазоваяЕдиница = СпрЕд.ТекущийЭлемент();
СпрН.ОсновнаяЕдиница = СпрЕд.ТекущийЭлемент();
СпрН.Записать();

// Сохраняем ссылку на созданный товар для дальнейшего использования
глИмпортируемыйТовар = СпрН.ТекущийЭлемент();

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

Альтернативное решение: эмуляция сохранения при необходимости контекста формы

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

Рассмотрим, как обойти ограничение фазы инициализации формы:

  1. В процедуре ПриОткрытии() мы только считываем параметры, заполняем реквизиты диалога, выставляем специальный флаг (переменную модуля) и сразу отдаем команду на закрытие формы: Форма.Закрыть(0);.
  2. В предопределенной процедуре ПриЗакрытии() проверяем выставленный флаг. В этот момент форма уже вышла из стадии ПриОткрытии(), поэтому вызов Записать() выполняется без системного конфликта.

Посмотрим на пример структуры модуля формы справочника:


Перем мАвтоЗапись;

Процедура ПриОткрытии()
    Если ПустоеЗначение(Форма.Параметр) = 0 Тогда
        ПолучПараметр = Форма.Параметр;
        ОкноExcel = ПолучПараметр.Получить("ОкноExcel");
        Сч = ПолучПараметр.Получить("Сч");
        
        Наименование     = ОкноExcel.Cells(Сч, 3).Value;
        ПолнНаименование = Наименование;
        Артикул          = ОкноExcel.Cells(Сч, 2).Value;
        
        // Взводим флаг для отложенной записи
        мАвтоЗапись = 1;
        
        // Закрываем окно, не дожидаясь отрисовки
        Форма.Закрыть(0);
    КонецЕсли;
КонецПроцедуры

Процедура ПриЗакрытии()
    Если мАвтоЗапись = 1 Тогда
        мАвтоЗапись = 0;
        Записать();
        глИмпортируемыйТовар = ТекущийЭлемент();
    КонецЕсли;
КонецПроцедуры

Также для эмуляции штатного интерактивного сохранения можно использовать стандартную формулу кнопки с кодом #Закрыть (аналог кнопки «ОК» с сохранением). При выполнении этой команды платформа сама корректно инициирует проверку заполнения, отрабатывает событие ПриЗаписи() и закрывает окно.

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

← На главную