В процессе автоматизации складского учета часто возникает задача синхронизации данных с внешними источниками. Рассмотрим ситуацию, когда нам необходимо получить актуальные остатки товаров от поставщика, которые хранятся в файле формата DBF на удаленном FTP-сервере, и обновить соответствующие значения в табличной части документа Заказ.
В этой статье мы подробно разберем весь цикл работы: от подключения к серверу и скачивания файла до оптимизации поиска номенклатуры и записи данных в информационную базу.
Прежде чем приступать к обработке данных, нам необходимо корректно настроить подключение и подготовить место для временного хранения файла. Разберем, как инициализировать объект XBase и загрузить файл во временный каталог пользователя.
Проанализируем фрагмент кода, отвечающий за создание структуры файла и его получение:
ИмяФайлаОстатков = "OstIs.DBF";
ПолноеИмяФайлаОстатков = КаталогВременныхФайлов();
ПолноеИмяФайла = СокрЛП(ПолноеИмяФайлаОстатков + ИмяФайлаОстатков);
XBase = Новый XBase;
XBase.Кодировка = КодировкаXBase.OEM; // Обычно DBF используют кодировку DOS (OEM)
// Создаем структуру файла, если планируем в него что-то писать,
// однако для чтения достаточно просто открыть существующий.
XBase.Поля.Добавить("KONTR","S",150);
XBase.Поля.Добавить("NOMENKL","S",150);
XBase.Поля.Добавить("REMAINS","S",60);
XBase.Поля.Добавить("DATE","D",25);
// Подключаемся к FTP и скачиваем файл
обФТП = Обработки.ftp.Создать();
обФТП.Конструктор(Константы.FTPАдрес.Получить(), Константы.FTPПорт.Получить(), Константы.FTPЛогин.Получить(), Константы.FTPПароль.Получить());
обФТП.Прочитать("OstNa.DBF", ПолноеИмяФайла);
обФТП.Деструктор();
Важно помнить, что функция КаталогВременныхФайлов() возвращает путь, который гарантированно доступен текущему пользователю для записи. Это избавляет нас от проблем с правами доступа в операционной системе.
После того как файл скачан, мы открываем его и начинаем перебор записей. Основная задача здесь — сопоставить строку из файла с объектом в справочнике Номенклатура и найти соответствующую строку в табличной части документа.
Рассмотрим базовый алгоритм решения задачи:
XBase.ОткрытьФайл(ПолноеИмяФайла);
Если XBase.Открыта() Тогда
XBase.Первая();
Пока Не XBase.ВКонце() Цикл
// Поиск номенклатуры по наименованию из файла
// Используем СокрЛП, так как в DBF строковые поля дополняются пробелами
ИмяТовара = СокрЛП(XBase.NOMENKL);
НомСсылка = Справочники.Номенклатура.НайтиПоНаименованию(ИмяТовара, Истина);
Если Не НомСсылка.Пустая() Тогда
// Ищем строку в табличной части "Состав" документа "Заказ"
// Предполагаем, что работа идет в модуле объекта документа
ПараметрыОтбора = Новый Структура("Номенклатура", НомСсылка);
НайденныеСтроки = Состав.НайтиСтроки(ПараметрыОтбора);
Для Каждого ТекущаяСтрока Из НайденныеСтроки Цикл
// Приводим строковое значение остатка из DBF к числу
ТекущаяСтрока.Остатки = Число(XBase.REMAINS);
КонецЦикла;
КонецЕсли;
XBase.Следующая();
КонецЦикла;
XBase.ЗакрытьФайл();
КонецЕсли;
Этот метод прост в реализации, но имеет существенный недостаток: если в табличной части документа много строк, поиск методом НайтиСтроки() внутри цикла по файлу будет работать медленно.
Чтобы ускорить процесс, мы можем заранее подготовить данные табличной части. Вместо того чтобы каждый раз сканировать таблицу документа, мы выгрузим её в объект Соответствие. Ключом будет выступать Номенклатура, а значением — ссылка на строку таблицы.
Разберем, как это реализовать:
Соответствие.Посмотрим на пример кода с оптимизацией:
// Подготавливаем кэш строк табличной части
КартаСтрок = Новый Соответствие;
Для Каждого СтрТЧ Из Состав Цикл
КартаСтрок.Вставить(СтрТЧ.Номенклатура, СтрТЧ);
КонецЦикла;
XBase.ОткрытьФайл(ПолноеИмяФайла);
XBase.Первая();
Пока Не XBase.ВКонце() Цикл
ИмяТовара = СокрЛП(XBase.NOMENKL);
НомСсылка = Справочники.Номенклатура.НайтиПоНаименованию(ИмяТовара, Истина);
Если Не НомСсылка.Пустая() Тогда
// Мгновенный поиск строки по ссылке номенклатуры
СтрокаДокумента = КартаСтрок.Получить(НомСсылка);
Если СтрокаДокумента <> Неопределено Тогда
СтрокаДокумента.Остатки = Число(XBase.REMAINS);
КонецЕсли;
КонецЕсли;
XBase.Следующая();
КонецЦикла;
XBase.ЗакрытьФайл();
Использование Соответствия сокращает сложность алгоритма и значительно ускоряет обработку больших заказов.
При работе с внешними файлами формата DBF нужно учитывать несколько критических моментов, которые могут привести к ошибкам или некорректным данным:
String в DBF имеют фиксированную длину. Если поле определено как 150 символов, а название товара занимает 20, остальные 130 будут заполнены пробелами. Всегда используйте функцию СокрЛП().REMAINS считано как строка. Для записи в числовой реквизит документа обязательно используйте явное преобразование Число().XBase.Кодировка. Чаще всего это либо КодировкаXBase.OEM (DOS), либо КодировкаXBase.ANSI (Windows).НайтиПоНаименованию) — самый ненадежный способ. Если у вас есть возможность, используйте поиск по Коду или Артикулу, предварительно договорившись с поставщиком о единых идентификаторах.Проанализируем правила "хорошего тона" при работе с файловой системой. После того как данные загружены, файл XBase должен быть закрыт методом ЗакрытьФайл(). Если этого не сделать, файл может остаться заблокированным процессом 1С, и его нельзя будет удалить или перезаписать программно.
Также рекомендуется удалять временный файл после обработки:
Попытка
УдалитьФайлы(ПолноеИмяФайла);
Исключение
Сообщить("Не удалось удалить временный файл: " + ПолноеИмяФайла);
КонецПопытки;
Таким образом, мы рассмотрели полный цикл загрузки остатков. Сочетание работы с FTP, объектом XBase и оптимизированным поиском через Соответствие позволяет создавать быстрые и надежные механизмы обмена данными в 1С.