При работе с 1С:Предприятием 8.3, особенно в управляемых формах, часто возникает задача программно заполнить реквизиты документа. С реквизитами самого объекта проблем обычно не возникает, поскольку они напрямую доступны для записи. Однако ситуация усложняется, когда речь идет о реквизитах формы. Возникает вопрос: как обратиться к реквизитам формы и записать в них значения, не открывая саму форму?
Давайте разберем эту непростую задачу, рассмотрим особенности взаимодействия реквизитов формы и объекта, а также узнаем, как использовать механизм ДополнительныеСвойства для достижения нашей цели.
Для начала, очень важно понять принципиальное различие между реквизитами формы и реквизитами объекта:
В большинстве случаев, если реквизит формы отображает или принимает данные, которые должны быть сохранены в базе данных, он связан с каким-либо реквизитом объекта. Именно эта связь становится ключом к решению нашей задачи.
Рассмотрим типовую ситуацию, описанную в теме, когда реквизит формы имеет тип ФорматированныйДокумент. Этот тип данных предназначен для работы с текстами, которые могут содержать форматирование (шрифты, цвета, выравнивание, списки, изображения и т.д.), что делает его мощным инструментом для отображения и редактирования "богатого" текста.
Однако, как вы верно подметили, реквизит объекта не может иметь тип ФорматированныйДокумент напрямую. Для хранения таких данных в базе данных используется тип ХранилищеЗначения. Таким образом, у нас выстраивается следующая цепочка:
НужныйРеквизитФормы с типом ФорматированныйДокумент.Комментарий с типом ХранилищеЗначения.При этом, как правило, в модуле формы документа описывается логика взаимодействия этих реквизитов. На основе приведенных в теме данных, мы можем реконструировать этот механизм:
Посмотрим на примеры процедур, которые обычно находятся в модуле формы документа:
1. Чтение данных из объекта при открытии/чтении формы:
В процедуре ПриЧтенииНаСервере(ТекущийОбъект) или ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) происходит загрузка данных из объекта в реквизит формы.
// Пример из Сообщения 6: Чтение данных
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Из объекта "Комментарий" (тип ХранилищеЗначения) получаем данные
// и помещаем их в реквизит формы "НужныйРеквизитФормы"
Если ТекущийОбъект.Комментарий.Получить() <> Неопределено Тогда
НужныйРеквизитФормы = ТекущийОбъект.Комментарий.Получить();
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Если документ создается копированием, тоже получаем комментарий
Если Параметры.Свойство("ЗначениеКопирования") Тогда
Если Параметры.ЗначениеКопирования.Комментарий.Получить() <> Неопределено Тогда
НужныйРеквизитФормы = Параметры.ЗначениеКопирования.Комментарий.Получить();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Здесь видно, что реквизит формы НужныйРеквизитФормы получает свое значение из реквизита объекта ТекущийОбъект.Комментарий, предварительно извлекая его из ХранилищеЗначения с помощью метода Получить(). Стоит отметить, что сам ФорматированныйДокумент может быть сохранен в ХранилищеЗначения.
2. Запись данных из формы в объект перед сохранением:
В процедуре ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) форма подготавливает данные для записи в объект.
// Пример из Сообщения 6: Запись данных
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Значение реквизита формы "НужныйРеквизитФормы" помещается
// во временное хранилище объекта - ДополнительныеСвойства
ТекущийОбъект.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", НужныйРеквизитФормы);
КонецПроцедуры
Этот фрагмент является критически важным для нашего понимания. Он показывает, что перед записью документа, значение реквизита формы НужныйРеквизитФормы не записывается напрямую в реквизит объекта Комментарий. Вместо этого оно помещается в коллекцию ДополнительныеСвойства объекта.
Свойство ДополнительныеСвойства объекта (например, документа, справочника) представляет собой структуру, предназначенную для временного хранения значений, связанных с объектом, без изменения самого объекта метаданных. Это чрезвычайно полезно, когда данные нужны только на время программной обработки или для передачи между модулями (объекта, формы, менеджера).
В нашем случае, форма использует ДополнительныеСвойства как "передаточный пункт". Это означает, что где-то в модуле объекта (например, в процедурах ПередЗаписью или ПриЗаписи самого модуля объекта) есть логика, которая извлекает значение по ключу "НужныйРеквизитФормы" из ТекущийОбъект.ДополнительныеСвойства и уже оттуда сохраняет его в реквизит Комментарий объекта, оборачивая его в ХранилищеЗначения.
Теперь, когда мы понимаем механизм взаимодействия, решение становится очевидным: нам необходимо имитировать действия формы при записи. То есть, создать объект документа, поместить в его ДополнительныеСвойства нужное значение, а затем записать объект.
Разберем это по шагам:
Если мы создаем новый документ:
новРабочийОтчет = Документы.ВашДокумент.СоздатьДокумент();
// Заполняем остальные реквизиты объекта
новРабочийОтчет.Дата = ТекущаяДата();
новРабочийОтчет.Номер = "0001";
// ... другие реквизиты объекта
Если мы модифицируем существующий документ:
СсылкаНаДокумент = Документы.ВашДокумент.НайтиПоНомер("0001", ТекущаяДата()); // Пример
Если СсылкаНаДокумент.Пустая() Тогда
// Обработка ошибки
Возврат;
КонецЕсли;
новРабочийОтчет = СсылкаНаДокумент.ПолучитьОбъект();
В нашем случае, это строка, которая будет отображаться как форматированный документ. Мы можем подготовить её как обычную строку или даже как 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).
ДополнительныеСвойства объекта.
Используем метод Вставить для коллекции ДополнительныеСвойства. Ключ должен точно соответствовать тому, который используется формой (в нашем случае "НужныйРеквизитФормы").
// Имитируем запись формы в ДополнительныеСвойства
новРабочийОтчет.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", СтрокаДляФорматированногоДокумента);
// или
// новРабочийОтчет.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", ТекстHTML);
Важно: Свойство ДополнительныеСвойства у объекта доступно только для чтения, но его можно дополнять новыми ключами и значениями. Это именно то, что мы делаем.
После того как все данные подготовлены, включая значения в ДополнительныеСвойства, мы вызываем метод Записать() объекта.
новРабочийОтчет.Записать(РежимЗаписиДокумента.Запись);
В этот момент сработают обработчики модуля объекта (например, ПередЗаписью или ПриЗаписи), которые должны считать значение из ДополнительныеСвойства и сохранить его в реквизит Комментарий, оборачивая в ХранилищеЗначения.
Если бы форма не использовала ДополнительныеСвойства, а напрямую записывала в реквизит объекта Комментарий (тип ХранилищеЗначения), то подход был бы немного другим. Для записи любого значения (строки, числа, даже объекта ФорматированныйДокумент) в ХранилищеЗначения, мы используем конструктор Новый ХранилищеЗначения():
// Пример прямой записи в реквизит типа ХранилищеЗначения
МоеЗначение = "Любая строка или объект";
ОбъектДокумента.Комментарий = Новый ХранилищеЗначения(МоеЗначение);
Для получения значения из ХранилищаЗначения используется метод Получить():
// Пример получения значения из ХранилищаЗначения
ПолученноеЗначение = ОбъектДокумента.Комментарий.Получить();
В нашем же случае, механизм платформы и логика конфигурации подразумевают, что форма передает уже готовое (или преобразуемое) значение через ДополнительныеСвойства, и сам объект заботится о его правильном сохранении в ХранилищеЗначения.
Представим, что у нас есть обработка, которая создает новый документ и заполняет его реквизиты, включая тот, что связан с реквизитом формы:
// Создание нового документа
Функция СоздатьДокументСКомментарием(НазваниеЗадачи)
// 1. Создаем новый объект документа (в данном случае "РабочийОтчет")
новРабочийОтчет = Документы.РабочийОтчет.СоздатьДокумент();
// 2. Заполняем основные реквизиты документа
новРабочийОтчет.Дата = ТекущаяДата();
новРабочийОтчет.Номер = "00001"; // Можно получить следующий номер
новРабочийОтчет.Организация = Справочники.Организации.НайтиПоНаименованию("Наша Организация"); // Пример
// 3. Подготавливаем текст, который должен быть отображен
// в реквизите формы "НужныйРеквизитФормы" (типа ФорматированныйДокумент)
// и сохранен в реквизите объекта "Комментарий" (типа ХранилищеЗначения)
// через механизм ДополнительныхСвойств.
СтрокаДляФорматированногоДокумента = "<h3>Заголовок задачи:</h3><p>" + НазваниеЗадачи + "</p><p><i>Детали выполнения...</i></p>";
// В более сложных случаях можно использовать объект ФорматированныйДокумент
// и его методы для программного формирования содержимого,
// а затем передавать его или его HTML-представление.
// Например:
// ФорматДок = Новый ФорматированныйДокумент;
// ФорматДок.УстановитьHTML(СтрокаДляФорматированногоДокумента);
// новРабочийОтчет.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", ФорматДок);
// Или, если объект ожидает именно строку:
// новРабочийОтчет.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", ФорматДок.ПолучитьHTML());
// 4. Помещаем значение в ДополнительныеСвойства объекта
// Ключ "НужныйРеквизитФормы" должен точно соответствовать
// тому, который используется в ПередЗаписьюНаСервере формы.
новРабочийОтчет.ДополнительныеСвойства.Вставить("НужныйРеквизитФормы", СтрокаДляФорматированногоДокумента);
// 5. Записываем объект
Попытка
новРабочийОтчет.Записать(РежимЗаписиДокумента.Запись);
Сообщить("Документ успешно создан и записан. Номер: " + новРабочийОтчет.Номер);
Возврат новРабочийОтчет.Ссылка;
Исключение
Сообщить("Ошибка при записи документа: " + ОписаниеОшибки(), СтатусСообщения.Важное);
Возврат Неопределено;
КонецПопытки;
КонецФункции
// Пример вызова функции
// СсылкаНаСозданныйДокумент = СоздатьДокументСКомментарием("Программное создание отчета о работе");
Мы выяснили, что прямая запись в реквизит формы без открытия самой формы невозможна, так как реквизиты формы существуют только в контексте открытой формы. Однако, когда реквизит формы связан с реквизитом объекта через специализированную логику (как правило, в серверных процедурах формы и объекта), мы можем имитировать действия формы.
В рассмотренном случае, решение заключалось в использовании механизма ДополнительныеСвойства объекта. Передавая требуемое значение через ДополнительныеСвойства, мы обеспечиваем корректную работу внутренних обработчиков объекта, которые затем сохраняют эти данные в постоянный реквизит типа ХранилищеЗначения.
Этот подход позволяет гибко управлять заполнением документов программно, используя те же механизмы, что и интерактивная работа пользователя с формой, но без необходимости ее открытия.