← Назад к вопросам

Создание справочника Скидки для номенклатуры

2.3 Middle🔥 181 комментариев
#Запросы и оптимизация#Конфигурации и типовые#Объекты метаданных

Условие

Создайте справочник "Скидки", где назначаются скидки на номенклатуру или группу номенклатуры.

Требования:

  1. Справочник "Номенклатура" с иерархией (5 уровней)

  2. Справочник "Скидки" с реквизитами:

    • Номенклатура/Группа номенклатуры
    • Процент скидки
    • Дата начала действия
    • Дата окончания действия
  3. При указании группы — скидка действует на все элементы внутри группы

  4. Функция получения актуальной скидки для товара на дату

Логика приоритета

Если для товара есть персональная скидка — использовать её. Иначе — искать скидку по иерархии групп вверх.

Комментарии (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. Скидка на непосредственную группу товара (родитель 1-го уровня)
  3. Скидка на группу выше (родитель 2-го уровня)
  4. И так далее до корня иерархии (до 5 уровней)

Пример: Товар "iPhone 15" находится в группе "Смартфоны" → "Apple" → "Электроника".

  • Если есть скидка на "iPhone 15" = 10% — используем её
  • Если нет — проверяем "Смартфоны" (5%?) → "Apple" (3%?) → "Электроника" (1%?)
  • Первая найденная скидка — результат

5. Оптимизация производительности

// Для массового расчёта скидок (например, в документе)
// используем один запрос с ИЕРАРХИЯ вместо цикла

Запрос.Текст = 
"ВЫБРАТЬ
|    Скидки.Номенклатура КАК Группа,
|    Скидки.ПроцентСкидки КАК Процент
|ИЗ
|    Справочник.Скидки КАК Скидки
|ГДЕ
|    &Номенклатура В ИЕРАРХИИ(Скидки.Номенклатура)
|    И Скидки.ДатаНачала <= &Дата
|    И (Скидки.ДатаОкончания >= &Дата
|        ИЛИ Скидки.ДатаОкончания = ДАТАВРЕМЯ(1, 1, 1))";

6. Проверка при записи

// В модуле объекта справочника Скидки
Процедура ПередЗаписью(Отказ)
    
    // Проверка: процент от 0 до 100
    Если ПроцентСкидки < 0 ИЛИ ПроцентСкидки > 100 Тогда
        Сообщить("Процент скидки должен быть от 0 до 100");
        Отказ = Истина;
    КонецЕсли;
    
    // Проверка: дата окончания >= дата начала
    Если ДатаОкончания <> '00010101' И ДатаОкончания < ДатаНачала Тогда
        Сообщить("Дата окончания не может быть раньше даты начала");
        Отказ = Истина;
    КонецЕсли;
    
КонецПроцедуры