Как программно записать значение в реквизит формы документа в 1С без открытия формы?

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

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

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

Особенности реквизитов формы и реквизитов объекта

Для начала, очень важно понять принципиальное различие между реквизитами формы и реквизитами объекта:

  1. Реквизиты объекта: Эти реквизиты хранятся непосредственно в базе данных. Они являются частью структуры самого объекта метаданных (например, документа, справочника) и доступны для программной работы с ним (создания, чтения, изменения, записи) независимо от того, открыта ли его форма.
  2. Реквизиты формы: Эти реквизиты существуют только в контексте открытой формы. Они создаются в оперативной памяти, когда форма открывается, и исчезают, когда форма закрывается. Их основное назначение — обеспечить интерактивное взаимодействие пользователя с данными, отобразить информацию из объекта или принять ввод от пользователя. Реквизиты формы могут быть напрямую связаны с реквизитами объекта, либо быть независимыми, используемыми для временных расчетов или хранения данных, специфичных только для формы.

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

Анализируем сценарий: Реквизит формы "ФорматированныйДокумент" и его связь с объектом

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

Однако, как вы верно подметили, реквизит объекта не может иметь тип ФорматированныйДокумент напрямую. Для хранения таких данных в базе данных используется тип ХранилищеЗначения. Таким образом, у нас выстраивается следующая цепочка:

  1. Реквизит формы: Допустим, НужныйРеквизитФормы с типом ФорматированныйДокумент.
  2. Реквизит объекта: Например, Комментарий с типом ХранилищеЗначения.

При этом, как правило, в модуле формы документа описывается логика взаимодействия этих реквизитов. На основе приведенных в теме данных, мы можем реконструировать этот механизм:

Процедуры модуля формы, обеспечивающие взаимодействие

Посмотрим на примеры процедур, которые обычно находятся в модуле формы документа:

1. Чтение данных из объекта при открытии/чтении формы:

В процедуре ПриЧтенииНаСервере(ТекущийОбъект) или ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) происходит загрузка данных из объекта в реквизит формы.


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

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

Здесь видно, что реквизит формы НужныйРеквизитФормы получает свое значение из реквизита объекта ТекущийОбъект.Комментарий, предварительно извлекая его из ХранилищеЗначения с помощью метода Получить(). Стоит отметить, что сам ФорматированныйДокумент может быть сохранен в ХранилищеЗначения.

2. Запись данных из формы в объект перед сохранением:

В процедуре ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) форма подготавливает данные для записи в объект.


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

Этот фрагмент является критически важным для нашего понимания. Он показывает, что перед записью документа, значение реквизита формы НужныйРеквизитФормы не записывается напрямую в реквизит объекта Комментарий. Вместо этого оно помещается в коллекцию ДополнительныеСвойства объекта.

Роль ДополнительныхСвойств

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

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

Как программно записать значение без открытия формы?

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

Разберем это по шагам:

  1. Создаем или получаем объект документа.

    Если мы создаем новый документ:

    
    новРабочийОтчет = Документы.ВашДокумент.СоздатьДокумент();
    // Заполняем остальные реквизиты объекта
    новРабочийОтчет.Дата = ТекущаяДата();
    новРабочийОтчет.Номер = "0001";
    // ... другие реквизиты объекта
    

    Если мы модифицируем существующий документ:

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

    В нашем случае, это строка, которая будет отображаться как форматированный документ. Мы можем подготовить её как обычную строку или даже как HTML-код, если ФорматированныйДокумент будет его интерпретировать.

    
    СтрокаДляФорматированногоДокумента = "Это текст, который будет отображен в форматированном документе.";
    // Или, если требуется HTML:
    ТекстHTML = "<!DOCTYPE html>
    |<html dir=""ltr"">
    |<head>
    |<meta http-equiv=""Content-Type"" content=""text/html; charset=utf-8"" />
    |<meta http-equiv=""X-UA-Compatible"" content=""IE=Edge"" />
    |<meta name=""format-detection"" content=""telephone=no"" />
    |<style type=""text/css"">
    |body{margin:0;padding:8px;}
    |p{line-height:1.15;margin:0;white-space:pre-wrap;}
    |ol,ul{margin-top:0;margin-bottom:0;}
    |img{border:none;}
    |li>p{display:inline;}
    |</style>
    |</head>
    |<body>
    |<p><span> "+ СтрокаМассива.НазваниеЗадачи +" </span></p>
    |</body>
    |</html>";
    

    В данном примере мы используем простую строку СтрокаМассива.НазваниеЗадачи, которая затем преобразуется в HTML. Важно убедиться, что внутренний механизм обработки ФорматированныйДокумент корректно воспримет передаваемый формат (строку или HTML).

  3. Помещаем значение в ДополнительныеСвойства объекта.

    Используем метод Вставить для коллекции ДополнительныеСвойства. Ключ должен точно соответствовать тому, который используется формой (в нашем случае "НужныйРеквизитФормы").

    
    // Имитируем запись формы в ДополнительныеСвойства
    новРабочийОтчет.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", СтрокаДляФорматированногоДокумента);
    // или
    // новРабочийОтчет.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", ТекстHTML);
    

    Важно: Свойство ДополнительныеСвойства у объекта доступно только для чтения, но его можно дополнять новыми ключами и значениями. Это именно то, что мы делаем.

  4. Записываем объект.

    После того как все данные подготовлены, включая значения в ДополнительныеСвойства, мы вызываем метод Записать() объекта.

    новРабочийОтчет.Записать(РежимЗаписиДокумента.Запись);

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

