← Назад к вопросам
Проверка отрицательных остатков с уведомлением
2.0 Middle🔥 191 комментариев
#Регистры#Стандарты разработки
Условие
Создайте регламентное задание, которое каждый день в 21:00 проверяет наличие отрицательных остатков товаров и отправляет уведомление на почту или в Telegram.
Требования:
- Проверка остатков по всем складам
- Формирование списка товаров с отрицательными остатками
- Отправка email или сообщения в Telegram ответственному
- Логирование результатов проверки
Формат уведомления
Обнаружены отрицательные остатки:
Склад: Основной
- Товар 1: -5 шт.
- Товар 2: -10 шт.
Дата проверки: 01.01.2024 21:00
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Регламентное задание для проверки отрицательных остатков
Рассмотрим архитектуру автоматической проверки остатков товаров с уведомлением через email и Telegram.
Создание регламентного задания
Конфигурация регламентного задания:
// В конфигураторе создаём:
// Объекты метаданных → Регламентные задания → ПроверкаОтрицательныхОстатков
РегламентноеЗадание ПроверкаОтрицательныхОстатков
Название: "Проверка отрицательных остатков"
Использование: "Используется"
Расписание: "Каждый день в 21:00"
ProcedureName: "МодульОбщегоНазначения.ПроверитьОтрицательныеОстатки"
КонецРегламентногоЗадания
Реализация процедуры проверки
Общий модуль МодульОбщегоНазначения:
// Основная процедура для регламентного задания
Процедура ПроверитьОтрицательныеОстатки(ПараметрыЗадания) Экспорт
ПопыткаПроверки = Новый ТекущаяДата();
ТекстОшибок = "";
Попытка
// Получаем список отрицательных остатков
ОтрицательныеОстатки = ПолучитьОтрицательныеОстатки();
Если ОтрицательныеОстатки.Количество() > 0 Тогда
// Формируем текст уведомления
ТекстУведомления = СформироватьТекстУведомления(ОтрицательныеОстатки);
// Отправляем на почту
ОтправитьEmail(ТекстУведомления);
// Отправляем в Telegram
ОтправитьTelegram(ТекстУведомления);
ЗаписатьВЖурнал("Проверка остатков", "Обнаружены отрицательные остатки. Количество: " + ОтрицательныеОстатки.Количество());
Иначе
ЗаписатьВЖурнал("Проверка остатков", "Отрицательные остатки не обнаружены");
КонецЕсли;
Исключение
ТекстОшибок = ОписаниеОшибки();
ЗаписатьВЖурнал("Проверка остатков", "Ошибка: " + ТекстОшибок, УровеньЖурналаРегистрации.Ошибка);
ВызватьОшибку("Ошибка при проверке остатков: " + ТекстОшибок);
КонецПопытки;
КонецПроцедуры
Запрос отрицательных остатков
// Функция для получения остатков с отрицательными значениями
Функция ПолучитьОтрицательныеОстатки()
РезультатТаблица = Новый ТаблицаЗначений();
РезультатТаблица.Колонки.Добавить("Склад", Новый ОписаниеТипов("Строка"));
РезультатТаблица.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("Строка"));
РезультатТаблица.Колонки.Добавить("Остаток", Новый ОписаниеТипов("Число"));
// SQL запрос к регистру накопления
Запрос = Новый Запрос();
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Склад.Наименование КАК СкладНаименование,
| Остатки.Номенклатура.Наименование КАК НоменклатураНаименование,
| СУММА(Остатки.КоличествоОстаток) КАК Остаток
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(,) КАК Остатки
|ГДЕ
| СУММА(Остатки.КоличествоОстаток) < 0
|СГРУППИРОВАТЬ ПО
| Остатки.Склад,
| Остатки.Номенклатура";
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДанных = РезультатЗапроса.Выбрать();
Пока ВыборкаДанных.Следующий() Цикл
НоваяСтрока = РезультатТаблица.Добавить();
НоваяСтрока.Склад = ВыборкаДанных.СкладНаименование;
НоваяСтрока.Номенклатура = ВыборкаДанных.НоменклатураНаименование;
НоваяСтрока.Остаток = ВыборкаДанных.Остаток;
КонецЦикла;
Возврат РезультатТаблица;
КонецФункции
Формирование текста уведомления
// Функция для форматирования сообщения
Функция СформироватьТекстУведомления(ОтрицательныеОстатки)
Текст = "Обнаружены отрицательные остатки:" + Символы.ПС + Символы.ПС;
// Группируем по складам
ТекущийСклад = "";
Для Каждого Строка Из ОтрицательныеОстатки Цикл
Если ТекущийСклад <> Строка.Склад Тогда
Текст = Текст + "Склад: " + Строка.Склад + Символы.ПС;
ТекущийСклад = Строка.Склад;
КонецЕсли;
// Форматируем остаток (количество товара отрицательное)
Остаток = Число(Строка.Остаток);
Текст = Текст + "- " + Строка.Номенклатура + ": " + Остаток + " шт." + Символы.ПС;
КонецЦикла;
Текст = Текст + Символы.ПС + "Дата проверки: " + Формат(ТекущаяДата(), "ДФ=dd.MM.yyyy ЧЧ:мм") + Символы.ПС;
Возврат Текст;
КонецФункции
Отправка Email
Процедура ОтправитьEmail(ТекстУведомления)
Попытка
// Получаем почту ответственного лица из параметров
СоответствиеНастроек = ПолучитьНастройкиУведомлений();
Email = СоответствиеНастроек.Получить("Email");
Если ЗначениеЗаполнено(Email) Тогда
ПочтовоеСообщение = Новый ПочтовоеСообщение();
ПочтовоеСообщение.Отправитель = "noreply@company.ru";
ПочтовоеСообщение.Тема = "Уведомление: Отрицательные остатки товаров";
ПочтовоеСообщение.Текст = ТекстУведомления;
ПочтовоеСообщение.Адресаты.Добавить(Email);
ПочтовоеСообщение.Отправить();
ЗаписатьВЖурнал("Email отправка", "Email отправлено на: " + Email);
КонецЕсли;
Исключение
ЗаписатьВЖурнал("Email отправка", "Ошибка отправки Email: " + ОписаниеОшибки(), УровеньЖурналаРегистрации.Ошибка);
КонецПопытки;
КонецПроцедуры
Отправка в Telegram
Процедура ОтправитьTelegram(ТекстУведомления)
Попытка
// Получаем параметры Telegram из конфигурации
СоответствиеНастроек = ПолучитьНастройкиУведомлений();
APIKey = СоответствиеНастроек.Получить("TelegramAPIKey");
ChatID = СоответствиеНастроек.Получить("TelegramChatID");
Если ЗначениеЗаполнено(APIKey) И ЗначениеЗаполнено(ChatID) Тогда
// HTTP запрос к Telegram Bot API
HTTPЗапрос = Новый HTTPЗапрос("sendMessage");
HTTPЗапрос.УстановитьПараметр("chat_id", ChatID);
HTTPЗапрос.УстановитьПараметр("text", ТекстУведомления);
HTTPЗапрос.УстановитьПараметр("parse_mode", "HTML");
URLТелеграм = "https://api.telegram.org/bot" + APIKey + "/";
HTTPСоединение = Новый HTTPСоединение("api.telegram.org");
Ответ = HTTPСоединение.ОтправитьДляПолучения(HTTPЗапрос);
ЗаписатьВЖурнал("Telegram отправка", "Сообщение отправлено в Telegram");
КонецЕсли;
Исключение
ЗаписатьВЖурнал("Telegram отправка", "Ошибка отправки в Telegram: " + ОписаниеОшибки(), УровеньЖурналаРегистрации.Ошибка);
КонецПопытки;
КонецПроцедуры
Логирование результатов
Процедура ЗаписатьВЖурнал(КатегорияСобытия, ТекстСообщения, Уровень = УровеньЖурналаРегистрации.Информация)
ЗаписьЖурнала = Новое Структура();
ЗаписьЖурнала.Вставить("Событие", КатегорияСобытия);
ЗаписьЖурнала.Вставить("Сообщение", ТекстСообщения);
ЗаписьЖурнала.Вставить("Дата", ТекущаяДата());
ЗаписьЖурнала.Вставить("Пользователь", ПолучитьТекущегоПользователя());
ЗаписатьВВнутреннийЖурнал(ЗаписьЖурнала.Сообщение, Уровень, , , "ПроверкаОстатков");
КонецПроцедуры
// Функция получения настроек
Функция ПолучитьНастройкиУведомлений()
Настройки = Новый Соответствие();
// Получаем из хранилища настроек (рекомендуется)
// или из справочника "НастройкиСистемы"
Настройки.Вставить("Email", ПолучитьОтветственногоЛица());
Настройки.Вставить("TelegramAPIKey", ПолучитьФункциональнуюОпцию("TelegramAPIKey"));
Настройки.Вставить("TelegramChatID", ПолучитьФункциональнуюОпцию("TelegramChatID"));
Возврат Настройки;
КонецФункции
Расписание задания
В конфигураторе:
- Тип расписания: Ежедневно
- Время: 21:00
- Временная зона: по умолчанию
Архитектурные решения
1. Разделение отправки по каналам:
- Email — официальное уведомление
- Telegram — оперативное уведомление
- Оба работают параллельно
2. Логирование всех операций:
- Помогает отследить проблемы с отправкой
- Ведёт историю проверок
3. Обработка ошибок:
- Ошибка в одном канале не блокирует другой
- Все события логируются
4. Безопасность:
- Ключи и пароли хранятся в параметрах конфигурации
- Не должны быть в исходном коде
Эта реализация обеспечивает надёжное и своевременное уведомление о проблемах с остатками товаров.