В процессе разработки в среде 1С:Предприятие 8.3 (особенно в типовых конфигурациях, таких как "Бухгалтерия предприятия 3.0") программисты часто сталкиваются со следующей задачей: необходимо программно создать документ, заполнить его реквизиты и табличные части сложными данными на сервере, а затем открыть эту форму пользователю на клиенте. При этом крайне важно, чтобы документ не записывался в базу данных сразу. Пользователь должен сам принять решение — отредактировать его, провести или просто закрыть без сохранения.
Сложность заключается в особенностях клиент-серверной архитектуры управляемого приложения. На сервере мы можем легко оперировать объектом типа ДокументОбъект, заполнять любые его свойства, но мы принципиально не можем открыть форму, так как это чисто клиентское действие. На клиенте же, наоборот, доступна процедура открытия формы, но нет прямой возможности полноценно создавать и заполнять прикладные объекты базы данных.
В этой статье мы подробно разберем три практических способа решения этой задачи — от простых стандартных механизмов платформы до наиболее продвинутого метода, который позволяет открыть заполненную форму без изменения кода самого документа (что критически важно для конфигураций на поддержке).
Давайте проанализируем ситуацию: как заполнить форму нового документа на сервере и показать её пользователю незаписанной, если мы не хотим вносить изменения в сам документ (например, в его форму или модуль объекта)? Это самый частый сценарий при обновляемой конфигурации.
Для решения этой задачи мы можем использовать изящный прием. Сначала мы получаем пустую форму нужного документа на клиенте, затем передаем её структуру данных на сервер, преобразуем в полноценный прикладной объект ДокументОбъект, заполняем его любыми данными, возвращаем обратно в данные формы и открываем форму пользователю.
Рассмотрим по шагам программный код, реализующий этот подход:
&НаКлиенте
Процедура СоздатьИОткрытьНовыйДокумент(Команда)
// Шаг 1. Получаем форму нового незаписанного документа в переменную
ФормаНовогоДокумента = ПолучитьФорму("Документ.ПеремещениеТоваров.Форма.ФормаДокумента");
// Шаг 2. Извлекаем данные формы (обычно это реквизит "Объект")
ДанныеФормы = ФормаНовогоДокумента.Объект;
// Шаг 3. Передаем данные на сервер для заполнения
ЗаполнитьДанныеФормыНаСервере(ДанныеФормы);
// Шаг 4. Копируем заполненные данные обратно в форму документа
КопироватьДанныеФормы(ДанныеФормы, ФормаНовогоДокумента.Объект);
// Шаг 5. Помечаем форму как измененную (чтобы при закрытии программа спросила о сохранении)
ФормаНовогоДокумента.Модифицированность = Истина;
// Шаг 6. Открываем форму пользователю
ФормаНовогоДокумента.Открыть();
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ЗаполнитьДанныеФормыНаСервере(ДанныеФормы)
// Преобразуем структуру данных управляемой формы в реальный прикладной объект 1С
ДокОбъект = ДанныеФормыВЗначение(ДанныеФормы, Тип("ДокументОбъект.ПеремещениеТоваров"));
// Теперь нам доступны все реквизиты и методы объекта. Выполняем заполнение:
ДокОбъект.Дата = ТекущаяДата();
ДокОбъект.Организация = Справочники.Организации.НайтиПоРеквизиту("ИНН", "7700000000");
ДокОбъект.СкладОтправитель = Справочники.Склады.НайтиПоНаименованию("Основной склад");
// Заполняем табличную часть "Товары"
НоваяСтрока = ДокОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("00-000001");
НоваяСтрока.Количество = 10;
// Конвертируем заполненный объект обратно в структуру данных формы
ЗначениеВДанныеФормы(ДокОбъект, ДанныеФормы);
КонецПроцедуры
Преимущества этого метода: нам не требуется вносить изменения в конфигурацию. Мы можем реализовать этот код во внешней обработке или в любой другой форме. Метод отлично подходит для работы с табличными частями любой сложности.
Многие разработчики сомневаются, можно ли передать заполненную табличную часть через обычные параметры открытия формы. Платформа 1С 8.3 предоставляет такую возможность. Мы можем передать в параметрах формы структуру ЗначенияЗаполнения, в которой ключами будут выступать имена реквизитов шапки, а для табличной части — массив структур, где каждая структура описывает строку таблицы.
Выясним, как это выглядит на практике:
&НаКлиенте
Процедура ОткрытьФормуСПараметрамиЗаполнения(Команда)
// Создаем структуру для хранения заполняемых реквизитов
ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("Организация", СсылкаОрганизации);
ПараметрыЗаполнения.Вставить("Комментарий", "Создано программно через параметры формы");
// Описываем табличную часть "Товары" как массив структур
МассивСтрокТовары = Новый Массив;
СтрокаТЧ = Новый Структура;
СтрокаТЧ.Вставить("Номенклатура", СсылкаНоменклатуры);
СтрокаТЧ.Вставить("Количество", 5);
СтрокаТЧ.Вставить("Цена", 1200);
МассивСтрокТовары.Добавить(СтрокаТЧ);
// Ключ в структуре должен строго совпадать с именем табличной части документа
ПараметрыЗаполнения.Вставить("Товары", МассивСтрокТовары);
// Обертываем в предопределенный параметр платформы "ЗначенияЗаполнения"
ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
// Открываем форму документа
ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры
Важное условие: чтобы этот способ сработал автоматически, у реквизитов шапки и реквизитов табличной части документа в конфигураторе должно быть установлено свойство "Заполнять из данных заполнения". Если это свойство отключено, заполнение не произойдет само по себе, и нам придется вручную прописывать код обработки в процедуре ОбработкаЗаполнения в модуле объекта создаваемого документа.
Если структура заполняемых данных слишком сложная или объем данных велик (например, мы переносим сотни строк табличной части), передача через параметры формы может оказаться неэффективной или привести к ошибкам. В таких случаях классическим решением является использование временного хранилища платформы.
Схема работы выглядит следующим образом:
ПриСозданииНаСервере мы считываем данные по адресу и заполняем форму.Давайте посмотрим на пример реализации. Сначала напишем код вызова на стороне нашей обработки:
&НаКлиенте
Процедура ОткрытьЧерезХранилище(Команда)
// Получаем адрес с сервера, где подготовили данные
АдресХранилища = ПодготовитьДанныеНаСервере();
// Передаем адрес в параметрах формы
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("АдресДанныхЗаполнения", АдресХранилища);
ОткрытьФорму("Документ.ПеремещениеТоваров.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры
&НаСервере
Функция ПодготовитьДанныеНаСервере()
// Формируем структуру данных для переноса
ДанныеДляПереноса = Новый Структура;
ДанныеДляПереноса.Вставить("Организация", Справочники.Организации.ПустаяСсылка());
ТаблицаТоваров = Новый ТаблицаЗначений;
ТаблицаТоваров.Колонки.Добавить("Номенклатура");
ТаблицаТоваров.Колонки.Добавить("Количество");
// Заполняем таблицу какими-то данными
НоваяСтрока = ТаблицаТоваров.Добавить();
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("000001");
НоваяСтрока.Количество = 15;
ДанныеДляПереноса.Вставить("Товары", ТаблицаТоваров);
// Помещаем во временное хранилище.
// В качестве уникального идентификатора передаем Новый УникальныйИдентификатор
Возврат ПоместитьВоВременноеХранилище(ДанныеДляПереноса, Новый УникальныйИдентификатор);
КонецФункции
Теперь рассмотрим, как должен выглядеть принимающий код в модуле формы самого открываемого документа (например, в форме документа "Перемещение товаров"):
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, передан ли нам параметр с адресом временного хранилища
Если Параметры.Свойство("АдресДанныхЗаполнения") Тогда
// Извлекаем наши данные
ДанныеЗаполнения = ПолучитьИзВременногоХранилища(Параметры.АдресДанныхЗаполнения);
Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") Тогда
// Заполняем реквизиты шапки формы
Объект.Организация = ДанныеЗаполнения.Организация;
// Заполняем табличную часть формы
Если ДанныеЗаполнения.Свойство("Товары") Тогда
Объект.Товары.Загрузить(ДанныеЗаполнения.Товары);
КонецЕсли;
// Удаляем данные из хранилища, так как они больше не нужны
УдалитьИзВременногоХранилища(Параметры.АдресДанныхЗаполнения);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Стоит отметить, что в конфигурациях, построенных на Библиотеке Стандартных Подсистем (БСП), таких как БП 3.0, многие типовые документы уже содержат встроенную обработку параметров заполнения из временного хранилища. Часто достаточно передать параметр с именем АдресЗаполнения или АдресПараметровЗаполнения, и БСП сама прочитает и заполнит форму документа без необходимости дописывать процедуру ПриСозданииНаСервере вручную.
Подведем итоги совместного анализа решений этой задачи:
ДанныеФормыВЗначение и КопироватьДанныеФормы. Это наиболее гибкий, чистый и современный способ, не требующий вмешательства в открываемый документ.ЗначенияЗаполнения.ПоместитьВоВременноеХранилище.