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

Настройка ценообразования по типам цен

2.0 Middle🔥 221 комментариев
#Конфигурации и типовые

Условие

Реализуйте систему ценообразования с разными типами цен.

Требования:

  1. Справочник "ТипыЦен" (Закупочная, Оптовая, Розничная и т.д.)
  2. Регистр сведений "ЦеныНоменклатуры" (Номенклатура, ТипЦен → Цена)
  3. Документ установки цен (массовое изменение цен)
  4. Возможность установки цен на основании документа поступления
  5. Отчёт "Прайс-лист" по выбранному типу цен

Дополнительно

При выборе типа цены в документе продажи автоматически подставлять соответствующую цену в табличную часть.

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Система ценообразования с типами цен

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

Справочник "ТипыЦен"

Справочник ТипыЦен
  Номер: строка (уникальный)
  Наименование: строка
  Описание: строка
  ПриоритетОтбора: число (для определения цены по умолчанию)
  ПометкаУдаления: булево
КонецСправочника

Стандартные типы цен:

  • 01 - Закупочная
  • 02 - Оптовая
  • 03 - Розничная
  • 04 - СПО (Специальная оптовая)
  • 05 - Контрактная

Регистр сведений "ЦеныНоменклатуры"

РегистрСведений ЦеныНоменклатуры
  Период: дата // для истории изменения цен
  
  // Измерения
  Измерение: Номенклатура (ссылка на Номенклатуру)
  Измерение: ТипЦены (ссылка на ТипыЦен)
  Измерение: ЕдиницаИзмерения (ссылка на ЕдиницыИзмерения)
  
  // Ресурсы
  Ресурс: Цена (число) // в валюте организации
  Ресурс: НижнийПредел (число) // мин. скидка при кол-ве
  Ресурс: ДатаНачала (дата) // начало действия цены
  Ресурс: ДатаОконча (дата) // конец действия цены
КонецРегистраСведений

Документ "УстановкаЦен"

Для массового изменения цен:

Документ УстановкаЦен
  Реквизит: Номер (строка)
  Реквизит: Дата (дата)
  Реквизит: ТипЦены (ссылка на ТипыЦен)
  Реквизит: ДатаНачала (дата)
  Реквизит: ДатаОконча (дата)
  
  Табличная часть: ЦеныТовары
    Колонка: Номенклатура (ссылка на Номенклатуру)
    Колонка: ЕдиницаИзмерения (ссылка на ЕдиницыИзмерения)
    Колонка: ОтклонениеПроцент (число) // % изменения от текущей
    Колонка: НоваяЦена (число)
    Колонка: НижнийПредел (число) // кол-во для скидки
    Колонка: СкидкаПроцент (число)
КонецДокумента

Реализация документа УстановкаЦен

