В процессе разработки в среде 1С часто возникает задача автоматизации оповещений. Одной из классических задач является мониторинг определенного Регистра сведений и оперативная отправка данных на электронную почту ответственным лицам или в службу поддержки. В этой статье мы подробно разберем, как построить надежный механизм уведомлений, начиная от архитектуры и заканчивая нюансами формирования текста письма.
Перед тем как приступить к написанию кода, проанализируем, какой механизм запуска лучше использовать. Существует два основных способа:
ПриЗаписи набора записей регистра. Это позволяет отправлять уведомление мгновенно. Однако, если записей много, это может замедлить работу пользователя, так как транзакция записи будет ждать завершения процесса отправки почты.Самая частая ошибка новичков — выборка записей просто за текущую дату. Это приводит к тому, что при каждом запуске регламентного задания одни и те же письма будут отправляться повторно. Чтобы этого избежать, рекомендуется добавить в регистр сведений (например, МП_ОчередьЧеков) специальный реквизит УведомлениеОтправлено с типом Булево.
Разберем, как должен выглядеть запрос для получения данных, которые еще не были обработаны системой уведомлений:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| МП_ОчередьЧеков.ЧекККМ.Дата КАК Дата,
| МП_ОчередьЧеков.ЧекККМ.Номер КАК Номер,
| МП_ОчередьЧеков.ЧекККМ.Магазин КАК Магазин,
| МП_ОчередьЧеков.ЧекККМ.Ответственный КАК Ответственный
|ИЗ
| РегистрСведений.МП_ОчередьЧеков КАК МП_ОчередьЧеков
|ГДЕ
| МП_ОчередьЧеков.УведомлениеОтправлено = ЛОЖЬ";
РезультатЗапроса = Запрос.Выполнить();
Проанализируем типичную проблему, с которой сталкиваются разработчики: при обходе коллекции в переменную ТелоПисьма попадает только последняя запись. Это происходит из-за перезаписи значения переменной вместо его накопления. Выясним, как правильно собрать все данные в одну строку.
Рассмотрим правильный алгоритм накопления текста в цикле Пока Выборка.Следующий():
Выборка = РезультатЗапроса.Выбрать();
ТекстПисьма = "Список чеков, требующих внимания:" + Символы.ПС;
КоличествоЗаписей = 0;
Пока Выборка.Следующий() Цикл
// Накапливаем строки, добавляя текущие данные к уже существующим
ТекстПисьма = ТекстПисьма + "Чек № " + Выборка.Номер + " от " + Формат(Выборка.Дата, "ДЛФ=DT") +
" (Магазин: " + Выборка.Магазин + ")" + Символы.ПС;
КоличествоЗаписей = КоличествоЗаписей + 1;
// Здесь же можно помечать записи как отправленные (если используется объектная техника)
// Либо собрать ссылки в массив для массового обновления после цикла
КонецЦикла;
ТекстПисьма = ТекстПисьма + Символы.ПС + "Всего записей: " + КоличествоЗаписей;
Важный совет: Если записей ожидается очень много (тысячи), использование оператора + для строк может работать медленно. В таких случаях эффективнее использовать объект ТекстовыйДокумент или массив с последующим вызовом функции СтрСоединить().
Иногда требования безопасности или политики компании запрещают использовать стандартные механизмы БСП (Библиотеки Стандартных Подсистем). В этом случае мы используем низкоуровневые объекты платформы: ИнтернетПочтовыйПрофиль и ИнтернетПочта.
Посмотрим на пример функции отправки, учитывающей современные требования почтовых серверов (SSL и авторизация):
&НаСервере
Процедура ОтправитьУведомление(АдресПолучателя, Тема, Тело)
Профиль = Новый ИнтернетПочтовыйПрофиль;
Профиль.АдресСервераSMTP = "smtp.yandex.ru"; // Укажите ваш сервер
Профиль.ПортSMTP = 465;
Профиль.ИспользоватьSSLSMTP = Истина;
Профиль.ПользовательSMTP = "robot@yourcompany.ru";
Профиль.ПарольSMTP = "vash_parol_prilozheniya"; // Используйте специальные пароли приложений!
Профиль.АутентификацияSMTP = СпособSMTPАутентификации.Login;
Сообщение = Новый ИнтернетПочтовоеСообщение;
Сообщение.Отправитель.Адрес = "robot@yourcompany.ru";
Сообщение.Отправитель.ОтображаемоеИмя = "Робот 1С:Розница";
Сообщение.Тема = Тема;
Сообщение.Получатели.Добавить(АдресПолучателя);
// Добавляем текст
Сообщение.Тексты.Добавить(Тело, ТипТекстаПочтовогоСообщения.ПростойТекст);
Почта = Новый ИнтернетПочта;
Попытка
Почта.Подключиться(Профиль);
Почта.Послать(Сообщение);
Почта.Отключиться();
Исключение
ЗаписьЖурналаРегистрации("ОтправкаПочты", УровеньЖурналаРегистрации.Ошибка, , ,
"Ошибка при отправке письма: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Часто возникает вопрос: как правильно передать результат поиска во вторую процедуру для отправки? Рассмотрим два основных способа:
ТаблицаЗначений. Вторая процедура принимает эту таблицу в качестве параметра. Это удобно, если логика разделена.МенеджерВременныхТаблиц. Это самый профессиональный и производительный метод для больших объемов данных.Разберем пример с передачей ТаблицыЗначений:
&НаСервере
Процедура ВыполнитьОбработкуОчереди()
ДанныеДляОтправки = ПолучитьНовыеЗаписиИзРегистра();
Если ДанныеДляОтправки.Количество() > 0 Тогда
ТекстСообщения = СформироватьТекстИзТаблицы(ДанныеДляОтправки);
ОтправитьУведомление("support@company.ru", "Зависшие чеки ККМ", ТекстСообщения);
ПометитьЗаписиКакОтправленные(ДанныеДляОтправки);
КонецЕсли;
КонецПроцедуры
Чтобы ваше решение было отказоустойчивым, проанализируем следующие моменты:
Безопасность: Никогда не храните пароли от почты прямо в коде в открытом виде. Используйте Безопасное хранилище данных или константы с ограниченным доступом. Для регламентных заданий часто требуется УстановитьПривилегированныйРежим(Истина), чтобы гарантировать доступ к контактной информации пользователей или системным настройкам почты.
Логирование: Обязательно используйте конструкцию Попытка...Исключение при работе с объектом ИнтернетПочта. Ошибки сети, изменения паролей или сбои SMTP-сервера не должны приводить к аварийному завершению работы регламентного задания. Все ошибки фиксируйте в ЖурналРегистрации.
Лимиты: Помните об ограничениях почтовых сервисов на количество писем в час/день. Если записей очень много, лучше формировать одно сводное письмо (как мы сделали в примере с циклом), чем отправлять отдельное письмо по каждой строке регистра.
Используя данный подход, вы создадите гибкую и надежную систему уведомлений, которая поможет оперативно реагировать на внештатные ситуации в информационной базе.