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