Как добавить дополнительный реквизит номенклатуры в печатную форму в 1С:Управление торговлей 11

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

При разработке внешних печатных форм в среде 1С часто возникает задача вывода данных, которые не хранятся в основных реквизитах объектов. Типичный пример из торговой практики — вывод Ячейки хранения для товаров в печатной форме документа Заказ клиента. Поскольку в типовых конфигурациях на базе БСП (Библиотеки стандартных подсистем), таких как 1С:Управление торговлей 11.4, ячейка хранения часто создается как дополнительный реквизит номенклатуры, стандартное обращение через точку в запросе здесь не сработает.

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

Теоретическая справка: Как БСП хранит дополнительные реквизиты

Прежде чем переходить к написанию кода, выясним причину, почему нельзя просто написать ЗаказКлиентаТовары.Номенклатура.ЯчейкаХранения. В платформе 1С дополнительные реквизиты не создаются как физические колонки в таблице справочника БД. Они хранятся в специальной подчиненной табличной части объекта. Для справочника номенклатуры это табличная часть ДополнительныеРеквизиты (системное имя — Справочник.Номенклатура.ДополнительныеРеквизиты).

Данная табличная часть состоит из двух ключевых реквизитов:

Таким образом, чтобы получить значение нужного нам реквизита, нам необходимо найти строку в этой табличной части, где поле Свойство соответствует нашей «Ячейке хранения», и прочитать значение из поля Значение этой же строки.

Рассмотрим подробнее два способа решения этой задачи для нашей внешней печатной формы.

Способ 1. Получение дополнительного реквизита через левое соединение в запросе (Рекомендуемый)

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

Разберем по шагам, как изменить код функции СформироватьПечатнуюФорму, представленной в исходном коде обработки.

Шаг 1. Модернизируем текст основного запроса. Мы добавим левое соединение с табличной частью Справочник.Номенклатура.ДополнительныеРеквизиты. Обратите внимание, что имя свойства в базе данных может содержать суффикс владельца, например, Ячейка хранения (Номенклатура). Чтобы избежать жесткой привязки к имени, используем оператор ПОДОБНО с маской поиска.

Посмотрим на пример измененного текста запроса:


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

В этом запросе функция ЕСТЬNULL(НоменклатураДопРеквизиты.Значение, "") проверяет, заполнена ли ячейка у номенклатуры. Если запись о дополнительном реквизите отсутствует, запрос вернет пустую строку вместо значения NULL, что предотвратит ошибки вывода.

Шаг 2. Заполняем параметр области макета в цикле обхода выборки. В исходном коде была пустая строка ОбластьСтрокаТаблицы.Параметры.ЯчейкаХранения = ;, которая вызывала синтаксическую ошибку при компиляции. Изменим ее на присвоение полученного из запроса значения:


Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    ОбластьСтрокаТаблицы.Параметры.НомерСтроки = ВыборкаДетальныеЗаписи.НомерСтроки;
    ОбластьСтрокаТаблицы.Параметры.Товар = ВыборкаДетальныеЗаписи.Номенклатура;
    ОбластьСтрокаТаблицы.Параметры.Количество = ВыборкаДетальныеЗаписи.Количество;
    ОбластьСтрокаТаблицы.Параметры.Артикул = ВыборкаДетальныеЗаписи.НоменклатураАртикул;
    ОбластьСтрокаТаблицы.Параметры.ЕдИзм = ВыборкаДетальныеЗаписи.НоменклатураЕдиницаИзмерения;
    
    // Присваиваем значение параметра из нашей выборки запроса
    ОбластьСтрокаТаблицы.Параметры.ЯчейкаХранения = ВыборкаДетальныеЗаписи.ЯчейкаХранения;
    
    // ... дальнейшая обработка веса и вывод области ...
    ТабличныйДокумент.Вывести(ОбластьСтрокаТаблицы);
КонецЦикла;

