При переносе данных между системами, интеграции с торговым оборудованием (весами с печатью этикеток, кассовыми узлами) или штрихкодировании часто возникает необходимость присваивать элементам справочника коды из строго определенного диапазона (например, от 00000000001 до 00000000999). Штатный автонумератор платформы 1С всегда выбирает максимальный существующий код и увеличивает его на единицу, поэтому он не умеет заполнять образовавшиеся «дыры» и пропуски в нумерации.
Разберем, как программно найти минимальный свободный код строкового типа с лидирующими нулями, какие особенности платформы необходимо учитывать и как правильно встроить этот механизм в типовую или доработанную конфигурацию.
Рассмотрим базовый и наиболее универсальный способ решения задачи: получение существующих элементов в нужном диапазоне через запрос и последующий поиск разрыва в нумерации при обходе выборки.
Проанализируем практический пример функции, возвращающей минимальный свободный код полной длины (11 знаков):
Функция ПолучитьНовыйКод(ГраницаДиапазона = 999, ДлинаКода = 11) Экспорт
// Формируем строковое значение верхней границы с ведущими нулями
СтрокаГраницы = Формат(ГраницаДиапазона, "ЧЦ=" + ДлинаКода + "; ЧРГ=; ЧГ=0");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Код КАК Код
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Код <= &ГраницаДиапазона
| И НЕ Номенклатура.ЭтоГруппа
|УПОРЯДОЧИТЬ ПО
| Номенклатура.Код ВОЗР";
Запрос.УстановитьПараметр("ГраницаДиапазона", СтрокаГраницы);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
ТекЧислоКода = 0;
Пока Выборка.Следующий() Цикл
// Приводим строковый код из базы к числу для арифметического сравнения
ЧислоИзБазы = Число(Выборка.Код);
Если (ЧислоИзБазы - ТекЧислоКода) > 1 Тогда
// Найден пропуск между предыдущим и текущим значением
СвободноеЧисло = ТекЧислоКода + 1;
Возврат Формат(СвободноеЧисло, "ЧЦ=" + ДлинаКода + "; ЧРГ=; ЧГ=0");
КонецЕсли;
ТекЧислоКода = ЧислоИзБазы;
КонецЦикла;
// Если пропусков в середине не было, проверяем следующий за последним
Если ТекЧислоКода < ГраницаДиапазона Тогда
СвободноеЧисло = ТекЧислоКода + 1;
Возврат Формат(СвободноеЧисло, "ЧЦ=" + ДлинаКода + "; ЧРГ=; ЧГ=0");
КонецЕсли;
// Свободных кодов в диапазоне не осталось
Возврат Неопределено;
КонецФункции
Разберем важные нюансы поведения платформы 1С при работе со строковыми полями:
"999" без лидирующих нулей, то в условие Код <= &ГраницаДиапазона попадут все коды, начинающиеся на цифры от "0" до "8" любой длины (например, "17000000000" или "55555555555"). Граничный параметр запроса обязательно должен содержать ровно столько же знаков, сколько составляет длина реквизита в метаданных.Формат() с параметрами ЧЦ (число цифр) и ЧГ=0 (отключение группировки разрядов), что исключает случайное появление неразрывных пробелов в коде.Если требуется разово найти свободный код для небольшого диапазона (например, до 1000 элементов) без выполнения запроса, разберем альтернативный вариант с перебором и методом НайтиПоКоду():
Функция НайтиСвободныйКодПеребором(МаксЗначение = 999, ДлинаКода = 11) Экспорт
Для Счетчик = 1 По МаксЗначение Цикл
СтрокаКода = Формат(Счетчик, "ЧЦ=" + ДлинаКода + "; ЧРГ=; ЧГ=0");
СсылкаНаЭлемент = Справочники.Номенклатура.НайтиПоКоду(СтрокаКода);
Если СсылкаНаЭлемент.Пустая() Тогда
Возврат СтрокаКода;
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункции
Такой способ подходит для разовых обработок переноса или группового переназначения реквизитов, однако для высоконагруженных систем предпочтителен запрос к базе данных.
Выясним, где именно в кодовой базе следует вызывать переопределение номера:
Номенклатура перехватываем штатное назначение кода. Устанавливаем СтандартнаяОбработка = Ложь только для целевых условий (например, если родитель элемента входит в группу весового товара), после чего заполняем реквизит Код полученным значением.БлокировкаДанных) по пространству кодов справочника.Код в качестве кассового номера (PLU) связывает бизнес-логику с технической нумерацией 1С. Архитектурно более надежным решением является выделение отдельного числового реквизита или регистра сведений для хранения кодов торгового оборудования.