Как перенести движения одного документа 1С в другой и не сломать учёт
Содержание
Скопировать движения документа в 1С кнопкой нельзя: команда «Скопировать» (F9) переносит только реквизиты и табличные части, а движения новый документ получает при собственном проведении. Готовые записи регистров из одного документа в другой переносят кодом: читают набор записей источника методом Выгрузить(), подставляют в колонку Регистратор ссылку на новый документ и записывают набор приёмника через Загрузить() и Записать().
Способ работает на любой конфигурации платформы 8.3, потому что опирается на механизмы самой платформы, а не на типовые доработки. Конфигурация важна в одном месте: в 1С:Бухгалтерии 3.0 у приёмника нужно включить ручную корректировку, иначе первое же перепроведение сотрёт скопированное.
Что можно сделать без кода, штатными средствами
Сначала стоит понять, нужен ли перенос записей вообще. Чаще всего задачу закрывает обычное копирование документа с проведением, а код нужен в узких случаях.
| Способ | Когда подходит | Что получится |
|---|---|---|
| Скопировать документ и провести | Алгоритм проведения даст те же движения | Свежие движения по текущим данным |
| Ручная корректировка в БП 3.0 | Нужно поправить несколько проводок | Правка движений прямо в форме документа |
| Документ «Операция» в БП 3.0 | Нужна проводка без первичного документа | Ручные записи в регистре бухгалтерии |
| Выгрузка в XML между базами | Документ переносится в другую базу | Документ уйдёт вместе с движениями |
| Обработка на встроенном языке | Движения нужно повторить один в один | Точная копия записей с новым регистратором |
Копирование документа и перепроведение — не одно и то же. Если с момента ввода исходного документа изменились остатки, цены или учётная политика, проведение копии даст другие суммы. Именно в этом случае и ищут, как скопировать движения документа без изменений.
Посмотреть, какие движения есть у документа, можно без программирования. В форме документа БП 3.0 есть кнопка «Показать проводки и другие движения документа» со значком Дт/Кт. В других конфигурациях регистры документа видны в панели навигации формы, в группе Перейти.
Если разошлась одна-две проводки, проще включить ручную корректировку и поправить строки руками. Обработка оправдана, когда регистров много или документов десятки.
Как устроены движения: регистратор и наборы записей
Движения — это записи в регистрах, у которых документ указан регистратором. Сам документ записей не хранит. У объекта документа есть коллекция Движения, в ней по одному набору записей на каждый регистр, отмеченный в свойствах документа на вкладке «Движения».
Набор записей привязан к документу отбором по полю Регистратор. Записать набор целиком — значит заменить все записи регистра с этим регистратором. Поэтому копирование сводится к простой схеме: прочитать набор источника, поменять регистратор, записать набор приёмника.
Состав полей зависит от вида регистра:
- 📦 Регистр накопления —
Период,Регистратор,НомерСтроки,Активность, измерения, ресурсы, реквизиты. У регистра остатков ещёВидДвижения(приход или расход). - 📒 Регистр бухгалтерии
— дополнительно
СчетДт,СчетКти значения субконто по каждой стороне. Субконто хранятся не простыми полями, а отдельной коллекцией. - 🗂 Регистр сведений
, подчинённый регистратору, — те же служебные поля плюс измерения и ресурсы. Независимые регистры сведений в
Движенияне входят и при копировании не участвуют. - 🧮 Регистр расчёта — записи связаны с перерасчётами и базовыми периодами. Их переносить кодом рискованно, здесь лучше перепровести.
Ограничение платформы: регистратором записи может быть только документ того типа, который указан в списке регистраторов регистра. Если копировать движения из «Реализации» в «Поступление», часть регистров просто не примет нового регистратора.
Порядок копирования движений через обработку
Перед стартом стоит пройти короткий список подготовки. Каждый пункт здесь закрывает отдельный риск.
Дальше порядок такой:
- Создайте документ-приёмник. Обычно это копия исходного документа через
F9с нужной датой. - Проведите приёмник. Так у него появится признак «Проведен», и отчёты будут его учитывать.
- В БП 3.0 откройте движения приёмника кнопкой
Дт/Кти поставьте флажок «Ручная корректировка (разрешает редактирование движений документа)». Запишите документ. - Откройте внешнюю обработку
через
Файл → Открытьв режиме 1С:Предприятие. - Выберите документ-источник и документ-приёмник, нажмите кнопку копирования.
- Сверьте движения обоих документов (как это сделать — ниже).
Копия документа с теми же движениями задваивает обороты: если исходный документ остаётся проведённым, остатки и выручка в отчётах удвоятся. Сразу решите, что будет с источником: его отменяют проведение, помечают на удаление или копия нужна временно и потом удаляется.
Код копирования движений документа на встроенном языке
Ниже рабочий вариант для внешней обработки. На форме два реквизита: Источник и Приемник с составным типом из нужных видов документов. Кнопка вызывает серверную процедуру.
Универсальная процедура для всех регистров
&НаКлиенте
Процедура СкопироватьДвижения(Команда)
Если Не ЗначениеЗаполнено(Источник) Или Не ЗначениеЗаполнено(Приемник) Тогда
Сообщить("Заполните источник и приемник");
Возврат;
КонецЕсли;
СкопироватьДвиженияНаСервере(Источник, Приемник, СдвинутьПериод);
Сообщить("Движения скопированы");
КонецПроцедуры
&НаСервереБезКонтекста
Процедура СкопироватьДвиженияНаСервере(Источник, Приемник, СдвинутьПериод)
ОбъектИсточник = Источник.ПолучитьОбъект();
ОбъектПриемник = Приемник.ПолучитьОбъект();
МетаПриемника = ОбъектПриемник.Метаданные();
НачатьТранзакцию();
Попытка
Для Каждого НаборИсточник Из ОбъектИсточник.Движения Цикл
МетаРегистра = НаборИсточник.Метаданные();
Если Не МетаПриемника.Движения.Содержит(МетаРегистра) Тогда
Продолжить; // у приемника нет такого регистра
КонецЕсли;
НаборИсточник.Прочитать();
Таблица = НаборИсточник.Выгрузить();
Таблица.ЗаполнитьЗначения(Приемник, "Регистратор");
Если СдвинутьПериод И Таблица.Колонки.Найти("Период") <> Неопределено Тогда
Таблица.ЗаполнитьЗначения(ОбъектПриемник.Дата, "Период");
КонецЕсли;
НаборПриемник = ОбъектПриемник.Движения[МетаРегистра.Имя];
НаборПриемник.Загрузить(Таблица);
НаборПриемник.ОбменДанными.Загрузка = Истина;
НаборПриемник.Записать(Истина);
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Что здесь происходит по шагам:
Прочитать()загружает записи источника: при получении объекта наборыДвиженияпустые.Выгрузить()отдаёт таблицу значений со всеми полями, включая служебные. Для регистра бухгалтерии в ней есть колонкиВидСубконтоДт1,СубконтоДт1и так далее, поэтому субконто переезжают без отдельного цикла.ЗаполнитьЗначения()меняет регистратор во всех строках разом. Без этого запись упадёт: регистратор в строках не совпадёт с отбором набора.ОбменДанными.Загрузка = Истинаотключает обработчики модуля набора записей. Типовые подписки не пересчитают и не перезапишут скопированное.Записать(Истина)заменяет все прежние записи приёмника по этому регистру. Движения, которые появились при проведении приёмника, исчезнут, на их месте окажутся копии.- Транзакция нужна, чтобы при ошибке на пятом регистре первые четыре не остались записанными наполовину.
Реквизит СдвинутьПериод (булево) добавьте на форму, если копия создаётся другой датой. Без сдвига записи останутся в периоде источника, и ОСВ покажет их не там, где лежит документ.
Перенос записей регистра бухгалтерии построчно
Иногда таблицу перед записью нужно отфильтровать или поправить: убрать часть проводок, заменить счёт. Тогда записи переносят в цикле. Здесь есть ловушка: ЗаполнитьЗначенияСвойств() не копирует субконто, их переносят отдельно и строго после счёта.
НаборИсточник = ОбъектИсточник.Движения.Хозрасчетный;
НаборИсточник.Прочитать();
НаборПриемник = ОбъектПриемник.Движения.Хозрасчетный;
НаборПриемник.Очистить();
Для Каждого Запись Из НаборИсточник Цикл
Новая = НаборПриемник.Добавить();
ЗаполнитьЗначенияСвойств(Новая, Запись, , "Регистратор, НомерСтроки");
Новая.Регистратор = Приемник;
Для Каждого Субконто Из Запись.СубконтоДт Цикл
Новая.СубконтоДт[Субконто.Ключ] = Субконто.Значение;
КонецЦикла;
Для Каждого Субконто Из Запись.СубконтоКт Цикл
Новая.СубконтоКт[Субконто.Ключ] = Субконто.Значение;
КонецЦикла;
КонецЦикла;
НаборПриемник.ОбменДанными.Загрузка = Истина;
НаборПриемник.Записать(Истина);
Порядок важен: сначала ЗаполнитьЗначенияСвойств() ставит СчетДт и СчетКт, и только потом заполняются субконто. Если счёт пустой, платформа не знает, какие виды субконто у строки, и значения не запишутся.
Хозрасчетный — имя основного регистра бухгалтерии в БП 3.0. В другой конфигурации подставьте своё имя из ветки «Регистры бухгалтерии» в Конфигураторе.
Как сохранить скопированные движения после перепроведения
Самая частая причина, почему движения «пропали»: приёмник перепровели. Проведение начинается с очистки всех наборов документа, затем алгоритм проведения формирует записи заново. От копии ничего не остаётся.
Что защищает движения:
- ✅ Ручная корректировка в БП 3.0. Документ с этим флажком при проведении не пересчитывает движения. Флажок хранится в документе, и групповое перепроведение его тоже учитывает.
- ✅ Исключение из группового перепроведения. В конфигурациях без ручной корректировки запишите номера таких документов и предупредите тех, кто закрывает месяц и восстанавливает последовательность.
- ✅ Комментарий в документе. Короткая пометка «движения перенесены из № … от …» сэкономит час тому, кто через полгода будет разбираться.
Отмена проведения тоже очищает движения, даже при включённой ручной корректировке. Если приёмник случайно распровели, копирование придётся повторить.
В БП 3.0 после переноса движений в закрытый период повторите закрытие месяца с этого месяца. Иначе себестоимость, курсовые разницы и финансовый результат останутся посчитанными без новых записей.
Ошибки при переносе движений и что с ними делать
Отдельно про права. Внешнюю обработку пользователь без роли администратора не откроет. В БП 3.0 при первом открытии файла платформа также показывает предупреждение защиты от опасных действий: обработку надо явно разрешить.
Проверка результата и контроль целостности
После копирования движения источника и приёмника должны совпасть по каждому регистру: по числу строк и по суммам ресурсов. Глазами это видно в форме Дт/Кт двух документов, но при десятке регистров удобнее проверить кодом.
Сверка числа записей по всем регистрам
&НаСервереБезКонтекста
Функция СверитьДвижения(Источник, Приемник)
Расхождения = Новый Массив;
ОбъектИсточник = Источник.ПолучитьОбъект();
ОбъектПриемник = Приемник.ПолучитьОбъект();
Для Каждого НаборИсточник Из ОбъектИсточник.Движения Цикл
ИмяРегистра = НаборИсточник.Метаданные().Имя;
Если Не ОбъектПриемник.Метаданные().Движения.Содержит(НаборИсточник.Метаданные()) Тогда
Продолжить;
КонецЕсли;
НаборИсточник.Прочитать();
НаборПриемник = ОбъектПриемник.Движения[ИмяРегистра];
НаборПриемник.Прочитать();
Если НаборИсточник.Количество() <> НаборПриемник.Количество() Тогда
Расхождения.Добавить(СтрШаблон("%1: %2 и %3 записей", ИмяРегистра,
Формат(НаборИсточник.Количество(), "ЧН=0; ЧГ=0"),
Формат(НаборПриемник.Количество(), "ЧН=0; ЧГ=0")));
КонецЕсли;
КонецЦикла;
Возврат Расхождения;
КонецФункции
Пустой массив — числа строк совпали. Если массив не пустой, в нём имена регистров с разным количеством записей.
Сверка сумм запросом
Число строк совпадает и при ошибке в субконто или суммах. Поэтому суммы ресурсов сверяют запросом. Пример для регистра бухгалтерии БП 3.0:
ВЫБРАТЬ
Хозрасчетный.Регистратор КАК Документ,
КОЛИЧЕСТВО(*) КАК Строк,
СУММА(Хозрасчетный.Сумма) КАК Сумма
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный
ГДЕ
Хозрасчетный.Регистратор В (&Источник, &Приемник)
СГРУППИРОВАТЬ ПО
Хозрасчетный.Регистратор
Две строки с одинаковыми суммами — проводки перенесены верно. Для регистров накопления запрос тот же, меняется только имя таблицы и ресурсы.
Последняя проверка — оборотно-сальдовая ведомость за период приёмника по затронутым счетам. Сравните её с ведомостью, сформированной до копирования. Если источник распроведён и период тот же, итоги не изменятся: обороты источника ушли, такие же пришли с приёмником. Если источник остался проведённым, обороты вырастут ровно на движения приёмника.