Как выгрузить движения регистра накопления без документов из одной базы 1С в другую?

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

В практике администрирования и разработки на платформе 1С:Предприятие нередки случаи, когда в результате некорректного обновления, сбоя или ошибки программиста затираются или искажаются движения по регистрам накопления. Ситуация осложняется, если инцидент произошел в закрытом периоде. Прямое перепроведение документов-регистраторов категорически запрещено, так как это может изменить финансовые результаты прошлых периодов или нарушить последовательность партионного учета.

Если у нас есть актуальная резервная копия (бэкап) базы данных, содержащая корректные движения до сбоя, мы можем перенести только записи регистра накопления, оставив сами документы нетронутыми. В этой статье мы подробно разберем, как восстановить движения регистра без перепроведения и изменения документов-регистраторов, рассмотрев несколько проверенных способов.

Важное теоретическое условие: синхронизация по GUID

Прежде чем приступать к переносу данных любым из способов, мы должны убедиться в выполнении важнейшего технического условия: база-источник (бэкап) и база-приемник (рабочая база) должны быть идентичны на уровне уникальных идентификаторов (GUID/UUID). Это означает, что база-приемник должна быть прямым наследником базы-источника. Ссылки на документы, справочники контрагентов, договоров и номенклатуры в обеих базах должны иметь абсолютно одинаковые внутренние идентификаторы в СУБД.

Если документы в базах создавались независимо (даже при одинаковых номерах и датах), у них будут разные GUID. В этом случае прямой перенос записей регистра приведет к появлению битых ссылок вида <Объект не найден> в поле «Регистратор».

---

Способ 1. Использование стандартной обработки «ВыгрузкаЗагрузкаДанныхXML»

Это самый быстрый, надежный и простой способ решения проблемы, не требующий написания кода или сложных правил обмена. Обработка ВыгрузкаЗагрузкаДанныхXML.epf (ее можно найти на диске ИТС или в каталоге установки шаблонов конфигураций) позволяет переносить данные напрямую между идентичными конфигурациями. Также для этой задачи подойдёт специализированная обработка для выгрузки и загрузки движений документов в XML.

Разберем по шагам, как правильно настроить процесс, чтобы не затереть лишние данные в рабочей базе:

  1. Откроем обработку ВыгрузкаЗагрузкаДанныхXML.epf в базе-источнике (резервной копии) через меню «Файл» — «Открыть».
  2. В дереве метаданных на вкладке «Выгрузка» найдем наш пострадавший регистр накопления (например, Взаиморасчеты) и отметим его галочкой.
  3. Критически важный шаг: снимем галочку «Выгружать объекты по ссылкам» (или аналогичную опцию автоматического добавления связанных объектов в зависимости от версии обработки). Если этого не сделать, система вместе с записями регистра выгрузит сами документы-регистраторы, справочники контрагентов, договоров и валют. Это может перезаписать актуальные реквизиты документов в рабочей базе старыми данными из бэкапа.
  4. Настроим отбор. Если нам нужно перенести данные только за определенный период или по конкретным контрагентам, нажмем кнопку «Настроить отбор» у выбранного регистра и укажем условия (например, Период МЕЖДУ <ДатаНачала> И <ДатаОкончания>).
  5. Укажем путь к файлу выгрузки (формат .xml) и нажмем кнопку «Выгрузить данные».
  6. Перейдем в базу-приемник (рабочую базу), откроем ту же обработку на вкладке «Загрузка», выберем созданный XML-файл и нажмем «Загрузить данные».

Результат: При загрузке набора записей регистра платформа автоматически найдет существующие документы по их GUID и свяжет движения с ними. Ни один документ не будет перепроведен, статус проведения («Проведен») не изменится, а движения встанут на свои места. Для контроля результатов восстановления и поиска возможных расхождений в проводках применяется автоматическая сверка бухгалтерских и налоговых проводок между исходной и целевой базами.

---

Способ 2. Программный перенос через XML-сериализацию наборов записей

Если стандартной обработки нет под рукой, или вам требуется сложная логика фильтрации (например, перенос записей только по определенному списку контрагентов из табличной части стороннего документа), мы можем написать простой скрипт за 15 минут. Платформа 1С обладает мощным механизмом сериализации объектов в формат XML.

Давайте разберем код для выгрузки движений из базы-источника. Нам потребуется создать внешнюю обработку и написать следующий обработчик:


// Код для выгрузки в базе-источнике (резервная копия)
Процедура ВыгрузитьДвиженияНаДиск(ПутьКФайлу, НачалоПериода, КонецПериода, МассивКонтрагентов) Экспорт

    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.ОткрытьФайл(ПутьКФайлу, "UTF-8");
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    ЗаписьXML.ЗаписатьНачалоЭлемента("ДанныеРегистра");

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

    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();

    Пока Выборка.Следующий() Цикл
        // Создаем набор записей для каждого регистратора отдельно
        НаборЗаписей = РегистрыНакопления.Взаиморасчеты.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Регистратор.Установить(Выборка.Регистратор);
        НаборЗаписей.Прочитать();
        
        Если НаборЗаписей.Количество() > 0 Тогда
            // Сериализуем набор записей в XML
            ЗаписатьXML(ЗаписьXML, НаборЗаписей);
        КонецЕсли;
    КонецЦикла;

    ЗаписьXML.ЗаписатьКонецЭлемента();
    ЗаписьXML.Закрыть();
    
    Сообщить("Выгрузка успешно завершена!");

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

