В процессе разработки и сопровождения систем на базе 1С часто возникает задача корректировки движений, которые уже были сформированы документами. Это может быть связано с исправлением ошибок прошлых периодов, массовым заполнением новых реквизитов или специфическими требованиями бизнес-логики. В данной статье мы подробно разберем, как правильно изменять реквизиты записей регистра накопления, избегая типичных ошибок, таких как «задвоение» записей или их затирание при перепроведении документов. Чтобы проконтролировать корректность выполненных доработок и исключить ошибки в учете, применяется программа для автоматического сравнения бухгалтерских и налоговых проводок.
Для начала проанализируем ситуацию: записи в регистрах накопления в 1С всегда жестко привязаны к документу-регистратору. Мы не можем просто так взять и изменить одну строку регистра, как в таблице Excel. Любое изменение должно происходить через объект НаборЗаписей. Рассмотрим пошагово, как это реализовать.
Основной алгоритм работы с набором записей выглядит следующим образом:
НаборЗаписей для конкретного регистра.Регистратору. Это обязательное условие для регистров накопления.Представим ситуацию, когда нам нужно обойти несколько документов и во всех их движениях по регистру накопления заполнить пустой реквизит. Рассмотрим пример кода, который решает эту задачу для регистра ТоварыОрганизаций и реквизита Качество.
// 1. Сначала найдем все регистраторы, по которым есть пустые значения
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыОрганизаций.Регистратор КАК Регистратор
|ИЗ
| РегистрНакопления.ТоварыОрганизаций КАК ТоварыОрганизаций
|ГДЕ
| ТоварыОрганизаций.Качество = &ПустоеКачество
|СГРУППИРОВАТЬ ПО
| ТоварыОрганизаций.Регистратор";
Запрос.УстановитьПараметр("ПустоеКачество", Справочники.Качество.ПустаяСсылка());
РезультатЗапроса = Запрос.Выполнить().Выбрать();
// 2. Перебираем регистраторы и правим их движения
Пока РезультатЗапроса.Следующий() Цикл
// Создаем набор записей для конкретного регистра
Набор = РегистрыНакопления.ТоварыОрганизаций.СоздатьНаборЗаписей();
// Устанавливаем отбор по документу
Набор.Отбор.Регистратор.Установить(РезультатЗапроса.Регистратор);
// Читаем текущие движения документа
Набор.Прочитать();
// В цикле обходим записи и меняем значения
Для Каждого Движение Из Набор Цикл
Если Не ЗначениеЗаполнено(Движение.Качество) Тогда
Движение.Качество = Справочники.Качество.Новый;
КонецЕсли;
КонецЦикла;
// Записываем набор с замещением (параметр Истина)
Набор.Записать(Истина);
КонецЦикла;
Разберем одну из самых частых проблем, с которой сталкиваются начинающие разработчики: почему после программной записи движения в регистре удваиваются? Выясним причину: это происходит из-за неправильного использования метода Записать().
Метод Записать(Замещать) принимает булев параметр. Если мы передаем Истина, 1С сначала удаляет из регистра все записи, соответствующие установленному отбору (в нашем случае — по регистратору), а затем записывает новые данные из набора. Если же передать Ложь, система просто добавит записи из набора к тем, что уже есть в базе. Важно всегда использовать Записать(Истина) при редактировании существующих движений, чтобы избежать дублей.
Если записей в документе очень много, обход коллекции в цикле может быть не самым быстрым решением. Проанализируем способ ускорения процесса через промежуточную таблицу значений. Это особенно удобно, когда нужно заменить значение во всем наборе сразу.
Набор = РегистрыНакопления.НДФЛРасчетыСБюджетом.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(ВыбранныйДокумент);
Набор.Прочитать();
// Выгружаем в ТЗ для быстрой обработки
ТаблицаДвижений = Набор.Выгрузить();
// Массово заполняем колонку
ТаблицаДвижений.ЗаполнитьЗначения(НовоеПодразделение, "Подразделение");
// Загружаем обратно в набор и сохраняем
Набор.Загрузить(ТаблицаДвижений);
Набор.Записать(Истина);
Рассмотрим критически важный нюанс: что произойдет, если пользователь решит перепровести документ, в котором вы программно изменили движения? По умолчанию стандартный алгоритм проведения (процедура ОбработкаПроведения в модуле документа) просто затрет все ваши ручные правки своими расчетными данными.
Чтобы этого избежать, в типовых конфигурациях (БП 3.0, ЗУП 3.1) предусмотрен механизм «Ручной корректировки». Рассмотрим, как его задействовать:
РучнаяКорректировка (тип Булево).Истина у самого документа-регистратора.Проанализируем ситуацию в многопользовательской среде. При массовом изменении движений (как в примере с циклом по всем документам) крайне рекомендуется использовать объект БлокировкаДанных. Выясним, почему это важно: если вы читаете набор, меняете его в памяти, а в этот момент другой пользователь или фоновое задание проводит тот же документ, возникнет конфликт. Предварительная блокировка по регистратору гарантирует целостность данных и отсутствие ошибок «Объект заблокирован».
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыОрганизаций");
ЭлементБлокировки.УстановитьПараметр("Регистратор", РегистраторСсылка);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
// Далее следует код чтения, изменения и записи набора...
Мы рассмотрели основные способы программного изменения реквизитов записей регистра накопления. Подведем итоги:
НаборЗаписей с обязательным отбором по регистратору.Набор.Записать(Истина) — ваш главный инструмент против дублирования записей.БлокировкуДанных для обеспечения стабильности работы базы.Понимание этих механизмов позволяет разработчику 1С гибко управлять данными в системе, исправлять ошибки и реализовывать сложные алгоритмы корректировки учета. Для быстрой интерактивной правки движений также подойдёт обработка для групповой корректировки записей регистров.