В практике разработчика 1С, особенно на этапе прохождения собеседований или обучения, часто встречается задача: создать документ Бухгалтерская операция и наполнить его данными (проводками) из других документов, таких как Реализация товаров и услуг или Поступление товаров и услуг. На первый взгляд задача кажется простой, но она скрывает в себе несколько важных архитектурных нюансов платформы «1С:Предприятие 8».
В этой статье мы подробно разберем, как устроен документ ОперацияБух, почему его нельзя рассматривать как обычный документ с табличной частью и как правильно реализовать перенос данных как в пользовательском, так и в программном режиме.
Для начала проанализируем ситуацию: в типовых решениях (например, в «1С:Бухгалтерии 3.0») документ ОперацияБух (в интерфейсе — «Операция, введенная вручную») является уникальным объектом. В отличие от большинства других документов, он практически не содержит собственных данных в реквизитах или табличных частях.
Рассмотрим подробнее: когда вы открываете этот документ в пользовательском режиме и видите таблицу с проводками, вы на самом деле работаете напрямую с данными Регистра бухгалтерии. Документ здесь выступает лишь в роли «оболочки» или визуализатора. Все записи, которые вы вносите, записываются в регистр Хозрасчетный с привязкой к этому документу как к Регистратору.
Важный момент: если вы планируете решать эту задачу программно, вы не сможете просто добавить строки в «табличную часть» документа, потому что её не существует в привычном понимании. Вам придется работать с Набором записей регистра бухгалтерии.
Если перед вами стоит задача выполнить перенос вручную (например, для проверки понимания основ бухгалтерского учета), алгоритм будет следующим:
СчетДт) и его аналитика (СубконтоДт).СчетКт) и его аналитика (СубконтоКт).Выясним причину, почему это может быть сложно для новичка: основная трудность заключается в правильном заполнении Субконто. Это аналитические разрезы (Контрагенты, Договоры, Номенклатура, Склады). Если вы укажете счет, но не заполните субконто, бухгалтерские отчеты (например, Оборотно-сальдовая ведомость) станут некорректными, так как данные «зависнут» на пустой аналитике.
Рассмотрим более сложный, но профессиональный подход — автоматизацию этого процесса. Допустим, нам нужно написать процедуру, которая находит последние документы и копирует их движения в новую Операцию.
Для поиска документов воспользуемся механизмом запросов. Нам нужно получить последние документы по времени, учитывая их статус Проведен.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Реализация.Ссылка КАК Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Проведен = ИСТИНА
|УПОРЯДОЧИТЬ ПО
| Реализация.МоментВремени УБЫВ;
|
|ВЫБРАТЬ ПЕРВЫЕ 1
| Поступление.Ссылка КАК Ссылка
|ИЗ
| Документ.ПоступлениеТоваровУслуг КАК Поступление
|ГДЕ
| Поступление.Проведен = ИСТИНА
|УПОРЯДОЧИТЬ ПО
| Поступление.МоментВремени УБЫВ";
РезультатыЗапроса = Запрос.ВыполнитьПакет();
Здесь мы используем МоментВремени для сортировки, так как это гарантирует правильный хронологический порядок, даже если документы созданы в одну секунду.
Теперь создадим объект документа и подготовимся к записи движений. Помните, что для документа ОперацияБух запись в регистр происходит в режиме «Ручного управления».
НоваяОперация = Документы.ОперацияБух.СоздатьДокумент();
НоваяОперация.Дата = ТекущаяДата();
НоваяОперация.Организация = Справочники.Организации.НайтиПоРеквизиту("ИНН", "7700000000"); // Пример
НоваяОперация.Содержание = "Перенос проводок из последних документов";
НоваяОперация.Записать();
// Получаем ссылку
СсылкаНаОперацию = НоваяОперация.Ссылка;
// Создаем набор записей регистра бухгалтерии
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаОперацию);
Разберем по шагам процесс переноса. Нам нужно прочитать движения исходного документа и построчно добавить их в наш набор записей. Проанализируем ситуацию с субконто: это коллекция, которую нужно копировать внимательно.
Процедура КопироватьДвижения(ДокументИсточник, НаборЗаписейПриемник)
// Читаем движения источника
ДвиженияИсточника = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
ДвиженияИсточника.Отбор.Регистратор.Установить(ДокументИсточник);
ДвиженияИсточника.Прочитать();
Для Каждого ЗаписьИсточник Из ДвиженияИсточника Цикл
НоваяЗапись = НаборЗаписейПриемник.Добавить();
// Копируем стандартные реквизиты (Счета, Суммы, Период)
ЗаполнитьЗначенияСвойств(НоваяЗапись, ЗаписьИсточник);
// Обязательно устанавливаем период и организацию
НоваяЗапись.Период = ТекущаяДата();
// Копируем Субконто Дебета
Для Каждого КлючИЗначение Из ЗаписьИсточник.СубконтоДт Цикл
НоваяЗапись.СубконтоДт[КлючИЗначение.Ключ] = КлючИЗначение.Значение;
КонецЦикла;
// Копируем Субконто Кредита
Для Каждого КлючИЗначение Из ЗаписьИсточник.СубконтоКт Цикл
НоваяЗапись.СубконтоКт[КлючИЗначение.Ключ] = КлючИЗначение.Значение;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Использование метода ЗаполнитьЗначенияСвойств() значительно упрощает код, копируя такие поля как Сумма, Валюта, Количество, СчетДт и СчетКт. Однако коллекция Субконто (Дебета и Кредита) требует обхода в цикле, так как это не просто реквизиты, а динамический набор значений.
После того как все записи добавлены в НаборЗаписей, необходимо вызвать метод НаборЗаписей.Записать(). В документе «Операция» важно также убедиться, что сумма документа в шапке соответствует сумме проводок (хотя для типовой бухгалтерии 3.0 это поле часто рассчитывается автоматически или берется из движений).
Резюме: Мы проанализировали два подхода. Пользовательский режим хорош для разовой проверки и понимания сути данных. Программный метод требует навыков работы с объектами НаборЗаписей и понимания того, как в 1С устроены регистры бухгалтерии. Главное — помнить, что документ «Операция» не хранит проводки внутри себя, он является их регистратором в системе.