В практике разработки на платформе 1С предприятие часто возникает классическая дилемма: как совместить жесткую математическую логику платформы и гибкие требования реального бизнеса. Типичный пример такой задачи — необходимость временно или навсегда убрать определенный товар из актуального прайс-листа (исключить из среза последних), сохранив при этом всю историю изменений его цен в прошлом.
Давайте подробно разберем, почему возникает эта проблема, какие ограничения накладывает платформа 1С, и проанализируем несколько практических методов решения — от самых простых (на уровне запросов) до продвинутых архитектурных подходов, которые используются в высоконагруженных типовых конфигурациях.
Для начала проанализируем ситуацию с точки зрения СУБД и платформы 1С. Виртуальная таблица СрезПоследних для периодического регистра сведений работает по строгому математическому алгоритму. Она возвращает последнюю по времени запись для каждого уникального набора измерений на указанную дату.
Если в документе «Установка цен номенклатуры №1» от 01.10.2023 была установлена цена на Товар А, а в документе «Установка цен номенклатуры №2» от 15.10.2023 мы просто «забыли» или намеренно не указали Товар А (потому что мы временно им не торгуем), то с точки зрения платформы 1С:
СрезПоследних абсолютно корректно продолжает возвращать старую цену Товара А.Попытка просто снять активность у старой записи (сделать ее неактивной) приведет к тому, что платформа начнет искать еще более раннюю запись по этой номенклатуре. Если мы хотим «выключить» позицию глобально, нам нужны другие инструменты. Рассмотрим их подробнее.
---
Это самый очевидный и простой в реализации способ, который часто применяется на практике. Если товар выводится из прайс-листа, мы создаем новый документ установки цен, где явно записываем для этого товара цену, равную нулю (или отрицательное значение).
Разберем по шагам, как в этом случае будет выглядеть запрос для получения действующих цен:
ВЫБРАТЬ
ЦеныСрезПоследних.Номенклатура КАК Номенклатура,
ЦеныСрезПоследних.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены = &ВидЦены) КАК ЦеныСрезПоследних
ГДЕ
ЦеныСрезПоследних.Цена > 0
Преимущества метода:
Недостатки метода:
ГДЕ Цена > 0. Если база сильно кастомизирована, это может быть трудоемко.---
Если вы проектируете систему самостоятельно или имеете возможность изменять структуру регистра сведений, лучшим решением будет добавление специального признака состояния непосредственно в регистр сведений ЦеныНоменклатуры.
Мы добавляем в регистр новый ресурс (или измерение) Статус (тип: Булево, либо ссылка на перечисление со значениями «Активно» / «Отменено»).
Когда нам нужно исключить Товар А из прайс-листа, документ «Установка цен номенклатуры» делает новую запись на текущую дату, в которой:
Номенклатура = Товар А.Статус = Ложь (или «Отменено»).Теперь при получении среза последних мы легко отсекаем ненужные позиции с помощью простого условия в запросе:
ВЫБРАТЬ
ЦеныСрезПоследних.Номенклатура КАК Номенклатура,
ЦеныСрезПоследних.Цена КАК Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.SрезПоследних(&Период, ВидЦены = &ВидЦены) КАК ЦеныСрезПоследних
ГДЕ
ЦеныСрезПоследних.Статус = ИСТИНА
Поскольку последняя запись по времени для Товара А будет содержать Статус = Ложь, этот товар гарантированно не попадет в итоговую выборку действующих цен.
---
Что делать, если запросы к регистру цен разбросаны по всей конфигурации и переписывать их вручную не представляется возможным? В платформе 1С существует встроенный механизм, способный модифицировать любые запросы «на лету» — это ограничение доступа на уровне записей (Row-Level Security, или RLS).
Проанализируем этот сценарий. Мы можем настроить шаблон RLS для регистра сведений ЦеныНоменклатуры на чтение. Платформа будет автоматически добавлять условия фильтрации к любому запросу (включая виртуальную таблицу СрезПоследних), выполняемому под обычным пользователем.
Например, мы можем связать проверку с реквизитом номенклатуры АрхивныйТовар (Булево):
ЦеныНоменклатуры ИЗ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ГДЕ ЦеныНоменклатуры.Номенклатура.АрхивныйТовар = ЛОЖЬ
Важные нюансы использования RLS:
---
В современных конфигурациях 1С (таких как УТ 11, ERP, КА) разработчики практически никогда не обращаются к таблице СрезПоследних напрямую из модулей документов. Вместо этого используются специализированные функции общих модулей (например, ЦенообразованиеКлиентСервер.ПолучитьЦеныНоменклатуры).
Если ваша база является типовой и находится на поддержке, лучшим решением будет использование механизма расширений:
&Вместо или &После.Этот подход невероятно гибок, безопасен при последующих обновлениях конфигурации и не снижает общую производительность базы данных.
---
Это продвинутый архитектурный паттерн, который часто применяется при проектировании высоконагруженных систем (Highload) для достижения максимальной производительности СУБД.
Вместо одного периодического регистра сведений мы создаем два:
Разберем, как работает эта схема при проведении документов:
Теперь любой оперативный запрос (в чеке ККМ, заказе клиента или прайс-листе) обращается к обычному плоскому непериодическому регистру ДействующиеЦены:
ВЫБРАТЬ
АктуальныеЦены.Номенклатура,
АктуальныеЦены.Цена
ИЗ
РегистрСведений.ДействующиеЦены КАК АктуальныеЦены
ГДЕ
АктуальныеЦены.ВидЦены = &ВидЦены
В этой таблице физически нет записи по Товару А, поэтому он мгновенно исключается из всех рабочих процессов. При этом СУБД выполняет простейший и самый быстрый запрос без использования тяжелых вычислений среза последних на временной оси.
---
Мы проанализировали различные методы решения задачи исключения позиций из среза последних. Выбор конкретного пути зависит от архитектуры вашей базы данных: