Как заставить общую команду работать в новом документе без предварительной записи?

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

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

Анализируем причину принудительной записи

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

Следовательно, платформа инициирует автоматическую цепочку действий: чтобы выполнить команду, ей нужен параметр; чтобы получить параметр-ссылку, объект должен быть физически создан в таблице базы данных. Именно поэтому мы видим системное окно с предложением произвести запись.

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

Метод 1. Использование локальной команды-дублера

Рассмотрим самый очевидный, но трудоемкий путь, о котором упоминалось в обсуждении. Если нам нужно, чтобы логика общей команды была доступна для незаписанного объекта, мы можем создать локальную команду непосредственно на форме документа.

Алгоритм действий будет следующим:

  1. Выносим основную бизнес-логику из модуля общей команды в ОбщийМодуль (с установленными флагами "Сервер", "Вызов сервера").
  2. В форме документа создаем команду формы.
  3. В обработчике этой команды вызываем процедуру из общего модуля, передавая в нее Объект (тип ДокументОбъект), а не ссылку.

Пример кода в модуле формы:


&НаКлиенте
Процедура ЛокальнаяКомандаВыполнить(Команда)
    
    // Проверяем, нужно ли нам работать с данными на сервере
    Результат = ВыполнитьДействиеНаСервере();
    
КонецПроцедуры

&НаСервере
Функция ВыполнитьДействиеНаСервере()
    
    // Передаем весь объект целиком, даже если он не записан
    Возврат ОбщиеМеханизмыСервер.ОбработатьДокумент(Объект);
    
КонецФункции

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

Метод 2. Непараметризуемая команда и программное создание кнопок

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

В новых версиях платформы (начиная с 8.3.20 и выше) это можно реализовать через перехват события ПриСозданииНаСервере для всех необходимых документов. Рассмотрим пример реализации в общем модуле:


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

В этом случае в модуле формы (или через расширение) нам достаточно один раз прописать обработчик Подключаемый_ВыполнитьОбщуюКоманду, который будет вызывать единую бизнес-логику без принудительной проверки ссылки платформой.

Метод 3. Работа через Определяемый тип (Нюансы)

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

Важно: попытка включить в ОпределяемыйТип объекты (например, ДокументОбъект) приведет к ошибке метаданных "Недопустимый тип", так как параметры команд в 1С жестко ограничены типами, которые могут быть переданы между контекстами (клиент-сервер) в рамках навигационной ссылки.

Резюме и рекомендации

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

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

  1. Вынесите исполняемый код в Общий модуль с передачей объекта в качестве параметра.
  2. Для существующих документов используйте ОбщуюКоманду (если запись не критична).
  3. Для новых документов создайте Команду формы. Чтобы избежать записи, убедитесь, что в свойствах команды формы НЕ стоит флаг "Изменяет данные", либо обрабатывайте этот процесс программно через ЭтотОбъект.Записать() только тогда, когда это действительно необходимо по логике вашего процесса.

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

← На главную