Как создать отдельный документ Поступление товаров и услуг для каждой строки из Excel

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет
← На главную

Загрузка данных из внешних файлов — одна из самых частых задач, с которыми сталкивается разработчик 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 по КоличествоСтрок Цикл
        // ... (код создания и заполнения документа) ...
        НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
    КонецЦикла;
    
    ЗафиксироватьТранзакцию();
    Сообщить("Загрузка успешно завершена!");
Исключение
    ОтменитьТранзакцию();
    Сообщить("Произошла ошибка, изменения отменены: " + ОписаниеОшибки());
КонецПопытки;

Отказ от COM-объекта в пользу Табличного документа

Использование Excel.Application (через COM-соединение) требует наличия установленного Microsoft Excel на компьютере. Это медленный и нестабильный способ. Проанализируем более современный подход, встроенный в платформу 1С 8.3.

Метод Прочитать() объекта ТабличныйДокумент позволяет загрузить файл .xlsx напрямую в память 1С. Это работает быстрее и безопаснее. Посмотрим на пример кода:


ТабДок = Новый ТабличныйДокумент;
Попытка
    ТабДок.Прочитать(ПутьКФайлу);
Исключение
    Сообщить("Не удалось прочитать файл!");
    Возврат;
КонецПопытки;

КоличествоСтрок = ТабДок.ВысотаТаблицы;

Для НомерСтроки = 2 по КоличествоСтрок Цикл
    // Получаем данные из ячеек табличного документа
    Артикул = ТабДок.Область(НомерСтроки, 1).Текст;
    Количество = Число(ТабДок.Область(НомерСтроки, 2).Текст);
    
    // Далее создаем документ по стандартной схеме
    // ...
КонецЦикла;

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

← На главную