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