Как идентифицировать документы при обмене через DBF, если в файле нет уникальных идентификаторов и меняются реквизиты?

Программист 1С v8.3 (Управляемые формы) Управленческий учет
← На главную

Обмен данными через формат DBF — это классический, но зачастую проблемный способ интеграции 1С со сторонними системами. Одной из самых сложных ситуаций является отсутствие в структуре файла GUID (уникального идентификатора). Если при этом пользователи в сторонней программе имеют возможность изменять номер и дату документа уже после того, как он был загружен в 1С, возникает дублирование данных. Алгоритм загрузки просто не находит документ по старым реквизитам и создает новый.

В этой статье мы разберем, как построить надежную систему идентификации объектов, даже если входные данные крайне нестабильны. Рассмотрим несколько подходов: от административных мер до продвинутых алгоритмов нечеткого поиска.

Решение 1: Внедрение пользовательского GUID (ГНОМ)

Самый надежный способ, который упоминается в обсуждении, — это добавление в структуру DBF-файла дополнительного поля для хранения уникального идентификатора. Программисты часто называют его ГНОМ (Глобальный Номер Обмена) или просто пользовательский GUID.

Разберем, как это работает. В сторонней программе при создании документа один раз генерируется уникальная строка (например, через NewId() в SQL или встроенные средства языка). Этот идентификатор записывается в поле DBF и никогда не меняется, даже если пользователь правит номер, дату или контрагента.

На стороне 1С нам необходимо:

  1. Добавить в документ дополнительный реквизит ИдентификаторСтороннейСистемы (тип: Строка, длина 36-50 символов).
  2. При загрузке выполнять поиск не по номеру и дате, а по этому реквизиту.

Проанализируем пример кода для поиска документа:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   РеализацияТоваровУслуг.Ссылка КАК Ссылка
    |ИЗ
    |   Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    |ГДЕ
    |   РеализацияТоваровУслуг.ИдентификаторСтороннейСистемы = &Идентификатор";

Запрос.УстановитьПараметр("Идентификатор", СтрокаИзDBF.EXT_ID);
РезультатЗапроса = Запрос.Выполнить();

Если НЕ РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    ДокументОбъект = Выборка.Ссылка.ПолучитьОбъект();
Иначе
    ДокументОбъект = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
    ДокументОбъект.ИдентификаторСтороннейСистемы = СтрокаИзDBF.EXT_ID;
КонецЕсли;

Решение 2: Метод весовых коэффициентов (Нечеткий поиск)

Если изменить структуру DBF невозможно, нам придется использовать логику "похожести". Мы можем предположить, что хотя номер и дата изменились, другие важные параметры (сумма, контрагент, состав товаров) остались прежними. Разберем, как реализовать механизм сопоставления по весам.

Каждому совпадению полей мы присваиваем определенный балл. Например:

Если итоговая сумма баллов превышает порог (например, 80), мы считаем, что это тот же самый документ. Рассмотрим логику функции сопоставления:


Функция НайтиПохожийДокумент(ДанныеФайла)
    // Ищем документы контрагента за период +/- 5 дней
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ Ссылка, СуммаДокумента, Дата ИЗ Документ.Продажа ГДЕ Контрагент = &Контрагент";
    // ... установка параметров периода ...
    
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        Вес = 0;
        Если Выборка.СуммаДокумента = ДанныеФайла.Сумма Тогда
            Вес = Вес + 50;
        КонецЕсли;
        
        Если НачалоДня(Выборка.Дата) = НачалоДня(ДанныеФайла.Дата) Тогда
            Вес = Вес + 30;
        КонецЕсли;
        
        Если Вес >= 80 Тогда
            Возврат Выборка.Ссылка;
        КонецЕсли;
    КонецЦикла;
    Возврат Неопределено;
КонецФункции

Решение 3: Использование физического номера записи (RECNO)

В технологии DBF каждая строка имеет свой порядковый физический номер — RECNO. Если программа-источник не создает файл каждый раз "с нуля", а обновляет существующий, то запись о документе №369852147 будет всегда находиться на одной и той же позиции в файле.

Важный нюанс: Этот метод рискован, так как после процедуры сжатия (Pack) или пересоздания файла индексы сместятся. Однако в стабильных системах это может стать временным решением. Мы можем сохранять номер строки из файла в 1С и при следующей загрузке проверять именно эту позицию.

Решение 4: Создание буферного регистра (Staging Table)

Чтобы контролировать изменения, проанализируем ситуацию через промежуточное звено. Создадим в 1С РегистрСведений, который будет хранить "слепки" (хэши) строк из последнего успешно загруженного файла.

Алгоритм действий следующий:

  1. При загрузке строки из DBF мы формируем строку из всех её значимых полей (Номер + Дата + Сумма + Контрагент).
  2. Вычисляем хэш-сумму этой строки.
  3. Сравниваем хэш с тем, что хранится в регистре для данного документа.
  4. Если данные в файле изменились (хэш другой), система выдает пользователю уведомление: "Документ такой-то изменен. Обновить существующий или создать новый?".

Такой подход позволяет избежать автоматического создания дублей и перекладывает принятие окончательного решения на оператора, предоставляя ему удобный интерфейс для сравнения старых и новых данных.

Решение 5: Ориентация на неизменяемые входящие данные

Как отмечалось в обсуждении, существуют реквизиты, которые подтверждены первичными документами и меняются крайне редко. Это могут быть Номер входящего документа или Номер БСО (бланка строгой отчетности). Если в вашей предметной области есть такие данные, они должны стать первичным ключом поиска.

Проанализируем преимущества этого метода:

Рекомендации по автоматизации процесса

Выясним причину, по которой "специалисты" так часто меняют данные. Если это неизбежное зло, то лучшей стратегией будет комбинированный метод:

Шаг 1: Попытка поиска по жесткому идентификатору (если его удалось внедрить).

Шаг 2: Поиск по входящим номерам документов (БСО).

Шаг 3: Сверка итоговых оборотов за день. Если в 1С и в файле итоговая сумма за день совпадает, но состав документов разный — это явный признак того, что какой-то документ был переименован. В этом случае стоит реализовать механизм "Сторно": помечать на удаление все загруженные за этот день документы и загружать их заново из файла целиком.

Рассмотрим пример реализации метода "перезагрузки периода":


Процедура ЗагрузитьПериодСПолнымОбновлением(ДатаНачала, ДатаОкончания, ДанныеФайла)
    // 1. Находим все документы, ранее загруженные за этот период
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ Документ.Продажа ГДЕ Дата МЕЖДУ &Д1 И &Д2 И ЗагруженИзВнешнейСистемы = ИСТИНА";
    // ...
    
    // 2. Помечаем их на удаление, чтобы не создавать дублей
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
        ДокОбъект.УстановитьПометкуУдаления(Истина);
        ДокОбъект.Записать();
    КонецЦикла;
    
    // 3. Создаем новые документы на основе текущих данных из DBF
    Для Каждого СтрокаДанных Из ДанныеФайла Цикл
        СоздатьНовыйДокумент(СтрокаДанных);
    КонецЦикла;
КонецПроцедуры

В заключение отметим, что работа с DBF без уникальных ключей — это всегда поиск компромисса между автоматизацией и ручным контролем. Использование промежуточных регистров истории и алгоритмов нечеткого поиска позволяет свести количество ошибок к минимуму, сохраняя при этом актуальность данных в учетной системе.

← На главную