Как найти документ в 1С по номеру, если в базе содержатся неразрывные и концевые пробелы?

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

При интеграции систем или загрузке данных из внешних файлов разработчики нередко сталкиваются с ситуацией, когда стандартный поиск документа по номеру не дает результатов. Например, во входящем файле указан номер вида "44106", а в информационной базе документ записан со значением "44 106     ". Выясним причину такого поведения платформы, проанализируем последствия для нумератора и разберем практические способы решения задачи.

Причины появления лишних пробелов в номерах документов

Рассмотрим, откуда в реквизите Номер появляются лишние символы:

  1. Неразрывный пробел внутри номера. Если при программном создании или перезаписи документа число преобразуется в строку неявно (например, через конкатенацию "" + Число или вызов Строка(Число)), платформа 1С применяет региональные настройки форматирования по умолчанию. В них разделителем триад цифр является неразрывный пробел с кодом 160 (в коде 1С доступен через Символы.НПП). В результате число 44106 превращается в "44 106" с неразрывным пробелом между группами. Чтобы избежать такой ошибки при приведении числа к строке, следует всегда явно отключать группировку: Формат(Число, "ЧГ=0").
  2. Концевые пробелы справа. Стандартный реквизит Номер у документов имеет тип «Строка» фиксированной длины. Если в данный реквизит записывается строка меньшей длины, платформа автоматически дополняет её пробелами справа до максимального количества символов, определенного в метаданных.

Ограничения стандартного метода НайтиПоНомеру

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

Посмотрим, к каким критическим последствиям приводит сохранение номеров с пробелами. Внутренний механизм автонумерации платформы выделяет числовую часть, анализируя символы с конца строки. Встретив пробел, автонумератор отсекает левую часть и считывает только правые цифры (в нашем примере — 106). Это приводит к тому, что последующие создаваемые документы получают заниженные номера либо вызывают фатальные ошибки контроля уникальности номеров в периоде.

Решение 1: Разовое исправление номеров в информационной базе (Рекомендуемое)

Наиболее правильным и надежным подходом является очистка базы от некорректных номеров. Это не только упростит поиск при обмене, но и восстановит нормальное функционирование встроенного автонумератора 1С.

Разберем по шагам алгоритм пакетного исправления номеров документов:

  1. Выбираем документы за проблемный период.
  2. Удаляем из реквизита Номер неразрывные и обычные пробелы с помощью функции СтрЗаменить().
  3. Записываем объект с отключением контроля уникальности номера.
  4. Обязательно вызываем метод ОбновитьНумерациюОбъектов(), чтобы платформа сбросила закешированный счетчик и пересчитала следующий свободный номер.

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


Выборка = Документы.РеализацияТоваровУслуг.Выбрать(НачалоГода(ТекущаяДата()), КонецГода(ТекущаяДата()));
Пока Выборка.Следующий() Цикл
    ТекущийНомер = Выборка.Номер;
    
    // Удаляем неразрывные пробелы и стандартные пробелы
    ОчищенныйНомер = СтрЗаменить(ТекущийНомер, Символы.НПП, "");
    ОчищенныйНомер = СокрЛП(СтрЗаменить(ОчищенныйНомер, " ", ""));
    
    Если ОчищенныйНомер <> СокрЛП(ТекущийНомер) Тогда
        ДокументОбъект = Выборка.ПолучитьОбъект();
        ДокументОбъект.Номер = ОчищенныйНомер;
        ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
    КонецЕсли;
КонецЦикла;

// Восстанавливаем корректную работу автонумератора платформы
ОбновитьНумерациюОбъектов(Метаданные.Документы.РеализацияТоваровУслуг);

Решение 2: Поиск через оператор ПОДОБНО в запросе

Если исправить данные в базе прямо сейчас невозможно (например, закрыт период для редактирования), рассмотрим вариант гибкого поиска средствами языка запросов. Поскольку функция ФОРМАТ() в запросах 1С отсутствует, а функция СТРЗАМЕНИТЬ() появилась только в платформе 8.3.20, универсальным решением является использование оператора ПОДОБНО с шаблонами подстановки.

Символ _ (подчеркивание) означает ровно один любой символ (включая неразрывный пробел), а символ % обозначает любую последовательность символов. Сформируем шаблон поиска на основе полученного из файла значения:


НомерИзФайла = "44106"; // Значение из внешнего источника

// Формируем шаблон с подстановочным знаком для возможного разделителя тысяч
Если СтрДлина(НомерИзФайла) = 5 Тогда
    ШаблонПоиска = Лев(НомерИзФайла, 2) + "_" + Прав(НомерИзФайла, 3) + "%";
Иначе
    ШаблонПоиска = "%" + НомерИзФайла + "%";
КонецЕсли;

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

Запрос.УстановитьПараметр("ДатаНачала", НачалоГода(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаКонца", КонецГода(ТекущаяДата()));
Запрос.УстановитьПараметр("ШаблонПоиска", ШаблонПоиска);

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

Решение 3: Поиск с использованием СТРЗАМЕНИТЬ в запросе (для платформы 8.3.20 и выше)

Рассмотрим вариант прямого сопоставления в запросе, если информационная база работает на версии платформы 8.3.20 или более новой. Начиная с этой версии, язык запросов поддерживает функцию СТРЗАМЕНИТЬ(), что позволяет избавиться от лишних символов непосредственно в условии ГДЕ.


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

Запрос.УстановитьПараметр("ДатаНачала", НачалоГода(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаКонца", КонецГода(ТекущаяДата()));
Запрос.УстановитьПараметр("НомерИзФайла", "44106");
Запрос.УстановитьПараметр("НПП", Символы.НПП);

Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
    Выборка = Результат.Выбрать();
    Выборка.Следующий();
    НайденныйДокумент = Выборка.Ссылка;
КонецЕсли;

Подведем итог: использование временных обходных путей поиска через оператор ПОДОБНО или строковые функции в запросе оправдано лишь как срочная мера. Для стабильной работы конфигурации и корректного формирования номеров системой необходимо очистить реквизиты документов от пробелов и выполнить вызов метода ОбновитьНумерациюОбъектов().

← На главную