Как перенести движения одного документа 1С в другой и не сломать учёт

· 9 мин

Содержание

Скопировать движения документа в 1С кнопкой нельзя: команда «Скопировать» (F9) переносит только реквизиты и табличные части, а движения новый документ получает при собственном проведении. Готовые записи регистров из одного документа в другой переносят кодом: читают набор записей источника методом Выгрузить(), подставляют в колонку Регистратор ссылку на новый документ и записывают набор приёмника через Загрузить() и Записать().

Способ работает на любой конфигурации платформы 8.3, потому что опирается на механизмы самой платформы, а не на типовые доработки. Конфигурация важна в одном месте: в 1С:Бухгалтерии 3.0 у приёмника нужно включить ручную корректировку, иначе первое же перепроведение сотрёт скопированное.

Что можно сделать без кода, штатными средствами

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

СпособКогда подходитЧто получится
Скопировать документ и провестиАлгоритм проведения даст те же движенияСвежие движения по текущим данным
Ручная корректировка в БП 3.0Нужно поправить несколько проводокПравка движений прямо в форме документа
Документ «Операция» в БП 3.0Нужна проводка без первичного документаРучные записи в регистре бухгалтерии
Выгрузка в XML между базамиДокумент переносится в другую базуДокумент уйдёт вместе с движениями
Обработка на встроенном языкеДвижения нужно повторить один в одинТочная копия записей с новым регистратором

Копирование документа и перепроведение — не одно и то же. Если с момента ввода исходного документа изменились остатки, цены или учётная политика, проведение копии даст другие суммы. Именно в этом случае и ищут, как скопировать движения документа без изменений.

Посмотреть, какие движения есть у документа, можно без программирования. В форме документа БП 3.0 есть кнопка «Показать проводки и другие движения документа» со значком Дт/Кт. В других конфигурациях регистры документа видны в панели навигации формы, в группе Перейти.

Если разошлась одна-две проводки, проще включить ручную корректировку и поправить строки руками. Обработка оправдана, когда регистров много или документов десятки.

Как устроены движения: регистратор и наборы записей

Движения — это записи в регистрах, у которых документ указан регистратором. Сам документ записей не хранит. У объекта документа есть коллекция Движения, в ней по одному набору записей на каждый регистр, отмеченный в свойствах документа на вкладке «Движения».

Набор записей привязан к документу отбором по полю Регистратор. Записать набор целиком — значит заменить все записи регистра с этим регистратором. Поэтому копирование сводится к простой схеме: прочитать набор источника, поменять регистратор, записать набор приёмника.

Состав полей зависит от вида регистра:

  • 📦 Регистр накопления — Период, Регистратор, НомерСтроки, Активность, измерения, ресурсы, реквизиты. У регистра остатков ещё ВидДвижения (приход или расход).
  • 📒 Регистр бухгалтерии — дополнительно СчетДт, СчетКт и значения субконто по каждой стороне. Субконто хранятся не простыми полями, а отдельной коллекцией.
  • 🗂 Регистр сведений , подчинённый регистратору, — те же служебные поля плюс измерения и ресурсы. Независимые регистры сведений в Движения не входят и при копировании не участвуют.
  • 🧮 Регистр расчёта — записи связаны с перерасчётами и базовыми периодами. Их переносить кодом рискованно, здесь лучше перепровести.

Ограничение платформы: регистратором записи может быть только документ того типа, который указан в списке регистраторов регистра. Если копировать движения из «Реализации» в «Поступление», часть регистров просто не примет нового регистратора.

Порядок копирования движений через обработку

Перед стартом стоит пройти короткий список подготовки. Каждый пункт здесь закрывает отдельный риск.

Перед копированием движений
Выполнено: 0 / 6

Дальше порядок такой:

  1. Создайте документ-приёмник. Обычно это копия исходного документа через F9 с нужной датой.
  2. Проведите приёмник. Так у него появится признак «Проведен», и отчёты будут его учитывать.
  3. В БП 3.0 откройте движения приёмника кнопкой Дт/Кт и поставьте флажок «Ручная корректировка (разрешает редактирование движений документа)». Запишите документ.
  4. Откройте внешнюю обработку через Файл → Открыть в режиме 1С:Предприятие.
  5. Выберите документ-источник и документ-приёмник, нажмите кнопку копирования.
  6. Сверьте движения обоих документов (как это сделать — ниже).

Копия документа с теми же движениями задваивает обороты: если исходный документ остаётся проведённым, остатки и выручка в отчётах удвоятся. Сразу решите, что будет с источником: его отменяют проведение, помечают на удаление или копия нужна временно и потом удаляется.

Код копирования движений документа на встроенном языке

