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