В процессе работы с такими конфигурациями, как Управление производственным предприятием 1.3 (УПП) или Управление торговлей 10.3 (УТ), часто возникает необходимость видеть детализацию по сериям номенклатуры прямо в форме списка документов (например, в «Реализации товаров и услуг»). Поскольку серии хранятся в табличной части Товары, их нельзя просто вытащить в список стандартным перетаскиванием поля.
В этой статье мы разберем несколько способов решения этой задачи: от простого добавления реквизита до более сложных и архитектурно правильных методов, которые не требуют перепроведения документов в закрытых периодах.
Это самый прямолинейный метод. Мы добавим в объект документа новый реквизит, в который при записи будем сохранять все серии из табличной части в виде одной строки через запятую.
Алгоритм действий:
СписокСерийСтрокой) с типом Строка. Длину лучше установить с запасом (например, 200–500 символов) или сделать неограниченной, если серий в одном документе может быть очень много.ПередЗаписью или ПриЗаписи.Рассмотрим пример кода для формирования строки:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Чтобы не дублировать одинаковые серии, используем массив и соответствие
МассивСерий = Новый Массив;
Для Каждого СтрокаТовара Из Товары Цикл
Если ЗначениеЗаполнено(СтрокаТовара.СерияНоменклатуры) Тогда
ТекстСерии = СокрЛП(СтрокаТовара.СерияНоменклатуры);
// Проверка на уникальность в рамках документа
Если МассивСерий.Найти(ТекстСерии) = Неопределено Тогда
МассивСерий.Добавить(ТекстСерии);
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Объединяем серии в одну строку
ЭтотОбъект.СписокСерийСтрокой = СтрСоединить(МассивСерий, ", ");
КонецПроцедуры
Важный нюанс: Если вы используете старую версию платформы (ниже 8.3.6), функция СтрСоединить может быть недоступна. В этом случае используем классический цикл:
ИтоговаяСтрока = "";
Для Каждого Стр Из МассивСерий Цикл
ИтоговаяСтрока = ИтоговаяСтрока + Стр + ", ";
КонецЦикла;
// Удаляем последнюю запятую и пробел
Если СтрДлина(ИтоговаяСтрока) > 0 Тогда
ЭтотОбъект.СписокСерийСтрокой = Лев(ИтоговаяСтрока, СтрДлина(ИтоговаяСтрока) - 2);
КонецЕсли;
Проблема первого способа заключается в том, что реквизит заполнится только у новых или пересохраненных документов. Для старых документов данные останутся пустыми, а дата запрета редактирования не позволит просто так их перепровести. Проанализируем, как обойти это ограничение.
Для обновления данных без изменения логики учета и без «сдвига» последовательностей, мы можем использовать свойство ОбменДанными.Загрузка = Истина. Это позволит записать объект даже в закрытом периоде.
Разберем пример кода внешней обработки:
Процедура ОбновитьСерииВДокументах(СсылкаНаДокумент)
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Выполняем тот же алгоритм сбора серий
МассивСерий = ДокОбъект.Товары.ВыгрузитьКолонку("СерияНоменклатуры");
// Очистим пустые и повторы через временную таблицу или соответствие
// ... (код очистки)
ДокОбъект.СписокСерийСтрокой = СтрСоединить(МассивСерий, ", ");
// Ключевой момент для обхода проверок и даты запрета
ДокОбъект.ОбменДанными.Загрузка = Истина;
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
КонецПроцедуры
Внимание: Используйте этот метод с осторожностью. Режим Загрузка = Истина отключает все проверки в процедуре ПередЗаписью, поэтому убедитесь, что ваш код формирования строки корректен.
Если изменять структуру документа (добавлять реквизиты) запрещено правилами разработки в вашей компании, или вы не хотите «раздувать» таблицы документов, проанализируем вариант с использованием вспомогательного Регистра Сведений.
Шаги реализации:
КэшСерийДокументов).Документ (тип: Ссылка на ваш документ).СтрокаСерий (тип: Строка, длина 250+).Преимущество этого метода в том, что сам документ вообще не меняется. Мы можем заполнить этот регистр отдельной обработкой один раз, а затем обновлять его при записи документов через Подписку на событие ПриЗаписи.
В конфигурациях на обычных формах (УПП, УТ 10) есть возможность вывести любые данные «на лету» без записи их в базу. Для этого используется событие списка ПриПолученииДанных.
Выясним причину, по которой этот метод требует осторожности: если делать по одному запросу для каждой строки, форма начнет «тормозить». Поэтому мы должны использовать пакетную выборку.
Пример реализации в форме списка:
Процедура СписокПриПолученииДанных(Элемент, ОформленияСтрок)
// Собираем ссылки на документы, которые сейчас видны на экране
МассивСсылок = Новый Массив;
Для Каждого Оформление Из ОформленияСтрок Цикл
МассивСсылок.Добавить(Оформление.ДанныеСтроки.Ссылка);
КонецЦикла;
// Одним запросом получаем все серии для этих документов
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Ссылка,
| Товары.СерияНоменклатуры КАК Серия
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК Товары
|ГДЕ
| Товары.Ссылка В (&МассивСсылок)";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
Результат = Запрос.Выполнить().Выгрузить();
// Теперь распределяем данные по строкам оформления
Для Каждого Оформление Из ОформленияСтрок Цикл
ДокСсылка = Оформление.ДанныеСтроки.Ссылка;
СтрокиСерий = Результат.НайтиСтроки(Новый Структура("Ссылка", ДокСсылка));
ТекстСерий = "";
Для Каждого СтрСерия Из СтрокиСерий Цикл
Если ЗначениеЗаполнено(СтрСерия.Серия) Тогда
ТекстСерий = ТекстСерий + СокрЛП(СтрСерия.Серия) + ", ";
КонецЕсли;
КонецЦикла;
// Устанавливаем текст в колонку (колонку нужно предварительно добавить в список)
Оформление.Ячейки.КолонкаСерии.УстановитьТекст(ТекстСерий);
КонецЦикла;
КонецПроцедуры
Сравнение методов:
Для большинства задач в УПП 1.3 оптимальным является Способ 1 (добавление реквизита) в сочетании с разовой обработкой существующих данных, так как пользователям чаще всего требуется не только видеть серии, но и искать по ним документы через стандартный поиск (Ctrl+F).