Ниже рабочий вариант для внешней обработки. На форме два реквизита: Источник и Приемник с составным типом из нужных видов документов. Кнопка вызывает серверную процедуру.

Универсальная процедура для всех регистров

&НаКлиенте
Процедура СкопироватьДвижения(Команда)
	Если Не ЗначениеЗаполнено(Источник) Или Не ЗначениеЗаполнено(Приемник) Тогда
		Сообщить("Заполните источник и приемник");
		Возврат;
	КонецЕсли;
	СкопироватьДвиженияНаСервере(Источник, Приемник, СдвинутьПериод);
	Сообщить("Движения скопированы");
КонецПроцедуры

&НаСервереБезКонтекста
Процедура СкопироватьДвиженияНаСервере(Источник, Приемник, СдвинутьПериод)

	ОбъектИсточник = Источник.ПолучитьОбъект();
	ОбъектПриемник = Приемник.ПолучитьОбъект();
	МетаПриемника  = ОбъектПриемник.Метаданные();

	НачатьТранзакцию();
	Попытка
		Для Каждого НаборИсточник Из ОбъектИсточник.Движения Цикл

			МетаРегистра = НаборИсточник.Метаданные();
			Если Не МетаПриемника.Движения.Содержит(МетаРегистра) Тогда
				Продолжить; // у приемника нет такого регистра
			КонецЕсли;

			НаборИсточник.Прочитать();
			Таблица = НаборИсточник.Выгрузить();
			Таблица.ЗаполнитьЗначения(Приемник, "Регистратор");

			Если СдвинутьПериод И Таблица.Колонки.Найти("Период") <> Неопределено Тогда
				Таблица.ЗаполнитьЗначения(ОбъектПриемник.Дата, "Период");
			КонецЕсли;

			НаборПриемник = ОбъектПриемник.Движения[МетаРегистра.Имя];
			НаборПриемник.Загрузить(Таблица);
			НаборПриемник.ОбменДанными.Загрузка = Истина;
			НаборПриемник.Записать(Истина);

		КонецЦикла;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;

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

Что здесь происходит по шагам:

  • Прочитать() загружает записи источника: при получении объекта наборы Движения пустые.
  • Выгрузить() отдаёт таблицу значений со всеми полями, включая служебные. Для регистра бухгалтерии в ней есть колонки ВидСубконтоДт1, СубконтоДт1 и так далее, поэтому субконто переезжают без отдельного цикла.
  • ЗаполнитьЗначения() меняет регистратор во всех строках разом. Без этого запись упадёт: регистратор в строках не совпадёт с отбором набора.
  • ОбменДанными.Загрузка = Истина отключает обработчики модуля набора записей. Типовые подписки не пересчитают и не перезапишут скопированное.
  • Записать(Истина) заменяет все прежние записи приёмника по этому регистру. Движения, которые появились при проведении приёмника, исчезнут, на их месте окажутся копии.
  • Транзакция нужна, чтобы при ошибке на пятом регистре первые четыре не остались записанными наполовину.

Реквизит СдвинутьПериод (булево) добавьте на форму, если копия создаётся другой датой. Без сдвига записи останутся в периоде источника, и ОСВ покажет их не там, где лежит документ.

Перенос записей регистра бухгалтерии построчно

Иногда таблицу перед записью нужно отфильтровать или поправить: убрать часть проводок, заменить счёт. Тогда записи переносят в цикле. Здесь есть ловушка: ЗаполнитьЗначенияСвойств() не копирует субконто, их переносят отдельно и строго после счёта.

НаборИсточник = ОбъектИсточник.Движения.Хозрасчетный;
НаборИсточник.Прочитать();
НаборПриемник = ОбъектПриемник.Движения.Хозрасчетный;
НаборПриемник.Очистить();

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

НаборПриемник.ОбменДанными.Загрузка = Истина;
НаборПриемник.Записать(Истина);

Порядок важен: сначала ЗаполнитьЗначенияСвойств() ставит СчетДт и СчетКт, и только потом заполняются субконто. Если счёт пустой, платформа не знает, какие виды субконто у строки, и значения не запишутся.

Хозрасчетный — имя основного регистра бухгалтерии в БП 3.0. В другой конфигурации подставьте своё имя из ветки «Регистры бухгалтерии» в Конфигураторе.

Как сохранить скопированные движения после перепроведения

Самая частая причина, почему движения «пропали»: приёмник перепровели. Проведение начинается с очистки всех наборов документа, затем алгоритм проведения формирует записи заново. От копии ничего не остаётся.

