Как реализовать массовую рассылку отчетов о задолженности контрагентам в 1С?

Программист 1С v8.3 (Обычные формы) Управленческий учет IT и автоматизация бизнеса
← На главную

Автоматическое информирование партнеров о состоянии взаиморасчетов — одна из ключевых задач при автоматизации торговых и учетных процессов. Часто разработчики сталкиваются с ситуацией, когда процедура рассылки выполняется без видимых ошибок платформы, но сообщение формируется и отправляется только по одному конкретному контрагенту либо вовсе не доходит до адресатов. Разберем типичные ошибки при построении таких алгоритмов и рассмотрим, как правильно организовать выборку данных и отправку писем.

Анализ проблемы: почему отчет отправляется только одному контрагенту

Проанализируем исходный код запроса, с которым возникла проблема при пакетной рассылке:


ВЫБРАТЬ
    РасчетыОстатки.Контрагент,
    РасчетыОстатки.Контрагент.ЭлПочта,
    СУММА(РасчетыОстатки.БалансОстаток) КАК БалансКонОст
ИЗ
    РегистрНакопления.Расчеты.Остатки(
            &НаДату,
            Контрагент.ЭлПочта <> ""
                И Контрагент.Наименование = "!РЕЗЕРВНЫЙ ФОНД") КАК РасчетыОстатки
СГРУППИРОВАТЬ ПО
    РасчетыОстатки.Контрагент,
    РасчетыОстатки.Контрагент.ЭлПочта

Причиной того, что цикл обрабатывал только одну запись, являлось жесткое условие в параметрах виртуальной таблицы: Контрагент.Наименование = "!РЕЗЕРВНЫЙ ФОНД" (а на следующем этапе отладки — конкретное ФИО). Запрос физически возвращал остаток исключительно по указанному элементу справочника.

Чтобы алгоритм обрабатывал всех партнеров, у которых заполнен адрес электронной почты, необходимо исключить фильтрацию по конкретному наименованию или параметризовать список отбираемых контрагентов.

Пошаговое построение корректного механизма рассылки

Разберем по шагам создание надежной процедуры массовой отправки уведомлений по взаиморасчетам.

  1. Корректировка текста запроса. Убираем жесткую привязку к наименованию и оптимизируем получение остатков:
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	РасчетыОстатки.Контрагент КАК Контрагент,
        |	РасчетыОстатки.Контрагент.ЭлПочта КАК ЭлПочта,
        |	РасчетыОстатки.БалансОстаток КАК БалансКонОст
        |ИЗ
        |	РегистрНакопления.Расчеты.Остатки(&НаДату, Контрагент.ЭлПочта ЕСТЬ НЕ NULL И Контрагент.ЭлПочта <> """") КАК РасчетыОстатки";
    
    Запрос.УстановитьПараметр("НаДату", ТекущаяДата());
    Выборка = Запрос.Выполнить().Выбрать();
    

    Обратите внимание: если в регистре измерение Контрагент является единственным или запрос строится только по нему, виртуальная таблица Остатки уже возвращает сгруппированные итоги, поэтому использование конструкции СГРУППИРОВАТЬ ПО и агрегатной функции СУММА() является избыточным.

  2. Формирование текста темы и тела письма. В цикле обхода выборки формируем персонализированные данные:
    
    ВыбНачПериода = ДобавитьМесяц(ТекущаяДата(), -1);
    ВыбКонПериода = ТекущаяДата();
    
    Пока Выборка.Следующий() Цикл
        
        ТекущийКонтрагент = Выборка.Контрагент;
        ТекущийБаланс = Выборка.БалансКонОст;
        
        // Формирование текста темы сообщения
        ПериодСтр = ПредставлениеПериода(ВыбНачПериода, ВыбКонПериода, "L=ru_RU");
        ТемаОтправки = "Взаиморасчеты по контрагенту " + СокрЛП(ТекущийКонтрагент.Наименование) + " за период " + ПериодСтр + ". ";
        
        Если ТекущийБаланс < 0 Тогда
            ТемаОтправки = ТемаОтправки + "Ваш долг: " + Формат(-ТекущийБаланс, "ЧДЦ=2") + " руб.";
        Иначе
            ТемаОтправки = ТемаОтправки + "Ваш баланс: " + Формат(ТекущийБаланс, "ЧДЦ=2") + " руб.";
        КонецЕсли;
        
        // Переход к формированию и отправке отчета
        // ...
    КонецЦикла;
    
  3. Формирование вложений и вызов процедуры отправки. Для каждого контрагента формируется отчет и отправляется почтовым клиентом.

Важные рекомендации по надежности и производительности рассылки

При массовой отправке писем стандартным кодом часто возникают скрытые ошибки, приводящие к блокировкам или падению сеанса. Рассмотрим, на что следует обратить внимание:

  1. Защита цикла блоком обработки исключений. Если отправка письма одному контрагенту завершится ошибкой (например, некорректный формат адреса или сбой почтового сервера), выполнение всего процесса не должно прерываться. Вызов отправки обязательно оборачивается в конструкцию Попытка ... Исключение ... КонецПопытки с записью ошибки в журнал регистрации:
    
    Попытка
        глОтправитьОтчетПоПочте(Таб, ТекущийКонтрагент, ТемаОтправки, 0, ПутьКФайлу, 2);
        Сообщить("Успешно отправлено: " + ТекущийКонтрагент);
    Исключение
        ЗаписьЖурналаРегистрации("Рассылка взаиморасчетов", УровеньЖурналаРегистрации.Ошибка,,, 
            "Ошибка отправки контрагенту " + ТекущийКонтрагент + ": " + ОписаниеОшибки());
    КонецПопытки;
    
  2. Работа с временными файлами вместо фиксированных путей. Использование фиксированного пути (например, G:\Bases2\Balance.htm) может привести к ошибкам доступа ОС при параллельной работе или быстрой перезаписи файла. Рекомендуется использовать метод ПолучитьИмяВременногоФайла("html") и удалять сгенерированный файл после отправки с помощью процедуры УдалитьФайлы().
  3. Отбор по группе или списку контрагентов. Чтобы рассылка была гибкой, передавайте список или группу контрагентов через параметры запроса с операторами В (&МассивКонтрагентов) или В ИЕРАРХИИ (&ГруппаКонтрагентов).
  4. Оптимизация почтовой сессии и антиспам-ограничения. При отправке большого количества писем не следует повторно подключаться к SMTP-серверу на каждой итерации цикла. Целесообразно открыть сессию один раз перед циклом выборки и закрыть ее после завершения обхода. Если почтовый провайдер ограничивает частоту отправки сообщений (Rate Limit), добавьте небольшую паузу между итерациями с помощью функции Приостановить().
← На главную