← Назад к вопросам

Обработка загрузки остатков из Excel

2.0 Middle🔥 151 комментариев
#Интеграции и обмены#Стандарты разработки

Условие

Создайте обработку загрузки начальных остатков из Excel-файла.

Структура Excel-файла:

НоменклатураСкладКоличество
Товар 1Осн.100
Товар 2Осн.50

Требования:

  • Выбор файла через диалог
  • Проверка существования номенклатуры и склада
  • Создание документа ввода начальных остатков
  • Вывод протокола загрузки (успешно/ошибки)

Обработка ошибок

  • Если номенклатура не найдена — записать в протокол
  • Если склад не найден — записать в протокол
  • После загрузки показать итоги: загружено X строк, ошибок Y

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Обработка загрузки начальных остатков из Excel

Рассмотрим реализацию обработки для импорта начальных остатков товаров из Excel-файла с валидацией данных.

Архитектура решения

Основные этапы:

  1. Выбор файла Excel пользователем
  2. Чтение и парсирование данных из файла
  3. Валидация (проверка существования номенклатуры и складов)
  4. Создание документа "ВводОстатков" или "ПриходТоваров"
  5. Логирование результатов загрузки

Структура Excel-файла

Требуемая структура:

Строка 1 (заголовок): Номенклатура | Склад | Количество | Цена (опционально)

Данные:
- Товар 1 | Основной | 100 | 500
- Товар 2 | Филиал | 50 | 1000

Реализация обработки

Форма обработки (управляемая форма):

// Процедура инициализации формы
Процедура ПриОткрытии(Отмена)
    
    // Инициализация таблицы результатов
    Протокол = ЭтаФорма.ОбъектДанных.Протокол;
    Протокол.Очистить();
    
    // Установка параметров по умолчанию
    ЭтаФорма.ОбъектДанных.СтатусЗагрузки = "Ожидание файла";
    
КонецПроцедуры

// Команда выбора файла
Процедура ВыбратьФайл(Команда)
    
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.ПолноеИмяФайла = "";
    Диалог.Filter = "Excel файлы (*.xlsx; *.xls)|*.xlsx;*.xls";
    Диалог.Заголовок = "Выбор файла с остатками";
    
    Если Диалог.Выбрать() Тогда
        ПолныйПутьФайла = Диалог.ПолноеИмяФайла;
        ОбработатьФайл(ПолныйПутьФайла);
    КонецЕсли;
    
КонецПроцедуры

// Основная процедура обработки файла
Процедура ОбработатьФайл(ПолныйПутьФайла)
    
    Попытка
        // Проверка существования файла
        Если НЕ Новый Файл(ПолныйПутьФайла).Существует() Тогда
            ВызватьОшибку("Файл не найден: " + ПолныйПутьФайла);
        КонецЕсли;
        
        // Считываем Excel файл
        ЭксельТаблица = ПрочитатьExcel(ПолныйПутьФайла);
        
        // Валидируем и создаём документ
        РезультатЗагрузки = ВалидироватьИЗагрузить(ЭксельТаблица);
        
        // Выводим итоги
        ВывестиИтоги(РезультатЗагрузки);
        
    Исключение
        Сообщение("Ошибка при загрузке файла: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Чтение Excel файла

// Функция для чтения Excel-файла
Функция ПрочитатьExcel(ПолныйПутьФайла)
    
    // Используем OLE Automation для Excel
    Excel = Новый COMОбъект("Excel.Application");
    Excel.Visible = Ложь;
    
    ТаблицаДанных = Новый ТаблицаЗначений();
    
    Попытка
        // Открываем рабочую книгу
        Книга = Excel.Workbooks.Open(ПолныйПутьФайла, Ложь, Истина);
        Лист = Книга.Worksheets(1);
        
        // Читаем заголовки из первой строки
        ЧислоСтолбцов = 3; // Номенклатура, Склад, Количество
        
        ТаблицаДанных.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("Строка"));
        ТаблицаДанных.Колонки.Добавить("Склад", Новый ОписаниеТипов("Строка"));
        ТаблицаДанных.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
        ТаблицаДанных.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
        
        // Читаем данные со второй строки (пропускаем заголовок)
        НомерСтроки = 2;
        Пока ЗначениеЗаполнено(Лист.Cells(НомерСтроки, 1).Value) Цикл
            
            НоваяСтрока = ТаблицаДанных.Добавить();
            НоваяСтрока.Номенклатура = Лист.Cells(НомерСтроки, 1).Value;
            НоваяСтрока.Склад = Лист.Cells(НомерСтроки, 2).Value;
            НоваяСтрока.Количество = Число(Лист.Cells(НомерСтроки, 3).Value);
            
            // Цена опциональна (может быть в 4-м столбце)
            ЗначениеЦены = Лист.Cells(НомерСтроки, 4).Value;
            Если ЗначениеЗаполнено(ЗначениеЦены) Тогда
                НоваяСтрока.Цена = Число(ЗначениеЦены);
            КонецЕсли;
            
            НомерСтроки = НомерСтроки + 1;
        КонецЦикла;
        
        Книга.Close(Ложь);
        
    Исключение
        ВызватьОшибку("Ошибка при чтении Excel: " + ОписаниеОшибки());
    Наконец
        Excel.Quit();
    КонецПопытки;
    
    Возврат ТаблицаДанных;
    
