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