Как программно создать несколько документов в 1С, разбив строки таблицы значений по лимиту?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Метод 1. Построчный обход таблицы значений с контролем наполнения

Это классический и наиболее интуитивно понятный способ решения. Мы обходим исходную таблицу значений Для Каждого, добавляем строки в документ по одной и контролируем текущее количество строк в табличной части с помощью свойства Количество().

При этом важно правильно обрабатывать момент создания первого документа и запись документов при переходе границы в 60 строк, чтобы избежать появления «пустышек» или пропуска последней пачки.

Рассмотрим оптимальную реализацию этого алгоритма:


Процедура СоздатьДокументыПострочно(ТЗ)

	// Обязательная проверка на пустую таблицу значений
	Если ТЗ.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;

	ТекущийДокумент = Неопределено;

	Для Каждого СтрокаТЗ Из ТЗ Цикл
		
		// Если документ еще не инициализирован или текущий документ заполнен до лимита
		Если ТекущийДокумент = Неопределено Или ТекущийДокумент.Товары.Количество() = 60 Тогда
			
			// Если это не первый документ, записываем предыдущий заполненный
			Если ТекущийДокумент <> Неопределено Тогда
				ТекущийДокумент.Записать();
			КонецЕсли;
			
			// Создаем новый объект документа
			ТекущийДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
			ЗаполнитьРеквизитыШапки(ТекущийДокумент);
			
		КонецЕсли;

		// Добавляем строку и переносим данные
		НоваяСтрока = ТекущийДокумент.Товары.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТЗ);
		
	КонецЦикла;

	// Записываем последний документ, в котором осталось менее 60 строк
	Если ТекущийДокумент <> Неопределено Тогда
		ТекущийДокумент.Записать();
	КонецЕсли;

КонецПроцедуры

Важный подводный камень: Если общее количество строк в таблице значений строго кратно 60 (например, ровно 120 строк), то логика создания документов «наперед» (внутри цикла до добавления строки) может привести к созданию лишнего пустого документа в самом конце. Приведенный выше код решает эту проблему, так как новый документ создается только тогда, когда реально появляется 61-я или 121-я строка для записи.

Также помните, что метод ЗаполнитьЗначенияСвойств сработает корректно только при полном совпадении имен и типов колонок в таблице значений и реквизитов табличной части документа. Если типы различаются, потребуется ручное сопоставление полей.

Метод 2. Итерация по индексам (пагинация)

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

Проанализируем пример реализации пагинации:


Процедура СоздатьДокументыПагинацией(ТЗ)

	ВсегоСтрок = ТЗ.Количество();
	Если ВсегоСтрок = 0 Тогда
		Возврат;
	КонецЕсли;

	ЛимитСтрок = 60;
	// Рассчитываем общее количество документов с округлением вверх
	ВсегоДокументов = Цел((ВсегоСтрок - 1) / ЛимитСтрок) + 1;

	Для НомерПачки = 1 По ВсегоДокументов Цикл
		
		НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
		ЗаполнитьРеквизитыШапки(НовыйДок);

		// Вычисляем индексы строк ТЗ для текущего документа
		НачальныйИндекс = (НомерПачки - 1) * ЛимитСтрок;
		КонечныйИндекс = Мин(НомерПачки * ЛимитСтрок - 1, ВсегоСтрок - 1);

		Для Индекс = НачальныйИндекс По КонечныйИндекс Цикл
			СтрокаТЗ = ТЗ[Индекс];
			НоваяСтрока = НовыйДок.Товары.Добавить();
			ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТЗ);
		КонецЦикла;

		НовыйДок.Записать();
		
	КонецЦикла;

КонецПроцедуры

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

Метод 3. Оптимизированная выгрузка через метод Загрузить()

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

Чтобы использовать этот метод, мы можем "нарезать" исходную таблицу значений на порции по 60 строк с помощью метода Скопировать():


Процедура СоздатьДокументыПакетнойЗагрузкой(ТЗ)

	ВсегоСтрок = ТЗ.Количество();
	Если ВсегоСтрок = 0 Тогда
		Возврат;
	КонецЕсли;

	ЛимитСтрок = 60;
	ИндексСтроки = 0;

	Пока ИндексСтроки < ВсегоСтрок Цикл
		
		НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
		ЗаполнитьРеквизитыШапки(НовыйДок);

		// Формируем массив строк для текущей порции
		МассивСтрокПорции = Новый Массив;
		ВерхняяГраница = Мин(ИндексСтроки + ЛимитСтрок, ВсегоСтрок);
		
		Для К = ИндексСтроки По ВерхняяГраница - 1 Цикл
			МассивСтрокПорции.Добавить(ТЗ[К]);
		КонецЦикла;

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

		// Переходим к следующей порции
		ИндексСтроки = ИндексСтроки + ЛимитСтрок;
		
	КонецЦикла;

КонецПроцедуры

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

Безопасность транзакций и режим записи

При пакетном создании документов важно помнить о целостности данных:

  1. Управление транзакциями: Если создание всей пачки документов логически неделимо (например, сбой при записи одного из них должен аннулировать всю операцию), обязательно оборачивайте процесс в явную транзакцию с помощью операторов НачатьТранзакцию() и ЗафиксироватьТранзакцию(), обрабатывая ошибки в блоке Попытка ... Исключение.
  2. Проведение документов: Если бизнес-логика требует, чтобы созданные документы были сразу проведены, вызывайте метод Записать(РежимЗаписиДокумента.Проведение). Делать это нужно строго после того, как табличная часть полностью сформирована. Попытка проведения недозаполненного документа приведет к ошибкам контроля остатков или взаиморасчетов в модуле объекта.
← На главную