Довольно часто возникает задача программного создания документа, его заполнения определенными данными и последующего показа пользователю, при этом без непосредственной записи документа в базу данных. Это позволяет предоставить пользователю уже подготовленный черновик, который он может просмотреть, при необходимости скорректировать и затем самостоятельно принять решение о его записи. Для большинства документов в системе 1С:Предприятие 8.3 этот подход реализуется достаточно прямолинейно, поскольку они обычно содержат табличные части, которые легко заполнить в оперативной памяти.
Однако, когда мы сталкиваемся с документом «Операция (бухгалтерская)» (или ОперацияБух), ситуация значительно усложняется. Особенность этого документа в том, что он не имеет привычных табличных частей для ввода данных. Вместо этого он напрямую взаимодействует с записями регистров бухгалтерии, которые, в свою очередь, требуют обязательного наличия регистратора – то есть, ссылки на уже записанный в базу данных документ. В этом подробном руководстве мы разберем, как обойти эту сложность и все-таки программно создать и показать пользователю заполненную форму «ОперацияБух» без ее сохранения.
Прежде чем перейти к решениям, давайте глубже проанализируем, почему документ «ОперацияБух» представляет такую проблему для нашей задачи. Ключевая сложность кроется в его устройстве и принципах работы системы 1С с регистрами.
В отличие от большинства документов, где данные сначала вводятся в табличные части (например, «Товары», «Услуги»), а затем при проведении формируются движения по регистрам, документ «ОперацияБух» работает иначе. То, что пользователи видят на форме в виде строк проводок, по сути, является интерактивным представлением будущих записей регистра бухгалтерии. Эти записи еще не существуют в базе данных, они как бы "собираются" на форме.
Система 1С:Предприятие построена таким образом, что абсолютное большинство записей в регистрах (накопления, бухгалтерии, сведений с регистратором) жестко привязаны к документу-регистратору. Это означает, что каждая запись регистра должна содержать ссылку на документ, который является ее "владельцем" или "автором". Без такой ссылки невозможно создать ни одну "настоящую" запись в регистре.
Выясним причину: если документ не записан в базу данных, у него нет уникальной ссылки (GUID). Соответственно, мы не можем указать эту "несуществующую" ссылку в качестве регистратора для записей регистров. Если попытаться программно создать объект НаборЗаписей регистра и установить его отбор по несуществующему регистратору, то это приведет к ошибке или невозможности работы с набором записей в нужном нам контексте.
Когда пользователь интерактивно вводит строки проводок в документ «ОперацияБух» до его сохранения, эти данные хранятся исключительно в контексте открытой формы. Они не записываются ни в какие временные таблицы базы данных и не создают никаких записей регистров. Если закрыть форму без сохранения, вся введенная информация будет безвозвратно утеряна. Это очень похоже на то, как вы заполняете данные в текстовом редакторе — пока вы не нажмете "Сохранить", файл не будет создан на диске, и данные существуют только в оперативной памяти программы.
Исходя из этих особенностей, мы приходим к выводу, что "стандартно" повесить движения на несуществующий регистратор невозможно. Нам необходимо имитировать эти движения на уровне формы, чтобы пользователь видел заполненные данные, но фактически реальные движения по регистрам будут созданы только после того, как он сам сохранит документ.
Поскольку мы не можем создать реальные движения по регистрам без записанного регистратора, наш подход будет заключаться в программном заполнении внутренних реквизитов формы документа, которые отвечают за отображение проводок. Это создаст иллюзию уже заполненного документа, но при этом сам документ останется незаписанным в базе данных. Пользователю останется только нажать кнопку «Записать и закрыть».
Рассмотрим по шагам, как это можно реализовать в управляемом приложении 1С:Предприятия 8.3.
Основной регистр, с которым работает «ОперацияБух», это РегистрБухгалтерии.Хозрасчетный. На форме документа для него предусмотрен специальный реквизит, представляющий собой набор записей, который мы можем программно заполнить.
Первым шагом нам необходимо получить форму нового экземпляра документа ОперацияБух. Для этого мы используем функцию ПолучитьФорму, указав путь к форме объекта.
// Пример получения формы нового документа на клиенте
Форма = ПолучитьФорму("Документ.ОперацияБух.ФормаОбъекта");
Здесь ФормаОбъекта – это стандартная форма документа ОперацияБух, которая открывается при создании нового документа или редактировании существующего. Если в вашей конфигурации используется другая форма, необходимо указать ее имя.
Прежде чем заполнять проводки, логично установить основные реквизиты документа, такие как организация, дата, комментарий и т.д. Эти реквизиты являются стандартными атрибутами объекта документа, доступными через свойства формы.
// Пример заполнения общих реквизитов формы
Форма.Организация = Справочники.Организации.НайтиПоНаименованию("Наша Основная Организация");
Форма.Дата = ТекущаяДата();
Форма.Комментарий = "Программно созданная операция без записи";
// ... другие реквизиты, если необходимо
ХозрасчетныйНаборЗаписей:
На форме документа ОперацияБух для регистра бухгалтерии (хозрасчетного) существует специальный реквизит, который обычно называется ХозрасчетныйНаборЗаписей. Это объект типа НаборЗаписейРегистраБухгалтерии, который находится в контексте формы и предназначен для временного хранения вводимых пользователем проводок.
Мы можем программно добавлять в него записи, как если бы это была обычная табличная часть. Разберем шаги:
Используем метод Добавить() для реквизита ХозрасчетныйНаборЗаписей формы. Этот метод возвращает новый объект записи регистра, который мы можем заполнить.
Проводка = Форма.ХозрасчетныйНаборЗаписей.Добавить();
Каждая проводка имеет множество свойств, таких как дебетовый и кредитовый счета, субконто, сумма, количество, валюта и т.д. Мы заполняем их по аналогии с тем, как это делает пользователь вручную или как они заполнялись бы при проведении документа.
// Заполняем первую проводку
Проводка.СчетДт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("60.01"); // Пример дебетового счета
Проводка.СчетКт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("51"); // Пример кредитового счета
Проводка.Сумма = 1000.00;
Проводка.ВалютаДт = Справочники.Валюты.НайтиПоКоду("RUB");
Проводка.ВалютаКт = Справочники.Валюты.НайтиПоКоду("RUB");
Проводка.СуммаДт = 1000.00;
Проводка.СуммаКт = 1000.00;
Проводка.Содержание = "Оплата поставщику";
// Пример заполнения субконто для дебетового счета 60.01
Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты] = Справочники.Контрагенты.НайтиПоНаименованию("Поставщик А");
Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ДоговорыКонтрагентов] = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию("Договор с Поставщиком А");
// Добавляем и заполняем вторую проводку
Проводка = Форма.ХозрасчетныйНаборЗаписей.Добавить();
Проводка.СчетДт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("76.05");
Проводка.СчетКт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("51");
Проводка.Сумма = 500.00;
Проводка.Содержание = "Возврат аванса";
Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты] = Справочники.Контрагенты.НайтиПоНаименованию("Клиент Б");
// Можно добавить и третью проводку, если требуется
Проводка = Форма.ХозрасчетныйНаборЗаписей.Добавить();
Проводка.СчетДт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("08.03");
Проводка.СчетКт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("60.01");
Проводка.Сумма = 15000.00;
Проводка.Содержание = "Поступление оборудования";
Важно помнить, что если для счета предусмотрены субконто, их также необходимо заполнять, используя коллекции СубконтоДт и СубконтоКт.
После того как все необходимые реквизиты и проводки заполнены, мы просто открываем форму. Пользователь увидит ее уже полностью заполненной.
Форма.Открыть();
В этот момент документ не записан в базу данных. Пользователь может просмотреть данные, отредактировать их и затем либо записать документ, либо закрыть его без сохранения.
Документ «ОперацияБух» может формировать движения не только по регистру бухгалтерии, но и по другим регистрам (например, регистры накопления, регистры сведений, регистры НДС). Стандартная форма документа имеет механизм для динамического управления составом отображаемых регистров.
Мы можем использовать экспортную процедуру формы НастроитьСоставРегистровЗавершение для указания, какие дополнительные регистры должны быть отображены на форме. После этого форма динамически создаст соответствующие реквизиты (НаборЗаписей) для этих регистров, которые мы сможем заполнить.
НастроитьСоставРегистровЗавершение:
Эта процедура принимает список значений, где для каждого регистра мы указываем его имя, представление и флаг активности (должен ли он отображаться на форме).
// Пример динамического добавления регистра "НДСПредъявленный"
// Получаем форму (как показано выше)
Форма = ПолучитьФорму("Документ.ОперацияБух.ФормаОбъекта");
// Заполняем общие реквизиты (как показано выше)
Форма.Организация = Справочники.Организации.НайтиПоНаименованию("Наша Основная Организация");
Форма.Дата = ТекущаяДата();
// Создаем список для передачи в процедуру НастроитьСоставРегистровЗавершение
СписокИзменений = Новый СписокЗначений;
// Добавляем регистр "НДСПредъявленный". Имя реквизита на форме будет "НДСПредъявленныйНаборЗаписей"
СписокИзменений.Добавить("НДСПредъявленный", "НДС предъявленный", Истина);
// Добавим еще один для примера, если он есть в конфигурации (например, какой-то регистр накопления)
// СписокИзменений.Добавить("РасчетыСПоставщиками", "Расчеты с поставщиками", Истина);
// Вызываем экспортную процедуру формы для настройки состава регистров
Форма.НастроитьСоставРегистровЗавершение(СписокИзменений, Неопределено);
После вызова этой процедуры, форма ОперацияБух динамически создает на своей панели соответствующие вкладки и реквизиты. Например, для НДСПредъявленный будет создан реквизит формы с именем НДСПредъявленныйНаборЗаписей.
После того как реквизит формы для дополнительного регистра создан, мы можем обращаться к нему и заполнять его записи аналогично тому, как мы это делали для ХозрасчетныйНаборЗаписей.
// Пример заполнения записей для регистра НДСПредъявленный
Если Форма.Свойства().Найти("НДСПредъявленныйНаборЗаписей") <> Неопределено Тогда
ЗаписьНДС = Форма.НДСПредъявленныйНаборЗаписей.Добавить();
ЗаписьНДС.ВидЦенности = Перечисления.ВидыЦенностейНДС.Товары;
ЗаписьНДС.Событие = Перечисления.СобытияНДС.Получение;
ЗаписьНДС.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию("Поставщик А");
ЗаписьНДС.ДокументОснование = Форма.Ссылка; // Для незаписанного документа это будет пустая ссылка, но для формы это допустимо.
ЗаписьНДС.СуммаБезНДС = 10000.00;
ЗаписьНДС.СуммаНДС = 2000.00;
// ... другие поля регистра НДСПредъявленный
КонецЕсли;
Важно: При заполнении полей, ссылающихся на регистратор (например, ДокументОснование), для незаписанного документа ссылка будет пустой. Это нормально для отображения на форме, но при записи документа система сама подставит реальную ссылку.
Как и в первом решении, после заполнения всех необходимых данных мы открываем форму:
Форма.Открыть();
Пользователь увидит документ с заполненными проводками по бухгалтерии и движениями по другим регистрам в соответствующих вкладках.
Все операции по получению формы (ПолучитьФорму) и прямому манипулированию ее реквизитами (Форма.ХозрасчетныйНаборЗаписей.Добавить(), Форма.НДСПредъявленныйНаборЗаписей.Добавить()) должны выполняться на клиенте. Это обусловлено тем, что мы работаем непосредственно с объектами формы и ее визуальным представлением.
Если у вас код выполняется на сервере, вам потребуется передать полученную форму на клиент для дальнейшей обработки и открытия.
Критически важно понимать, что до момента, пока пользователь не нажмет кнопку «Записать» или «Провести» на форме документа, никаких реальных движений по регистрам в базе данных создано не будет. Все, что мы сделали, это заполнили временные структуры данных на форме, которые имитируют эти движения.
Конечная ответственность за запись документа и, следовательно, за создание движений по регистрам, лежит на пользователе. Наша задача – лишь подготовить для него заполненный шаблон.
При программном заполнении реквизитов формы, возможно, не будут автоматически срабатывать некоторые события формы (например, ПриИзменении для полей), которые обычно реагируют на интерактивный ввод. Если какая-либо логика зависит от таких событий, ее, возможно, придется вызывать явно после заполнения данных или учесть при проектировании.
Также следует учитывать, что проверки на корректность данных, которые выполняются при интерактивном вводе (например, проверка баланса проводок), будут срабатывать после нашего программного заполнения, но до записи документа. Это хорошо, так как пользователь сможет исправить потенциальные ошибки до сохранения.
Имена реквизитов формы, таких как ХозрасчетныйНаборЗаписей или НДСПредъявленныйНаборЗаписей, могут немного отличаться в разных конфигурациях или версиях платформы. Всегда рекомендуется проверять их точное имя в отладчике или в конфигураторе, изучая структуру формы документа ОперацияБух.
Применяя описанные подходы, вы сможете эффективно создавать и демонстрировать пользователям предварительно заполненные операции без их немедленной записи в базу данных, что значительно улучшит пользовательский опыт и автоматизацию рутинных задач.