Как правильно вывести цену номенклатуры в печатную форму 1С?

Программист 1С v8.3 (Обычные формы) Торговля и дистрибуция
← На главную

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

Анализ исходной проблемы в коде

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


// Ошибочный подход
ТекстЗапроса = "ВЫБРАТЬ Цена ИЗ РегистрСведений.ЦеныНоменклатуры.СрезПоследних Где Номенклатура = &Номенклатура и ТипЦен = &ТипЦен";
Запрос.УстановитьПараметр("ТипЦен", Справочники.Номенклатура.НайтиПоНаименованию("Розничная"));

В данном примере допущены две критические ошибки. Во-первых, условия в виртуальных таблицах крайне желательно передавать в параметры самой таблицы, а не в секцию ГДЕ. Во-вторых, поиск типа цен ведется в справочнике Номенклатура, хотя типы цен обычно хранятся в справочнике ТипыЦенНоменклатуры.

Шаг 1. Оптимизация и исправление запроса

Для корректного получения цены нам необходимо использовать параметры виртуальной таблицы СрезПоследних. Это позволит платформе сразу отсечь ненужные записи на уровне СУБД. Выясним причину, почему это важно: использование секции ГДЕ после получения среза может привести к тому, что система сначала получит последние цены для всех товаров, а потом начнет их фильтровать, что крайне непроизводительно.

Рассмотрим правильный вариант запроса:


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

Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("ДатаСреза", ТекущаяДата()); // Или дата документа
Запрос.УстановитьПараметр("Номенклатура", СсылкаНаТовар);
Запрос.УстановитьПараметр("ТипЦен", Справочники.ТипыЦенНоменклатуры.НайтиПоНаименованию("Розничная"));

РезультатЗапроса = Запрос.Выполнить();

Шаг 2. Работа с макетом и параметрами вывода

Если запрос возвращает данные (это можно проверить в отладчике, посмотрев РезультатЗапроса.Пустой()), но в печатной форме все равно пусто, проблему нужно искать в макете. Проанализируем основные моменты:

  1. Свойство "Заполнение": У ячейки, куда должна выводиться цена, в свойствах на закладке "Макет" должно стоять значение Параметр. Если там стоит "Текст", программа просто проигнорирует ваши попытки присвоить значение.
  2. Имена параметров: Убедитесь, что имя параметра в макете (например, ЦенаТовара) полностью совпадает с тем, что вы пишете в коде: Область.Параметры.ЦенаТовара = .... Регистр букв имеет значение.
  3. Видимость текста: Проверьте цвет шрифта в макете. Иногда по ошибке устанавливается белый цвет на белом фоне.

Шаг 3. Исключение запросов в цикле (Best Practices)

Одной из самых грубых ошибок является выполнение запроса к ценам внутри цикла обхода строк документа. Если в документе 100 строк, программа сделает 100 обращений к базе данных, что существенно замедлит печать. Разберем, как сделать это правильно с помощью пакетной выборки или условия В ИЕРАРХИИ.

Рассмотрим алгоритм эффективного получения цен:

  1. Сначала выгрузим всю номенклатуру из табличной части документа в массив.
  2. Передадим этот массив в один запрос.
  3. Результат запроса поместим во временную таблицу или выгрузим в Соответствие для быстрого доступа.

Пример кода для массового получения цен:


// Собираем массив уникальных ссылок номенклатуры
МассивНоменклатуры = СсылкаНаОбъект.Товары.ВыгрузитьКолонку("Номенклатура");
ОбщегоНазначенияКлиентСервер.СвернутьМассив(МассивНоменклатуры);

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   Цены.Номенклатура КАК Номенклатура,
|   Цены.Цена КАК Цена
|ИЗ
|   РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, Номенклатура В (&МассивНоменклатуры) И ТипЦен = &ТипЦен) КАК Цены";

Запрос.УстановитьПараметр("Дата", СсылкаНаОбъект.Дата);
Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
Запрос.УстановитьПараметр("ТипЦен", НужныйТипЦен);

// Выгружаем в соответствие для удобного поиска в цикле
ТаблицаЦен = Запрос.Выполнить().Выгрузить();
СоответствиеЦен = Новый Соответствие;
Для Каждого Стр Из ТаблицаЦен Цикл
    СоответствиеЦен.Вставить(Стр.Номенклатура, Стр.Цена);
КонецЦикла;

Теперь при выводе строк макета достаточно просто обратиться к соответствию: Область.Параметры.Цена = СоответствиеЦен[ТекущаяСтрока.Номенклатура];. Это в десятки раз быстрее, чем одиночные запросы.

Шаг 4. Учет характеристик и форматирование

В современных конфигурациях 1С (УТ 11, ERP, КА) цена часто зависит не только от номенклатуры, но и от характеристики. Если вы не укажете характеристику в параметрах виртуальной таблицы, запрос может вернуть несколько цен или не вернуть ни одной. Всегда проверяйте, ведется ли в базе учет по характеристикам.

Также важно красиво оформить числовое значение цены. Используем функцию Формат(), чтобы цена выглядела профессионально (с двумя знаками после запятой и разделителем тысяч):

Область.Параметры.Цена = Формат(ЗначениеЦены, "ЧЦ=15; ЧДЦ=2; ЧРГ=' '");

Резюме: чек-лист для проверки

Если цена не выводится, пройдите по шагам:

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

← На главную