В практике автоматизации на платформе 1С часто возникает задача разделения нумерации документов. Стандартный механизм 1С отлично справляется с префиксами организаций или узлов распределенных баз, но когда требуется вести отдельную «внутреннюю» нумерацию для конкретных контрагентов (начиная с единицы для каждого или для группы избранных), типовых средств становится недостаточно. В этой статье мы подробно разберем, как спроектировать и внедрить надежный механизм дополнительной нумерации, не нарушая работу стандартных механизмов платформы.
Рассмотрим ситуацию: для большинства клиентов используется общая нумерация (например, №0001, №0002...), а для ключевых контрагентов требуется своя последовательность (№1, №2, №3...), которая будет выводиться в печатные формы, такие как ТОРГ-12 или УПД. Основной номер документа при этом должен оставаться уникальным в рамках системы для корректной работы ссылочной целостности и учета.
Проанализируем предложенные варианты решения. Использование префиксов (стандартный механизм) в данном случае не подходит, так как количество контрагентов может быть большим, а длина номера ограничена. Оптимальным решением является создание независимого регистра сведений, в котором будет храниться текущее значение счетчика, и добавление дополнительного реквизита в документ.
Прежде всего, нам необходимо расширить структуру базы данных. Мы рекомендуем использовать расширения конфигурации, чтобы сохранить основную базу на поддержке. Выполним следующие действия:
РеализацияТоваровУслуг реквизит ДополнительныйНомер (тип: Число или Строка).ДоговорыКонтрагентов (или Контрагенты) булевский признак ИспользоватьСпецНумерацию, чтобы система понимала, для кого именно нужно запускать этот механизм.ДополнительнаяНумерация.Разберем структуру регистра подробнее:
Организация (тип: СправочникСсылка.Организации) — нумерация обычно ведется в разрезе юрлиц.Контрагент (тип: СправочникСсылка.Контрагенты) — если нумерация индивидуальна для каждого клиента.Год (тип: Число) — чтобы в начале нового года счетчик обнулялся автоматически.ПоследнийНомер (тип: Число) — хранит текущее максимальное значение.Для автоматического заполнения номера лучше всего использовать подписку на событие ПередЗаписью или ПриЗаписи. Однако, крайне важно учитывать многопользовательскую работу. Если два пользователя одновременно создадут документ, они могут получить один и тот же номер. Чтобы этого избежать, воспользуемся механизмом управляемых блокировок.
Рассмотрим пример кода для получения нового номера:
Функция ПолучитьСледующийДопНомер(ВыбраннаяОрганизация, ВыбранныйКонтрагент) Экспорт
ТекущийГод = Год(ТекущаяДата());
// Блокируем запись в регистре, чтобы другие сеансы ждали
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ДополнительнаяНумерация");
ЭлементБлокировки.УстановитьЗначение("Организация", ВыбраннаяОрганизация);
ЭлементБлокировки.УстановитьЗначение("Контрагент", ВыбранныйКонтрагент);
ЭлементБлокировки.УстановитьЗначение("Год", ТекущийГод);
Блокировка.Заблокировать();
// Пытаемся найти текущее значение
МенеджерЗаписи = РегистрыСведений.ДополнительнаяНумерация.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Организация = ВыбраннаяОрганизация;
МенеджерЗаписи.Контрагент = ВыбранныйКонтрагент;
МенеджерЗаписи.Год = ТекущийГод;
МенеджерЗаписи.Прочитать();
НовыйНомер = МенеджерЗаписи.ПоследнийНомер + 1;
// Обновляем значение в регистре
МенеджерЗаписи.ПоследнийНомер = НовыйНомер;
МенеджерЗаписи.Записать();
Возврат НовыйНомер;
КонецФункции
Выясним причину, по которой номер лучше присваивать именно в момент записи, а не при открытии формы. Если пользователь откроет форму, получит номер, но закроет её без сохранения — в последовательности возникнет «дырка». Поэтому проанализируем ситуацию и реализуем вызов в подписке на событие ПередЗаписью объекта ДокументОбъект.РеализацияТоваровУслуг.
Процедура ПередЗаписьюДокумента(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
// Проверяем, нужно ли нам вообще нумеровать этот документ
Если Источник.ДополнительныйНомер = 0
И Источник.ДоговорКонтрагента.ИспользоватьСпецНумерацию Тогда
Источник.ДополнительныйНомер = ПолучитьСледующийДопНомер(Источник.Организация, Источник.Контрагент);
КонецЕсли;
КонецПроцедуры
Важный момент: Если документ помечается на удаление, номер в регистре обычно не уменьшают, чтобы сохранить историческую точность. Но если бизнес-требования допускают «откат», это можно реализовать в этом же модуле, проверяя Источник.ПометкаУдаления.
Теперь, когда у документа есть ДополнительныйНомер, его нужно вывести в печатную форму. Чтобы не изменять типовые механизмы печати, которые затираются при обновлении, рекомендуем использовать Внешние печатные формы.
В модуле внешней печатной формы (например, ТОРГ-12) найдем код, отвечающий за вывод номера, и добавим условие: если ДополнительныйНомер заполнен, выводим его, иначе используем стандартный Номер. Посмотрим на логику:
ТекстНомера = ?(ЗначениеЗаполнено(Шапка.ДополнительныйНомер), Шапка.ДополнительныйНомер, Шапка.Номер);
Рассмотрим подробнее несколько нюансов, которые могут возникнуть при эксплуатации данного механизма:
Год. Это позволяет автоматически начинать нумерацию с "1" каждый январь. Если ваша компания требует сквозную нумерацию за всё время, просто исключите это измерение из регистра.БлокировкаДанных) критически важен. Без него в высоконагруженных базах вы неизбежно столкнетесь с дублями номеров.Таким образом, мы создали гибкую систему, которая не мешает типовому обновлению 1С, корректно работает в многопользовательской среде и решает специфическую задачу бизнеса по индивидуальной нумерации для контрагентов. Использование регистра сведений в качестве хранилища счетчика является наиболее надежным методом, так как он обеспечивает быстрый доступ к данным и легко поддается блокировке на время транзакции.