При работе с управляемыми формами в платформе «1С:Предприятие 8.3» начинающие разработчики часто сталкиваются со специфическим поведением некоторых стандартных документов. Особенно много вопросов вызывает документ «Операция (бухгалтерский и налоговый учет)» (в конфигурации он называется ОперацияБух). Попытка программно заполнить его движения, передать их на клиента и открыть форму нового документа часто заканчивается неудачей: форма открывается абсолютно пустой, хотя в коде все движения были честно добавлены.
Давайте подробно разберем, почему возникает эта проблема, проанализируем внутреннее устройство управляемой формы документа ОперацияБух и рассмотрим два рабочих и надежных способа программного заполнения этого документа без его предварительной принудительной записи в базу данных.
Для большинства обычных документов (например, Реализация товаров и услуг или Поступление товаров и услуг) все данные табличных частей хранятся внутри самого объекта документа. Когда мы получаем форму нового документа через ПолучитьФорму(), платформа создает структуру данных формы, которая полностью проецирует структуру метаданных объекта. В этом случае связка методов ДанныеФормыВЗначение и ЗначениеВДанныеФормы отрабатывает предсказуемо и переносит любые изменения табличных частей на форму.
С документом ОперацияБух ситуация принципиально иная. Давайте разберем особенности его архитектуры:
Хозрасчетный, где документ выступает в роли регистратора.РегистрБухгалтерииНаборЗаписей.Хозрасчетный). Обычно этот реквизит называется ДвиженияХозрасчетный или Хозрасчетный.Именно поэтому у автора темы возникала ситуация, когда при предварительной записи документа проводки появлялись только после закрытия и повторного открытия формы из журнала. При первой генерации формы обработчик ПриСозданииНаСервере выполнялся тогда, когда объект в базе данных еще фактически отсутствовал или не был связан с набором записей в памяти формы.
Давайте рассмотрим, какими путями мы можем решить эту задачу красиво, не нарушая стандарты разработки «1С».
Этот способ является самым простым и логичным. Вместо того чтобы пытаться работать с физическим объектом ДокументОбъект.ОперацияБух через преобразование типов, мы передадим на сервер саму полученную управляемую форму документа и заполним её реквизиты напрямую.
Давайте посмотрим на пример реализации этого механизма в нашей внешней обработке.
Код на клиенте:
&НаКлиенте
Процедура ЗаполнитьИОткрытьОперацию(Команда)
// Шаг 1. Получаем форму нового, еще не открытого и незаписанного документа
ФормаДокумента = ПолучитьФорму("Документ.ОперацияБух.ФормаОбъекта");
// Шаг 2. Передаем форму на сервер для заполнения реквизитов шапки и таблицы проводок
ЗаполнитьФормуОперацииНаСервере(ФормаДокумента, Организация, ВыбраннаяДата, ВыбранныйСчет);
// Шаг 3. Устанавливаем признак модифицированности, чтобы пользователь видел, что данные изменены
ФормаДокумента.Модифицированность = Истина;
// Шаг 4. Открываем полностью готовую заполненную форму пользователю
ФормаДокумента.Открыть();
КонецПроцедуры
Код на сервере:
&НаСервереБезКонтекста
Процедура ЗаполнитьФормуОперацииНаСервере(ФормаДокумента, Организация, ДатаОперации, СчетУчета)
// 1. Заполняем реквизиты шапки через Объект формы
ДокОбъект = ФормаДокумента.Объект;
ДокОбъект.Дата = КонецДня(ДатаОперации);
ДокОбъект.Организация = Организация;
ДокОбъект.СпособЗаполнения = "Вручную";
ДокОбъект.Ответственный = ПараметрыСеанса.ТекущийПользователь;
ДокОбъект.Комментарий = "Заполнено программно из внешней обработки";
// 2. Обращаемся напрямую к реквизиту формы, который отображает проводки.
// В конфигурации Бухгалтерия Предприятия 3.0 этот реквизит формы называется "ДвиженияХозрасчетный"
ТаблицаПроводокФормы = ФормаДокумента.ДвиженияХозрасчетный;
ТаблицаПроводокФормы.Очистить();
// 3. Выполняем наш запрос для выборки данных
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстатки.Субконто1 КАК Номенклатура,
| ХозрасчетныйОстатки.Субконто2 КАК Склад,
| ХозрасчетныйОстатки.СуммаОстаток КАК Сумма
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, Счет = &Счет, , Организация = &Организация) КАК ХозрасчетныйОстатки";
Запрос.УстановитьПараметр("Период", Новый Граница(ДатаОперации, ВидГраницы.Включая));
Запрос.УстановитьПараметр("Счет", СчетУчета);
Запрос.УстановитьПараметр("Организация", Организация);
Выборка = Запрос.Выполнить().Выбрать();
СуммаОперации = 0;
Пока Выборка.Следующий() Цикл
// Добавляем строку непосредственно в коллекцию формы
НоваяСтрока = ТаблицаПроводокФормы.Добавить();
НоваяСтрока.Период = ДатаОперации;
НоваяСтрока.Организация = Организация;
// Установка счетов дебета и кредита (Обязательно делать перед установкой субконто!)
НоваяСтрока.СчетДт = ПланыСчетов.Хозрасчетный.ДебетМатериалов; // Для примера
НоваяСтрока.СчетКт = СчетУчета;
// Заполнение субконто. В УФ субконто заполняются через обращение по типу или по индексу
НоваяСтрока.СубконтоКт.Номенклатура = Выборка.Номенклатура;
НоваяСтрока.СубконтоКт.Склады = Выборка.Склад;
// Заполняем суммовые показатели
НоваяСтрока.Сумма = Выборка.Сумма;
НоваяСтрока.СуммаНУДт = Выборка.Сумма;
НоваяСтрока.СуммаНУКт = Выборка.Сумма;
СуммаОперации = СуммаОперации + Выборка.Сумма;
КонецЦикла;
// Записываем итоговую сумму в шапку документа
ДокОбъект.СуммаОперации = СуммаОперации;
КонецПроцедуры
Этот способ позволяет открыть документ абсолютно чистым в базе данных. Пользователь увидит все проводки на экране, сможет их отредактировать, дополнить и самостоятельно нажать кнопку «Записать и закрыть». При этом физическая запись в базу данных произойдет штатно средствами самой формы.
Если вы хотите использовать стандартные подсистемы конфигурации БСП и не хотите «вручную» перебирать элементы формы на сервере, можно воспользоваться механизмом параметров заполнения формы. Платформа 1С позволяет передать при открытии формы структуру параметров заполнения ЗначенияЗаполнения.
Для этого мы можем упаковать таблицу наших будущих проводок во временное хранилище и передать адрес этого хранилища в параметрах открытия формы. Давайте разберем, как это реализовать.
Шаг 1. Формируем таблицу на клиенте/сервере обработки и передаем параметры:
&НаКлиенте
Процедура ЗаполнитьЧерезПараметры(Команда)
ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("Организация", Организация);
ПараметрыЗаполнения.Вставить("Дата", Дата);
// Получаем адрес таблицы с проводками во временном хранилище
АдресТаблицыПроводок = ПодготовитьТаблицуПроводокНаСервере();
ПараметрыЗаполнения.Вставить("АдресТаблицыПроводок", АдресТаблицыПроводок);
// Передаем параметры заполнения в форму документа
ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
ОткрытьФорму("Документ.ОперацияБух.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры
&НаСервере
Функция ПодготовитьТаблицуПроводокНаСервере()
// Создаем таблицу значений, повторяющую структуру движений регистра
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("СчетДт", Новый ОписаниеТипов("ПланСчетовСсылка.Хозрасчетный"));
Таблица.Колонки.Добавить("СчетКт", Новый ОписаниеТипов("ПланСчетовСсылка.Хозрасчетный"));
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
// Добавьте другие необходимые колонки субконто и валют
// Заполняем таблицу данными...
НоваяСтрока = Таблица.Добавить();
НоваяСтрока.СчетДт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("20.01");
НоваяСтрока.СчетКт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("10.01");
НоваяСтрока.Сумма = 15000;
// Помещаем таблицу во временное хранилище с уникальным идентификатором формы обработки
Возврат ПоместитьВоВременноеХранилище(Таблица, УникальныйИдентификатор);
КонецФункции
Для того чтобы документ «прочитал» этот параметр при открытии, в типовых конфигурациях (например, Бухгалтерия Предприятия 3.0) существует встроенный механизм. Если вы разрабатываете свою конфигурацию или хотите доработать типовую без изменения кода, вы можете использовать механизм расширений, перехватив процедуру ОбработкаЗаполнения в модуле объекта документа ОперацияБух:
&После("ОбработкаЗаполнения")
Процедура Расш_ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура")
И ДанныеЗаполнения.Свойство("АдресТаблицыПроводок") Тогда
ТаблицаПроводок = ПолучитьИзВременногоХранилища(ДанныеЗаполнения.АдресТаблицыПроводок);
Если ТипЗнч(ТаблицаПроводок) = Тип("ТаблицаЗначений") Тогда
// Заполняем движения документа из полученной таблицы
ЭтотОбъект.Движения.Хозрасчетный.Загрузить(ТаблицаПроводок);
ЭтотОбъект.Движения.Хозрасчетный.Записывать = Истина;
// Рассчитываем сумму операции
ЭтотОбъект.СуммаОперации = ТаблицаПроводок.Итог("Сумма");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
При программном заполнении проводок крайне важно соблюдать определенные технические правила платформы «1С:Предприятие 8». Игнорирование этих правил может привести к очистке данных или некорректному отображению аналитики:
СчетДт и СчетКт в строке проводки, и только после этого обращайтесь к коллекциям субконто (СубконтоДт, СубконтоКт). Если вы попытаетесь заполнить субконто у строки с пустым счетом, платформа не сможет определить виды субконто (типы аналитики) для этого счета и просто проигнорирует заполнение либо вызовет ошибку.СуммаОперации не рассчитывается платформой автоматически «на лету» при простом заполнении движений на форме. Обязательно вычисляйте итог по колонке суммы ваших проводок программно и записывайте его в реквизит шапки. В противном случае в списке документов (журнале) сумма операции будет отображаться равной нулю до тех пор, пока пользователь не пересчитает ее вручную.ПолучитьСсылку() менеджера документа.Применяя данные подходы, мы получаем чистый, стабильный и поддерживаемый код, соответствующий стандартам разработки управляемого интерфейса 1С.