При разработке в среде «1С:Предприятие» часто возникает задача: передать специфический признак или команду из интерактивной формы в модуль объекта в процессе записи. Например, нужно указать системе, что данная запись инициирована из специализированного рабочего места и часть стандартных проверок нужно пропустить.
Бывает и обратная задача: при записи на сервере выполнился сложный расчет, результаты которого нужно показать пользователю на клиенте, но только в случае успешного завершения транзакции.
Попытка использовать для этого обычные переменные - не лучшая идея: модуль формы и модуль объекта выполняются в разных контекстах, а клиент и сервер в общем случае - разные машины. Для решения этих задач в платформе предусмотрены два механизма: ПараметрыЗаписи (на стороне формы) и ДополнительныеСвойства (на стороне объекта).
Что такое "ПараметрыЗаписи"?
ПараметрыЗаписи — это структура, которая существует только в контексте формы. Она предназначена для хранения параметров, управляющих процессом записи на стороне интерфейса.
Эта структура последовательно передается платформой сквозь все события формы:
- ПередЗаписью (на клиенте);
- ПередЗаписьюНаСервере (на сервере);
- ПриЗаписиНаСервере (на сервере);
- ПослеЗаписиНаСервере (на сервере);
- ПослеЗаписи (на клиенте).
Поскольку ПараметрыЗаписи живут только в форме, модуль объекта напрямую не имеет к ним доступа. Чтобы передать эти данные в транзакцию записи, их переносят в сам объект.
Что такое "ДополнительныеСвойства"?
ДополнительныеСвойства — это свойство прикладного объекта (например, ДокументОбъект или СправочникОбъект), представляющее собой структуру. Оно создано специально для того, чтобы разработчик мог прикрепить к объекту любые произвольные данные в оперативной памяти.
Эта коллекция доступна везде, где доступен сам прикладной объект:
- В событиях модуля объекта (ПередЗаписью, ПриЗаписи, ПриКопировании и др.);
- В процедурах-обработчиках подписок на события.
Данные в Дополнительных свойствах хранятся в памяти до тех пор, пока существует сам экземпляр объекта в этой серверной сессии. Они не записываются в базу данных и уничтожаются после того, как объект прекращает свое существование в памяти.
Учебный пример: расчет бонусов при покупке (двусторонний цикл)
Бизнес-задача: Кассир пробивает документ «Реализация товаров».
Прямой поток: При проведении кассир может вручную выбрать опцию «Повышенный кэшбэк» (флаг на форме). Этот флаг нужно передать в модуль объекта, чтобы система начислила больше баллов.
Обратный поток: Расчет бонусных баллов происходит строго на сервере внутри транзакции проведения (чтобы избежать мошенничества и коллизий). Нам нужно вернуть количество реально начисленных бонусов на клиент и показать кассиру красивое всплывающее окно «Начислено 150 бонусов».
Важно: Окно должно показаться только в том случае, если документ действительно записался и провелся (транзакция зафиксирована).
Шаг 1. Прямой поток: Передаем флаг с клиента на сервер формы
В модуле формы перехватываем событие ПередЗаписью и добавляем наш флаг в структуру ПараметрыЗаписи
&НаКлиенте Процедура ПередЗаписью(Отказ, ПараметрыЗаписи) // ЭтотОбъект.ПовышенныйКэшбэк — реквизит формы (флажок на интерфейсе) Если ЭтотОбъект.ПовышенныйКэшбэк Тогда ПараметрыЗаписи.Вставить("ПрименитьПовышенныйКэшбэк", Истина); КонецЕсли; КонецПроцедуры
Шаг 2. Переносим флаг в свойства прикладного объекта
В событии формы ПередЗаписьюНаСервере переносим значение из параметров записи в свойства самого объекта
&НаСервере Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) ПрименитьПовышенныйКэшбэк = Ложь; Если ПараметрыЗаписи.Свойство("ПрименитьПовышенныйКэшбэк", ПрименитьПовышенныйКэшбэк) Тогда // Кладем во временные свойства объекта внутри транзакции ТекущийОбъект.ДополнительныеСвойства.Вставить("ПрименитьПовышенныйКэшбэк", ПрименитьПовышенныйКэшбэк); КонецЕсли; КонецПроцедуры
Шаг 3. Обрабатываем данные на сервере и готовим обратный поток
В модуле объекта (в событии ПриЗаписи) считываем флаг, выполняем расчет и записываем результат обратно в ДополнительныеСвойства.
Процедура ПриЗаписи(Отказ) // 1. Считываем входящий параметр ПовышенныйТариф = Ложь; ДополнительныеСвойства.Свойство("ПрименитьПовышенныйКэшбэк", ПовышенныйТариф); // 2. Рассчитываем бонусы (условный алгоритм) Коэффициент = ?(ПовышенныйТариф, 2, 1); НачисленныеБонусы = РассчитатьБонусыПоДокументу(ЭтотОбъект) * Коэффициент; // ... логика записи бонусов в регистры базы данных ... // 3. Записываем результат расчета, чтобы вернуть его на форму ДополнительныеСвойства.Вставить("РезультатРасчетаБонусов", НачисленныеБонусы); КонецПроцедуры
Шаг 4. Обратный поток: Забираем результат расчета после фиксации транзакции
Событие формы ПослеЗаписиНаСервере срабатывает, когда транзакция в базе данных уже успешно завершена (запись зафиксирована). Здесь мы забираем результат расчета из объекта и помещаем его обратно в ПараметрыЗаписи
&НаСервере Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи) КоличествоБонусов = 0; // Читаем из записанного объекта информацию о бонусах Если ТекущийОбъект.ДополнительныеСвойства.Свойство("РезультатРасчетаБонусов", КоличествоБонусов) Тогда // Помещаем в параметры записи, которые отправятся на клиент ПараметрыЗаписи.Вставить("НачисленоБонусовДляКлиента", КоличествоБонусов); КонецЕсли; КонецПроцедуры
Шаг 5. Показываем результат пользователю на клиенте
Событие ПослеЗаписи срабатывает на клиенте в самом конце цепочки. Поскольку мы передали данные в ПараметрыЗаписи, они доступны здесь без совершения дополнительных серверных вызовов
&НаКлиенте Процедура ПослеЗаписи(ПараметрыЗаписи) НачисленоБонусов = Неопределено; Если ПараметрыЗаписи.Sвойство("НачисленоБонусовДляКлиента", НачисленоБонусов) Тогда // Показываем красивое всплывающее оповещение в углу экрана ПоказатьОповещениеПользователя( "Начисление бонусов", , СтрШаблон("Покупателю успешно начислено %1 бонусов!", НачисленоБонусов), БиблиотекаКартинок.Информация ); КонецЕсли; КонецПроцедуры
Заключение и некоторые рекомендации
Итак, мы рассмотрели использование связки структур ПараметрыЗаписи и ДополнительныеСвойства для того, чтобы обменяться информацией между формой и объектом в момент записи этого объекта. Вот несколько рекомендаций, чтобы избежать проблем с этими механизмами:
Безопасное извлечение данных: Во избежание падения системы с ошибкой всегда используйте метод .Свойство() при обращении к ДополнительнымСвойствам или ПараметрамЗаписи.
Помните про программную запись: При программной записи (например, через регламентное задание или обработку) формы не существует, поэтому события формы и ПараметрыЗаписи не вызываются. Бизнес-логика в модуле объекта должна быть готова к тому, что дополнительных свойств может не оказаться, и уметь рассчитывать дефолтные значения.
Не выводите интерактивные окна до завершения транзакции: не следует выводить пользователю какие-либо сообщения, связанные с бизнес-логикой, в событиях ПередЗаписьюНаСервере или ПриЗаписи. Если транзакция откатится из-за ошибки СУБД, пользователь получит недостоверную информацию. Всегда используйте клиентское событие ПослеЗаписи.
Чувствуете, что застряли в основах 1С?
Информация в интернете кажется обрывочной, а на решение простых задач уходят часы? Вы не одиноки. Я запустил Клуб для 1С разработчиков Alexcode.PRO. Внутри - продвинутые статьи, видео, материалы для скачивания, закрытый чат для резидентов и возможность влиять на контент.
