Загрузка данных из внешних файлов — одна из самых частых задач, с которыми сталкивается разработчик 1С. Однако при реализации алгоритма «одна строка — один документ» новички часто совершают логические ошибки в структуре циклов. В этой статье мы подробно разберем, как правильно организовать обход таблицы Excel, почему нельзя использовать одинаковые переменные счетчиков и как оптимизировать процесс загрузки, чтобы программа работала быстро и без сбоев.
Проанализируем ситуацию, возникшую у автора темы. Основная проблема заключалась в том, что код содержал несколько вложенных циклов, использующих одну и ту же переменную СтрокаОтсчета. Кроме того, команда создания нового документа СоздатьДокумент() находилась либо вне основного цикла, либо логика заполнения была нарушена так, что данные всех строк записывались в один и тот же объект, который в итоге просто перезаписывался.
Рассмотрим, как выглядит ошибочная структура, которую часто пытаются применить:
// ОШИБОЧНЫЙ ПРИМЕР
Для СтрокаОтсчета = 2 по КоличествоСтрок Цикл
// ... какие-то проверки ...
Для СтрокаОтсчета = 2 по КоличествоСтрок Цикл // Вторая попытка запустить тот же цикл!
НовыйДокумент = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
// ... заполнение ...
Для СтрокаОтсчета = 2 по КоличествоСтрок Цикл // Третья попытка!
// Заполнение ТЧ
КонецЦикла;
НовыйДокумент.Записать();
КонецЦикла;
КонецЦикла;
В данном случае программа просто «запутывается» в итераторе СтрокаОтсчета. Когда внутренний цикл завершается, значение переменной уже равно КоличествоСтрок, и внешний цикл прекращает работу. Именно поэтому создается всего один документ.
Чтобы для каждой строки создавался новый документ, мы должны четко следовать правилу: один проход по строке — одно создание объекта. Разберем по шагам правильную структуру алгоритма.
1. Инициализируем COM-объект Excel (или используем чтение через табличный документ).
2. Определяем количество строк в файле.
3. Запускаем один единственный основной цикл по строкам.
4. Внутри цикла создаем объект СоздатьДокумент().
5. Заполняем реквизиты шапки и табличную часть из текущей строки.
6. Записываем документ.
Проанализируем исправленный код:
Для СтрокаОтсчета = 2 по КоличествоСтрок Цикл
// 1. Создаем новый объект документа для КАЖДОЙ итерации цикла
НовыйДокумент = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
// 2. Заполняем основные реквизиты шапки
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Организация = Объект.Организация;
НовыйДокумент.Склад = Объект.Склад;
НовыйДокумент.Контрагент = Объект.Контрагент;
// Если контрагент в каждой строке разный, ищем его в Excel:
// ТекКонтрагентНаименование = Excel.Cells(СтрокаОтсчета, 23).Value;
// НовыйДокумент.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию(ТекКонтрагентНаименование);
// 3. Заполняем табличную часть "Товары"
// Предположим, что в один документ должна попасть одна строка из Excel
НоваяСтрокаТЧ = НовыйДокумент.Товары.Добавить();
// Получаем данные напрямую из ячеек текущей строки
НоваяСтрокаТЧ.Номенклатура = Объект.Номенклатура; // Или поиск по коду из Excel
НоваяСтрокаТЧ.Количество = Excel.Cells(СтрокаОтсчета, 7).Value;
НоваяСтрокаТЧ.Цена = Excel.Cells(СтрокаОтсчета, 8).Value;
НоваяСтрокаТЧ.Сумма = НоваяСтрокаТЧ.Количество * НоваяСтрокаТЧ.Цена;
НоваяСтрокаТЧ.СтавкаНДС = Перечисления.СтавкиНДС.НДС18; // Или соответствующее значение
// 4. Записываем готовый документ
Попытка
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
Сообщить("Успешно создан документ: " + Строка(НовыйДокумент));
Исключение
Сообщить("Ошибка при записи строки " + СтрокаОтсчета + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Выясним причину, по которой использование режима ОтменаПроведения при записи нового документа, как это было в исходном сообщении, является нецелесообразным. Метод Записать(РежимЗаписиДокумента.ОтменаПроведения) используется для того, чтобы снять документ с учета, если он уже был проведен. Если вы создаете новый документ и просто хотите сохранить его в базе (как «черновик»), используйте РежимЗаписиДокумента.Запись. Если нужно сразу отразить его в учете — РежимЗаписиДокумента.Проведение.
Также обратим внимание на поиск ссылочных данных (Номенклатура, Контрагенты). Поиск по наименованию НайтиПоНаименованию() крайне ненадежен. Рекомендуем использовать поиск по артикулу, коду или ИНН. Это исключит дублирование объектов из-за лишних пробелов или кавычек в файле Excel.
Если в вашем файле 100 или более строк, создание каждого документа по отдельности может занять значительное время. Это происходит потому, что каждая команда Записать() открывает и закрывает транзакцию в базе данных. Выясним, как ускорить этот процесс.
Мы можем обернуть весь цикл загрузки в одну большую транзакцию. Это ускорит запись в несколько раз. Однако помните, что если внутри произойдет критическая ошибка, транзакция отменит создание всех документов. Рассмотрим пример реализации:
НачатьТранзакцию();
Попытка
Для СтрокаОтсчета = 2 по КоличествоСтрок Цикл
// ... (код создания и заполнения документа) ...
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
КонецЦикла;
ЗафиксироватьТранзакцию();
Сообщить("Загрузка успешно завершена!");
Исключение
ОтменитьТранзакцию();
Сообщить("Произошла ошибка, изменения отменены: " + ОписаниеОшибки());
КонецПопытки;
Использование Excel.Application (через COM-соединение) требует наличия установленного Microsoft Excel на компьютере. Это медленный и нестабильный способ. Проанализируем более современный подход, встроенный в платформу 1С 8.3.
Метод Прочитать() объекта ТабличныйДокумент позволяет загрузить файл .xlsx напрямую в память 1С. Это работает быстрее и безопаснее. Посмотрим на пример кода:
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ПутьКФайлу);
Исключение
Сообщить("Не удалось прочитать файл!");
Возврат;
КонецПопытки;
КоличествоСтрок = ТабДок.ВысотаТаблицы;
Для НомерСтроки = 2 по КоличествоСтрок Цикл
// Получаем данные из ячеек табличного документа
Артикул = ТабДок.Область(НомерСтроки, 1).Текст;
Количество = Число(ТабДок.Область(НомерСтроки, 2).Текст);
// Далее создаем документ по стандартной схеме
// ...
КонецЦикла;
Подведем итоги: для успешного создания множества документов необходимо следить за чистотой циклов, избегать дублирования переменных-счетчиков и всегда создавать новый экземпляр объекта СоздатьДокумент() строго внутри цикла итерации по данным. Использование транзакций и встроенных средств чтения файлов 1С сделает вашу обработку профессиональной и эффективной.