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