При разработке в среде 1С:Предприятие 8.3 программисты часто сталкиваются с поведением платформы, которое кажется избыточным: при нажатии на кнопку общей команды в еще не записанном документе система настойчиво предлагает сначала сохранить объект. Разберем детально, почему так происходит, и какие архитектурные решения позволяют обойти это ограничение, обеспечив комфортную работу пользователя.
Давайте разберем внутренний механизм работы параметризуемых команд. Когда мы создаем объект ОбщаяКоманда и указываем в свойстве Тип параметра команды конкретную ссылку (например, ДокументСсылка.РеализацияТоваровУслуг), платформа ожидает, что в обработчик команды будет передан уникальный идентификатор (GUID) объекта. Однако у нового, еще не записанного в базу данных документа, этого идентификатора фактически не существует — ссылка пустая.
Следовательно, платформа инициирует автоматическую цепочку действий: чтобы выполнить команду, ей нужен параметр; чтобы получить параметр-ссылку, объект должен быть физически создан в таблице базы данных. Именно поэтому мы видим системное окно с предложением произвести запись.
Важно также помнить про свойство команды Изменяет данные. Если оно установлено в значение Истина, платформа в любом случае будет требовать записи (даже для уже существующих, но модифицированных объектов), так как предполагает, что действие команды может войти в противоречие с несохраненными правками пользователя в форме.
Рассмотрим самый очевидный, но трудоемкий путь, о котором упоминалось в обсуждении. Если нам нужно, чтобы логика общей команды была доступна для незаписанного объекта, мы можем создать локальную команду непосредственно на форме документа.
Алгоритм действий будет следующим:
Объект (тип ДокументОбъект), а не ссылку.Пример кода в модуле формы:
&НаКлиенте
Процедура ЛокальнаяКомандаВыполнить(Команда)
// Проверяем, нужно ли нам работать с данными на сервере
Результат = ВыполнитьДействиеНаСервере();
КонецПроцедуры
&НаСервере
Функция ВыполнитьДействиеНаСервере()
// Передаем весь объект целиком, даже если он не записан
Возврат ОбщиеМеханизмыСервер.ОбработатьДокумент(Объект);
КонецФункции
Минус этого подхода: если документов много, придется вручную добавлять команду на каждую форму, что лишает "общую команду" её главного преимущества — централизованного управления размещением.
Проанализируем более элегантный способ. Мы можем оставить общую команду "пустой" (без указания типа параметра). В этом случае она не будет автоматически отображаться в командных панелях, но её логика останется доступной глобально. Чтобы избежать ручного дублирования кнопок на каждой форме, воспользуемся механизмом расширений или общих модулей для программного добавления элементов формы. Для стандартизации этой задачи можно использовать общий модуль для программного добавления элементов форм и команд.
В новых версиях платформы (начиная с 8.3.20 и выше) это можно реализовать через перехват события ПриСозданииНаСервере для всех необходимых документов. Рассмотрим пример реализации в общем модуле:
Процедура ПриСозданииНаСервере(Форма, Отказ, СтандартнаяОбработка) Экспорт
// Проверяем, является ли форма формой документа
Если ТипЗнч(Форма.Объект) = Тип("ДанныеФормыСтруктура") Тогда
// Программно добавляем команду формы, которая будет имитировать общую
НоваяКоманда = Форма.Команды.Добавить("ВнешнееДействие");
НоваяКоманда.Действие = "Подключаемый_ВыполнитьОбщуюКоманду";
НоваяКоманда.Заголовок = "Выполнить действие";
// Добавляем кнопку на панель
НовыйЭлемент = Форма.Элементы.Добавить("КнопкаДействия", Тип("КнопкаФормы"), Форма.КоманднаяПанель);
НовыйЭлемент.ИмяКоманды = "ВнешнееДействие";
КонецЕсли;
КонецПроцедуры
В этом случае в модуле формы (или через расширение) нам достаточно один раз прописать обработчик Подключаемый_ВыполнитьОбщуюКоманду, который будет вызывать единую бизнес-логику без принудительной проверки ссылки платформой. Для ознакомления с логикой динамической настройки элементов подойдёт пример программного создания элементов управляемой формы.
В ходе обсуждения предлагалось использовать ОпределяемыйТип. Рассмотрим, поможет ли это. Если вы объедините несколько ссылочных типов в один определяемый тип и укажете его в качестве параметра общей команды, это упростит назначение команды сразу на группу документов. Однако это не решит проблему записи, так как тип все равно останется ссылочным.
Важно: попытка включить в ОпределяемыйТип объекты (например, ДокументОбъект) приведет к ошибке метаданных "Недопустимый тип", так как параметры команд в 1С жестко ограничены типами, которые могут быть переданы между контекстами (клиент-сервер) в рамках навигационной ссылки.
Выяснив причины поведения платформы, мы можем подвести итог. Если ваша задача требует обязательной работы с данными до их записи в базу (например, предварительная проверка заполнения или расчет данных "на лету"), стандартная параметризуемая общая команда вам не подойдет.
Рекомендуемый алгоритм действий:
ОбщуюКоманду (если запись не критична).ЭтотОбъект.Записать() только тогда, когда это действительно необходимо по логике вашего процесса.Таким образом, вы сохраните баланс между типизацией 1С и удобством пользователя, избавляя его от лишних подтверждений при работе с новыми документами.