Каждый практикующий специалист или администратор баз данных 1С рано или поздно сталкивается со сбоем автонумерации документов. Особенно часто эта проблема проявляется при загрузке данных из внешних систем, таких как «Клиент-Банк». Типичный сценарий: при импорте документов за определенный период (например, конец года) процесс внезапно прерывается ошибкой уникальности номера на значении вида ччч9999, где ччч — это префикс организации, а далее следует числовая часть. При этом длина номера в конфигурации может составлять 11 символов, а периодичность нумерации установлена в пределах года.
Давайте подробно проанализируем, почему возникает эта ошибка, как устроен механизм автонумерации платформы «1С:Предприятие», и рассмотрим по шагам все возможные способы решения этой проблемы — от простых интерактивных методов до программной корректировки поведения системы.
Для того чтобы эффективно устранить ошибку, нам необходимо выяснить первопричину ее возникновения. В платформе «1С:Предприятие» номера документов хранятся в виде текстовых строк, а не обычных чисел. Это необходимо для обеспечения гибкости — возможности использования префиксов организаций, префиксов информационных баз и разделителей.
Когда система пытается определить следующий свободный номер для нового документа, она ищет в базе данных документ с максимальным номером для текущего периода нумерации (в нашем случае — за год) и прибавляет к его числовой части единицу. Однако поиск «максимального» значения выполняется по законам символьного (лексикографического) сравнения строк, а не математического сравнения чисел.
Рассмотрим конкретный пример. Пусть в системе есть документ с некорректным номером ччч9999 (длина 7 символов вместо положенных 11) и документ с правильным номером ччч00009998. При строковом сравнении платформа посимвольно сравнивает строки слева направо:
ччч).ччч9999 признается платформой **большей**, чем ччч00009998 и даже больше, чем потенциальный номер ччч00010000.Когда лидирующие нули в номере документа оказываются утеряны (например, из-за некорректной ручной правки или сбойной загрузки из внешнего источника), автонумератор платформы «зацикливается». Платформа считывает номер ччч9999 как максимально возможный в текущем диапазоне. При попытке создать следующий документ система пытается прибавить единицу к значению «9999» и получить «10000». Но при попытке записать строку ччч10000 система обнаруживает, что этот номер по правилам строкового сравнения меньше, чем уже существующий ччч9999. В итоге генератор номеров пытается повторно выдать номер ччч9999, что мгновенно приводит к конфликту уникальности в базе данных.
Самый быстрый и безопасный способ восстановить нормальную работу автонумерации без глобального изменения данных — это найти и исправить конкретный документ, который нарушил структуру маски номера.
Разберем этот процесс по шагам:
ПлатежноеПоручениеВходящее и установим отбор за проблемный период (в нашем примере — 2018 год).ччч9999, скорее всего, окажется в самом низу или самом вверху списка из-за отсутствия лидирующих нулей.ччч9999 в ччч00009999.Как только маска номера будет приведена к стандартному виду, платформа 1С при создании следующего документа без проблем определит правильный максимальный номер и автоматически предложит значение ччч00010000. Автонумерация восстановится мгновенно.
Если документов с нарушенной структурой номера оказалось слишком много (например, несколько десятков платежных поручений загрузились из банка без лидирующих нулей), исправлять их вручную будет долго. В этом случае мы можем воспользоваться штатным инструментом платформы.
Проанализируем алгоритм группового восстановления номеров:
УниверсальныйПодборИОбработкаОбъектов.epf).ДокументСсылка.ПлатежноеПоручениеВходящее.Номер.Номер, установим напротив него флаг изменения и оставим значение пустым (или укажем пустую строку). Выполним изменение. Номера всех выбранных документов очистятся.Этот способ отлично подходит в ситуации, когда вам нужно срочно завершить загрузку документов из внешней системы (например, из Клиент-Банка), отложив наведение порядка в нумерации на более позднее время. Для этого мы можем задействовать специальное свойство объекта 1С.
Рассмотрим подробнее работу механизма ОбменДанными.Загрузка. При установке этого свойства в значение Истина платформа переходит в режим интеграции. В этом режиме отключаются прикладные проверки в модулях объектов, подписках на события, а также встроенные проверки уникальности номеров на уровне прикладного кода конфигурации.
Чтобы применить этот метод, нам потребуется внести небольшое изменение в код обработки загрузки из Клиент-Банка. Откроем код обработки в конфигураторе, найдем процедуру создания и записи нового документа и внесем следующие изменения перед вызовом метода Записать():
// Установка режима загрузки данных для обхода проверок нумерации
ТекДокументОбъект.ОбменДанными.Загрузка = Истина;
ТекДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Важное предупреждение: Использование режима ОбменДанными.Загрузка = Истина устраняет препятствия для записи документов на уровне встроенного языка 1С, но оно **не отменяет** ограничения уникальности полей, настроенные на уровне СУБД (MS SQL, PostgreSQL и др.), если они там заданы жестко. Кроме того, этот метод является лишь временным решением (костылем), так как после загрузки документов пользователи все равно не смогут создавать новые документы вручную, пока нумератор не будет исправлен методами, описанными в Решении 1 или Решении 2.
Если у вас нет прав на изменение кода обработки «Клиент-Банк» или конфигурации в конфигураторе, но загрузку нужно выполнить прямо сейчас, можно прибегнуть к административной хитрости с префиксом организации.
Разберем эту схему по шагам:
Префикс (в нашем случае это был префикс, формирующий начало номера ччч) и временно заменим его на другой свободный префикс (например, ввр).ввр00000001, ввр00000002 и т.д.), которые никак не пересекаются со старыми сбойными номерами диапазона ччч9999. Загрузка пройдет успешно и без ошибок.ччч обратно.Иногда возникает ситуация, когда вы уже исправили все неверные номера документов в базе данных вручную или с помощью групповой обработки, но платформа 1С при создании нового документа все равно продолжает настойчиво предлагать старый ошибочный номер. Почему это происходит?
Дело в том, что в целях повышения производительности сервер приложений «1С:Предприятие» кэширует последние выданные номера объектов в оперативной памяти. Изменение номеров непосредственно в базе данных не всегда мгновенно сбрасывает этот кэш.
Чтобы принудительно заставить платформу пересчитать нумерацию на основе актуальных данных физических таблиц СУБД, мы можем воспользоваться методом глобального контекста ОбновитьНумерациюОбъектов(). Для этого откроем консоль кода (или внешнюю обработку однократного выполнения) и выполним следующую команду:
// Принудительное обновление кэша автонумератора для входящих платежных поручений
ОбновитьНумерациюОбъектов(Метаданные.Документы.ПлатежноеПоручениеВходящее);
После выполнения этой строки кода кэш сервера будет сброшен, система заново просканирует индексы таблицы документов в базе данных и начнет предлагать корректные, следующие по порядку номера.
Основным источником появления номеров без лидирующих нулей является загрузка файлов выгрузки из банковских программ. Банковские системы оперируют простыми номерами документов («15», «125», «9999»), которые не содержат префиксов информационных баз 1С и ведущих нулей.
Чтобы предотвратить повторение проблемы в будущем, рекомендуется настроить правила обработки входящих номеров в модуле загрузки Клиент-Банка. Код загрузчика должен содержать функцию форматирования номера, которая приводит любое полученное из файла числовое значение к стандартному виду конфигурации перед записью объекта. Для этого можно использовать встроенную функцию дополнения строки символами:
// Пример функции форматирования номера перед записью документа в 1С
Функция СформироватьКорректныйНомер(НомерИзБанка, ПрефиксОрганизации)
ДлинаНомераКонфигурации = 11;
ЧисловойНомер = СокрЛП(НомерИзБанка);
ДлинаПрефикса = СтрДлина(ПрефиксОрганизации);
КоличествоНулей = ДлинаНомераКонфигурации - ДлинаПрефикса - СтрДлина(ЧисловойНомер);
Если КоличествоНулей > 0 Тогда
ЛидирующиеНули = "";
Для Счетчик = 1 По КоличествоНулей Цикл
ЛидирующиеНули = ЛидирующиеНули + "0";
КонецЦикла;
Возврат ПрефиксОрганизации + ЛидирующиеНули + ЧисловойНомер;
Иначе
Возврат ПрефиксОрганизации + ЧисловойНомер;
КонецЕсли;
КонецФункции
Внедрение подобного контроля на входе полностью обезопасит вашу информационную базу от появления «битых» номеров документов и исключит возникновение внезапных остановок бизнес-процессов из-за ошибок уникальности нумератора 1С.