Как исключить позицию из среза последних регистра сведений в 1С?

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

В практике разработки на платформе 1С предприятие часто возникает классическая дилемма: как совместить жесткую математическую логику платформы и гибкие требования реального бизнеса. Типичный пример такой задачи — необходимость временно или навсегда убрать определенный товар из актуального прайс-листа (исключить из среза последних), сохранив при этом всю историю изменений его цен в прошлом.

Давайте подробно разберем, почему возникает эта проблема, какие ограничения накладывает платформа 1С, и проанализируем несколько практических методов решения — от самых простых (на уровне запросов) до продвинутых архитектурных подходов, которые используются в высоконагруженных типовых конфигурациях.

Выясняем причину: почему стандартный «Срез последних» работает именно так?

Для начала проанализируем ситуацию с точки зрения СУБД и платформы 1С. Виртуальная таблица СрезПоследних для периодического регистра сведений работает по строгому математическому алгоритму. Она возвращает последнюю по времени запись для каждого уникального набора измерений на указанную дату.

Если в документе «Установка цен номенклатуры №1» от 01.10.2023 была установлена цена на Товар А, а в документе «Установка цен номенклатуры №2» от 15.10.2023 мы просто «забыли» или намеренно не указали Товар А (потому что мы временно им не торгуем), то с точки зрения платформы 1С:

Попытка просто снять активность у старой записи (сделать ее неактивной) приведет к тому, что платформа начнет искать еще более раннюю запись по этой номенклатуре. Если мы хотим «выключить» позицию глобально, нам нужны другие инструменты. Рассмотрим их подробнее.

---

Решение 1. Использование специального значения-маркера (Цена = 0 или цена < 0)

Это самый очевидный и простой в реализации способ, который часто применяется на практике. Если товар выводится из прайс-листа, мы создаем новый документ установки цен, где явно записываем для этого товара цену, равную нулю (или отрицательное значение).

Разберем по шагам, как в этом случае будет выглядеть запрос для получения действующих цен:


ВЫБРАТЬ
    ЦеныСрезПоследних.Номенклатура КАК Номенклатура,
    ЦеныСрезПоследних.Цена КАК Цена
ИЗ
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены = &ВидЦены) КАК ЦеныСрезПоследних
ГДЕ
    ЦеныСрезПоследних.Цена > 0

Преимущества метода:

  1. Предельная простота реализации. Не нужно менять структуру метаданных.
  2. Логика истории сохраняется: мы всегда видим, в какой момент цена товара стала «нулевой» (то есть когда он был выведен из оборота).

Недостатки метода:

---

Решение 2. Архитектурный паттерн: Добавление измерения или ресурса «Статус»

Если вы проектируете систему самостоятельно или имеете возможность изменять структуру регистра сведений, лучшим решением будет добавление специального признака состояния непосредственно в регистр сведений ЦеныНоменклатуры.

Мы добавляем в регистр новый ресурс (или измерение) Статус (тип: Булево, либо ссылка на перечисление со значениями «Активно» / «Отменено»).

Когда нам нужно исключить Товар А из прайс-листа, документ «Установка цен номенклатуры» делает новую запись на текущую дату, в которой:

Теперь при получении среза последних мы легко отсекаем ненужные позиции с помощью простого условия в запросе:


ВЫБРАТЬ
    ЦеныСрезПоследних.Номенклатура КАК Номенклатура,
    ЦеныСрезПоследних.Цена КАК Цена
ИЗ
    РегистрСведений.ЦеныНоменклатуры.SрезПоследних(&Период, ВидЦены = &ВидЦены) КАК ЦеныСрезПоследних
ГДЕ
    ЦеныСрезПоследних.Статус = ИСТИНА

Поскольку последняя запись по времени для Товара А будет содержать Статус = Ложь, этот товар гарантированно не попадет в итоговую выборку действующих цен.

---

Решение 3. Глобальное скрытие позиций без изменения кода запросов через RLS

Что делать, если запросы к регистру цен разбросаны по всей конфигурации и переписывать их вручную не представляется возможным? В платформе 1С существует встроенный механизм, способный модифицировать любые запросы «на лету» — это ограничение доступа на уровне записей (Row-Level Security, или RLS).

Проанализируем этот сценарий. Мы можем настроить шаблон RLS для регистра сведений ЦеныНоменклатуры на чтение. Платформа будет автоматически добавлять условия фильтрации к любому запросу (включая виртуальную таблицу СрезПоследних), выполняемому под обычным пользователем.

Например, мы можем связать проверку с реквизитом номенклатуры АрхивныйТовар (Булево):


ЦеныНоменклатуры ИЗ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ГДЕ ЦеныНоменклатуры.Номенклатура.АрхивныйТовар = ЛОЖЬ

Важные нюансы использования RLS:

  1. Механизм RLS по умолчанию не применяется к пользователям с Полными правами. Для них записи все равно будут видны, если только во встроенном языке не включить принудительное ограничение прав.
  2. Использование RLS создает дополнительную нагрузку на СУБД, так как к каждому запросу неявно добавляются левые соединения. На больших объемах данных это может привести к снижению производительности.

---

Решение 4. Использование Расширений конфигурации для перехвата запросов

В современных конфигурациях 1С (таких как УТ 11, ERP, КА) разработчики практически никогда не обращаются к таблице СрезПоследних напрямую из модулей документов. Вместо этого используются специализированные функции общих модулей (например, ЦенообразованиеКлиентСервер.ПолучитьЦеныНоменклатуры).

Если ваша база является типовой и находится на поддержке, лучшим решением будет использование механизма расширений:

  1. Создаем новое расширение конфигурации.
  2. Находим общий модуль, отвечающий за выборку цен.
  3. Перехватываем нужную функцию с помощью аннотации &Вместо или &После.
  4. Внутри нашего метода модифицируем возвращаемую таблицу значений (или дерево значений), удаляя из нее строки с товарами, которые помечены на удаление, находятся в архивных папках или имеют специальный признак «Не используется» в карточке номенклатуры.

Этот подход невероятно гибок, безопасен при последующих обновлениях конфигурации и не снижает общую производительность базы данных.

---

Решение 5. Разделение данных на «Архивный» и «Оперативный» регистры

Это продвинутый архитектурный паттерн, который часто применяется при проектировании высоконагруженных систем (Highload) для достижения максимальной производительности СУБД.

Вместо одного периодического регистра сведений мы создаем два:

  1. Регистр «История цен» (периодический): хранит всю хронологию изменений. В него только пишутся данные. К нему обращаются исключительно редкие исторические отчеты.
  2. Регистр «Действующие цены» (НЕпериодический): хранит только актуальные на текущий момент цены.

Разберем, как работает эта схема при проведении документов:

Теперь любой оперативный запрос (в чеке ККМ, заказе клиента или прайс-листе) обращается к обычному плоскому непериодическому регистру ДействующиеЦены:


ВЫБРАТЬ
    АктуальныеЦены.Номенклатура,
    АктуальныеЦены.Цена
ИЗ
    РегистрСведений.ДействующиеЦены КАК АктуальныеЦены
ГДЕ
    АктуальныеЦены.ВидЦены = &ВидЦены

В этой таблице физически нет записи по Товару А, поэтому он мгновенно исключается из всех рабочих процессов. При этом СУБД выполняет простейший и самый быстрый запрос без использования тяжелых вычислений среза последних на временной оси.

---

Подведем итоги

Мы проанализировали различные методы решения задачи исключения позиций из среза последних. Выбор конкретного пути зависит от архитектуры вашей базы данных:

← На главную