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