Подписка на событие 1С — объект конфигурации из ветки «Общие», который вызывает экспортную процедуру общего модуля при записи, проведении, заполнении или удалении объектов. Одна подписка обслуживает десяток документов, а её код живёт отдельно от модуля объекта. На подписках держится БСП, и через них же удобно дорабатывать типовые из расширения.
Ниже — как устроены подписки на события в 1С 8.3; имена типовых объектов сверены по УТ 11.4 и КА 2.5.
Подписка нужна, когда одну логику надо повесить на многие объекты или встроить в типовую, не трогая модули: заполнить реквизит, запретить проведение, поставить изменения в очередь выгрузки. В УТ 11.4 подписок больше 260: около 120 на ПередЗаписью, 75 на ПриЗаписи и всего две на ОбработкаПроведения. В КА 2.5 их больше 500, а на документ «Реализация товаров и услуг» в УТ 11.4 срабатывает больше 50 подписок.
Список — в ветке конфигуратора «Общие» → «Подписки на события». «Поиск ссылок на объект» по документу находит не всё: подписки БСП часто ссылаются на определяемый тип (ВерсионируемыеДанныеОбъект) или сразу на все документы. Надёжнее спросить у метаданных из внешней обработки:
// Модуль формы внешней обработки, команда ПоказатьПодписки.
// Выводит подписки на события, в источнике которых есть указанный тип.
&НаКлиенте
Процедура ПоказатьПодписки(Команда)
ВывестиПодпискиНаСервере("ДокументОбъект.РеализацияТоваровУслуг");
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ВывестиПодпискиНаСервере(ИмяТипа)
ТипИсточника = Тип(ИмяТипа);
Найдено = 0;
Для Каждого Подписка Из Метаданные.ПодпискиНаСобытия Цикл
Если Не Подписка.Источник.СодержитТип(ТипИсточника) Тогда
Продолжить;
КонецЕсли;
Найдено = Найдено + 1;
// Собственные подписки расширений, применённых в сеансе, тоже здесь.
Расширение = Подписка.РасширениеКонфигурации();
Принадлежность = ?(Расширение = Неопределено, "конфигурация", "расширение " + Расширение.Имя);
// Много типов в источнике — подписка на все документы или определяемый тип:
// с неё начинают, если запись документа тормозит.
Сообщить(СтрШаблон("%1 (%2): типов в источнике %3, %4",
Подписка.Имя, Подписка.Синоним, Подписка.Источник.Типы().Количество(), Принадлежность));
КонецЦикла;
Сообщить(СтрШаблон("Всего подписок на %1: %2", ИмяТипа, Найдено));
КонецПроцедуры
Обход — на сервере: в тонком клиенте свойства подписки недоступны. Событие и обработчик смотрите в конфигураторе — для свойств Событие и Обработчик справка прямо говорит, что работа с их значениями во встроенном языке не предусмотрена.
ДокументОбъект.<Имя>, СправочникОбъект.<Имя>, наборы записей регистров, константы, для ОбработкаПолученияФормы — менеджеры объектов. Можно указать определяемый тип (с 8.3.5) или все документы сразу.ПроверитьДоступПередЗаписью, ПроверитьДоступПередЗаписьюДокумента, ПроверитьДоступПередЗаписьюНабораЗаписей.Подписки на события при записи — ПередЗаписью и ПриЗаписи — самые частые, но не единственные:
| Событие | Когда вызывается | Параметры обработчика |
|---|---|---|
ПередЗаписью | в транзакции, до записи; реквизиты ещё можно менять | документ: Источник, Отказ, РежимЗаписи, РежимПроведения; прочие объекты: Источник, Отказ |
ПриЗаписи | после записи в базу, до конца транзакции | Источник, Отказ |
ОбработкаПроведения | при проведении, в транзакции записи | Источник, Отказ, РежимПроведения |
ОбработкаУдаленияПроведения | при отмене проведения | Источник, Отказ |
ОбработкаЗаполнения | ввод на основании, Заполнить(), интерактивный ввод нового | Источник, ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка |
ПриКопировании | при копировании | Источник, ОбъектКопирования |
ПередУдалением | перед удалением из базы | Источник, Отказ |
ПередЗаписью, ПриЗаписи набора записей | запись движений и наборов регистров | Источник, Отказ, Замещение |
ОбработкаПолученияФормы менеджера | при получении стандартной формы | Источник, ВидФормы, Параметры, ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка |
Типичная подписка на событие проведения — запрет провести заказ клиента и реализацию с нулевой ценой. Проверять надо до движений, поэтому событие — ПередЗаписью в режиме проведения: ОбработкаПроведения подписки вызывается после модуля документа, и отказ в ней выбросит готовые движения. Колонки Товары.Цена и Товары.Отменено (только у заказа) есть в УТ 11.4 и КА 2.5.
// Общий модуль КонтрольЦенСобытия (суффикс «События» — как у модулей подписок в БСП,
// например ВерсионированиеОбъектовСобытия). Флаги «Сервер», «Внешнее соединение»,
// «Клиент (обычное приложение)»; «Вызов сервера» и «Глобальный» сняты.
// Подписка КонтрольЦенПередПроведением:
// Источник — ДокументОбъект.ЗаказКлиента, ДокументОбъект.РеализацияТоваровУслуг;
// Событие — ПередЗаписью;
// Обработчик — КонтрольЦенСобытия.ПроверитьЦеныПередЗаписью.
Процедура ПроверитьЦеныПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
// Сначала дешёвые проверки: загрузка обмена, режим записи, флаг от вызывающего кода.
Если Источник.ОбменДанными.Загрузка
Или РежимЗаписи <> РежимЗаписиДокумента.Проведение
Или Источник.ДополнительныеСвойства.Свойство("НеПроверятьЦены") Тогда
Возврат;
КонецЕсли;
// В заказе есть отменённые строки, у реализации колонки Отменено нет.
ЭтоЗаказ = ТипЗнч(Источник) = Тип("ДокументОбъект.ЗаказКлиента");
Для Каждого СтрокаТоваров Из Источник.Товары Цикл
Если ЭтоЗаказ И СтрокаТоваров.Отменено Тогда
Продолжить;
КонецЕсли;
Если ЗначениеЗаполнено(СтрокаТоваров.Цена) Тогда
Продолжить;
КонецЕсли;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = СтрШаблон(НСтр("ru = 'Строка %1: не указана цена для «%2».'"),
СтрокаТоваров.НомерСтроки, СтрокаТоваров.Номенклатура);
// Индекс строки в пути к полю — с нуля и без разделителя разрядов.
Сообщение.Поле = "Товары[" + Формат(СтрокаТоваров.НомерСтроки - 1, "ЧН=0; ЧГ=0") + "].Цена";
Сообщение.УстановитьДанные(Источник);
Сообщение.Сообщить();
Отказ = Истина;
КонецЦикла;
КонецПроцедуры
Источник: ЭтотОбъект и Движения в общем модуле нет.ДокОбъект.ДополнительныеСвойства.Вставить("НеПроверятьЦены", Истина) перед Записать(), например когда вы создаёте документы программно.Отменено у реализации нет, но условие с И 1С вычисляет слева направо и до неё не дойдёт.Поле и УстановитьДанные(Источник) привязывают сообщение к цене нужной строки в форме документа. На БСП то же делает ОбщегоНазначения.СообщитьПользователю(Текст, Источник, Поле, , Отказ).По справке платформы:
&Перед и &После из расширений.Отказ = Истина или вызвал исключение, действие прерывается, подписки не вызываются.Источник приходит тот же объект.Отказ или исключение в подписке тоже прерывает действие, транзакция откатывается.Отсюда три правила. Подписка видит объект после модуля: всё, что модуль изменил в ПередЗаписью, уже в Источник, а при проведении документа подписка на событие ОбработкаПроведения получает его с готовыми движениями. Отменить запись подписка может, помешать коду модуля — нет: для этого нужен перехватчик, см. расширение конфигурации. И подписки на одно событие не должны зависеть друг от друга: два связанных действия делайте одной подпиской.
С платформы 8.3.17 в расширении можно создавать свои подписки и заимствовать типовые. Для типовой на поддержке это основной путь: конфигурация не меняется и обновляется штатно, а подписке всё равно, как 1С переименует методы модуля документа. Подписка на событие в расширении создаётся так же:
Пример — очередь выгрузки реализаций во внешнюю систему. Подписка не отправляет данные сама, а пишет документ в регистр, который разбирает регламентное задание:
// Расширение «Интеграция», префикс Расш1_. Заимствован документ РеализацияТоваровУслуг.
// Собственный регистр сведений Расш1_ОчередьОтправки (независимый, непериодический):
// измерение Документ — ДокументСсылка.РеализацияТоваровУслуг;
// ресурсы Действие — Строка(20), ДатаИзменения — Дата (дата и время).
// Собственный общий модуль Расш1_ОчередьОтправкиСобытия, флаги — как в листинге 2.
// Подписки расширения с источником ДокументОбъект.РеализацияТоваровУслуг:
// Расш1_ОчередьПриПроведении — событие ОбработкаПроведения, обработчик ПриПроведении;
// Расш1_ОчередьПриОтменеПроведения — событие ОбработкаУдаленияПроведения,
// обработчик ПриОтменеПроведения.
Процедура ПриПроведении(Источник, Отказ, РежимПроведения) Экспорт
// Вызывается после ОбработкаПроведения модуля документа.
// Если проведение потом откатится, исчезнет и запись в очереди.
ПоставитьВОчередь(Источник.Ссылка, "Проведение");
КонецПроцедуры
Процедура ПриОтменеПроведения(Источник, Отказ) Экспорт
ПоставитьВОчередь(Источник.Ссылка, "ОтменаПроведения");
КонецПроцедуры
// В транзакции только записываем, что отправить. Саму отправку во внешнюю
// систему делает регламентное задание после фиксации транзакции.
Процедура ПоставитьВОчередь(Документ, Действие)
// Прав на регистр очереди у пользователя может не быть. Привилегированный
// режим работает, только если у расширения снят флаг «Безопасный режим».
УстановитьПривилегированныйРежим(Истина);
Запись = РегистрыСведений.Расш1_ОчередьОтправки.СоздатьМенеджерЗаписи();
Запись.Документ = Документ;
Запись.Действие = Действие;
Запись.ДатаИзменения = ТекущаяДатаСеанса();
// Ключ записи — документ: перепроведение перезапишет строку, дублей не будет.
Запись.Записать(Истина);
КонецПроцедуры
Почему не отправить сразу: HTTP-запрос в обработчике держал бы транзакцию открытой, пока отвечает чужой сервер, а при откате проведения отправку уже не вернуть.
Обработчик типовой подписки — экспортная процедура общего модуля: заимствуйте модуль и перехватите её. В УТ 11.4 подписка УстановитьАвтораДокумента ставит автором нового заказа клиента, реализации и других документов текущего пользователя, и автор, которого указала фоновая загрузка заказов с сайта, затирается пользователем задания:
// Расширение: заимствован общий модуль ЗаполнениеСвойствПоСтатистикеСервер (УТ 11.4).
// Его процедура — обработчик типовой подписки УстановитьАвтораДокумента (ПередЗаписью).
// В КА 2.5 то же делает ЗаполнениеОбъектовПоСтатистике.УстановитьАвтораОбъектаПередЗаписью.
&Вместо("УстановитьАвтораДокументаПередЗаписью")
Процедура Расш1_УстановитьАвтораДокументаПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения)
// Загрузка заказов с сайта в фоновом задании сама указывает автора и ставит
// этот флаг. Без него типовой код заменил бы автора пользователем задания.
Если Источник.ДополнительныеСвойства.Свойство("Расш1_СохранитьАвтора") Тогда
Возврат;
КонецЕсли;
// Во всех остальных случаях — типовое поведение.
ПродолжитьВызов(Источник, Отказ, РежимЗаписи, РежимПроведения);
КонецПроцедуры
ПродолжитьВызов типовая логика выключится для всех документов источника.Подписка на события формы невозможна: подписки обрабатывают только неинтерактивные события прикладных объектов. ПриСозданииНаСервере, ПередЗаписьюНаСервере и команды формы дорабатывают расширением формы. Подписка умеет другое: событие менеджера ОбработкаПолученияФормы подменяет открываемую форму целиком. В УТ 11.4 так работают девять подписок, например ПереопределитьПолучаемуюФормуПрисоединенногоФайла.
// Общий модуль расширения, флаги — как в листинге 2.
// Подписка Расш1_ФормаЗаказаДляСклада: источник ДокументМенеджер.ЗаказКлиента,
// событие ОбработкаПолученияФормы. В заимствованном документе создана
// собственная форма расширения Расш1_ФормаСклад.
Процедура ФормаЗаказаДляСкладаОбработкаПолученияФормы(Источник, ВидФормы, Параметры,
ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка) Экспорт
// Кладовщику вместо типовой формы заказа открываем упрощённую.
// Форма списка и форма выбора остаются типовыми.
Если ВидФормы = "ФормаОбъекта" И РольДоступна("Расш1_Кладовщик") Тогда
ВыбраннаяФорма = "Расш1_ФормаСклад";
СтандартнаяОбработка = Ложь;
КонецЕсли;
КонецПроцедуры
И наоборот: проверку, которая должна работать при любой записи, не кладите в ПередЗаписьюНаСервере формы — обработка или обмен её обойдут, а подписку нет.
Подписка — часть каждой записи и работает в её транзакции, поэтому лишний запрос в обработчике умножается на перепроведение за месяц и загрузку обмена.
ОбменДанными.Загрузка, режим записи, тип, флаг в ДополнительныеСвойства. Типовая подписка на все документы ОтветственныеЛицаДокументаПриКопировании выходит по проверке, закэшированной в ОтветственныеЛицаПовтИсп.Источник.Контрагент.ИНН заставляет платформу прочитать объект контрагента, а не одно поле. Одно-два поля берите запросом или ОбщегоНазначения.ЗначенияРеквизитовОбъекта.ОбменДанными.Загрузка = Истина ставят обмен, загрузка из XML, групповые обработки и обработчики обновления БСП: у ОбновлениеИнформационнойБазы.ЗаписатьОбъект по умолчанию ВключитьБизнесЛогику = Ложь. Платформа делает минимум проверок, но обработчики модуля и подписок вызывает, поэтому флаг проверяет сам обработчик, первой строкой, — как ДатыЗапретаИзменения.ПроверитьДатуЗапретаИзмененияПередЗаписьюДокумента в УТ 11.4. Это не догма: ВерсионированиеОбъектовСобытия.ЗаписатьВерсиюОбъекта флаг сознательно не проверяет, чтобы хранить версии и при обмене. Проверки и автозаполнение при загрузке пропускайте, а регистрацию для своих выгрузок обычно оставляйте — см. план обмена.
Экспорт, её переименовали или модуль не компилируется там, где идёт запись: снят флаг «Сервер», а для обычного приложения — «Клиент (обычное приложение)».ЭтотОбъект на Источник, а Движения — на Источник.Движения.ОбменДанными.Загрузка или расширение не применено. ОбработкаПроверкиЗаполнения вызывают интерактивная запись и ПроверитьЗаполнение(), а не Записать().ПриЗаписи не сохранились. Объект к этому моменту уже в базе. Реквизиты меняют в ПередЗаписью, а Источник.Записать() внутри обработчика снова вызовет ту же подписку.Логика одного своего объекта — в модуле объекта, там её и ищут. Одна логика на много объектов — подписка, а для типовой на поддержке — подписка в расширении. Прямо в типовой подписку создать можно, но придётся включить возможность изменения конфигурации, и обновления пойдут через объединение.
Из кода — никак. Обработчик проверяет флаг в ДополнительныеСвойства, а вызывающий код ставит его перед Записать(), как в листингах 2 и 4. ОбменДанными.Загрузка тоже выключит подписки, которые его проверяют, но вместе со всей логикой типовой.
Да. Источник — РегистрНакопленияНаборЗаписей.<Имя> или РегистрСведенийНаборЗаписей.<Имя>, события ПередЗаписью и ПриЗаписи с параметром Замещение, отбор набора — в Источник.Отбор. Для констант источник — КонстантаМенеджерЗначения.<Имя>; в УТ 11.4 подписка ПриЗаписиКонстанты срабатывает на запись любой константы.
Если доработку нужно встроить в проведение десятков типовых документов, перенести правки из снятой с поддержки конфигурации в расширение или найти, какая из полусотни подписок тормозит запись, быстрее поручить это программисту: доработка 1С. Опишите задачу на странице «Разместить задание» — оценка бесплатная, ответ в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.