Как обойти весь регистр накопления в цикле и изменить записи по условию в 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

При разработке и сопровождении конфигураций 1С часто возникает задача массовой корректировки движений регистра накопления по определенному условию. Начинающие разработчики нередко пытаются прочитать весь регистр накопления целиком в один набор записей без отборов или изменить реквизиты напрямую у объекта набора. В результате платформа выдает ошибку о неустановленном отборе по регистратору либо ошибку об отсутствии поля объекта. Разберем особенности устройства регистров накопления, выясним причины этих ошибок и рассмотрим правильный пошаговый алгоритм пакетного изменения записей.

Ключевые особенности регистров накопления

В отличие от независимых регистров сведений, регистры накопления всегда подчинены регистратору. Ключом уникальности строки в таблице движений является связка Регистратор + НомерСтроки. Из этого следуют важные платформенные правила:

  1. Обязательность отбора по регистратору: Объект НаборЗаписей регистра накопления не может быть прочитан или записан без явной установки отбора по конкретному документу-регистратору. Считать «весь регистр разом» в один набор записей невозможно.
  2. Набор записей — это коллекция: Нельзя присвоить значение ресурсу или реквизиту напрямую набору (например, НаборЗаписей.Стоимость = ... вызовет исключение «Поле объекта не обнаружено»). Изменять значения нужно у конкретных элементов коллекции — строк движений.
  3. Способ установки отбора: Если вы задаете значение через свойство Набор.Отбор.Регистратор.Значение = ДокументСсылка, необходимо также обязательно указывать Набор.Отбор.Регистратор.Использование = Истина. Рекомендуется использовать метод Набор.Отбор.Регистратор.Установить(ДокументСсылка), который включает отбор автоматически.

Пошаговый алгоритм изменения записей регистра

Чтобы корректно и производительно обновить данные во всем регистре накопления, разобьем задачу на три этапа:

  1. Формирование выборки: Запросом получаем список документов-регистраторов и условий, по которым требуется выполнить изменение. Группируем выборку по регистраторам, чтобы не перезаписывать один и тот же документ многократно.
  2. Чтение и модификация набора записей: В цикле по регистраторам создаем НаборЗаписей, устанавливаем отбор по текущему документу и считываем данные методом Прочитать().
  3. Обход движений и сохранение: Во внутреннем цикле проверяем условия для каждой строки, вносим необходимые правки и записываем набор методом Записать().

Пример правильного программного кода

Рассмотрим пример процедуры на сервере, которая находит все записи регистра накопления Продажи с расхождениями стоимости и обновляет их:


&НаСервере
Процедура ИсправитьЗаписиРегистраНакопления()
    
    // 1. Формируем запрос для поиска документов, требующих корректировки
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |    Продажи.Регистратор КАК Регистратор
        |ИЗ
        |    РегистрНакопления.Продажи КАК Продажи
        |ГДЕ
        |    Продажи.СуммаПродажи < Продажи.Стоимость
        |    И ЕСТЬNULL(Продажи.СуммаПродажи, 0) >= 0";
    
    ВыборкаРегистраторов = Запрос.Выполнить().Выбрать();
    
    // 2. Обходим выбранные регистраторы
    Пока ВыборкаРегистраторов.Следующий() Цикл
        
        НаборЗаписей = РегистрыНакопления.Продажи.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Регистратор.Установить(ВыборкаРегистраторов.Регистратор);
        НаборЗаписей.Прочитать();
        
        БылиИзменения = Ложь;
        
        // 3. Обходим строки набора движений конкретного регистратора
        Для Каждого Движение Из НаборЗаписей Цикл
            
            // Проверяем условие для каждой отдельной строки
            Если Движение.СуммаПродажи < Движение.Стоимость И Движение.СуммаПродажи >= 0 Тогда
                Движение.Стоимость = Движение.СуммаПродажи;
                БылиИзменения = Истина;
            КонецЕсли;
            
        КонецЦикла;
        
        // 4. Записываем набор только при наличии изменений
        Если БылиИзменения Тогда
            НаборЗаписей.Записать();
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Важные архитектурные нюансы и рекомендации

При выполнении подобных регламентных или сервисных корректировок важно помнить о сопутствующих ограничениях платформы 1С:

  1. Перепроведение документов затирает правки: Прямое изменение набора записей регистра не меняет данные в табличных частях самих документов. Если в будущем пользователь, групповая обработка или процедура закрытия месяца перепроведет этот документ, модуль объекта сформирует движения заново, и ручные исправления в регистре будут потеряны. Если необходимо постоянное исправление, следует корректировать реквизиты самого документа или использовать типовые документы вида КорректировкаРегистров.
  2. Транзакции и блокировки: При обработке сотен тысяч записей запись каждого набора вызывает пересчет итогов регистра и накладывает блокировки в СУБД. Рекомендуется группировать запись порциями (по 200–500 регистраторов) внутри явных транзакций НачатьТранзакцию() / ЗафиксироватьТранзакцию().
  3. Подписки на события: Метод НаборЗаписей.Записать() вызывает обработчики событий ПередЗаписью и ПриЗаписи, определенные в конфигурации. Убедитесь, что выполняемые проверки (например, контроль остатков или запрет редактирования закрытых периодов) не препятствуют записи наборов.
← На главную