Как автоматически заполнить цену в документе из регистра сведений при выборе номенклатуры

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

При разработке конфигураций на платформе 1С:Предприятие 8.3 одной из наиболее частых задач является автоматизация ввода данных. Пользователю неудобно вводить цены вручную, особенно если они уже зафиксированы в системе (например, в регистре сведений ЦеныНоменклатуры или ЦеныПоставщиков). В этой статье мы подробно разберем, как реализовать автоматическое подтягивание цены в документ сразу после выбора товара.

Суть задачи и логика работы

Представим ситуацию: вы создаете документ УстановкаЦен или ЗаказПокупателя. В табличной части или в реквизитах шапки вы выбираете Номенклатуру. В этот момент система должна «сходить» в регистр сведений, найти самую актуальную цену на дату документа и подставить её в соответствующее поле. Рассмотрим, как это сделать правильно с точки зрения архитектуры управляемого приложения.

Решение 1: Использование метода менеджера регистра (Простой способ)

Для решения несложных задач, где в регистре всего пара измерений, можно использовать встроенный метод ПолучитьПоследнее(). Этот метод возвращает значения ресурсов актуальной записи на определенный момент времени.

Сначала создадим функцию в Общем модуле (убедитесь, что у модуля стоят галочки "Сервер" и "Вызов сервера"):


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

Затем в Модуле формы документа вызовем эту функцию в обработчике события ПриИзменении:


&НаКлиенте
Процедура НоменклатураПриИзменении(Элемент)
    
    // Вызываем серверную функцию и заполняем реквизит объекта
    Объект.ЦенаТовара = ИмяВашегоОбщегоМодуля.ПолучитьАктуальнуюЦену(Объект.Дата, Объект.Номенклатура);
    
КонецПроцедуры

Решение 2: Использование запроса к виртуальной таблице СрезПоследних (Профессиональный способ)

Использование запросов считается «правилом хорошего тона» в разработке 1С, так как это работает быстрее при больших объемах данных и позволяет гибко настраивать условия. Рассмотрим вариант использования функции &НаСервереБезКонтекста. Это наиболее оптимальный способ с точки зрения производительности, так как на сервер не передаются все данные формы, а только необходимые параметры.

Разберем реализацию в модуле формы:


&НаКлиенте
Процедура НоменклатураПриИзменении(Элемент)
    
    // Передаем дату и номенклатуру на сервер для поиска цены
    Цена = ПолучитьЦенуНаСервере(Объект.Дата, Объект.Номенклатура);
    Объект.ЗакупочнаяЦена = Цена;
    
КонецПроцедуры

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

Важное пояснение: обратите внимание на параметры виртуальной таблицы СрезПоследних(&ДатаСреза, Номенклатура = &Номенклатура). Крайне важно накладывать фильтр по номенклатуре именно в параметрах виртуальной таблицы, а не в секции ГДЕ. Это значительно ускоряет работу базы данных.

Разбор типичных ошибок новичков

Проанализируем основные проблемы, с которыми сталкиваются начинающие разработчики при решении этой задачи:

  1. Переменная не определена: Ошибка возникает, когда вы пытаетесь использовать Номенклатура или ДатаСреза внутри запроса, не установив их через Запрос.УстановитьПараметр().
  2. Отсутствие возврата значения: Процедура на сервере выполняет расчет, но не возвращает его клиенту. Всегда проверяйте, что ваша функция заканчивается оператором Возврат.
  3. Работа с пустой выборкой: Если в регистре нет записи для выбранного товара, запрос вернет пустой результат. Попытка обратиться к Выборка.ЗакупочнаяЦена без проверки РезультатЗапроса.Пустой() приведет к аварийному завершению программы.
  4. Контекстные вызовы: Использование &НаСервере вместо &НаСервереБезКонтекста заставляет систему гонять данные всей формы туда-обратно. Для получения одной цифры это избыточно.

Продвинутый уровень: Учет характеристик и типов цен

В реальных конфигурациях, таких как 1С:Управление торговлей или 1С:ERP, цена зависит не только от номенклатуры, но и от других разрезов. Проанализируем, как дополнить наш запрос.

Если в вашем регистре есть измерение ВидЦены (например: Оптовая, Розничная), ваш отбор должен обязательно включать этот параметр. В противном случае система может вернуть случайную цену из всех доступных для этой номенклатуры.

Пример структуры отбора для метода ПолучитьПоследнее с учетом типа цены:


Отбор = Новый Структура;
Отбор.Вставить("Номенклатура", ЭлементНоменклатуры);
Отбор.Вставить("ВидЦены", Объект.ВидЦены); // Берем вид цены из реквизита документа

ЗначениеРесурсов = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(АктуальнаяДата, Отбор);

Как получить «старую» и «новую» цену?

Иногда требуется вывести в форму документа динамику цен. Метод СрезПоследних вернет только одну, самую свежую запись. Чтобы получить предыдущую цену, мы должны выполнить запрос к основной таблице регистра сведений с сортировкой по дате:


Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |	ЦеныПоставщика.ЗакупочнаяЦена
    |ИЗ
    |	РегистрСведений.ЦеныПоставщика КАК ЦеныПоставщика
    |ГДЕ
    |	ЦеныПоставщика.Номенклатура = &Номенклатура
    |	И ЦеныПоставщика.Период < &ДатаАктуальнойЦены
    |УПОРЯДОЧИТЬ ПО
    |	ЦеныПоставщика.Период УБЫВ";

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

Совет: После автоматического заполнения цены не забудьте вызвать пересчет суммы строки (Цена * Количество), если это табличная часть. Обычно для этого в модуле формы уже существует типовая процедура, которую достаточно вызвать программно после присвоения значения цене.

← На главную