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