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