Как в 1С:Конвертация данных искать документ по номеру в произвольном периоде

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

При переносе данных между базами 1С часто возникает ситуация, когда стандартные механизмы поиска «по уникальному идентификатору» (GUID) или «по номеру и дате» не срабатывают. Одной из самых распространенных проблем является несовпадение дат документов в базе-источнике и базе-приемнике. Например, документ в источнике может быть за одну дату, а в приемнике его уже успели отредактировать и изменить дату на более актуальную. Если при этом стандартный поиск по номеру захватывает лишние документы прошлых лет, возникает необходимость ограничить поиск определенным интервалом (например, последние 7 месяцев).

В этой статье мы подробно разберем, как реализовать программный поиск документа по номеру в заданном периоде, используя возможности конфигурации «Конвертация данных 2.0» (КД 2.0).

Почему стандартный поиск может не подойти?

Рассмотрим ситуацию: мы настраиваем Правило Конвертации Объектов (ПКО) для документа РасходнаяНакладная. Если в настройках ПКС для реквизита Дата не установлена галочка «Искать по дате на равенство», платформа пытается выполнить нечеткий поиск. Однако метод НайтиПоНомеру(), который используется системой «под капотом», жестко привязан к периодичности нумерации документа. Если периодичность установлена в значение «Год», а искомый документ находится в другом году или интервал поиска пересекает границу года, поиск может завершиться неудачей. Кроме того, если нам нужно ограничить поиск ровно 7 месяцами от текущей даты, стандартных настроек ПКО будет недостаточно.

Решение проблемы через обработчик «Поля поиска»

Наиболее гибкий способ решить задачу — использовать обработчик события «Поля поиска» в ПКО нужного документа. Этот обработчик выполняется в базе-приемнике непосредственно в момент загрузки данных. Проанализируем алгоритм действий.

Для начала убедимся, что в правилах конвертации свойств (ПКС) у реквизита Номер установлена галочка «Поиск». Это необходимо, чтобы значение номера попало в структуру СвойстваПоиска, доступную в обработчике.

Разберем пример кода, который необходимо разместить в обработчике «Поля поиска»:


// Проверяем, что поиск по идентификатору не дал результатов
Если СсылкаНаОбъект = Неопределено Тогда

    // Подготовим запрос для поиска документа по номеру в интервале 7 месяцев
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	РасходнаяНакладная.Ссылка КАК Ссылка
        |ИЗ
        |	Документ.РасходнаяНакладная КАК РасходнаяНакладная
        |ГДЕ
        |	РасходнаяНакладная.Номер = &Номер
        |	И РасходнаяНакладная.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
        |	И РасходнаяНакладная.ПометкаУдаления = ЛОЖЬ";

    // Устанавливаем параметры запроса
    Запрос.УстановитьПараметр("Номер", СвойстваПоиска["Номер"]);
    
    // Вычисляем период: 7 месяцев назад от текущей даты
    ДатаОкончания = ТекущаяДата();
    ДатаНачала = ДобавитьМесяц(ДатаОкончания, -7);
    
    Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
    Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);

    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();

    Если Выборка.Следующий() Тогда
        // Если объект найден, присваиваем его ссылке
        СсылкаНаОбъект = Выборка.Ссылка;
        
        // Важно! Сообщаем системе, что поиск завершен успешно
        ПрекратитьПоиск = Истина;
    КонецЕсли;

КонецЕсли;

Разбор ключевых параметров обработчика

Проанализируем основные переменные, с которыми мы работали в коде выше:

  1. СсылкаНаОбъект — это результат поиска. Если мы нашли документ программно, мы должны записать его ссылку в эту переменную.
  2. СвойстваПоиска — структура, содержащая значения полей, для которых в ПКС установлена галочка «Поиск». Именно отсюда мы получаем СвойстваПоиска["Номер"].
  3. ПрекратитьПоиск — булево значение. Если установить его в Истина, то стандартный механизм поиска 1С (который идет после выполнения кода обработчика) будет пропущен. Это критически важно, чтобы система не попыталась переопределить найденную вами ссылку.

