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