Как правильно выводить данные в разные колонки макета 1С и избежать дублирования номеров

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

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

Причина проблемы: эффект «памяти» параметров области

Разберем ситуацию, представленную в вопросе. Программист использует объект ОбластьДанные, который получается из макета. В цикле обхода выборки для каждого документа проверяется его статус, и номер документа присваивается соответствующему параметру области. Однако, если для текущей строки выборки условие (например, СтатусЗаявки.Принята) выполняется, а для следующей строки — нет, параметр ОбластьДанные.Parameters.Принята сохранит значение из предыдущей итерации.

Объект области макета в памяти 1С — это структура. Пока вы не очистите параметры или не перезапишете их, они будут содержать последние установленные значения. Именно поэтому в таблице автора номера документов начинали «размножаться» и заполнять все последующие строки.

Способ 1. Очистка параметров перед заполнением (Быстрое решение)

Самый простой и очевидный способ — принудительно обнулять все параметры, которые могут быть выведены в строке, перед тем как начинать проверку условий Если...ИначеЕсли. Это гарантирует, что каждая новая строка в табличном документе начнется с «чистого листа».

Рассмотрим пример кода, который исправляет ситуацию:


// Внутри цикла выборки
ОбластьДанные.Параметры.Возвращена = "";
ОбластьДанные.Параметры.Выполнена = "";
ОбластьДанные.Параметры.НаВыполнении = "";
ОбластьДанные.Параметры.НаТесте = "";
ОбластьДанные.Параметры.Отменена = "";
ОбластьДанные.Параметры.Принята = "";
ОбластьДанные.Параметры.НеРаспределено = "";

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

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

Важное примечание: Если параметров в области очень много, вместо ручного перечисления можно использовать цикл Для каждого по коллекции параметров. Это сделает код более универсальным:


Для каждого Параметр Из ОбластьДанные.Параметры Цикл
    Параметр = "";
КонецЦикла;

Способ 2. Использование динамического обращения к параметрам

Конструкции Если...ИначеЕсли на 10 и более условий считаются «плохим тоном» в разработке (так называемый «говнокод»). Мы можем значительно упростить логику, если назовем параметры в макете так же, как называются значения перечисления в конфигураторе.

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


// Очищаем параметры (см. способ выше)
Для каждого Параметр Из ОбластьДанные.Параметры Цикл
    ОбластьДанные.Параметры[Параметр.Имя] = "";
КонецЦикла;

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

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

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

Наиболее профессиональный подход — подготовить данные так, чтобы в коде 1С вообще не было условий. Мы можем использовать конструкцию ВЫБОР прямо в тексте запроса. Это позволит распределить номера по колонкам на уровне СУБД.

Рассмотрим, как это выглядит в запросе:


ВЫБРАТЬ
    Заявка.Номер КАК Номер,
    ВЫБОР
        КОГДА Заявка.Статус = ЗНАЧЕНИЕ(Перечисление.Статусы.Принята)
            ТОГДА Заявка.Номер
        ИНАЧЕ ""
    КОНЕЦ КАК Принята,
    ВЫБОР
        КОГДА Заявка.Статус = ЗНАЧЕНИЕ(Перечисление.Статусы.Выполнена)
            ТОГДА Заявка.Номер
        ИНАЧЕ ""
    КОНЕЦ КАК Выполнена
ИЗ
    Документ.Заявка КАК Заявка

При таком подходе в цикле обхода выборки нам достаточно использовать метод Заполнить(), который автоматически сопоставит поля запроса с именами параметров макета:


Пока Выборка.Следующий() Цикл
    ОбластьДанные.Параметры.Заполнить(Выборка);
    ТабДок.Вывести(ОбластьДанные);
КонецЦикла;

Метод Заполнить() работает очень быстро и автоматически очищает те параметры, для которых в текущей строке выборки пришла пустая строка или NULL.

Подведение итогов и рекомендации

Выяснив причину дублирования данных, мы можем сделать следующие выводы:

  1. Всегда очищайте параметры области перед повторным выводом в цикле, если не используете метод полного заполнения.
  2. Для проверки на пустой статус используйте функцию ЗначениеЗаполнено(), а не сравнение с пустой строкой " ", так как перечисления — это ссылочный тип данных, а не строковый.
  3. Стремитесь переносить логику распределения данных в запрос. Это делает код модуля более читаемым и упрощает его поддержку.
  4. Если задача требует вывода большого количества колонок, которые могут меняться, рассмотрите использование Системы компоновки данных (СКД). В СКД такие задачи решаются простым добавлением группировки колонок, без написания программного кода.

Выбор конкретного метода зависит от сложности вашего отчета, но для большинства простых реестров метод с очисткой параметров (Способ 1) или заполнение через запрос (Способ 3) являются наиболее надежными.

← На главную