Как вывести описание этапов ресурсной спецификации в печатную форму 1С:ERP?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Промышленность, строительство и АПК
← На главную

Введение в задачу и архитектуру 1С:ERP

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

Давайте проанализируем архитектурную связь этих объектов. В 1С:ERP справочник этапов является подчиненным. Его реквизит Владелец ссылается на элемент справочника РесурсныеСпецификации. Сложность заключается в том, что в самом документе калькуляции табличная часть содержит реквизит Объект составного типа. Там может лежать как спецификация, так и номенклатура. Из-за этого мы не можем просто обратиться к данным через точку, и типовые запросы начинают выдавать ошибки.

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

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

1. Ошибка операторов сравнения при работе с массивами

Когда мы передаем в запрос коллекцию значений (например, массив ссылок на распечатываемые документы), мы не можем использовать стандартные математические операторы.

Если мы напишем код так:


И РесурсныеСпецификации.Ссылка >= &МассивОбъектов
// ИЛИ
И РесурсныеСпецификации.Ссылка = &МассивОбъектов

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

ГДЕ ДокументКалькуляции.Ссылка В (&МассивОбъектов)

2. Обращение через точку к составному типу (Неявные соединения)

Попытка написать путь вида ПлановаяКалькуляция.Объект.Этап.Описание приведет либо к синтаксической ошибке, либо к возврату значения NULL. Поскольку реквизит Объект имеет составной тип, платформа не знает наверняка, есть ли у этого объекта реквизит "Этап". Для решения этой проблемы разберем использование функции ВЫРАЗИТЬ.

Чтобы явно указать платформе, с каким типом мы работаем, применим конструкцию:

ВЫРАЗИТЬ(ПлановаяКалькуляция.Объект КАК Справочник.РесурсныеСпецификации)

Если в реквизите окажется другой тип данных (например, номенклатура), функция безопасно вернет NULL, и запрос не завершится с ошибкой.

Проблема множественности этапов

Проанализируем физический смысл данных. Ресурсная спецификация (например, приготовление "Азу из говядины") редко состоит из одного шага. Обычно это многоэтапный производственный процесс. Если мы просто присоединим таблицу этапов к основному печатному запросу левым или внутренним соединением, строки калькуляции в результате запроса задвоятся или затроятся (по количеству этапов).

Нам необходимо собрать все описания этапов для конкретной спецификации и склеить их в один текст, либо выводить в макет отдельным списком.

Решение 1: Получение данных через Временные Таблицы

Посмотрим на классический способ интеграции нашего запроса с помощью пакета запросов и временных таблиц. Этот подход хорош, если мы хотим сделать все вычисления на стороне СУБД.

  1. Сначала мы собираем все спецификации из нужных нам документов во временную таблицу.
  2. Затем связываем эту временную таблицу со справочником этапов.

Рассмотрим пример кода:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ВЫРАЗИТЬ(ПлановаяКалькуляция.Объект КАК Справочник.РесурсныеСпецификации) КАК Спецификация
ПОМЕСТИТЬ ВТ_Спецификации
ИЗ
    Документ.ПлановаяКалькуляция2_2.ОбъектыКалькуляции КАК ПлановаяКалькуляция
ГДЕ
    ПлановаяКалькуляция.Ссылка В(&МассивОбъектов)
    И ПлановаяКалькуляция.Объект ССЫЛКА Справочник.РесурсныеСпецификации
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ЭтапыПроизводства.Владелец КАК Спецификация,
    ЭтапыПроизводства.Описание КАК ОписаниеЭтапа
ИЗ
    Справочник.ЭтапыПроизводства КАК ЭтапыПроизводства
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Спецификации КАК ВТ_Спецификации
        ПО ЭтапыПроизводства.Владелец = ВТ_Спецификации.Спецификация
ГДЕ
    НЕ ЭтапыПроизводства.ПометкаУдаления

Этот запрос вернет нам плоскую таблицу, где каждой спецификации будут соответствовать строки с описаниями её этапов. Главный минус: если этапов много, нам всё равно придется обрабатывать их программно при выводе макета.

Решение 2: Модульный подход (Оптимальный для Внешних Печатных Форм)

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

Разберем архитектурно правильный (модульный) подход к разработке:

  1. Мы оставляем типовой запрос калькуляции без изменений. Он выполняет свою работу и собирает шапку и состав.
  2. Мы программно обходим результат типового запроса и собираем уникальные ссылки на спецификации в массив МассивСпецификаций.
  3. Мы пишем отдельный, легкий запрос только к справочнику Справочник.ЭтапыПроизводства, передавая туда наш массив.
  4. При выводе строк в макет, мы подтягиваем описание из результатов второго запроса.

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


// Предположим, ВыборкаЭтапов - это результат нашего второго запроса,
// отсортированный по Владельцу (Спецификации) и номеру этапа.

ОписаниеОбщее = Новый Массив;

Пока ВыборкаЭтапов.Следующий() Цикл
    // Собираем описания всех этапов для текущего блюда/изделия
    Если ЗначениеЗаполнено(ВыборкаЭтапов.Описание) Тогда
        ОписаниеОбщее.Добавить(ВыборкаЭтапов.Описание);
    КонецЕсли;
КонецЦикла;

// Получаем область макета
ОбластьОписание = Макет.ПолучитьОбласть("ОписаниеТехнологии");

// Склеиваем массив в одну строку с переносом строк
Если ОписаниеОбщее.Количество() > 0 Тогда
    ОбластьОписание.Параметры.Описание = СтрСоединить(ОписаниеОбщее, Символы.ПС);
Иначе
    ОбластьОписание.Параметры.Описание = "Технологическое описание отсутствует.";
КонецЕсли;

ТабличныйДокумент.Вывести(ОбластьОписание);

Подведение итогов

Мы выяснили причину, по которой прямое обращение к описанию этапа из плановой калькуляции не работает. Реквизиты составного типа требуют особого обращения в запросах (использование проверки ССЫЛКА и приведения типов ВЫРАЗИТЬ).

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

← На главную