Как программно скопировать одну проводку из одного набора записей в другой с сохранением субконто

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8 часто возникает задача копирования или переноса конкретных записей (проводок) из одного документа в другой или между наборами записей регистра бухгалтерии. На первый взгляд задача кажется тривиальной, однако при работе с регистром Хозрасчетный (или любым другим регистром бухгалтерии) разработчики сталкиваются с тем, что стандартные методы копирования не переносят аналитику — субконто.

В этой статье мы подробно разберем, почему простой метод ЗаполнитьЗначенияСвойств не справляется с задачей, и рассмотрим несколько надежных способов копирования проводок, включая работу с таблицами значений и прямой обход коллекций.

Проблема использования метода ЗаполнитьЗначенияСвойств

Рассмотрим стандартную ситуацию. У нас есть два набора записей для разных регистраторов (документов). Мы хотим взять первую запись из первого набора и добавить её во второй. Типичная ошибка начинающего разработчика выглядит так:


НаборЗаписейИсточник = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписейИсточник.Отбор.Регистратор.Установить(СсылкаИсточник);
НаборЗаписейИсточник.Прочитать();

НаборЗаписейПриемник = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписейПриемник.Отбор.Регистратор.Установить(СсылкаПриемник);
НаборЗаписейПриемник.Прочитать();

НоваяЗапись = НаборЗаписейПриемник.Добавить();
// Попытка копирования
ЗаполнитьЗначенияСвойств(НоваяЗапись, НаборЗаписейИсточник[0]);

Проанализируем этот код. Метод ЗаполнитьЗначенияСвойств успешно скопирует такие реквизиты, как СчетДт, СчетКт, Сумма, Организация и Период. Однако поле Субконто (для дебета и кредита) останется пустым. Это происходит потому, что Субконто в регистре бухгалтерии — это не просто значение, а специальный объект-коллекция (РегистрБухгалтерииСубконто). Платформа не умеет автоматически копировать содержимое одной коллекции в другую через этот метод.

Способ 1: Использование промежуточной Таблицы Значений

Этот метод считается наиболее универсальным и простым в реализации. При выгрузке набора записей в таблицу значений, платформа 1С динамически создает колонки для каждого вида субконто (например, СубконтоДт1, СубконтоКт1 и так далее). Это позволяет манипулировать данными как обычными строками таблицы.

Разберем алгоритм действий по шагам:

  1. Прочитаем набор записей, в который нужно добавить проводку.
  2. Выгрузим его в ТаблицаЗначений.
  3. Выгрузим запись-источник во вторую (временную) таблицу значений.
  4. Скопируем строку из временной таблицы в основную.
  5. Загрузим таблицу обратно в набор записей.

// 1. Читаем целевой набор
НаборПриемник = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборПриемник.Отбор.Регистратор.Установить(СсылкаПриемник);
НаборПриемник.Прочитать();

// 2. Выгружаем существующие проводки в ТЗ
ТЗ_Приемник = НаборПриемник.Выгрузить();

// 3. Получаем данные источника (можно запросом для оптимизации)
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ * 
    |ИЗ РегистрБухгалтерии.Хозрасчетный 
    |ГДЕ Регистратор = &РегистраторИсточник И НомерСтроки = &НомерСтроки";
Запрос.УстановитьПараметр("РегистраторИсточник", СсылкаИсточник);
Запрос.УстановитьПараметр("НомерСтроки", 1); // К примеру, первая строка

ТЗ_Источник = Запрос.Выполнить().Выгрузить();

// 4. Добавляем строку из источника в приемник
Если ТЗ_Источник.Количество() > 0 Тогда
    НоваяСтрока = ТЗ_Приемник.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, ТЗ_Источник[0]);
    
    // Важно: Регистратор в ТЗ должен соответствовать отбору набора
    НоваяСтрока.Регистратор = СсылкаПриемник;
КонецЕсли;

// 5. Загружаем данные обратно
НаборПриемник.Загрузить(ТЗ_Приемник);
НаборПриемник.Записать();

Преимущество: Метод автоматически обрабатывает все субконто, так как имена колонок в ТЗ при выгрузке регистра бухгалтерии стандартизированы.

Способ 2: Прямое копирование с обходом коллекции Субконто

Если вы не хотите использовать промежуточные таблицы и предпочитаете работать напрямую с объектами набора записей, необходимо реализовать цикл по коллекции субконто. Выясним причину, почему это важно: у каждого счета свой набор видов субконто, и прямое присвоение всей коллекции невозможно.

Рассмотрим пример функции для копирования одной записи:


Процедура СкопироватьЗаписьРегистра(ЗаписьИсточник, ЗаписьПриемник)
    
    // Копируем основные реквизиты, исключая системные
    ЗаполнитьЗначенияСвойств(ЗаписьПриемник, ЗаписьИсточник, "Регистратор, НомерСтроки");
    
    // Копируем Субконто Дебета
    Для Каждого КлючИЗначение Из ЗаписьИсточник.СубконтоДт Цикл
        ЗаписьПриемник.СубконтоДт[КлючИЗначение.Ключ] = КлючИЗначение.Значение;
    КонецЦикла;
    
    // Копируем Субконто Кредита
    Для Каждого КлючИЗначение Из ЗаписьИсточник.СубконтоКт Цикл
        ЗаписьПриемник.СубконтоКт[КлючИЗначение.Ключ] = КлючИЗначение.Значение;
    КонецЦикла;

КонецПроцедуры

В этом примере мы используем ЗаполнитьЗначенияСвойств, но явно указываем список исключений ("Регистратор, НомерСтроки"), чтобы не нарушить целостность целевого набора. Затем мы вручную переносим аналитику. Обратите внимание, что объект Субконто ведет себя как соответствие (Key-Value), где ключом является ВидСубконто.

Важные технические нюансы

При переносе проводок программным способом следует учитывать несколько критически важных моментов, которые могут повлиять на корректность учета:

Оптимизация производительности

Проанализируем ситуацию, когда в документе-источнике тысячи проводок, а нам нужна всего одна. Вызов метода НаборЗаписей.Прочитать() заставит платформу поднять в память все записи этого регистратора. Это крайне неэффективно с точки зрения потребления оперативной памяти и нагрузки на SQL-сервер.

В таких случаях рекомендуется использовать Запрос. С помощью запроса мы выбираем только нужные поля конкретной строки. Результат запроса можно выгрузить в таблицу значений и использовать алгоритм, описанный во втором способе. Это значительно ускорит работу системы, особенно в крупных базах данных.

Таким образом, мы рассмотрели основные подходы к переносу проводок. Использование Таблицы Значений является наиболее безопасным и быстрым в написании кодом способом, в то время как пообъектный обход коллекции Субконто дает более тонкий контроль над процессом копирования.

← На главную