При работе в 1С:Управление торговлей 11.4 часто возникает задача создания внешних печатных форм, которые должны отображать данные, отсутствующие в самом документе. Типичный пример — печать накладной из документа ПоступлениеТоваровУслуг, где вместо закупочных цен должны фигурировать розничные цены, установленные для конкретного магазина (склада).
В этой статье мы подробно разберем, как программно получить актуальную цену из регистра сведений, рассмотрим типовые ошибки начинающих разработчиков и проанализируем профессиональные способы решения этой задачи с использованием API конфигурации.
Представим ситуацию: в систему вводится документ поступления. Цены в нем — закупочные. Однако для внутреннего учета или для передачи товара в торговый зал требуется распечатать форму, где будет указана розничная цена. Сложность заключается в том, что в УТ 11.4 розничная цена может быть разной для разных магазинов.
Разберем алгоритм действий, который нам необходимо реализовать:
ВидЦены, привязанный к этому складу (обычно это реквизит РозничныйВидЦены).ЦеныНоменклатуры.Этот способ подходит для понимания механики работы с регистрами сведений. Как выяснилось в ходе обсуждения на форуме, начинающие программисты часто сталкиваются с тем, что вместо числа в печатную форму выводится слово "Структура". Проанализируем правильный код получения цены.
Рассмотрим пример кода внутри цикла обработки строк документа:
// 1. Формируем структуру отбора для регистра
Отбор = Новый Структура;
Отбор.Вставить("Номенклатура", ВыборкаПоТоварам.Номенклатура);
Отбор.Вставить("Характеристика", ВыборкаПоТоварам.Характеристика);
Отбор.Вставить("ВидЦены", ДанныеПечати.Склад.РозничныйВидЦены);
// 2. Получаем последнее значение из регистра на дату документа
// Важно использовать дату документа, а не ТекущуюДату!
СтруктураРесурсов = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(ДанныеПечати.Дата, Отбор);
// 3. Извлекаем цену из структуры ресурсов
ЦенаРозничная = 0;
Если СтруктураРесурсов.Количество() > 0 Тогда
ЦенаРозничная = СтруктураРесурсов.Цена;
КонецЕсли;
// 4. Заполняем параметры области макета
СтруктураДанныхЦенаРоз = Новый Структура;
СтруктураДанныхЦенаРоз.Вставить("ЦенаРозничная", ЦенаРозничная);
ОбластьДанных.Параметры.Заполнить(СтруктураДанныхЦенаРоз);
Важные замечания к этому коду:
Объект.Ссылка), а не наименование товара (строку). Это критично для корректной работы запроса к БД.Характеристика в отборе, вы рискуете получить неверную цену или пустое значение.ПолучитьПоследнее всегда возвращает объект Структура, содержащий все ресурсы регистра (Цена, Валюта, Упаковка). Чтобы получить само число, нужно обратиться к ключу .Цена.Метод ПолучитьПоследнее внутри цикла — это классическая ошибка производительности "N+1". Если в накладной 200 строк, система сделает 200 отдельных запросов к базе данных. Проанализируем, как сделать это правильно с помощью одного запроса.
Рассмотрим построение запроса для получения цен сразу по всему списку товаров из документа:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыДокумента.Номенклатура КАК Номенклатура,
| ТоварыДокумента.Характеристика КАК Характеристика,
| ЦеныНоменклатурыСрезПоследних.Цена КАК ЦенаРозничная
|ИЗ
| Документ.ПоступлениеТоваровУслуг.Товары КАК ТоварыДокумента
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
| &Период,
| ВидЦены = &ВидЦены
| И Номенклатура В (ВЫБРАТЬ Т.Номенклатура ИЗ Документ.ПоступлениеТоваровУслуг.Товары КАК Т ГДЕ Т.Ссылка = &Ссылка)) КАК ЦеныНоменклатурыСрезПоследних
| ПО ТоварыДокумента.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура
| И ТоварыДокумента.Характеристика = ЦеныНоменклатурыСрезПоследних.Характеристика
|ГДЕ
| ТоварыДокумента.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Запрос.УстановитьПараметр("Период", СсылкаНаДокумент.Дата);
Запрос.УстановитьПараметр("ВидЦены", СсылкаНаДокумент.Склад.РозничныйВидЦены);
РезультатЗапроса = Запрос.Выполнить();
Такой подход работает в десятки раз быстрее и является стандартом разработки в среде 1С:Предприятие 8.
Разработчики фирмы "1С" уже предусмотрели множество функций для получения цен. Использование встроенных модулей гарантирует, что вы учтете дополнительные нюансы: упаковки, валюты и наборы. Рассмотрим функцию ПродажиСервер.ПолучитьЦенуПоОтбору, которую упоминали эксперты на форуме.
Проанализируем пример использования типового механизма:
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("Номенклатура", СтрокаТовара.Номенклатура);
ПараметрыОтбора.Вставить("Характеристика", СтрокаТовара.Характеристика);
ПараметрыОтбора.Вставить("ВидЦены", СкладДокумента.РозничныйВидЦены);
ПараметрыОтбора.Вставить("Дата", Объект.Дата);
// Типовая функция вернет уже готовую цену с учетом всех правил системы
Цена = ПродажиСервер.ПолучитьЦенуПоОтбору(ПараметрыОтбора);
Также в конфигурации Управление торговлей версии 11 существует мощный модуль ЦенообразованиеВызовСервера. Его методы позволяют получать цены массово для списка товаров, автоматически обрабатывая пересчет из одной валюты в другую.
Выясним причины, по которым цена может не выводиться или быть некорректной, даже если код написан правильно:
РозничныйВидЦены может быть не заполнен. В коде необходимо предусмотреть проверку: Если ЗначениеЗаполнено(Склад.РозничныйВидЦены) Тогда....Установка цен номенклатуры. Если менеджер создал поступление, но не сделал установку цен, ваша печатная форма выведет ноль.РаботаСВалютами для пересчета по курсу на дату документа.Мы разобрали путь от простого (но не совсем эффективного) метода ПолучитьПоследнее до использования оптимизированных запросов и типового API конфигурации. Для создания надежной внешней печатной формы в УТ 11.4 рекомендуем всегда привязываться к дате документа и использовать механизмы характеристик. Это обеспечит точность данных даже при изменении цен в будущем.