Часто в практических задачах 1С возникает необходимость обработать таблицу данных (например, полученную из внешнего источника, файла или заполненную на форме обработки) и на ее основе сформировать один или несколько документов, распределив строки по определенному признаку (например, по складам, организациям или контрагентам).
Разберем по шагам, как правильно организовать получение данных на форме, сгруппировать их и программно создать документы с заполнением шапки и табличной части.
Проанализируем частую ошибку начинающих разработчиков: при наличии таблицы на форме нередко пытаются заново создавать объект ТаблицаЗначений вручную через конструктор или использовать тяжелую трансформацию РеквизитФормыВЗначение. Если данные уже находятся в табличной части обработки или реквизите формы типа ДанныеФормыКоллекция, на сервере их можно выгрузить напрямую:
&НаСервере
Процедура СоздатьДокументыНаСервере()
// Получаем таблицу значений напрямую из реквизита формы
ТаблицаДанных = Объект.Товары.Выгрузить();
// Либо, если это реквизит формы типа ТаблицаЗначений:
// ТаблицаДанных = ДанныеФормыВЗначение(Элементы.ТаблицаТоваров, Тип("ТаблицаЗначений"));
КонецПроцедуры
Рассмотрим наиболее надежный и производительный вариант. Когда в исходной таблице присутствуют строки для разных складов (или контрагентов), наиболее просто и наглядно разделить строки с помощью языка запросов 1С и конструкции ИТОГИ ПО.
Разберем реализацию поэтапно:
Склад).
&НаСервере
Процедура СоздатьПоступленияПоСкладам(ТаблицаТоваров)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Данные.Склад КАК Склад,
| Данные.Товар КАК Номенклатура,
| Данные.Количество КАК Количество,
| Данные.Цена КАК Цена
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТаблицаТоваров КАК Данные
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Товары.Склад КАК Склад,
| ВТ_Товары.Номенклатура КАК Номенклатура,
| ВТ_Товары.Количество КАК Количество,
| ВТ_Товары.Цена КАК Цена
|ИЗ
| ВТ_Товары КАК ВТ_Товары
|ИТОГИ ПО
| Склад";
Запрос.УстановитьПараметр("ТаблицаТоваров", ТаблицаТоваров);
РезультатЗапроса = Запрос.Выполнить();
// Обход по группировке верхнего уровня (по складам)
ВыборкаСклад = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаСклад.Следующий() Цикл
// Создаем новый документ
НовыйДокумент = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДатаСеанса();
НовыйДокумент.Склад = ВыборкаСклад.Склад;
// При необходимости инициализируем значения по умолчанию в типовых конфигурациях
НовыйДокумент.Заполнить(Неопределено);
НовыйДокумент.Склад = ВыборкаСклад.Склад;
// Обход детальных записей для заполнения табличной части
ВыборкаДетали = ВыборкаСклад.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
НоваяСтрока = НовыйДокумент.Товары.Добавить();
НоваяСтрока.Номенклатура = ВыборкаДетали.Номенклатура;
НоваяСтрока.Количество = ВыборкаДетали.Количество;
НоваяСтрока.Цена = ВыборкаДетали.Цена;
НоваяСтрока.Сумма = ВыборкаДетали.Количество * ВыборкаДетали.Цена;
КонецЦикла;
// Сохраняем документ в информационной базе
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
КонецЦикла;
КонецПроцедуры
Рассмотрим альтернативный вариант без использования запроса, когда все манипуляции производятся исключительно методами коллекции ТаблицаЗначений. Для этого получаем список уникальных складов методом Свернуть(), а затем отбираем нужные строки для каждого документа:
&НаСервере
Процедура СоздатьДокументыЧерезТЗ(ТаблицаТоваров)
// Получаем список уникальных складов
ТаблицаСкладов = ТаблицаТоваров.Скопировать(, "Склад");
ТаблицаСкладов.Свернуть("Склад");
Для Каждого СтрСклад Из ТаблицаСкладов Цикл
НовыйДокумент = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДатаСеанса();
НовыйДокумент.Склад = СтрСклад.Склад;
// Отбираем строки по текущему складу
Отбор = Новый Структура("Склад", СтрСклад.Склад);
НайденныеСтроки = ТаблицаТоваров.НайтиСтроки(Отбор);
Для Каждого СтрокаТЧ Из НайденныеСтроки Цикл
НоваяСтрока = НовыйДокумент.Товары.Добавить();
НоваяСтрока.Номенклатура = СтрокаТЧ.Товар;
НоваяСтрока.Количество = СтрокаТЧ.Количество;
НоваяСтрока.Цена = СтрокаТЧ.Цена;
НоваяСтрока.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
КонецЦикла;
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
КонецЦикла;
КонецПроцедуры
Обратим внимание на ключевые особенности платформы 1С:Предприятие 8, которые необходимо учитывать при генерации документов:
Документы[ИмяДокумента].СоздатьДокумент() (метод СоздатьОбъект() относился к версии 7.7).СоздатьДокумент(), находится только в оперативной памяти сервера. Чтобы он появился в базе данных, обязательно нужно вызвать метод Записать() в режиме РежимЗаписиДокумента.Запись или РежимЗаписиДокумента.Проведение.НачатьТранзакцию() / ЗафиксироватьТранзакцию()), чтобы в случае ошибки при создании одного из документов не оставалось частично созданных данных.