Как вывести серии номенклатуры из табличной части в форму списка документа

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

В процессе работы с такими конфигурациями, как Управление производственным предприятием 1.3 (УПП) или Управление торговлей 10.3 (УТ), часто возникает необходимость видеть детализацию по сериям номенклатуры прямо в форме списка документов (например, в «Реализации товаров и услуг»). Поскольку серии хранятся в табличной части Товары, их нельзя просто вытащить в список стандартным перетаскиванием поля.

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

Способ 1. Добавление строкового реквизита в документ

Это самый прямолинейный метод. Мы добавим в объект документа новый реквизит, в который при записи будем сохранять все серии из табличной части в виде одной строки через запятую.

Алгоритм действий:

  1. Откроем конфигуратор и найдем нужный документ.
  2. Добавим новый реквизит (например, СписокСерийСтрокой) с типом Строка. Длину лучше установить с запасом (например, 200–500 символов) или сделать неограниченной, если серий в одном документе может быть очень много.
  3. В модуле объекта пропишем логику заполнения этого реквизита в процедуре ПередЗаписью или ПриЗаписи.

Рассмотрим пример кода для формирования строки:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    // Чтобы не дублировать одинаковые серии, используем массив и соответствие
    МассивСерий = Новый Массив;
    Для Каждого СтрокаТовара Из Товары Цикл
        Если ЗначениеЗаполнено(СтрокаТовара.СерияНоменклатуры) Тогда
            ТекстСерии = СокрЛП(СтрокаТовара.СерияНоменклатуры);
            // Проверка на уникальность в рамках документа
            Если МассивСерий.Найти(ТекстСерии) = Неопределено Тогда
                МассивСерий.Добавить(ТекстСерии);
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    // Объединяем серии в одну строку
    ЭтотОбъект.СписокСерийСтрокой = СтрСоединить(МассивСерий, ", ");
КонецПроцедуры

Важный нюанс: Если вы используете старую версию платформы (ниже 8.3.6), функция СтрСоединить может быть недоступна. В этом случае используем классический цикл:


ИтоговаяСтрока = "";
Для Каждого Стр Из МассивСерий Цикл
    ИтоговаяСтрока = ИтоговаяСтрока + Стр + ", ";
КонецЦикла;

// Удаляем последнюю запятую и пробел
Если СтрДлина(ИтоговаяСтрока) > 0 Тогда
    ЭтотОбъект.СписокСерийСтрокой = Лев(ИтоговаяСтрока, СтрДлина(ИтоговаяСтрока) - 2);
КонецЕсли;

Способ 2. Обработка документов в закрытом периоде

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

Для обновления данных без изменения логики учета и без «сдвига» последовательностей, мы можем использовать свойство ОбменДанными.Загрузка = Истина. Это позволит записать объект даже в закрытом периоде.

Разберем пример кода внешней обработки:


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

Внимание: Используйте этот метод с осторожностью. Режим Загрузка = Истина отключает все проверки в процедуре ПередЗаписью, поэтому убедитесь, что ваш код формирования строки корректен.

Способ 3. Использование внешнего Регистра Сведений

Если изменять структуру документа (добавлять реквизиты) запрещено правилами разработки в вашей компании, или вы не хотите «раздувать» таблицы документов, проанализируем вариант с использованием вспомогательного Регистра Сведений.

Шаги реализации:

  1. Создаем новый независимый Регистр Сведений (например, КэшСерийДокументов).
  2. Измерение: Документ (тип: Ссылка на ваш документ).
  3. Ресурс: СтрокаСерий (тип: Строка, длина 250+).
  4. В форме списка документов через «Настройку списка» (если это динамический список на 8.3) или программно (в обычных формах) соединяем основную таблицу с этим регистром по ссылке.

Преимущество этого метода в том, что сам документ вообще не меняется. Мы можем заполнить этот регистр отдельной обработкой один раз, а затем обновлять его при записи документов через Подписку на событие ПриЗаписи.

Способ 4. Вывод данных через событие ПриПолученииДанных (для обычных форм)

В конфигурациях на обычных формах (УПП, УТ 10) есть возможность вывести любые данные «на лету» без записи их в базу. Для этого используется событие списка ПриПолученииДанных.

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

Пример реализации в форме списка:


Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
    // Собираем ссылки на документы, которые сейчас видны на экране
    МассивСсылок = Новый Массив;
    Для Каждого Оформление Из ОформленияСтрок Цикл
        МассивСсылок.Добавить(Оформление.ДанныеСтроки.Ссылка);
    КонецЦикла;
    
    // Одним запросом получаем все серии для этих документов
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |   Товары.Ссылка КАК Ссылка,
    |   Товары.СерияНоменклатуры КАК Серия
    |ИЗ
    |   Документ.РеализацияТоваровУслуг.Товары КАК Товары
    |ГДЕ
    |   Товары.Ссылка В (&МассивСсылок)";
    Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
    
    Результат = Запрос.Выполнить().Выгрузить();
    
    // Теперь распределяем данные по строкам оформления
    Для Каждого Оформление Из ОформленияСтрок Цикл
        ДокСсылка = Оформление.ДанныеСтроки.Ссылка;
        СтрокиСерий = Результат.НайтиСтроки(Новый Структура("Ссылка", ДокСсылка));
        
        ТекстСерий = "";
        Для Каждого СтрСерия Из СтрокиСерий Цикл
            Если ЗначениеЗаполнено(СтрСерия.Серия) Тогда
                ТекстСерий = ТекстСерий + СокрЛП(СтрСерия.Серия) + ", ";
            КонецЕсли;
        КонецЦикла;
        
        // Устанавливаем текст в колонку (колонку нужно предварительно добавить в список)
        Оформление.Ячейки.КолонкаСерии.УстановитьТекст(ТекстСерий);
    КонецЦикла;
КонецПроцедуры

Сравнение методов:

Для большинства задач в УПП 1.3 оптимальным является Способ 1 (добавление реквизита) в сочетании с разовой обработкой существующих данных, так как пользователям чаще всего требуется не только видеть серии, но и искать по ним документы через стандартный поиск (Ctrl+F).

← На главную