КонецФункции

Валидация и загрузка

// Функция для валидации и загрузки данных
Функция ВалидироватьИЗагрузить(ТаблицаDанных)
    
    РезультатЗагрузки = Новый Структура();
    РезультатЗагрузки.Вставить("ВсегоСтрок", ТаблицаDанных.Количество());
    РезультатЗагрузки.Вставить("УспешноЗагружено", 0);
    РезультатЗагрузки.Вставить("Ошибок", 0);
    РезультатЗагрузки.Вставить("Протокол", Новый ТаблицаЗначений());
    
    // Инициализируем протокол ошибок
    Протокол = РезультатЗагрузки.Протокол;
    Протокол.Колонки.Добавить("СтрокаФайла", Новый ОписаниеТипов("Число"));
    Протокол.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("Строка"));
    Протокол.Колонки.Добавить("Статус", Новый ОписаниеТипов("Строка"));
    Протокол.Колонки.Добавить("Описание", Новый ОписаниеТипов("Строка"));
    
    // Создаём документ-заголовок
    Документ = Documents.ПриходТоваров.CreateDocument();
    Документ.Дата = ТекущаяДата();
    Документ.Организация = ПолучитьОрганизацию();
    
    // Проходим по каждой строке
    НомерСтроки = 2; // Нумерация начинается с 2 (в Excel с учётом заголовка)
    
    Для Каждого СтрокаДанных Из ТаблицаDанных Цикл
        
        ОшибкиСтроки = ПроверитьСтрок(СтрокаДанных, НомерСтроки);
        
        Если ОшибкиСтроки.Количество() = 0 Тогда
            // Стрка валидна — добавляем в документ
            НоваяСтрока = Документ.Товары.Добавить();
            НоваяСтрока.Номенклатура = НайтиНоменклатуру(СтрокаДанных.Номенклатура);
            НоваяСтрока.Склад = НайтиСклад(СтрокаДанных.Склад);
            НоваяСтрока.Количество = СтрокаДанных.Количество;
            НоваяСтрока.Цена = ?(ЗначениеЗаполнено(СтрокаДанных.Цена), СтрокаДанных.Цена, 0);
            НоваяСтрока.Сумма = НоваяСтрока.Количество * НоваяСтрока.Цена;
            
            РезультатЗагрузки.УспешноЗагружено = РезультатЗагрузки.УспешноЗагружено + 1;
        Иначе
            // Есть ошибки — записываем в протокол
            Для Каждого Ошибка Из ОшибкиСтроки Цикл
                СтрокаПротокола = Протокол.Добавить();
                СтрокаПротокола.СтрокаФайла = НомерСтроки;
                СтрокаПротокола.Номенклатура = СтрокаДанных.Номенклатура;
                СтрокаПротокола.Статус = "Ошибка";
                СтрокаПротокола.Описание = Ошибка;
            КонецЦикла;
            
            РезультатЗагрузки.Ошибок = РезультатЗагрузки.Ошибок + 1;
        КонецЕсли;
        
        НомерСтроки = НомерСтроки + 1;
    КонецЦикла;
    
    // Сохраняем документ
    Если РезультатЗагрузки.УспешноЗагружено > 0 Тогда
        Документ.Записать(РежимЗаписиДокумента.Проведение);
        РезультатЗагрузки.Вставить("НомерДокумента", Документ.Номер);
    КонецЕсли;
    
    Возврат РезультатЗагрузки;
    
КонецФункции

Проверка строки

