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