Где и как срабатывает код 1С: события объектов, форм, подписки и обмены
Содержание
Обработчик в 1С — это процедура на встроенном языке, которую платформа вызывает сама, когда наступает событие: запись документа, открытие формы, изменение поля, приход данных из другой базы. Разработчик не вызывает такую процедуру напрямую. Он только пишет её в нужном модуле с нужным именем, а 1С:Предприятие 8.3 запускает код в нужный момент.
Виды обработчиков различаются по тому, где лежит код и что его запускает. Событие объекта (ПередЗаписью, ОбработкаПроведения) живёт в модуле объекта. Событие формы (ПриСозданииНаСервере, ПриИзменении) — в модуле формы. Подписка на событие позволяет повесить один обработчик на десятки объектов сразу.
Что такое обработчик в 1С и чем он отличается от обработки
Новички путают два слова. Обработка — это объект конфигурации: отдельная форма с кнопками, например «Групповое перепроведение документов
» или внешняя .epf. Обработчик — это процедура, привязанная к событию. Внутри обработки, кстати, тоже есть обработчики: нажатие кнопки на её форме — это событие, и код под ним — обработчик команды.
Главное свойство обработчика — его вызывает платформа. Отсюда три следствия:
- 📌 Имя и параметры фиксированы. Процедура
ПередЗаписью(Отказ)в модуле справочника сработает. ПроцедураДоЗаписи(Отказ)— нет, платформа её не знает. - 📌 Контекст фиксирован. Обработчик
ПриОткрытииформы выполняется на клиенте,ПриСозданииНаСервере— на сервере. Перепутать директиву компиляции нельзя. - 📌 Можно отменить действие. У многих событий есть параметр
Отказ. УстановилиОтказ = Истина— запись, проведение или закрытие формы не состоится.
Если код «не срабатывает», первым делом сверьте имя процедуры и её место. Обработчик формы в модуле объекта просто не будет вызван, и никакой ошибки вы не увидите.
Виды обработчиков в 1С: от модуля объекта до регламентных заданий
В 1С 8.3 набор механизмов событий довольно широкий. Удобно разложить их по месту, где пишется код.
| Вид обработчика | Где пишется код | Что запускает | Пример |
|---|---|---|---|
| Событие объекта | Модуль объекта, модуль набора записей | Запись, удаление, проведение, заполнение | ПередЗаписью, ОбработкаПроведения, ОбработкаЗаполнения |
| Событие формы | Модуль формы | Открытие, закрытие, запись формы | ПриСозданииНаСервере, ПриОткрытии, ПередЗакрытием |
| Событие элемента формы | Модуль формы | Действие пользователя с полем, таблицей | ПриИзменении, НачалоВыбора, Выбор |
| Обработчик команды | Модуль формы или модуль команды | Нажатие кнопки | Процедура с параметром Команда |
| Подписка на событие | Общий модуль (серверный) | Событие у группы объектов | Проверка ИНН у всех справочников с полем ИНН |
| Обработчик ожидания | Модуль формы (клиент) | Таймер | Автообновление списка раз в 60 секунд |
| Обработчик оповещения | Модуль формы (клиент) | Ответ пользователя, закрытие окна | Продолжение кода после ПоказатьВопрос |
| Регламентное задание | Общий модуль (серверный) | Расписание | Ночная загрузка курсов валют |
| Обработчик обмена | Правила обмена, модуль менеджера обмена | Выгрузка и загрузка данных | ПередВыгрузкойОбъекта, ПриЗагрузкеОбъекта |
| Обработчик HTTP-сервиса | Модуль HTTP-сервиса | Входящий HTTP-запрос | Функция, возвращающая HTTPСервисОтвет |
Ещё один слой — обработчики модуля приложения и модуля сеанса: ПередНачаломРаботыСистемы, ПриНачалеРаботыСистемы, УстановкаПараметровСеанса. Они срабатывают при входе пользователя в базу.
Порядок событий при записи документа
Порядок важно знать, чтобы положить проверку в правильное место. При проведении документа из формы цепочка выглядит так:
ПередЗаписьюв модуле формы — на клиенте.ПередЗаписьюНаСерверев модуле формы.ОбработкаПроверкиЗаполненияв модуле объекта — при проведении проверка заполнения вызывается автоматически.ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)в модуле объекта — данные ещё можно менять.ПриЗаписи(Отказ)— объект уже записан в базу внутри транзакции.ОбработкаПроведения(Отказ, РежимПроведения)— формирование движений.ПослеЗаписиНаСервереиПослеЗаписив модуле формы.
Всё с 3 по 6 шаг идёт в одной транзакции. Отказ = Истина на любом из них откатывает запись целиком.
Как создать обработчик в 1С: пошагово в Конфигураторе
Обработчик создают в Конфигураторе или в 1С:EDT. Порядок для Конфигуратора такой.
Обработчик события объекта
- Откройте дерево конфигурации и найдите объект, например документ «Реализация товаров и услуг».
- В контекстном меню объекта откройте модуль объекта.
- Напишите процедуру с точным именем события и тем же набором параметров, что указан в синтакс-помощнике для этого объекта. Лишний или пропущенный параметр — ошибка при вызове.
- Добавьте код и сохраните конфигурацию:
F7— обновить конфигурацию базы данных.
Процедура ПередЗаписью(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если Не ЗначениеЗаполнено(ИНН) Тогда
ОбщегоНазначения.СообщитьПользователю("Не заполнен ИНН", ЭтотОбъект, "ИНН", , Отказ);
КонецЕсли;
КонецПроцедуры
ОбщегоНазначения.СообщитьПользователю — процедура Библиотеки стандартных подсистем. В конфигурации без БСП используйте объект СообщениеПользователю и явно ставьте Отказ = Истина.
Обработчик события формы или элемента
- Откройте форму в редакторе.
- Выделите форму (корневой элемент) или нужное поле.
- В палитре свойств найдите группу «События».
- Нажмите кнопку с лупой справа от события, например «ПриИзменении».
- Платформа спросит, где создать обработчик: на клиенте, на клиенте с серверной процедурой без контекста и т. д. Выберите вариант — заготовка появится в модуле формы, а её имя пропишется в свойстве события.
Имя обработчика формы, в отличие от модуля объекта, можно поменять. Связь держится не на имени, а на значении в палитре свойств. Поэтому, переименовав процедуру, не забудьте поправить и свойство.
Подписка на событие
- В дереве конфигурации раскройте ветку «Общие» → «Подписки на события» и добавьте новую подписку.
- В свойстве «Источник» отметьте типы объектов: например, все справочники или только «Контрагенты» и «Организации».
- В свойстве «Событие» выберите событие:
ПередЗаписью,ПриЗаписи,ОбработкаПроверкиЗаполненияи др. - В свойстве «Обработчик» укажите экспортную процедуру серверного общего модуля.
// Общий модуль ПодпискиПроверкиСервер (Сервер = Истина)
Процедура ПроверитьКомментарийПередЗаписью(Источник, Отказ) Экспорт
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если СтрДлина(Источник.Комментарий) > 500 Тогда
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Первый параметр подписки всегда Источник — сам объект. Дальше идут параметры события в том же порядке, что и в модуле объекта.
Доработка типовой: обработчики в расширении
В типовой конфигурации на поддержке модуль лучше не трогать. Обработчик добавляют через расширение конфигурации (доступно с платформы 8.3.6). Заимствуете объект, в модуле расширения пишете процедуру с аннотацией:
&Перед("ПередЗаписью")— ваш код выполнится до типового;&После("ПередЗаписью")— после типового;&Вместо("ПередЗаписью")— заменяет типовой; вызвать исходный можно черезПродолжитьВызов().
Такой обработчик переживает обновление типовой, если не изменилась сигнатура исходной процедуры.
Обработчики событий формы: клиент, сервер и асинхронность
Форма работает в двух контекстах, и обработчики разделены между ними. Грубая схема:
- 🖥 Сервер:
ПриСозданииНаСервере,ПриЧтенииНаСервере,ПередЗаписьюНаСервере,ПослеЗаписиНаСервере,ОбработкаПроверкиЗаполненияНаСервере. - 💻 Клиент:
ПриОткрытии,ПередЗакрытием,ОбработкаОповещения,ОбработкаВыбора, события элементов (ПриИзменении,НачалоВыбора).
ПриСозданииНаСервере срабатывает один раз, до показа формы. Здесь ставят видимость элементов, заполняют реквизиты формы по параметрам открытия. ПриОткрытии — уже на клиенте, когда форма появилась.
Как вызывать сервер из события элемента
Пример: пользователь выбрал номенклатуру, нужно подставить цену.
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
ТекущиеДанные.Цена = ЦенаНоменклатуры(ТекущиеДанные.Номенклатура, Объект.Дата);
ТекущиеДанные.Сумма = ТекущиеДанные.Цена * ТекущиеДанные.Количество;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ЦенаНоменклатуры(Номенклатура, Дата)
// запрос к регистру цен
Возврат 0;
КонецФункции
Директива &НаСервереБезКонтекста не передаёт на сервер всю форму. На табличной части в 300 строк разница в скорости заметна каждому пользователю.
Вопрос пользователю: обработчик оповещения
Модальные окна (Вопрос(), Предупреждение()) в веб-клиенте и при отключённом режиме модальности не работают. Вместо них используют немодальный вызов и обработчик оповещения — процедуру, которую платформа вызовет, когда пользователь ответит.
&НаКлиенте
Процедура Очистить(Команда)
Оповещение = Новый ОписаниеОповещения("ОчиститьПослеВопроса", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Очистить табличную часть?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ОчиститьПослеВопроса(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
Объект.Товары.Очистить();
КонецЕсли;
КонецПроцедуры
Процедура-обработчик оповещения обязана быть экспортной. В новых версиях платформы тот же сценарий можно написать через Асинх и Ждать — код читается линейно, но под капотом это всё тот же отложенный вызов.
Обработчик ожидания
Таймер на форме включают методом ПодключитьОбработчикОжидания:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ПодключитьОбработчикОжидания("ОбновитьСписокЗаказов", 60);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьСписокЗаказов()
Элементы.Список.Обновить();
КонецПроцедуры
Третий параметр Истина делает вызов однократным. Остановить повторяющийся таймер — ОтключитьОбработчикОжидания("ОбновитьСписокЗаказов").
Обработчики при обмене данными и интеграции
Когда данные приходят из другой базы, срабатывают те же события объекта, что и при ручной записи. Разница — во флаге ОбменДанными.Загрузка. Если он установлен в Истина, платформа пропускает проверки, а разработчик в своих обработчиках должен сделать то же самое: выйти из ПередЗаписью и ПриЗаписи без бизнес-логики. Объект при загрузке пишется «как есть».
Плюс у механизмов обмена есть свои обработчики:
- 🔄 Правила «Конвертации данных» 2.0 (формат XML
-правил). Обработчики на уровне всего обмена —
ПередВыгрузкойДанных,ПослеЗагрузкиДанных, и на уровне правила объекта —ПередВыгрузкой,ПриВыгрузке,ПослеВыгрузки,ПередЗагрузкой,ПриЗагрузке,ПослеЗагрузки. Код пишется прямо в правилах и выполняется обработкой «Универсальный обмен данными в формате XML» или механизмом обмена типовой. - 🔄 Обмен через формат EnterpriseData (типовые БП, УТ, ЗУП). Код обработчиков лежит в модуле менеджера обмена: события вроде
ПриОтправкеДанныхиПриКонвертацииДанныхXDTOпреобразуют объект в формат и обратно. - 🔄 Планы обмена. Объекты регистрируются к выгрузке автоматически по составу плана обмена. В
ПередЗаписьюобъекта можно поправитьОбменДанными.Получатели, чтобы не отправлять конкретный объект конкретному узлу.
HTTP-сервис как обработчик
Для интеграции с сайтом или внешней системой в конфигурации создают HTTP-сервис. На каждый метод шаблона URL (GET, POST) назначается функция-обработчик:
Функция ОстаткиGET(Запрос)
Артикул = Запрос.ПараметрыURL["article"];
Ответ = Новый HTTPСервисОтвет(200);
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Ответ.УстановитьТелоИзСтроки("{""article"": """ + Артикул + """, ""qty"": 0}");
Возврат Ответ;
КонецФункции
Сервис начинает отвечать после публикации базы на веб-сервере. В рабочем коде JSON собирают через ЗаписьJSON, а не склеиванием строк — так не сломаются кавычки в артикуле.
Типичные ошибки в обработчиках и как их не допустить
Эти ошибки встречаются в реальных доработках и не всегда видны сразу.
- ❌ Нет проверки
ОбменДанными.Загрузка. Обмен начинает падать на ваших проверках или, хуже, пересчитывает данные, пришедшие из центральной базы. Первая строкаПередЗаписью,ПриЗаписии подписок — выход при загрузке. - ❌ Изменение реквизитов в
ПриЗаписи. Объект уже записан. ПрисваиваниеЭтотОбъект.Комментарий = ...в этом обработчике в базу не попадёт. Менять данные нужно вПередЗаписью. - ❌
Записать()внутри своего же события. Вызов записи объекта из егоПриЗаписидаёт рекурсию. Если нужно что-то передать между событиями, используйтеДополнительныеСвойства:ДополнительныеСвойства.Вставить("ПропуститьПроверку", Истина). - ❌ Вызов сервера на каждое нажатие клавиши. Серверный вызов в
ИзменениеТекстаРедактированияпо полю поиска тормозит форму. Добавьте обработчик ожидания с задержкой в полсекунды и однократным вызовом. - ❌ Подписка на процедуру без
Экспортили в клиентском общем модуле. Подписка не сработает. - ❌ Таймер, который не отключили. Обработчик ожидания с интервалом 1 секунда и серверным вызовом внутри при 50 открытых формах — это 50 обращений к серверу в секунду.
- ❌ Тяжёлые запросы в
ПриЗаписииОбработкаПроведения. Транзакция держит блокировки, пока обработчик не закончит. Длинный обработчик проведения у одного пользователя превращается в ожидание на блокировке у остальных.
Отлаживайте обработчики на копии базы. Ошибка в обработчике проведения или в подписке на ПередЗаписью может остановить запись документов у всех пользователей сразу.
Для отладки поставьте точку останова (F9) на первой строке обработчика и запустите базу в режиме отладки (F5) из Конфигуратора. Если точка не срабатывает — значит, событие не вызывается вообще, и проблема в привязке, а не в коде.
Примеры обработчиков из практики
Несколько задач, которые закрываются одним обработчиком.
Запрет редактирования закрытого периода
// Модуль документа
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если Дата < '20260101' Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Период закрыт. Изменения запрещены.";
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
В типовых БСП-конфигурациях для этого есть готовая подсистема «Даты запрета изменения». Свой обработчик нужен, только если правило нестандартное.
Заполнение нового документа по основанию
Событие ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка) в модуле объекта срабатывает при вводе на основании и при создании через Заполнить(). Проверяете тип ДанныеЗаполнения и копируете нужные реквизиты: контрагента, договор, табличную часть.
Обязательное поле только при условии
Событие ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты) позволяет управлять списком обязательных реквизитов. Например, «Договор» обязателен, только если вид операции — продажа комиссионеру:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если ВидОперации <> Перечисления.ВидыОперацийРеализация.ПередачаНаКомиссию Тогда
Индекс = ПроверяемыеРеквизиты.Найти("Договор");
Если Индекс <> Неопределено Тогда
ПроверяемыеРеквизиты.Удалить(Индекс);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Имена перечисления и значений в примере условные — в вашей конфигурации они свои.
Частые вопросы об обработчиках в 1С
Можно ли повесить два обработчика на одно событие объекта?
Чем `ОбработкаПроверкиЗаполнения` лучше проверок в `ПередЗаписью`?
ПроверитьЗаполнение(), работает с флагом «Проверка заполнения» у реквизитов и умеет подсвечивать поле в форме. Простую запись черновика она не блокирует, а ПередЗаписью — блокирует.Срабатывают ли обработчики объекта при записи через запрос или регистр напрямую?
Записать(), Удалить() и при записи из формы. У наборов записей регистров свои события — в модуле набора записей.Как временно отключить обработчик, не удаляя код?
ДополнительныеСвойства, который проверяется в начале процедуры. Закомментировать код в рабочей базе можно, но это потребует обновления конфигурации.Почему обработчик ожидания срабатывает, хотя форма закрыта?
ОтключитьОбработчикОжидания.