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