Что защищает движения:

  • ✅ Ручная корректировка в БП 3.0. Документ с этим флажком при проведении не пересчитывает движения. Флажок хранится в документе, и групповое перепроведение его тоже учитывает.
  • ✅ Исключение из группового перепроведения. В конфигурациях без ручной корректировки запишите номера таких документов и предупредите тех, кто закрывает месяц и восстанавливает последовательность.
  • ✅ Комментарий в документе. Короткая пометка «движения перенесены из № … от …» сэкономит час тому, кто через полгода будет разбираться.

Отмена проведения тоже очищает движения, даже при включённой ручной корректировке. Если приёмник случайно распровели, копирование придётся повторить.

В БП 3.0 после переноса движений в закрытый период повторите закрытие месяца с этого месяца. Иначе себестоимость, курсовые разницы и финансовый результат останутся посчитанными без новых записей.

Ошибки при переносе движений и что с ними делать

Диагностика: выберите симптом

Отдельно про права. Внешнюю обработку пользователь без роли администратора не откроет. В БП 3.0 при первом открытии файла платформа также показывает предупреждение защиты от опасных действий: обработку надо явно разрешить.

Проверка результата и контроль целостности

После копирования движения источника и приёмника должны совпасть по каждому регистру: по числу строк и по суммам ресурсов. Глазами это видно в форме Дт/Кт двух документов, но при десятке регистров удобнее проверить кодом.

Сверка числа записей по всем регистрам

&НаСервереБезКонтекста
Функция СверитьДвижения(Источник, Приемник)

	Расхождения = Новый Массив;
	ОбъектИсточник = Источник.ПолучитьОбъект();
	ОбъектПриемник = Приемник.ПолучитьОбъект();

	Для Каждого НаборИсточник Из ОбъектИсточник.Движения Цикл
		ИмяРегистра = НаборИсточник.Метаданные().Имя;
		Если Не ОбъектПриемник.Метаданные().Движения.Содержит(НаборИсточник.Метаданные()) Тогда
			Продолжить;
		КонецЕсли;
		НаборИсточник.Прочитать();
		НаборПриемник = ОбъектПриемник.Движения[ИмяРегистра];
		НаборПриемник.Прочитать();
		Если НаборИсточник.Количество() <> НаборПриемник.Количество() Тогда
			Расхождения.Добавить(СтрШаблон("%1: %2 и %3 записей", ИмяРегистра,
				Формат(НаборИсточник.Количество(), "ЧН=0; ЧГ=0"),
				Формат(НаборПриемник.Количество(), "ЧН=0; ЧГ=0")));
		КонецЕсли;
	КонецЦикла;

	Возврат Расхождения;

КонецФункции

Пустой массив — числа строк совпали. Если массив не пустой, в нём имена регистров с разным количеством записей.

Сверка сумм запросом

Число строк совпадает и при ошибке в субконто или суммах. Поэтому суммы ресурсов сверяют запросом. Пример для регистра бухгалтерии БП 3.0:

ВЫБРАТЬ
	Хозрасчетный.Регистратор КАК Документ,
	КОЛИЧЕСТВО(*) КАК Строк,
	СУММА(Хозрасчетный.Сумма) КАК Сумма
ИЗ
	РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
	Хозрасчетный.Регистратор В (&Источник, &Приемник)

СГРУППИРОВАТЬ ПО
	Хозрасчетный.Регистратор

Две строки с одинаковыми суммами — проводки перенесены верно. Для регистров накопления запрос тот же, меняется только имя таблицы и ресурсы.

Последняя проверка — оборотно-сальдовая ведомость за период приёмника по затронутым счетам. Сравните её с ведомостью, сформированной до копирования. Если источник распроведён и период тот же, итоги не изменятся: обороты источника ушли, такие же пришли с приёмником. Если источник остался проведённым, обороты вырастут ровно на движения приёмника.

Частые вопросы

Можно ли скопировать движения в документ другого вида?
Только по тем регистрам, где вид приёмника указан среди регистраторов. Остальные регистры такого регистратора не примут.
Переносятся ли при копировании неактивные проводки?
Да. Поле Активность входит в выгруженную таблицу, и строки переносятся с тем же признаком, что у источника.
Как перенести движения документа в другую базу?
Внутренней обработкой нельзя: ссылки на документы в двух базах разные. Используйте выгрузку и загрузку данных XML с выгрузкой движений или правила обмена.
Нужно ли пересчитывать итоги регистров после копирования?
Нет. Платформа обновляет итоги при записи набора. Пересчёт итогов нужен только при подозрении на сбой базы.
Чем такой перенос опасен в рабочей базе?
Задвоением оборотов, если источник остался проведённым, и отрицательными остатками: режим загрузки не проверяет остатки. Поэтому сначала копия базы, потом сверка.