При разработке конфигураций в 1С часто возникает необходимость внедрить специфическую схему нумерации документов — например, добавлять буквы, буквенные индексы участков или суффиксы (постфиксы) вида 0001/ХРК. Начинающие разработчики нередко пишут собственные алгоритмы поиска последнего номера через запрос и выборку в таблице значений. Разберем, какие критические ошибки скрывает такой подход и как правильно решить задачу средствами платформы 1С.
Проанализируем базовый код кастомного нумератора, где выборка документов обрабатывается вручную, из номера вырезаются буквы и лидирующие нули, после чего к максимальному числу прибавляется единице и добавляется буквенный суффикс:
БлокировкаДанных.Строка() для формирования номера. При преобразовании числа в строку вызовом Строка(Число) платформа 1С автоматически добавляет неразрывные пробелы как разделители триад разрядов, когда число превышает 999 (например, получаем строку "1 000/ХРК" с пробелом внутри). В номерах документов это недопустимо. Для отключения группировки разрядов необходимо использовать функцию Формат(Число, "ЧГ=0").Если Участок = Перечисления.УчасткиРК.Хорошево Тогда... привязывают логику к конкретным значениям метаданных. При добавлении нового участка придется изменять исходный код модуля. Все суффиксы, префиксы и настройки нумерации должны храниться в реквизитах справочников или в регистрах сведений.Самое надежное решение — не переписывать логику нумерации с нуля, а перенести буквенные обозначения в начало номера (сделать их префиксами). В этом случае платформа 1С возьмет на себя контроль уникальности, работу с параллельными сеансами и сброс нумерации при смене периода.
Для переопределения префикса используется стандартное событие модуля объекта ПриУстановкеНовогоНомера:
Процедура ПриУстановкеНовогоНомера(СтандартнаяОбработка, Префикс)
// Получаем буквенный код участка из реквизита справочника или регистра
БуквенныйКод = Источник.УчастокРК.ПрефиксНомера; // Перемещение логики в реквизит
Если ЗначениеЗаполнено(БуквенныйКод) Тогда
Префикс = БуквенныйКод + "-";
КонецЕсли;
КонецПроцедуры
В данном случае номер документа будет иметь вид ХРК-000000001. Такой номер легко сортируется в списках, не вызывает сбоев платформы и гарантирует корректную работу при одновременной записи нескольких документов.
Если структура с суффиксом строго регламентирована и менять её на префикс запрещено бизнес-требованиями, необходимо как минимум вынести маппинг обозначений из кода процедуры. Для этого создается функция в модуле менеджера или используется реквизит справочника:
Функция ПолучитьСуффиксУчастка(ЗначениеУчастка) Экспорт
Если ЗначениеУчастка = Перечисления.УчасткиРК.Хорошево Тогда
Возврат "/ХРК";
ИначеЕсли ЗначениеУчастка = Перечисления.УчасткиРК.Мытищи Тогда
Возврат "/МРК";
ИначеЕсли ЗначениеУчастка = Перечисления.УчасткиРК.Ярославль Тогда
Возврат "/ЯРК";
ИначеЕсли ЗначениеУчастка = Перечисления.УчасткиРК.Коломна Тогда
Возврат "/КРК";
КонецЕсли;
Возврат "";
КонецФункции
Тогда сборка номера выполняется без громоздких условий ИначеЕсли:
Суффикс = Перечисления.УчасткиРК.ПолучитьСуффиксУчастка(Источник.УчастокРК);
Источник.Номер = Формат(СледующийНомер, "ЧГ=0") + Суффикс;
Чтобы сохранить стандартную надежную нумерацию платформы и одновременно показывать пользователям номер с любыми суффиксами и спецсимволами, применяется подход с пользовательским представлением.
Номер оставляют стандартным (например, чисто числовым или с префиксом 000000001).ПредставлениеНомера или переопределяется обработчик ОбработкаПолученияПредставления в модуле менеджера документа.Рассмотрим пример переопределения представления документа в модуле менеджера:
Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Формируем пользовательское представление номера с суффиксом
ЧисловойНомер = СокрЛП(СлужебныеФункции.УбратьЛидирующиеНули(Данные.Номер));
Суффикс = Перечисления.УчасткиРК.ПолучитьСуффиксУчастка(Данные.УчастокРК);
Представление = СтрШаблон("%1 № %2%3 от %4",
Метаданные().Синоним,
ЧисловойНомер,
Суффикс,
Формат(Данные.Дата, "ДФ=dd.MM.yyyy"));
КонецПроцедуры
При таком подходе платформа физически хранит строгий уникальный номер, обеспечивающий высокую скорость поиска и отсутствие блокировок, а во всех журналах, печатных формах и отчетах пользователь видит привычный номер вида 15/ХРК.
Если требуется физически записывать нестандартный номер в поле Номер и нумеровать документы строго по порядку в разрезе участков, корректной архитектурой будет использование вспомогательного регистра сведений (например, СчетчикиНомеровДокументов).
Схема работы включает следующие шаги:
УчастокРК (и при необходимости ПериодГод) и ресурсом ТекущийНомер (Тип: Число).
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СчетчикиНомеровДокументов");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("УчастокРК", Источник.УчастокРК);
Блокировка.Заблокировать();
// Читаем текущий номер из регистра, увеличиваем на 1, записываем обратно
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Счетчики.ТекущийНомер КАК ТекущийНомер
|ИЗ
| РегистрСведений.СчетчикиНомеровДокументов КАК Счетчики
|ГДЕ
| Счетчики.УчастокРК = &УчастокРК";
Запрос.УстановитьПараметр("УчастокРК", Источник.УчастокРК);
Выборка = Запрос.Выполнить().Выбрать();
НовыйНомерЧисло = 1;
Если Выборка.Следующий() Тогда
НовыйНомерЧисло = Выборка.ТекущийНомер + 1;
КонецЕсли;
// Фиксируем новый номер в регистре
МенеджерЗаписи = РегистрыСведений.СчетчикиНомеровДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.УчастокРК = Источник.УчастокРК;
МенеджерЗаписи.ТекущийНомер = НовыйНомерЧисло;
МенеджерЗаписи.Записать();
// Присваиваем номер документу с отключением триад разрядов
Суффикс = Перечисления.УчасткиРК.ПолучитьСуффиксУчастка(Источник.УчастокРК);
Источник.Номер = Формат(НовыйНомерЧисло, "ЧГ=0") + Суффикс;
Использование управляемой блокировки РежимБлокировкиДанных.Исключительный гарантирует, что параллельные транзакции дождутся завершения установки номера и не получат одинаковые значения.