Данный подход максимально быстрый и рекомендуется для промышленного использования на реальных базах данных 1С с большим объемом документов.

Способ 2. Получение данных через программный интерфейс БСП (Упрощенный)

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

Проанализируем, как получить значение реквизита с помощью этого модуля.

Шаг 1. Перед началом формирования табличного документа (или непосредственно перед циклом вывода строк) найдем ссылку на сам дополнительный реквизит «Ячейка хранения» в плане видов характеристик:


СвойствоЯчейка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Ячейка хранения (Номенклатура)");
Если Не ЗначениеЗаполнено(СвойствоЯчейка) Тогда
    // Если точное наименование с постфиксом не найдено, пробуем найти по краткому наименованию
    СвойствоЯчейка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Ячейка хранения");
КонецЕсли;

Шаг 2. Внутри цикла обхода товаров Пока ВыборкаДетальныеЗаписи.Следующий() Цикл вызовем экспортную функцию общего модуля БСП для получения значения этого свойства у текущей номенклатуры:


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

Важное предупреждение: Использование метода УправлениеСвойствами.ЗначениеСвойства() внутри цикла приводит к тому, что на каждой итерации (для каждой строки товара в заказе) будет выполняться отдельный запрос к базе данных. Если в заказе содержится 100-200 строк, формирование печатной формы может заметно замедлиться. Используйте этот метод только для небольших документов или в учебных целях.

Настройка макета печатной формы

Каким бы способом мы ни получили данные в коде, платформа 1С не сможет вывести их на экран, если в макете печатной формы не настроена соответствующая ячейка.

Давайте выполним необходимые настройки в макете:

  1. Откройте макет нашей внешней обработки (в коде он называется ПФ_MXL_ЗаказКлиента_Количественный).
  2. Найдите строку, принадлежащую области СтрокаТаблицы.
  3. Добавьте новую колонку (или выделите существующую свободную ячейку), куда должна выводиться информация о ячейке хранения.
  4. Откройте свойства этой ячейки (нажатием клавиши F4).
  5. В свойстве Заполнение переключите значение с положения «Текст» на положение Параметр.
  6. В поле Параметр укажите точное имя параметра: ЯчейкаХранения. Имя должно полностью совпадать с именем свойства структуры параметров области, которое мы заполняем в коде: ОбластьСтрокаТаблицы.Параметры.ЯчейкаХранения.

После этого сохраните макет и заново зарегистрируйте внешнюю печатную форму в справочнике Дополнительные отчеты и обработки вашей информационной базы 1С.

Полный пример готовой функции формирования печатной формы

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