// Функция для проверки одной строки данных
Функция ПроверитьСтрок(СтрокаДанных, НомерСтроки)
    
    Ошибки = Новый Массив();
    
    // Проверка номенклатуры
    Если НЕ ЗначениеЗаполнено(СтрокаДанных.Номенклатура) Тогда
        Ошибки.Добавить("Номенклатура не указана");
    Иначе
        Номенклатура = НайтиНоменклатуру(СтрокаДанных.Номенклатура);
        Если НЕ ЗначениеЗаполнено(Номенклатура) Тогда
            Ошибки.Добавить("Номенклатура не найдена: " + СтрокаДанных.Номенклатура);
        КонецЕсли;
    КонецЕсли;
    
    // Проверка склада
    Если НЕ ЗначениеЗаполнено(СтрокаДанных.Склад) Тогда
        Ошибки.Добавить("Склад не указан");
    Иначе
        Склад = НайтиСклад(СтрокаДанных.Склад);
        Если НЕ ЗначениеЗаполнено(Склад) Тогда
            Ошибки.Добавить("Склад не найден: " + СтрокаДанных.Склад);
        КонецЕсли;
    КонецЕсли;
    
    // Проверка количества
    Если СтрокаДанных.Количество <= 0 Тогда
        Ошибки.Добавить("Количество должно быть больше нуля");
    КонецЕсли;
    
    Возврат Ошибки;
    
КонецФункции

// Поиск номенклатуры по наименованию
Функция НайтиНоменклатуру(Наименование)
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Ссылка
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |    Номенклатура.Наименование = @Наименование
    |    И Номенклатура.ПометкаУдаления = Ложь";
    
    Запрос.УстановитьПараметр("Наименование", Наименование);
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Ссылка;
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

// Поиск склада по наименованию
Функция НайтиСклад(Наименование)
    
    Запрос = Новый Запрос();
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Склады.Ссылка
    |ИЗ
    |    Справочник.Склады КАК Склады
    |ГДЕ
    |    Склады.Наименование = @Наименование
    |    И Склады.ПометкаУдаления = Ложь";
    
    Запрос.УстановитьПараметр("Наименование", Наименование);
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Ссылка;
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

Вывод итогов

// Процедура вывода результатов загрузки
Процедура ВывестиИтоги(РезультатЗагрузки)
    
    ТекстИтогов = "";
    ТекстИтогов = ТекстИтогов + "ИТОГИ ЗАГРУЗКИ ОСТАТКОВ" + Символы.ПС + Символы.ПС;
    ТекстИтогов = ТекстИтогов + "Всего строк: " + РезультатЗагрузки.ВсегоСтрок + Символы.ПС;
    ТекстИтогов = ТекстИтогов + "Успешно загружено: " + РезультатЗагрузки.УспешноЗагружено + Символы.ПС;
    ТекстИтогов = ТекстИтогов + "Ошибок: " + РезультатЗагрузки.Ошибок + Символы.ПС + Символы.ПС;
    
    Если РезультатЗагрузки.УспешноЗагружено > 0 Тогда
        ТекстИтогов = ТекстИтогов + "Документ создан: " + РезультатЗагрузки.НомерДокумента + Символы.ПС;
    КонецЕсли;
    
    Если РезультатЗагрузки.Ошибок > 0 Тогда
        ТекстИтогов = ТекстИтогов + Символы.ПС + "ОШИБКИ:" + Символы.ПС;
        Для Каждого СтрокаОшибки Из РезультатЗагрузки.Протокол Цикл
            ТекстИтогов = ТекстИтогов + "Строка " + СтрокаОшибки.СтрокаФайла + ": " + СтрокаОшибки.Описание + Символы.ПС;
        КонецЦикла;
    КонецЕсли;
    
    // Выводим информацию в форму
    ЭтаФорма.ОбъектДанных.ТекстРезультата = ТекстИтогов;
    ЭтаФорма.ОбъектДанных.СтатусЗагрузки = "Загрузка завершена";
    
КонецПроцедуры

Ключевые особенности реализации

1. Использование OLE Automation:

  • Позволяет читать Excel с сохранением форматирования
  • Работает с .xlsx и .xls форматами

2. Валидация данных:

  • Проверка существования справочников
  • Проверка заполненности обязательных полей
  • Собираются все ошибки перед сохранением

3. Эффективность:

  • Документ создаётся один раз
  • Все строки добавляются в оперативную память
  • Логирование проводится в таблице формы

4. Пользовательский опыт:

  • Подробный протокол ошибок
  • Четкие итоги загрузки
  • Понятные сообщения об ошибках

Эта реализация обеспечивает надёжный и удобный импорт начальных остатков из Excel-файла с полной валидацией и отчётностью.