// Процедура проведения документа
Процедура ПроведениеДокумента(Отмена, РежимПроведения)
    
    Попытка
        // Очищаем регистр
        Движения.ЦеныНоменклатуры.Очистить();
        
        Для Каждого ЦенаСтрока Из ЭтотОбъект.ЦеныТовары Цикл
            
            // Валидация
            Если НЕ ЗначениеЗаполнено(ЦенаСтрока.Номенклатура) Тогда
                ВызватьОшибку("Не указана номенклатура");
            КонецЕсли;
            
            Если ЦенаСтрока.НоваяЦена <= 0 Тогда
                ВызватьОшибку("Цена должна быть больше нуля");
            КонецЕсли;
            
            // Создаём запись в регистре
            Движение = Движения.ЦеныНоменклатуры.Добавить();
            Движение.Период = ЭтотОбъект.Дата;
            Движение.Номенклатура = ЦенаСтрока.Номенклатура;
            Движение.ТипЦены = ЭтотОбъект.ТипЦены;
            Движение.ЕдиницаИзмерения = ЦенаСтрока.ЕдиницаИзмерения;
            Движение.Цена = ЦенаСтрока.НоваяЦена;
            Движение.НижнийПредел = ЦенаСтрока.НижнийПредел;
            Движение.ДатаНачала = ЭтотОбъект.ДатаНачала;
            Движение.ДатаОконча = ЭтотОбъект.ДатаОконча;
        КонецЦикла;
        
        ЗаписатьВЖурнал("Установка цен", "Установлены цены по типу: " + ЭтотОбъект.ТипЦены.Наименование);
        
    Исключение
        ВызватьОшибку("Ошибка при проведении: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

// Процедура заполнения цен на основании поступления
Процедура ЗаполнитьНаОснованииПоступления(Команда)
    
    Диалог = Новый ДиалогВыбораИБ();
    Диалог.ПолеВыбора = "Documents.ПриходТоваров";
    
    Если Диалог.Выбрать() Тогда
        ПриходТоваров = Диалог.ВыбранныхЗначений[0];
        
        ЭтотОбъект.ЦеныТовары.Очистить();
        
        Для Каждого СтрокаПриход Из ПриходТоваров.Товары Цикл
            НоваяСтрока = ЭтотОбъект.ЦеныТовары.Добавить();
            НоваяСтрока.Номенклатура = СтрокаПриход.Номенклатура;
            НоваяСтрока.ЕдиницаИзмерения = СтрокаПриход.ЕдиницаИзмерения;
            НоваяСтрока.НоваяЦена = СтрокаПриход.Цена;
        КонецЦикла;
        
        Сообщение("Цены заполнены из документа поступления");
    КонецЕсли;
    
КонецПроцедуры

// Процедура пересчёта цен с применением отклонения
Процедура ПересчитатьЦены(Команда)
    
    Для Каждого ЦенаСтрока Из ЭтотОбъект.ЦеныТовары Цикл
        
        Если ЦенаСтрока.ОтклонениеПроцент <> 0 Тогда
            // Получаем текущую цену
            ТекущаяЦена = ПолучитьТекущуюЦену(ЦенаСтрока.Номенклатура, ЭтотОбъект.ТипЦены);
            
            // Применяем отклонение
            ЦенаСтрока.НоваяЦена = ТекущаяЦена * (1 + ЦенаСтрока.ОтклонениеПроцент / 100);
        КонецЕсли;
        
    КонецЦикла;
    
    Сообщение("Цены пересчитаны");
    
КонецПроцедуры

// Функция получения текущей цены
Функция ПолучитьТекущуюЦену(Номенклатура, ТипЦены)
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Цены.Цена
    |ИЗ
    |    РегистрСведений.ЦеныНоменклатуры КАК Цены
    |ГДЕ
    |    Цены.Номенклатура = @Номенклатура
    |    И Цены.ТипЦены = @ТипЦены
    |    И Цены.Период <= @ТекущаяДата
    |    И (Цены.ДатаОконча > @ТекущаяДата ИЛИ Цены.ДатаОконча = '00010101')
    |УПОРЯДОЧИТЬ ПО
    |    Цены.Период УБЫВ";
    
    Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
    Запрос.УстановитьПараметр("ТипЦены", ТипЦены);
    Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата());
    
    Результат = Запрос.Выполнить();
    
    Если НЕ Результат.Пусто() Тогда
        Выборка = Результат.Выбрать();
        Выборка.Следующий();
        Возврат Выборка.Цена;
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

Функция автоматической подстановки цены в документ продажи

// Процедура при заполнении номенклатуры в табличной части
Процедура ТаблицаПродажиНоменклатураПриИзменении(Элемент)
    
    ТекущаяСтрока = Элемент.ТекущиеДанные;
    
    // Получаем выбранный тип цены
    ТипЦены = ЭтаФорма.ОбъектДанных.ТипЦены;
    
    Если НЕ ЗначениеЗаполнено(ТипЦены) Тогда
        Сообщение("Сначала выберите тип цены");
        Возврат;
    КонецЕсли;
    
    // Получаем цену для номенклатуры и типа
    Цена = ПолучитьЦенуДляДокумента(
        ТекущаяСтрока.Номенклатура,
        ТипЦены,
        ТекущаяСтрока.Количество
    );
    
    Если ЗначениеЗаполнено(Цена) Тогда
        ТекущаяСтрока.Цена = Цена;
        ТекущаяСтрока.Сумма = ТекущаяСтрока.Количество * ТекущаяСтрока.Цена;
    Иначе
        Сообщение("Цена не установлена для выбранной номенклатуры");
    КонецЕсли;
    
КонецПроцедуры