Теперь разберем код для загрузки в базе-приемнике. Обратите внимание на свойство ОбменДанными.Загрузка = Истина, которое предотвращает срабатывание прикладных подписок на события и проверку закрытого периода при записи набора:


// Код для загрузки в базе-приемнике (рабочая база)
Процедура ЗагрузитьДвиженияСДиска(ПутьКФайлу) Экспорт

    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
    
    // Пропускаем корневой элемент "ДанныеРегистра"
    ЧтениеXML.Прочитать(); 
    
    НачатьТранзакцию();
    Попытка
        Пока ЧтениеXML.Прочитать() Цикл
            // Проверяем начало элемента сериализованного набора записей
            Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента 
                И ЧтениеXML.Имя = "РегистрНакопленияНаборЗаписей.Взаиморасчеты" Тогда
                
                // Десериализуем объект обратно в набор записей
                НаборЗаписей = ПрочитатьXML(ЧтениеXML, Тип("РегистрНакопленияНаборЗаписей.Взаиморасчеты"));
                
                // Включаем режим загрузки данных, чтобы обойти проверки и обработчики
                НаборЗаписей.ОбменДанными.Загрузка = Истина;
                
                // Записываем набор. Параметр "Истина" означает замещение существующих записей 
                // по данному регистратору в базе-приемнике
                НаборЗаписей.Записать(Истина);
                
            КонецЕсли;
        КонецЦикла;
        
        ЗафиксироватьТранзакцию();
        Сообщить("Загрузка успешно завершена!");
    Исключение
        ОтменитьТранзакцию();
        Сообщить("Ошибка при загрузке: " + ОписаниеОшибки());
    КонецПопытки;
    
    ЧтениеXML.Закрыть();

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

---

Способ 3. Перенос с помощью конфигурации «Конвертация Данных 2.1»

Если вы привыкли работать через правила обмена и хотите выполнить перенос через универсальный обмен данными (XML), вы можете быстро настроить правила в Конвертации Данных. Посмотрим, как это сделать правильно:

  1. Создадим новую конвертацию, выгрузив структуры метаданных из источника и приемника.
  2. Создадим Правило Конвертации Объектов (ПКО) для каждого вида документов, которые могут выступать регистраторами для вашего регистра.
  3. В ПКО документа перейдем на вкладку «Движения» и отметим галочкой нужный регистр накопления.
  4. Для того чтобы документы не перепроводились при загрузке, в обработчике события ПередЗагрузкой или ПриЗагрузке для ПКО документов обязательно установим свойство: РежимЗаписи = "Записать"; (или укажем ОбменДанными.Загрузка = Истина;). Это крайне важно, иначе платформа попытается перепровести документ по всем регистрам.
  5. Создадим Правила Выгрузки Данных (ПВД) для документов, настроив отборы по периоду или контрагентам на уровне выборки данных.

Этот способ сложнее первого, но он незаменим, если базы не на 100% идентичны, и вам требуется на лету сопоставлять какие-то реквизиты движений (например, если в базах различаются GUID некоторых договоров или статей движения денежных средств). В таких случаях для точечной миграции с сопоставлением объектов по произвольным полям поиска применяется обработка для переноса данных между похожими конфигурациями 1С.

---

Способ 4. Перенос на уровне СУБД (SQL) — Критическая опасность и решение

Иногда системные администраторы предлагают выполнить перенос напрямую в СУБД (например, через MS SQL Server Management Studio) с помощью запроса INSERT INTO... из одной таблицы базы данных в другую. Это самый быстрый способ для баз объемом в сотни гигабайт, но он таит в себе смертельную опасность для итогов регистра.

Проанализируем структуру регистра накопления в СУБД. На уровне базы данных регистр состоит минимум из двух таблиц:

Если вы выполните прямой SQL-перенос записей в таблицу движений _AccumReg12345, СУБД ничего не узнает о таблице итогов. В результате вы столкнетесь со следующими проблемами:

Решение: Если вы все же воспользовались SQL-переносом, сразу после этого необходимо запустить Конфигуратор, открыть меню «Администрирование» — «Тестирование и исправление» и выбрать пункт «Пересчет итогов». Также можно выполнить это программно в режиме «Предприятие» для конкретного регистра:


// Полный пересчет итогов для конкретного регистра накопления
РегистрыНакопления.Взаиморасчеты.УстановитьИспользованиеИтогов(Истина);
РегистрыНакопления.Взаиморасчеты.ПересчитатьИтоги();

---

Выводы и рекомендации

Мы рассмотрели четыре способа восстановления утерянных движений. Давайте подведем итог и выберем оптимальный инструмент:

← На главную