В многопользовательских базах 1С часто возникает неприятная ситуация: пользователь открывает новый документ, долго заполняет реквизиты, а при попытке записи получает сообщение «Номер не уникален». Это происходит потому, что пока один человек работал с формой, другой успел создать и записать документ с тем же номером. В итоге первому пользователю приходится либо вручную менять номер (если есть права), либо заново перебивать весь документ. Рассмотрим подробно, как профессионально решить эту проблему и настроить систему так, чтобы номера присваивались корректно.
Для начала проанализируем, почему платформа ведет себя именно так. В свойствах формы документа есть параметр Автонумерация. Если там установлено значение Использовать, платформа запрашивает новый номер у системы в момент открытия формы. Если два бухгалтера одновременно нажали кнопку «Создать», они оба могут получить в своих формах один и тот же номер, например, «00001». Тот, кто нажмет «Записать» первым, займет этот номер, а второй получит ошибку уникальности.
Самый простой и правильный способ решить проблему — сделать так, чтобы номер присваивался не при открытии документа, а непосредственно в момент его записи в базу данных. Разберем по шагам, как это сделать:
Автонумерация.Теперь при создании нового документа поле Номер будет оставаться пустым. Номер будет автоматически сгенерирован платформой только тогда, когда пользователь нажмет кнопку «Записать» или «ОК», то есть в момент начала транзакции записи. Это сводит вероятность конфликта к минимуму, так как время между получением номера и завершением записи исчисляется миллисекундами.
Выясним, как настройки самой конфигурации влияют на этот процесс. В корне дерева конфигурации (самый верхний элемент) есть свойство Режим автонумерации объектов. Рассмотрим два доступных варианта:
Важный момент: Если вы столкнулись с тем, что номера «перескакивают» через 10 или 100 значений в платформе 8.3, это работа механизма кэширования номеров. Для большинства бизнес-задач это не критично, но если бухгалтерия требует строгой последовательности, кэширование можно отключить в настройках сервера 1С.
Если нам нужно не просто присвоить номер, а добавить к нему префикс организации или подразделения, лучше всего использовать встроенное событие ПриУстановкеНовогоНомера. Проанализируем, как это реализовано в типовых конфигурациях.
Вместо того чтобы писать код в модуле формы, мы воспользуемся модулем объекта. Это гарантирует, что логика сработает и при ручном вводе, и при создании документа программно (например, через обмен данными).
Процедура ПриУстановкеНовогоНомера(СтандартнаяОбработка, Префикс)
// Добавляем префикс организации, если он задан
Префикс = СокрЛП(Организация.Префикс) + "ЦБ";
// СтандартнаяОбработка = Истина означает, что платформа сама
// сформирует остальную часть номера после префикса
КонецПроцедуры
Для «своих» документов в типовых конфигурациях (например, Бухгалтерия 2.0 или 3.0) правильнее использовать Подписки на события. Это позволит не снимать документ с поддержки и сохранить возможность легкого обновления. Создадим подписку на событие ПриУстановкеНовогоНомера и привяжем её к общему модулю.
Иногда возникают ситуации, когда специфические требования заказчика не позволяют использовать стандартный механизм (например, сложная нумерация в зависимости от валюты или склада). В этом случае можно добавить в форму кнопку «Присвоить номер», которая будет выполнять запрос к базе и находить последний свободный номер. Посмотрим на пример кода такой обработки:
&НаСервере
Процедура ПрисвоитьНомерНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Док.Номер КАК Номер
|ИЗ
| Документ.НашСвойДокумент КАК Док
|ГДЕ
| Док.Дата МЕЖДУ &НачалоГода И &КонецГода
|УПОРЯДОЧИТЬ ПО
| Док.Номер УБЫВ";
Запрос.УстановитьПараметр("НачалоГода", НачалоГода(Объект.Дата));
Запрос.УстановитьПараметр("КонецГода", КонецГода(Объект.Дата));
Результат = Запрос.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
// Логика инкремента строкового номера
НовыйЧисловойНомер = Число(Результат.Номер) + 1;
Объект.Номер = Формат(НовыйЧисловойНомер, "ЧЦ=9; ЧВН=; ЧГ=0");
Иначе
Объект.Номер = "000000001";
EndIf;
КонецПроцедуры
Внимание: Этот метод является рискованным в высоконагруженных системах, так как между выполнением запроса и записью документа другой пользователь может успеть занять этот же номер. Если вы используете ручной расчет номера, обязательно делайте это внутри транзакции с использованием блокировки данных.
Чтобы навсегда забыть об ошибке «Номер не уникален», придерживайтесь следующей стратегии:
Автонумерация в формах новых документов. Это переносит момент получения номера на время фактической записи.УстановитьНовыйНомер() в обработчике ПередЗаписью, если нужно программно управлять моментом генерации.ПриУстановкеНовогоНомера, обращаясь к общему модулю МеханизмНумерацииОбъектов (в случае типовых решений).Рассмотренные подходы позволят сделать работу пользователей комфортной, а нумерацию документов — стабильной и предсказуемой.