Чтение входящих счетов от контрагентов — классическая задача для разработчика 1С. Однако на практике мы часто сталкиваемся с тем, что файлы имеют сложную структуру: объединенные ячейки, "плавающие" колонки, вложенные таблицы или вовсе приходят в формате PDF. Разберем основные стратегии и технические приемы, которые позволят автоматизировать загрузку таких данных, минимизируя ручной труд пользователей.
Самый простой и доступный способ прочитать Excel-файл без установленного Microsoft Office на сервере — это использование встроенных средств платформы 1С. Рассмотрим, как это реализовать технически. Основным инструментом здесь выступает объект ТабличныйДокумент.
Проанализируем базовый алгоритм чтения:
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
Сообщить("Ошибка при чтении файла: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
Важный нюанс при работе со счетами, сформированными в 1С и выгруженными в Excel: они часто содержат объединенные ячейки. Выясним, как программа воспринимает такие области. При объединении нескольких колонок (например, с 2-й по 5-ю), фактическое значение будет содержаться только в самой левой верхней ячейке этой области. Посмотрим на пример обхода строк:
Для НомерСтроки = 1 По ТабДок.ВысотаТаблицы Цикл
// Предположим, наименование товара в колонке 2, которая объединена
ТоварНаименование = ТабДок.Область(НомерСтроки, 2).Текст;
Если ПустаяСтрока(ТоварНаименование) Тогда
Продолжить;
КонецЕсли;
// Дальнейшая обработка
КонецЦикла;
При работе со сложными счетами мы не можем полагаться на фиксированные номера строк и колонок, так как поставщик может добавить логотип, рекламный баннер или изменить ширину шапки. Рассмотрим стратегию поиска по ключевым словам или «якорям».
Вместо обращения к ячейке (10, 5), мы проанализируем таблицу на наличие заголовков, таких как «Наименование», «Кол-во», «Сумма». Разберем, как реализовать универсальный поиск координат:
КолонкаНаименования = 0;
КолонкаКоличества = 0;
Для НомерКолонки = 1 По ТабДок.ШиринаТаблицы Цикл
ТекстЗаголовка = ТабДок.Область(НомерСтрокиШапки, НомерКолонки).Текст;
Если Найти(ТекстЗаголовка, "Наименование") > 0 Тогда
КолонкаНаименования = НомерКолонки;
ИначеЕсли Найти(ТекстЗаголовка, "Кол") > 0 Тогда
КолонкаКоличества = НомерКолонки;
КонецЕсли;
КонецЦикла;
Этот подход делает ваш парсер устойчивым к изменениям формата файла. Даже если контрагент добавит новую колонку «Артикул» в начало таблицы, ваш код автоматически найдет нужные данные по тексту заголовков.
Если задача стоит остро, а времени на написание собственного кода нет, можно воспользоваться легендарными универсальными загрузками, такими как «Прыг-Скок». Проанализируем, в чем их преимущество. Эти инструменты уже содержат в себе логику очистки данных от «мусора» (пустых строк, промежуточных итогов, подписей в подвале документа) и позволяют настраивать сопоставление полей через визуальный интерфейс.
Это особенно полезно, когда нужно загрузить данные в типовые документы, такие как ПоступлениеТоваровУслуг или ЗаказПоставщику.
Часто счета приходят в формате PDF. Если это «правильный» PDF (содержащий текстовый слой, а не просто картинку), попытка конвертировать его в Excel через сторонние утилиты часто приводит к тому, что верстка «разъезжается», и данные попадают в непредсказуемые ячейки.
Рассмотрим альтернативный путь: прямой парсинг текста PDF. Для этого можно использовать внешние компоненты или консольные утилиты (например, на базе poppler или unipdf). Выясним преимущества этого метода: вы получаете поток текста с координатами, что позволяет программно вычислить принадлежность текста к той или иной колонке, основываясь на его горизонтальном смещении.
Однако, наиболее современным решением в экосистеме 1С является сервис «1С:Распознавание первичных документов». Посмотрим, как он решает проблему:
Номенклатура.Если у вас десятки поставщиков с разными форматами счетов, писать отдельный код под каждого — тупиковый путь. Разберем создание системы маппинга. Создадим в базе справочник или регистр сведений «НастройкиЗагрузкиИзExcel», где для каждого контрагента будем хранить:
Проанализируем пример функции, использующей такие настройки:
Функция ПолучитьЗначениеПоНастройке(ТабДок, Строка, Настройка)
Если Настройка.ТипПоиска = Перечисления.ТипПоиска.ПоНомеруКолонки Тогда
Возврат ТабДок.Область(Строка, Настройка.НомерКолонки).Текст;
Иначе
// Логика поиска по координатам, найденным через "якорь"
КонецЕсли;
КонецФункции
Если Excel-файл содержит тысячи строк, ТабличныйДокумент может работать медленно. В таких случаях рассмотрим использование COM-объекта ADODB.Connection. Это позволяет работать с листом Excel как с таблицей базы данных, используя SQL-запросы.
Посмотрим на пример инициализации соединения:
Connection = Новый COMОбъект("ADODB.Connection");
ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ПутьКФайлу + ";Extended Properties=""Excel 12.0 Xml;HDR=YES"";";
Connection.Open(ConnectionString);
Recordset = Connection.Execute("SELECT * FROM [Лист1$]");
Пока НЕ Recordset.EOF() Цикл
// Обработка полей через Recordset.Fields("НазваниеКолонки").Value
Recordset.MoveNext();
КонецЦикла;
Важно: Этот метод требует наличия установленного драйвера Access Database Engine на сервере 1С и не всегда подходит для файлов с очень сложным форматированием и объединенными ячейками, так как он ожидает увидеть «чистую» таблицу.
Для достижения максимальной стабильности загрузки, мы рекомендуем придерживаться следующих правил:
VBScript.RegExp для очистки строк от лишних символов (например, когда в ячейке с ценой написано «150.00 руб.»).Таким образом, выбор метода зависит от сложности входящего файла и частоты задачи. Для разовых загрузок достаточно ТабличногоДокумента с ручным указанием колонок, а для потоковой обработки лучше инвестировать время в разработку системы шаблонов или подключение сервисов распознавания.