Разработка и Конфигурация · 13 мин
Как изменить записи регистра накопления 1С программно
Как программно изменить записи регистра накопления в 1С: через набор записей, документ-регистратор и корректировку. Примеры кода, риски, проверка результата и FAQ.
Регистр накопления в 1С хранит количественные и суммовые остатки и обороты: товары на складах, взаиморасчёты, денежные средства. Записи в него почти всегда попадают через проведение документов, поэтому прямое редактирование таблиц регистра — крайняя мера. Программно изменить записи можно несколькими способами: перезаписать движения документа-регистратора, создать документ «Корректировка регистров» (или «Операция» в бухгалтерских конфигурациях) либо напрямую сформировать и записать набор записей.
Выбор способа зависит от задачи. Если нужно исправить движения конкретного документа — работают с его набором записей через объект документа или обработку проведения. Если нужно внести разовую корректировку без привязки к первичному документу — создают документ-регистратор. Прямая запись набора без документа используется редко: например, при загрузке начальных остатков или в сервисных обработках миграции данных.
Ниже разобраны все три подхода с примерами кода на встроенном языке 1С, ограничениями каждого метода и способами проверки результата. Примеры ориентированы на управляемые формы и типовый синтаксис платформы 8.3, но логика применима и к обычным формам.
Как устроены записи регистра накопления и что можно менять
Каждая запись регистра накопления содержит измерения (склад, номенклатура, контрагент), ресурсы (количество, сумма), реквизиты, а также служебные поля: регистратор, номер строки, период, вид движения (приход или расход). Физически записи всегда принадлежат регистратору — документу, который их сформировал. Исключение — регистры, у которых в конфигураторе отключено использование регистратора, но в типовых решениях это редкость.
Из этого следует главное правило: изменить запись можно только в составе набора, подчинённого регистратору. Нельзя «подправить одну строку» в таблице напрямую — платформа работает с набором записей целиком: при записи с замещением старые движения регистратора удаляются и заменяются новыми. Поэтому любая программная правка сводится к схеме: прочитать набор, изменить, записать.
Перед изменением уточните, включён ли для регистра режим «Итоги» и не участвует ли он в последовательностях документов. Если регистр входит в последовательность, ручная правка движений нарушит границу последовательности, и отчёты по партиям или расчётам могут стать недостоверными до восстановления последовательности.
Способ 1. Изменение движений через документ-регистратор
Самый корректный сценарий — исправить движения документа, который их сформировал. Для этого получают объект документа, обращаются к его коллекции движений, модифицируют строки и записывают. Такой подход сохраняет связь данных с первичным документом и не ломает логику проведения.
ДокОбъект = Документы.РеализацияТоваровУслуг.ПолучитьСсылку().ПолучитьОбъект(); // или по ссылке
НаборЗаписей = ДокОбъект.Движения.ТоварыНаСкладах;
НаборЗаписей.Прочитать();
Для Каждого Запись Из НаборЗаписей Цикл
Если Запись.Номенклатура = НужнаяНоменклатура Тогда
Запись.Количество = 10; // исправляем значение ресурса
КонецЕсли;
КонецЦикла;
НаборЗаписей.Записать();
Обратите внимание: после чтения набора через Прочитать() в нём находятся фактические движения документа. Если не вызвать Прочитать(), набор будет пустым, и при записи вы затрёте существующие движения пустым набором — это частая причина «пропавших» остатков.
Альтернатива — перепровести документ штатно (ДокОбъект.Записать(РежимЗаписиДокумента.Проведение)), если логика формирования движений исправлена в модуле объекта или подписке на событие. Это предпочтительнее ручной правки, когда ошибка системная и затрагивает много документов.
Способ 2. Прямая запись набора записей без получения документа
Когда нужно изменить движения массово или документ недоступен для модификации, работают напрямую через менеджер регистра. Набор создаётся, на него накладывается отбор по регистратору, затем он читается, изменяется и записывается.
НаборЗаписей = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаДокумента);
НаборЗаписей.Прочитать();
Для Каждого Запись Из НаборЗаписей Цикл
Запись.Склад = НовыйСклад;
КонецЦикла;
НаборЗаписей.Записать(Истина); // Истина — замещение существующих записей
Параметр Истина в методе Записать() означает замещение: все прежние записи этого регистратора удаляются. Если вызвать Записать(Ложь) без чтения, новые строки добавятся к существующим — так делают, когда нужно дописать дополнительные движения к документу, не трогая его собственные.
Для полной очистки движений документа достаточно создать пустой набор с отбором по регистратору и записать его с замещением: НаборЗаписей.Записать() без вызова Прочитать(). Это штатный способ «распровести» документ по конкретному регистру, не трогая остальные его движения.
- 1Сделайте резервную копию базы или протестируйте на копии
- 2Найдите регистратора, чьи движения нужно изменить
- 3Создайте набор записей и установите отбор по регистратору
- 4Вызовите Прочитать() — иначе сотрёте существующие движения
- 5Измените нужные строки в цикле или добавьте новые
- 6Запишите набор с замещением
- 7Сверьте остатки отчётом до и после изменения
Способ 3. Корректировка регистров документом
В типовых конфигурациях (ERP, УТ, КА) есть документ «Корректировка регистров» (в бухгалтерии — «Операция» с ручной операцией), который является регистратором для выбранных регистров. Программное создание такого документа — правильный способ внести разовую правку, не привязанную к первичке.
Док = Документы.КорректировкаРегистров.СоздатьДокумент();
Док.Дата = ТекущаяДатаСеанса();
СтрокаРегистра = Док.ТаблицаРегистров.Добавить();
СтрокаРегистра.Имя = "ТоварыНаСкладах";
НоваяЗапись = Док.Движения.ТоварыНаСкладах.Добавить();
НоваяЗапись.ВидДвижения = ВидДвиженияНакопления.Приход;
НоваяЗапись.Период = Док.Дата;
НоваяЗапись.Номенклатура = НужнаяНоменклатура;
НоваяЗапись.Склад = НужныйСклад;
НоваяЗапись.Количество = -5; // сторнирующее движение
Док.Записать(РежимЗаписиДокумента.Проведение);
Такой подход оставляет в базе видимый след: документ с понятной датой и комментарием, который можно найти, отменить или перепровести. Для аудита и разбора расхождений это существенно лучше «невидимых» прямых записей в регистр.
Точное имя документа и структура его табличных частей зависят от конфигурации: в одних используется «Корректировка регистров», в других — «Операция» или специализированные документы ввода остатков. Перед написанием кода откройте конфигуратор и проверьте, какие регистры документ может двигать.
Сравнение способов изменения записей
Подходит при системной ошибке в алгоритме проведения; требует исправления кода модуля и массового перепроведения
Быстрое точечное исправление; не оставляет видимого документа-обоснования, риск рассинхронизации смежных регистров
Прозрачная разовая правка с аудитным следом; требует аккуратного заполнения всех измерений вручную
Только для сервисных сценариев и загрузки остатков; в типовых регистрах обычно невозможна или нежелательна
Добавление и удаление отдельных строк движений
Чтобы добавить новую строку в существующие движения, после чтения набора вызывают Добавить() и заполняют обязательные поля: вид движения, период, все измерения и ресурсы. Незаполненные измерения приведут к записям с пустыми значениями, которые исказят отчёты и могут заблокировать проведение других документов при контроле остатков.
Удаление строки выполняется методом Удалить() по индексу или через поиск нужной записи в цикле. Удобнее собирать список строк на удаление в отдельный массив и удалять после цикла, чтобы не сбивать индексацию коллекции.
КУдалению = Новый Массив;
Для Каждого Запись Из НаборЗаписей Цикл
Если Запись.Количество = 0 Тогда
КУдалению.Добавить(Запись);
КонецЕсли;
КонецЦикла;
Для Каждого Запись Из КУдалению Цикл
НаборЗаписей.Удалить(Запись);
КонецЦикла;
НаборЗаписей.Записать();
При добавлении строк вручную не забывайте про поле Период: если оставить его пустым, запись попадёт на дату 01.01.0001 или на дату регистратора в зависимости от настроек, что исказит обороты по периодам. Поле Активность по умолчанию устанавливается в Истина, но при копировании строк из других источников его стоит проверить явно.
Транзакции, блокировки и массовая обработка
Любую правку регистров в рабочей базе выполняйте в транзакции, особенно если обрабатывается много документов. Это гарантирует, что при ошибке на середине обработки данные откатятся к исходному состоянию. Для массовых операций используйте НачатьТранзакцию() с обработкой исключений и ОтменитьТранзакцию() в блоке Исключение.
При изменении большого числа наборов записей возможны управляемые блокировки данных: другие пользователи, проводящие документы по тем же регистрам, получат ошибку ожидания. Планируйте массовые правки на нерабочее время и, где возможно, разбивайте обработку на небольшие порции с фиксацией каждой порции.
Для очень больших объёмов (сотни тысяч документов) рассмотрите вариант выгрузки данных через запрос и пакетной записи, а также временное отключение итогов регистра на время загрузки с последующим пересчётом — это штатный приём ускорения массовых операций, но он требует монопольного доступа или аккуратной организации работы.
Как проверить результат после изменения
После записи убедитесь, что данные изменились так, как задумано, и не пострадали смежные учёты. Минимальный набор проверок: сформировать отчёт по регистру до и после правки, сравнить итоговые остатки по затронутым измерениям и убедиться, что документ-регистратор по-прежнему проводится без ошибок.
Как проверить результат
Остатки изменились ровно на величину правки
Появились неожиданные строки с пустыми измерениями или дубли
Набор содержит нужное число строк, период и вид движения корректны
Строки пропали или период сбит на пустую дату
Взаиморасчёты, себестоимость и остатки согласованы между собой
Расхождения между регистрами, ошибки при перепроведении
Документ перепроводится без сообщений об ошибках
Контроль остатков блокирует проведение из-за отрицательных остатков
Для программной проверки удобно использовать запрос к виртуальной таблице остатков регистра с отбором по изменённым измерениям и сравнить результат с ожидаемым значением. Если правка выполнялась обработкой, полезно выводить в журнал или табличный документ список изменённых регистраторов и дельту по каждому ресурсу.
Если после правки обнаружились расхождения, не накатывайте новые исправления поверх: восстановите данные из резервной копии или отмените изменения сторнирующими движениями, разберитесь в причине и только потом повторите операцию.
Что важно запомнить
Записи регистра накопления меняются только через набор записей, подчинённый регистратору: прочитать — изменить — записать с замещением. Для разовых правок предпочтителен документ «Корректировка регистров», для системных ошибок — исправление проведения и перепроведение. Всегда работайте в транзакции, на копии базы и проверяйте остатки отчётом после изменения.
Частые вопросы
Можно ли изменить записи регистра накопления без документа-регистратора?
Технически — только если у регистра в конфигураторе отключена подчинённость регистратору, что в типовых решениях почти не встречается. На практике вместо «записей без документа» создают документ «Корректировка регистров» или «Операция», который выступает формальным регистратором и сохраняет аудитный след.
Почему после Записать() пропали все движения документа?
Набор записей не был прочитан перед записью. Пустой набор с установленным отбором по регистратору при записи с замещением удаляет все существующие строки. Всегда вызывайте Прочитать() перед модификацией, если цель — изменить, а не очистить движения.
Как добавить движения к документу, не стирая его собственные?
Создайте набор записей, установите отбор по регистратору, добавьте строки через Добавить() и вызовите Записать(Ложь). Параметр Ложь отключает замещение, и новые строки допишутся к существующим. Либо прочитайте набор, добавьте строки и запишите с замещением — результат тот же.
Опасно ли править регистры в закрытом периоде?
Да. Изменение движений прошлых периодов меняет остатки и обороты, на которых строились отчётность, расчёты налогов и себестоимость. Корректнее вносить правку текущей датой через корректирующий документ, а не переписывать исторические движения.
Чем отличается Записать() набора записей от Записать() документа?
Запись набора меняет только движения конкретного регистра и не запускает обработчики проведения документа. Запись документа в режиме проведения выполняет полную логику модуля: пересчитывает движения по всем регистрам, проверяет заполнение и контролирует остатки.
Как массово исправить движения у тысячи документов?
Выберите запросом нужные регистраторы, затем в цикле для каждого создавайте набор записей, читайте, изменяйте и записывайте. Оборачивайте итерации в транзакции порциями, выполняйте обработку в нерабочее время и предварительно прогоните её на копии базы с замером результата по отчётам.