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