Функция СформироватьПечатнуюФорму(СсылкаНаДокумент, ОбъектыПечати)
    ТабличныйДокумент = Новый ТабличныйДокумент;
    ТабличныйДокумент.ИмяПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_ЗаказКлиента_ЗаказКлиентаКоличественный";
    
    МакетОбработки = ПолучитьМакет("ПФ_MXL_ЗаказКлиента_Количественный");
    
    // Вывод заголовка
    ОбластьЗаголовок = МакетОбработки.ПолучитьОбласть("Заголовок");
    ОбластьЗаголовок.Параметры.ТекстЗаголовка = "Заказ клиента № " + СсылкаНаДокумент.Номер + " от " + СсылкаНаДокумент.Дата;
    ТабличныйДокумент.Вывести(ОбластьЗаголовок);
    
    // Вывод информации о поставщике
    ОбластьПоставщик = МакетОбработки.ПолучитьОбласть("Поставщик");
    ОбластьПоставщик.Параметры.ПредставлениеОрганизации = СсылкаНаДокумент.Организация;
    ТабличныйДокумент.Вывести(ОбластьПоставщик);
    
    // Вывод информации о покупателе
    ОбластьПокупатель = МакетОбработки.ПолучитьОбласть("Покупатель");
    ОбластьПокупатель.Параметры.ПредставлениеПартнера = СсылкаНаДокумент.Партнер;
    
    // Получение адреса партнера через запрос
    ЗапросАдрес = Новый Запрос;
    ЗапросАдрес.Текст = 
        "ВЫБРАТЬ
        |	ПартнерыКонтактнаяИнформация.Представление КАК Представление
        |ИЗ
        |	Справочник.Партнеры.КонтактнаяИнформация КАК ПартнерыКонтактнаяИнформация
        |ГДЕ
        |	ПартнерыКонтактнаяИнформация.Ссылка = &Ссылка";
    
    ЗапросАдрес.УстановитьПараметр("Ссылка", СсылкаНаДокумент.Партнер);
    РезультатАдрес = ЗапросАдрес.Выполнить();
    ВыборкаАдрес = РезультатАдрес.Выбрать();
    
    Если ВыборкаАдрес.Следующий() Тогда
        ОбластьПокупатель.Параметры.Адрес = ВыборкаАдрес.Представление;
    КонецЕсли;
    ТабличныйДокумент.Вывести(ОбластьПокупатель);
    
    // Вывод шапки таблицы товаров
    ОбластьШапкаТаблицы = МакетОбработки.ПолучитьОбласть("ШапкаТаблицы");
    ТабличныйДокумент.Вывести(ОбластьШапкаТаблицы);
    
    ОбластьСтрокаТаблицы = МакетОбработки.ПолучитьОбласть("СтрокаТаблицы");
    
    // Основной запрос для получения товаров и их дополнительных реквизитов (Ячейка хранения)
    ЗапросТовары = Новый Запрос;
    ЗапросТовары.Текст = 
        "ВЫБРАТЬ
        |	ЗаказКлиентаТовары.Номенклатура КАК Номенклатура,
        |	ЗаказКлиентаТовары.Номенклатура.Артикул КАК НоменклатураАртикул,
        |	ЗаказКлиентаТовары.Номенклатура.ЕдиницаИзмерения КАК НоменклатураЕдиницаИзмерения,
        |	ВЫБОР
        |		КОГДА ЗаказКлиентаТовары.Номенклатура.ВесЗнаменатель <> 0
        |		ТОГДА ЗаказКлиентаТовары.Номенклатура.ВесЧислитель / ЗаказКлиентаТовары.Номенклатура.ВесЗнаменатель * ЗаказКлиентаТовары.Количество
        |		ИНАЧЕ &Ничего
        |	КОНЕЦ КАК Вес,
        |	ВЫБОР
        |		КОГДА ЗаказКлиентаТовары.Номенклатура.ВесЗнаменатель <> 0
        |		ТОГДА ЗаказКлиентаТовары.Номенклатура.ВесЕдиницаИзмерения
        |		ИНАЧЕ &Ничего
        |	КОНЕЦ КАК ВесЕдИзм,
        |	ЗаказКлиентаТовары.Цена КАК Цена,
        |	ЗаказКлиентаТовары.Количество КАК Количество,
        |	ЗаказКлиентаТовары.Сумма КАК Сумма,
        |	ЗаказКлиентаТовары.НомерСтроки КАК НомерСтроки,
        |	ЕСТЬNULL(НоменклатураДопРеквизиты.Значение, """") КАК ЯчейкаХранения
        |ИЗ
        |	Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
        |	ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДопРеквизиты
        |		ПО ЗаказКлиентаТовары.Номенклатура = НоменклатураДопРеквизиты.Ссылка
        |		И НоменклатураДопРеквизиты.Свойство.Наименование ПОДОБНО ""%Ячейка хранения%""
        |ГДЕ
        |	ЗаказКлиентаТовары.Ссылка = &Ссылка";
    
    ЗапросТовары.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
    ЗапросТовары.УстановитьПараметр("Ничего", "---");
    
    РезультатТовары = ЗапросТовары.Выполнить();
    ВыборкаТовары = РезультатТовары.Выбрать();
    КоличествоСтрок = ВыборкаТовары.Количество();
    
    СуммаКоличество = 0;
    СуммаВес = 0;
    
    Пока ВыборкаТовары.Следующий() Цикл
        ОбластьСтрокаТаблицы.Параметры.НомерСтроки = ВыборкаТовары.НомерСтроки;
        ОбластьСтрокаТаблицы.Параметры.Товар = ВыборкаТовары.Номенклатура;
        ОбластьСтрокаТаблицы.Параметры.Количество = ВыборкаТовары.Количество;
        ОбластьСтрокаТаблицы.Параметры.Артикул = ВыборкаТовары.НоменклатураАртикул;
        ОбластьСтрокаТаблицы.Параметры.ЕдИзм = ВыборкаТовары.НоменклатураЕдиницаИзмерения;
        
        // Заполняем наш новый параметр "ЯчейкаХранения"
        ОбластьСтрокаТаблицы.Параметры.ЯчейкаХранения = ВыборкаТовары.ЯчейкаХранения;
        
        // Форматирование вывода веса
        Если ВыборкаТовары.Вес = "---" Тогда
            ОбластьСтрокаТаблицы.Параметры.Вес = ВыборкаТовары.Вес;
        Иначе
            ОбластьСтрокаТаблицы.Параметры.Вес = Формат(Окр(ВыборкаТовары.Вес, 1), "ЧДЦ=1");
        КонецЕсли;
        ОбластьСтрокаТаблицы.Параметры.ВесЕдИзм = ВыборкаТовары.ВесЕдИзм;
        
        ТабличныйДокумент.Вывести(ОбластьСтрокаТаблицы);
        
        // Подсчет итогов по весу
        ТекущВес = ВыборкаТовары.Вес;
        Если ТекущВес = "---" Тогда
            ТекущВес = 0;
        КонецЕсли;
        
        СуммаКоличество = СуммаКоличество + ВыборкаТовары.Количество;
        СуммаВес = СуммаВес + ТекущВес;
    КонецЦикла;
    
    // Вывод подвала таблицы с итогами
    ОбластьПодвалТаблицы = МакетОбработки.ПолучитьОбласть("ПодвалТаблицы");
    ОбластьПодвалТаблицы.Параметры.ИтогКоличество = СуммаКоличество;
    ОбластьПодвалТаблицы.Параметры.ИтогВес = Формат(Окр(СуммаВес, 1), "ЧДЦ=1");
    ТабличныйДокумент.Вывести(ОбластьПодвалТаблицы);
    
    // Вывод подписей и итоговой суммы прописью
    ОбластьПодписи = МакетОбработки.ПолучитьОбласть("Подписи");
    ТекстИтоговойСтроки = НСтр("ru = 'Всего наименований %ВсегоНаименований% на сумму %Сумма% руб.'");
    ТекстИтоговойСтроки = СтрЗаменить(ТекстИтоговойСтроки, "%ВсегоНаименований%", КоличествоСтрок);
    ТекстИтоговойСтроки = СтрЗаменить(ТекстИтоговойСтроки, "%Сумма%", СсылкаНаДокумент.СуммаДокумента);
    
    ОбластьПодписи.Параметры.ИтоговаяСумма = ТекстИтоговойСтроки;
    ОбластьПодписи.Параметры.СуммаПрописью = ЧислоПрописью(СсылкаНаДокумент.СуммаДокумента, "Л = ru_RU; ДП = Истина", "рубль, рубля, рублей, м, копейка, копейки, копеек, ж, 2");
    ОбластьПодписи.Параметры.Менеджер = СсылкаНаДокумент.Менеджер;
    ТабличныйДокумент.Вывести(ОбластьПодписи);
    
    ТабличныйДокумент.АвтоМасштаб = Истина;
    Возврат ТабличныйДокумент;
КонецФункции

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

← На главную