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