Как из внешней обработки заполнения изменить данные формы документа без записи самого документа?

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

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

В этой статье мы подробно разберем, как правильно взаимодействовать с данными формы, рассмотрим механизмы работы через контекст владельца и изучим профессиональные приемы использования методов платформы для обновления данных «на лету».

Способ 1: Прямое обращение к данным через владельца формы на клиенте

Самый простой и часто используемый способ — это работа с контекстом формы, которая вызвала внешнюю обработку. Когда мы открываем форму внешней обработки из формы документа, у новой формы заполняется свойство ВладелецФормы. Через него мы получаем прямой доступ ко всем реквизитам и табличным частям документа, открытого у пользователя.

Рассмотрим пошагово, как реализовать этот алгоритм в процедуре ПриОткрытии вашей внешней обработки. Предположим, нам нужно пересчитать цены в табличной части документа.


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

Важное примечание: Использование ВладелецФормы.Модифицированность = Истина критически важно. Это заставляет платформу считать форму измененной. Если пользователь попытается закрыть документ после работы вашей обработки, система выдаст стандартное предупреждение: «Данные были изменены. Сохранить изменения?». Если этого не сделать, форма может закрыться без вопросов, и изменения будут потеряны.

Способ 2: Использование метода ЗначениеВДанныеФормы (профессиональный подход)

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

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

  1. На клиенте получаем структуру данных формы.
  2. Передаем её на сервер.
  3. На сервере конвертируем данные в прикладной объект.
  4. Вносим правки.
  5. Конвертируем объект обратно в данные формы.

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

&НаКлиенте
Процедура ВыполнитьЗаполнение()
    // В БСП при вызове команды заполнения обычно доступна переменная ЭтаФорма (контекст документа)
    // Либо используем ВладелецФормы
    ЗаполнитьНаСервере(ВладелецФормы.Объект);
    ВладелецФормы.Модифицированность = Истина;
КонецПроцедуры

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

Способ 3: Метод КопироватьДанныеФормы

Существует еще один эффективный метод — КопироватьДанныеФормы(Источник, Приемник). Он часто применяется, когда у вас во внешней обработке уже подготовлена таблица или объект, который нужно «залить» в форму документа. Это работает быстрее, чем ручной обход строк, особенно на больших табличных частях.

Проанализируем пример: мы подготовили таблицу значений с результатами подбора товаров и хотим заменить ими содержимое документа.


// На сервере подготавливаем временную структуру данных формы
// Копируем из нашего результата в объект владельца
КопироватьДанныеФормы(ПодготовленныйОбъект, ВладелецФормы.Объект);

Почему нельзя использовать метод Прочитать()?

В некоторых обсуждениях (например, в Сообщении 4) встречается ошибка: попытка вызвать ФормаДока.Прочитать(). Давайте выясним причину, почему это категорически запрещено для нашей задачи. Метод Прочитать() принудительно перечитывает данные из базы данных. Если вы внесли изменения в объект программно, но не вызвали Записать(), то вызов Прочитать() просто сотрет всё, что вы сделали, вернув форму к состоянию «как в базе». Более того, если пользователь до запуска обработки что-то вводил руками и не сохранил — его данные также будут уничтожены.

Интеграция через Библиотеку стандартных подсистем (БСП)

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

При использовании этого вида команды, в процедуру ВыполнитьКоманду на клиенте в параметрах выполнения прилетает поле ЭтаФорма. Это и есть форма документа. Вам даже не нужно открывать форму своей обработки, чтобы манипулировать данными.


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

Подведем итоги

Для корректного изменения данных формы без записи в 1С 8.3 следует придерживаться следующих правил:

  1. Никогда не вызывайте Записать() в серверном коде обработки, если хотите оставить пользователю возможность отмены.
  2. Всегда устанавливайте Модифицированность = Истина для формы владельца.
  3. Для простых правок используйте прямой обход ВладелецФормы.Объект.ИмяТабличнойЧасти на клиенте.
  4. Для сложных расчетов используйте связку ДанныеФормыВЗначение и ЗначениеВДанныеФормы на сервере.
  5. Избегайте метода Прочитать(), так как он откатывает состояние формы к последней сохраненной версии в БД.

Используя эти методы, вы создадите удобный и предсказуемый интерфейс для пользователей, соблюдая стандарты разработки на платформе 1С:Предприятие 8.

← На главную