Как изменить данные на форме документа без записи в базу данных через внешнюю обработку

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

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

В этой статье мы подробно разберем, как внести изменения непосредственно в данные формы, имея на руках ссылку на документ, и при этом избежать преждевременной записи в информационную базу. Рассмотрим несколько эффективных подходов, начиная от использования механизмов БСП и заканчивая прямой работой с контекстом формы.

Способ 1. Использование механизма БСП «Заполнение объекта»

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

Разберем, как это работает. В модуле объекта внешней обработки в процедуре ВыполнитьКоманду нам доступен параметр ПараметрыВыполнения. Рассмотрим пример кода:


Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения) Экспорт
    
    // Получаем форму, из которой вызвана команда
    ЭтаФормаДокумента = ПараметрыВыполнения.ЭтаФорма;
    
    // Обращаемся напрямую к данным формы (объекту)
    ДокументОбъектНаФорме = ЭтаФормаДокумента.Объект;
    
    // Изменяем строки табличной части "Товары"
    Для Каждого СтрокаТЧ Из ДокументОбъектНаФорме.Товары Цикл
        СтрокаТЧ.Цена = СтрокаТЧ.Цена * 1.1; // Увеличим цену на 10%
    КонецЦикла;
    
    // Устанавливаем признак модифицированности, чтобы пользователь видел изменения
    ЭтаФормаДокумента.Модифицированность = Истина;

КонецПроцедуры

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

Способ 2. Поиск открытой формы через метод ПолучитьФорму

Иногда обработка запускается не через стандартное меню заполнения, а как произвольная внешняя обработка. В этом случае у нас есть СсылкаНаДокумент, и нам нужно найти уже открытое окно этого документа у пользователя.

Рассмотрим пошагово, как это реализовать на клиенте:

  1. Используем функцию ПолучитьФорму, передавая в качестве ключа структуру со ссылкой на документ.
  2. Система проверяет, открыта ли уже форма с таким ключом. Если да — возвращает существующий экземпляр.
  3. Вносим изменения в коллекцию Объект.ИмяТабличнойЧасти.

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

Важный нюанс: при таком подходе мы работаем с типом ДанныеФормыКоллекция. Это не совсем тот же объект, что и в модуле документа, поэтому методы типа ЗаполнитьЗначенияСвойств() или специфические процедуры модуля объекта здесь напрямую не сработают без преобразования.

Способ 3. Преобразование данных через серверный контекст

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

Выясним причину, почему это удобно: это позволяет временно превратить данные формы в полноценный прикладной объект, выполнить с ним любые манипуляции (даже вызвать процедуру Заполнить() из модуля документа), а затем «наложить» результат обратно на форму, не записывая его в базу.


&НаСервере
Процедура ИзменитьТЧНаСервере(ЭтаФорма)
    
    // 1. Преобразуем данные формы в объект для полноценной работы
    ДокОбъект = ДанныеФормыВЗначение(ЭтаФорма.Объект, Тип("ДокументОбъект.РеализацияТоваровУслуг"));
    
    // 2. Выполняем действия с объектом (данные в БД еще не изменены!)
    Для Каждого Строка Из ДокОбъект.Товары Цикл
        Строка.Количество = 1;
    КонецЦикла;
    
    // 3. Копируем измененные данные обратно в реквизит формы
    КопироватьДанныеФормы(ДокОбъект, ЭтаФорма.Объект);
    
    // 4. Оповещаем форму о модификации
    ЭтаФорма.Модифицированность = Истина;
    
КонецПроцедуры

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

Способ 4. Взаимодействие через механизм оповещений (Оповестить)

Если мы хотим добиться максимальной «чистоты» кода и независимости внешней обработки от конкретной формы, проанализируем использование метода Оповестить(). Этот подход полезен, когда обработка выполняет расчеты, а форма сама решает, как их применить.

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

  1. В обработке подготавливаем структуру с новыми данными.
  2. Вызываем Оповестить("ЗаполнитьТабличнуюЧастьИзОбработки", СтруктураДанных, СсылкаНаДокумент);.
  3. В форме документа в процедуре ОбработкаОповещения прописываем логику приема данных.

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

Важные технические нюансы

При работе с данными формы без записи объекта важно помнить о следующих моментах:

Типы данных: Помните, что на форме вы работаете с ДанныеФормыСтруктура, а не с ДокументОбъект. У них нет методов Записать(), ПроверитьЗаполнение() и прочих. Если вам нужны эти методы, используйте преобразование через ДанныеФормыВЗначение.

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

Модифицированность: Всегда устанавливайте ЭтаФорма.Модифицированность = Истина;. Без этого флажка система может позволить пользователю закрыть форму без предупреждения о сохранении изменений, и вся работа внешней обработки будет потеряна.

Таким образом, мы рассмотрели основные способы внесения изменений «на лету». Выбор конкретного метода зависит от сложности вашей задачи и наличия БСП в конфигурации, но наиболее надежным и гибким является использование КопироватьДанныеФормы на стороне сервера.

← На главную