Работа с ХранилищемЗначения

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


// Пример прямой записи в реквизит типа ХранилищеЗначения
МоеЗначение = "Любая строка или объект";
ОбъектДокумента.Комментарий = Новый ХранилищеЗначения(МоеЗначение);

Для получения значения из ХранилищаЗначения используется метод Получить():


// Пример получения значения из ХранилищаЗначения
ПолученноеЗначение = ОбъектДокумента.Комментарий.Получить();

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

Пример полного кода для записи

Представим, что у нас есть обработка, которая создает новый документ и заполняет его реквизиты, включая тот, что связан с реквизитом формы:


// Создание нового документа
Функция СоздатьДокументСКомментарием(НазваниеЗадачи)

    // 1. Создаем новый объект документа (в данном случае "РабочийОтчет")
    новРабочийОтчет = Документы.РабочийОтчет.СоздатьДокумент();

    // 2. Заполняем основные реквизиты документа
    новРабочийОтчет.Дата = ТекущаяДата();
    новРабочийОтчет.Номер = "00001"; // Можно получить следующий номер
    новРабочийОтчет.Организация = Справочники.Организации.НайтиПоНаименованию("Наша Организация"); // Пример

    // 3. Подготавливаем текст, который должен быть отображен
    // в реквизите формы "НужныйРеквизитФормы" (типа ФорматированныйДокумент)
    // и сохранен в реквизите объекта "Комментарий" (типа ХранилищеЗначения)
    // через механизм ДополнительныхСвойств.
    СтрокаДляФорматированногоДокумента = "<h3>Заголовок задачи:</h3><p>" + НазваниеЗадачи + "</p><p><i>Детали выполнения...</i></p>";

    // В более сложных случаях можно использовать объект ФорматированныйДокумент
    // и его методы для программного формирования содержимого,
    // а затем передавать его или его HTML-представление.
    // Например:
    // ФорматДок = Новый ФорматированныйДокумент;
    // ФорматДок.УстановитьHTML(СтрокаДляФорматированногоДокумента);
    // новРабочийОтчет.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", ФорматДок);
    // Или, если объект ожидает именно строку:
    // новРабочийОтчет.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", ФорматДок.ПолучитьHTML());


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

    // 5. Записываем объект
    Попытка
        новРабочийОтчет.Записать(РежимЗаписиДокумента.Запись);
        Сообщить("Документ успешно создан и записан. Номер: " + новРабочийОтчет.Номер);
        Возврат новРабочийОтчет.Ссылка;
    Исключение
        Сообщить("Ошибка при записи документа: " + ОписаниеОшибки(), СтатусСообщения.Важное);
        Возврат Неопределено;
    КонецПопытки;

КонецФункции

// Пример вызова функции
// СсылкаНаСозданныйДокумент = СоздатьДокументСКомментарием("Программное создание отчета о работе");

Заключение

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

В рассмотренном случае, решение заключалось в использовании механизма ДополнительныеСвойства объекта. Передавая требуемое значение через ДополнительныеСвойства, мы обеспечиваем корректную работу внутренних обработчиков объекта, которые затем сохраняют эти данные в постоянный реквизит типа ХранилищеЗначения.

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

← На главную