Почему не меняется программно номер документа в 1С и как убрать лишние пробелы?

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

Каждый разработчик 1С рано или поздно сталкивается с ситуацией, когда простой и логичный код не дает ожидаемого результата. Типичный пример — попытка очистить номер документа от лишних пробелов или спецсимволов. Мы пишем код, проверяем его работу в отладчике, видим, что строка успешно преобразована, но после вызова метода Записать() пробелы волшебным образом возвращаются на свое место. В этой статье мы подробно разберем, почему так происходит, рассмотрим внутренние механизмы платформы «1С:Предприятие» и найдем правильные способы решения этой проблемы.

Анализ проблемы: почему стандартный код не работает

Рассмотрим классический пример кода, с которого часто начинаются подобные темы на форумах:


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

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

Если мы поставим точку останова в конфигураторе сразу после строки преобразования, то увидим, что в переменной Док.Номер действительно находится чистая строка без пробелов. Но как только управление проходит строку Док.Записать(), платформа заново заполняет хвостовую часть строки пробелами. Выясним, почему это происходит.

Глубокая техническая причина: фиксированная длина номера

Главная причина такого поведения кроется не в ошибках кода, а в настройках метаданных конкретного документа или связанного с ним нумератора в конфигураторе. В платформе «1С:Предприятие» для реквизитов Код (у справочников) и Номер (у документов) существует важное системное свойство — «Допустимая длина».

Это свойство может принимать два значения:

  1. Фиксированная. В этом режиме платформа жестко следит за тем, чтобы длина строки номера в базе данных всегда соответствовала значению, указанному в поле «Длина номера» (например, 16 символов). Если записываемый номер физически короче (например, состоит всего из 10 символов), платформа автоматически дополняет его справа стандартными пробелами (символ с кодом ASCII 32) до достижения установленного лимита в момент транзакции записи в СУБД. Именно поэтому любые программные попытки «обрезать» эти пробелы с помощью функций СокрЛП() или СтрЗаменить() игнорируются при сохранении.
  2. Переменная. В данном режиме строка номера сохраняется ровно в том виде, в котором её передал разработчик или пользователь. Платформа контролирует только максимальный предел длины, но не пытается дополнять строку недостающими символами справа.

Поскольку у автора вопроса в метаданных документа была установлена длина номера 16 символов с типом «Фиксированная», платформа принудительно возвращала недостающие пробелы в конец строки при каждом вызове метода Записать().

Решение №1: Изменение метаданных в конфигураторе (рекомендуемый способ)

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

Разберем по шагам, как это сделать:

  1. Откройте конфигурацию в режиме «Конфигуратор».
  2. Найдите нужный документ в дереве метаданных (в нашем примере это НалоговаяНакладная) и откройте его свойства.
  3. Перейдите на вкладку «Нумерация».
  4. Обратите внимание на свойство «Допустимая длина». Если там установлено значение «Фиксированная», измените его на «Переменная».
  5. Если документ использует сквозной нумератор (свойство «Нумератор» заполнено), то аналогичные изменения необходимо внести в свойствах самого объекта «Нумератор» в ветке «Общие -> Нумераторы».
  6. Выполните обновление конфигурации базы данных (клавиша F7).

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

Решение №2: Что делать, если конфигурацию нельзя менять?

В случае, когда база данных находится на строгой поддержке (например, это типовая «1С:Бухгалтерия», закрытая от изменений), менять метаданные нельзя. В такой ситуации программисту приходится подстраиваться под особенности хранения данных. Рассмотрим, как правильно работать с номерами фиксированной длины.

1. Очистка «на лету» при выводе на печать или выгрузке

Поскольку хранить номера в базе без пробелов физически невозможно из-за ограничений метаданных, очищать их нужно непосредственно перед выводом пользователю, отправкой по API или выгрузкой во внешние файлы (XML, Excel). Для этого используйте стандартную функцию СокрЛП():


// Очищаем номер только для передачи во внешнюю систему
НомерДляВыгрузки = СокрЛП(ДокументОбъект.Номер);

Записывать результат обратно в объект бессмысленно — это приведет к повторному заполнению пробелами.

2. Борьба с неразрывными пробелами (НПП)

Иногда обычная функция СокрЛП() не справляется с удалением невидимых символов. Это происходит, когда пользователи копируют номера документов из внешних источников (например, из писем или таблиц Excel), занося в базу так называемые неразрывные пробелы (символ с кодом Unicode 160, или Символы.НПП).

Стандартная функция СокрЛП() в старых версиях платформы или при определенных условиях может не распознавать неразрывный пробел как символ, подлежащий удалению. Чтобы гарантированно очистить строку от всех видов пробелов, используем следующую конструкцию:


ЧистыйНомер = СтрЗаменить(ДокументОбъект.Номер, Символы.НПП, "");
ЧистыйНомер = СтрЗаменить(ЧистыйНомер, " ", "");

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

Важный нюанс: Поиск документов по номеру в запросах

При работе с номерами фиксированной длины часто возникает неочевидная проблема при написании запросов. Допустим, мы ищем документ по номеру, который получили из внешнего источника без пробелов:


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

Запрос.УстановитьПараметр("Номер", "НО000012"); // Номер без пробелов

Если в базе данных длина номера равна 16 символам с фиксированной длиной, данный запрос может вернуть пустой результат, так как в базе фактически записано значение "НО000012 " (с восемью пробелами на конце).

Поведение этого запроса зависит от используемой СУБД:

Чтобы гарантировать стабильную работу поиска на любой СУБД, перед передачей параметра в запрос необходимо дополнить поисковую строку пробелами до нужной длины либо использовать оператор сравнения ПОДОБНО с автоподстановкой процента:


// Вариант с ПОДОБНО (может снизить производительность на больших базах)
Запрос.УстановитьПараметр("Номер", "НО000012%");

Или, что более правильно с точки зрения производительности СУБД, дополнить строку пробелами до фиксированной длины метаданных:


ПоисковыйНомер = "НО000012";
НужнаяДлина = Метаданные.Документы.НалоговаяНакладная.ДлинаНомера;

// Дополняем строку пробелами справа до нужной длины
Пока СтрДлина(ПоисковыйНомер) < НужнаяДлина Цикл
    ПоисковыйНомер = ПоисковыйНомер + " ";
КонецЦикла;

Запрос.УстановитьПараметр("Номер", ПоисковыйНомер);

Резюме

Мы подробно проанализировали проблему программного изменения номера документа в 1С. Подведем итог всему вышесказанному:

← На главную