← Назад к вопросам
Создание справочника Скидки для номенклатуры
2.3 Middle🔥 181 комментариев
#Запросы и оптимизация#Конфигурации и типовые#Объекты метаданных
Условие
Создайте справочник "Скидки", где назначаются скидки на номенклатуру или группу номенклатуры.
Требования:
-
Справочник "Номенклатура" с иерархией (5 уровней)
-
Справочник "Скидки" с реквизитами:
- Номенклатура/Группа номенклатуры
- Процент скидки
- Дата начала действия
- Дата окончания действия
-
При указании группы — скидка действует на все элементы внутри группы
-
Функция получения актуальной скидки для товара на дату
Логика приоритета
Если для товара есть персональная скидка — использовать её. Иначе — искать скидку по иерархии групп вверх.
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Создание справочника Скидки для номенклатуры
Архитектура решения
Создаём справочник "Скидки" с механизмом иерархического поиска актуальной скидки для товара.
1. Структура справочника Номенклатура
// Справочник Номенклатура
// Свойства:
// Иерархический = Истина
// КоличествоУровней = 5
// Реквизиты:
// - Артикул (Строка, 50)
// - ЕдиницаИзмерения (СправочникСсылка.ЕдиницыИзмерения)
// - Цена (Число, 15, 2)
2. Справочник Скидки
// Справочник Скидки
// Реквизиты:
// - Номенклатура (СправочникСсылка.Номенклатура)
// - ПроцентСкидки (Число, 5, 2)
// - ДатаНачала (Дата)
// - ДатаОкончания (Дата)
// - ЭтоГруппа (Булево) // Истина, если скидка на группу
3. Функция получения актуальной скидки
Функция ПолучитьАктуальнуюСкидку(Номенклатура, ДатаПроверки = Неопределено) Экспорт
Если ДатаПроверки = Неопределено Тогда
ДатаПроверки = ТекущаяДата();
КонецЕсли;
// Шаг 1: Ищем персональную скидку на конкретный товар
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Скидки.ПроцентСкидки КАК ПроцентСкидки
|ИЗ
| Справочник.Скидки КАК Скидки
|ГДЕ
| Скидки.Номенклатура = &Номенклатура
| И Скидки.ДатаНачала <= &Дата
| И (Скидки.ДатаОкончания >= &Дата
| ИЛИ Скидки.ДатаОкончания = ДАТАВРЕМЯ(1, 1, 1))
|УПОРЯДОЧИТЬ ПО
| Скидки.ПроцентСкидки УБЫВ";
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Запрос.УстановитьПараметр("Дата", ДатаПроверки);
Результат = Запрос.Выполнить();
Если НЕ Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
Возврат Выборка.ПроцентСкидки;
КонецЕсли;
// Шаг 2: Ищем скидку по иерархии групп (снизу вверх)
ТекущийРодитель = Номенклатура.Родитель;
Пока ТекущийРодитель <> Справочники.Номенклатура.ПустаяСсылка() Цикл
Запрос.УстановитьПараметр("Номенклатура", ТекущийРодитель);
Результат = Запрос.Выполнить();
Если НЕ Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
Возврат Выборка.ПроцентСкидки;
КонецЕсли;
ТекущийРодитель = ТекущийРодитель.Родитель;
КонецЦикла;
// Шаг 3: Скидка не найдена
Возврат 0;
КонецФункции
4. Логика приоритета
Приоритет поиска скидки (от высшего к низшему):
- Персональная скидка на конкретный товар
- Скидка на непосредственную группу товара (родитель 1-го уровня)
- Скидка на группу выше (родитель 2-го уровня)
- И так далее до корня иерархии (до 5 уровней)
Пример: Товар "iPhone 15" находится в группе "Смартфоны" → "Apple" → "Электроника".
- Если есть скидка на "iPhone 15" = 10% — используем её
- Если нет — проверяем "Смартфоны" (5%?) → "Apple" (3%?) → "Электроника" (1%?)
- Первая найденная скидка — результат
5. Оптимизация производительности
// Для массового расчёта скидок (например, в документе)
// используем один запрос с ИЕРАРХИЯ вместо цикла
Запрос.Текст =
"ВЫБРАТЬ
| Скидки.Номенклатура КАК Группа,
| Скидки.ПроцентСкидки КАК Процент
|ИЗ
| Справочник.Скидки КАК Скидки
|ГДЕ
| &Номенклатура В ИЕРАРХИИ(Скидки.Номенклатура)
| И Скидки.ДатаНачала <= &Дата
| И (Скидки.ДатаОкончания >= &Дата
| ИЛИ Скидки.ДатаОкончания = ДАТАВРЕМЯ(1, 1, 1))";
6. Проверка при записи
// В модуле объекта справочника Скидки
Процедура ПередЗаписью(Отказ)
// Проверка: процент от 0 до 100
Если ПроцентСкидки < 0 ИЛИ ПроцентСкидки > 100 Тогда
Сообщить("Процент скидки должен быть от 0 до 100");
Отказ = Истина;
КонецЕсли;
// Проверка: дата окончания >= дата начала
Если ДатаОкончания <> '00010101' И ДатаОкончания < ДатаНачала Тогда
Сообщить("Дата окончания не может быть раньше даты начала");
Отказ = Истина;
КонецЕсли;
КонецПроцедуры