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