Вариант с использованием метода «НайтиПоНомеру»

Иногда разработчики пытаются использовать метод НайтиПоНомеру() прямо в коде поиска. Выглядит это примерно так:


// Попытка поиска через встроенный метод документа
СсылкаНаОбъект = Документы.РасходнаяНакладная.НайтиПоНомеру(СвойстваПоиска["Номер"], ДатаНачала);

Если ЗначениеЗаполнено(СсылкаНаОбъект) Тогда
    ПрекратитьПоиск = Истина;
КонецЕсли;

Рассмотрим ситуацию подробнее. Выясним причину, почему этот метод может работать нестабильно. Метод НайтиПоНомеру использует второй параметр (дату) только для того, чтобы определить период нумерации. Если в вашей конфигурации для документа РасходнаяНакладная установлена периодичность «Год», то передав дату 01.01.2023, вы ограничите поиск только документами 2023 года. Если нужный документ был создан в декабре 2022 года, а ваша «граница в 7 месяцев» его захватывает — НайтиПоНомеру его не найдет. Поэтому использование прямого запроса к таблице базы данных является более надежным решением.

Оптимизация производительности (Кэширование)

Если вы загружаете большое количество документов (тысячи и десятки тысяч), выполнение отдельного запроса в «Полях поиска» для каждого объекта может существенно замедлить процесс загрузки. Проанализируем, как это оптимизировать.

Вместо выполнения запроса каждый раз, мы можем один раз собрать все номера документов в базе-приемнике за нужный период и сохранить их в памяти. Посмотрим на алгоритм реализации через глобальный параметр Параметры:

  1. В обработчике конвертации «Перед загрузкой данных» создаем соответствие и заполняем его запросом.
  2. В обработчике «Поля поиска» просто извлекаем данные из этого соответствия.

Пример кода для «Перед загрузкой данных»:


Запрос = Новый Запрос("ВЫБРАТЬ Номер, Ссылка ИЗ Документ.РасходнаяНакладная ГДЕ Дата > &ДатаОгр");
Запрос.УстановитьПараметр("ДатаОгр", ДобавитьМесяц(ТекущаяДата(), -7));
ТаблицаКэша = Запрос.Выполнить().Выгрузить();

// Создаем соответствие для быстрого поиска: Ключ - Номер, Значение - Ссылка
Параметры.Вставить("КэшНомеров", Новый Соответствие);
Для Каждого Стр Из ТаблицаКэша Цикл
    Параметры.КэшНомеров.Вставить(Стр.Номер, Стр.Ссылка);
КонецЦикла;

Теперь в «Полях поиска» код станет максимально коротким и быстрым:


НайденнаяСсылка = Параметры.КэшНомеров.Получить(СвойстваПоиска["Номер"]);
Если НайденнаяСсылка <> Неопределено Тогда
    СсылкаНаОбъект = НайденнаяСсылка;
    ПрекратитьПоиск = Истина;
КонецЕсли;

Особенности работы в тонком клиенте

При использовании «Универсального обмена данными XML» в режиме тонкого клиента (управляемые формы) стоит помнить, что выполнение кода происходит на стороне сервера. Если вы используете параметры обработки (например, даты, выбранные на форме), убедитесь, что они корректно передаются в контекст поиска. Часто безопаснее вычислять границы периода (те самые 7 месяцев) непосредственно внутри кода поиска, используя функцию ТекущаяДата(), чтобы избежать ошибок инициализации параметров.

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

Подводя итог, можно сказать, что решение задачи поиска в произвольном периоде в КД 2.0 сводится к написанию небольшого, но эффективного фрагмента кода на языке 1С в обработчике «Поля поиска», который полностью заменяет или дополняет стандартный алгоритм поиска платформы.

← На главную