// Функция для получения цены с учётом скидок
Функция ПолучитьЦенуДляДокумента(Номенклатура, ТипЦены, Количество)
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Цены.Цена,
    |    Цены.НижнийПредел
    |ИЗ
    |    РегистрСведений.ЦеныНоменклатуры КАК Цены
    |ГДЕ
    |    Цены.Номенклатура = @Номенклатура
    |    И Цены.ТипЦены = @ТипЦены
    |    И Цены.Период <= @ТекущаяДата
    |    И (Цены.ДатаОконча > @ТекущаяДата ИЛИ Цены.ДатаОконча = '00010101')
    |УПОРЯДОЧИТЬ ПО
    |    Цены.Период УБЫВ";
    
    Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
    Запрос.УстановитьПараметр("ТипЦены", ТипЦены);
    Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата());
    
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Цена = Выборка.Цена;
        
        // Применяем скидку если превышен нижний предел
        Если Количество >= Выборка.НижнийПредел И Выборка.НижнийПредел > 0 Тогда
            // Можно применить скидку здесь
        КонецЕсли;
        
        Возврат Цена;
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

Отчёт "Прайс-лист"

// Функция для получения прайс-листа
Функция ПолучитьПрайсЛист(ТипЦены, НаДату = Неопределено)
    
    Если НаДату = Неопределено Тогда
        НаДату = ТекущаяДата();
    КонецЕсли;
    
    Таблица = Новый ТаблицаЗначений();
    Таблица.Колонки.Добавить("Код", Новый ОписаниеТипов("Строка"));
    Таблица.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("Строка"));
    Таблица.Колонки.Добавить("ЕдиницаИзмерения", Новый ОписаниеТипов("Строка"));
    Таблица.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
    Таблица.Колонки.Добавить("НижнийПредел", Новый ОписаниеТипов("Число"));
    Таблица.Колонки.Добавить("ДатаНачала", Новый ОписаниеТипов("Дата"));
    Таблица.Колонки.Добавить("ДатаОконча", Новый ОписаниеТипов("Дата"));
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Номер КАК Код,
    |    Номенклатура.Наименование КАК Номенклатура,
    |    ЕдиницыИзмерения.Наименование КАК ЕдиницаИзмерения,
    |    Цены.Цена,
    |    Цены.НижнийПредел,
    |    Цены.ДатаНачала,
    |    Цены.ДатаОконча
    |ИЗ
    |    РегистрСведений.ЦеныНоменклатуры КАК Цены
    |    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
    |        ПО Цены.Номенклатура = Номенклатура.Ссылка
    |    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ЕдиницыИзмерения КАК ЕдиницыИзмерения
    |        ПО Цены.ЕдиницаИзмерения = ЕдиницыИзмерения.Ссылка
    |ГДЕ
    |    Цены.ТипЦены = @ТипЦены
    |    И Цены.Период <= @НаДату
    |    И (Цены.ДатаОконча > @НаДату ИЛИ Цены.ДатаОконча = '00010101')
    |    И НЕ Номенклатура.ПометкаУдаления = Истина
    |УПОРЯДОЧИТЬ ПО
    |    Номенклатура.Номер,
    |    Номенклатура.Наименование";
    
    Запрос.УстановитьПараметр("ТипЦены", ТипЦены);
    Запрос.УстановитьПараметр("НаДату", НаДату);
    
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        НоваяСтрока = Таблица.Добавить();
        НоваяСтрока.Код = Выборка.Код;
        НоваяСтрока.Номенклатура = Выборка.Номенклатура;
        НоваяСтрока.ЕдиницаИзмерения = Выборка.ЕдиницаИзмерения;
        НоваяСтрока.Цена = Выборка.Цена;
        НоваяСтрока.НижнийПредел = Выборка.НижнийПредел;
        НоваяСтрока.ДатаНачала = Выборка.ДатаНачала;
        НоваяСтрока.ДатаОконча = Выборка.ДатаОконча;
    КонецЦикла;
    
    Возврат Таблица;
    
КонецФункции

Архитектурные решения

1. История изменения цен:

  • Регистр с Периодом позволяет хранить историю
  • Можно откатиться на любую дату

2. Гибкое управление:

  • Документ УстановкаЦен для массовых изменений
  • Возможность автоматизации из поступлений

3. Автоматизация в документах:

  • События табличной части подставляют цену
  • Скидки и пределы рассчитываются автоматически

4. Безопасность:

  • Валидация цен
  • Логирование изменений
  • История для аудита

Эта система обеспечивает гибкое и удобное управление ценами в конфигурации 1С:Предприятие.