Автоматизация отправки прайс-листов клиентам — одна из наиболее востребованных задач в учетных системах. В конфигурации 1С:Бухгалтерия 3.0, построенной на базе Библиотеки стандартных подсистем (БСП), решить эту задачу можно двумя способами: через использование встроенного функционала рассылки отчетов или написанием собственного кода на языке 1С. Рассмотрим оба варианта подробнее, разберем программные нюансы установки отборов и настройки расписания.
Прежде чем приступать к написанию программного кода, проанализируем возможности типового решения. В современных версиях 1С:Бухгалтерия 3.0 реализован мощный механизм Рассылки отчетов. Мы рекомендуем начинать именно с него, так как это избавит от необходимости отлаживать код отправки почты и управления регламентными заданиями.
Для настройки выполним следующие шаги:
Организацию и Склад.Преимущество этого метода: гибкость настройки без участия программиста. Если завтра потребуется добавить еще один склад в отбор, бухгалтер сможет сделать это самостоятельно через пользовательский интерфейс.
Бывают ситуации, когда логика формирования прайс-листа слишком сложна для типового механизма, или требуется выполнить специфические действия перед отправкой. В этом случае мы используем программный подход. Рассмотрим, как правильно инициализировать УниверсальныйОтчет и программно установить параметры и отборы.
Проанализируем базовый алгоритм создания отчета. Основная ошибка при работе с СКД — путаница между параметрами данных и отборами. Параметры определяются в самой схеме (например, НачалоПериода), а отборы — это динамические условия, которые накладываются на результат запроса.
Разберем пример кода для установки периода и организации:
Функция СформироватьПрайсЛист()
// 1. Получаем схему и настройки
СхемаКомпоновкиДанных = Отчеты.УниверсальныйОтчет.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
// 2. Установка параметров (Период)
ПараметрДата = Настройки.ПараметрыДанных.Элементы.Найти("Период");
Если ПараметрДата <> Неопределено Тогда
ПараметрДата.Значение = ТекущаяДата();
ПараметрДата.Использование = Истина;
КонецЕсли;
// 3. Установка отбора (Организация и Склад)
// Очистим текущие отборы, если это необходимо
Настройки.Отбор.Элементы.Очистить();
// Добавляем отбор по организации
ЭлементОтбора = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Организация");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Справочники.Организации.НайтиПоКоду("000000001");
ЭлементОтбора.Использование = Истина;
// Добавляем отбор по складу
ЭлементОтбораСклад = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбораСклад.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад");
ЭлементОтбораСклад.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбораСклад.ПравоеЗначение = Справочники.Склады.НайтиПоНаименованию("Основной склад");
ЭлементОтбораСклад.Использование = Истина;
// 4. Компоновка результата
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
ТабДок = Новый ТабличныйДокумент;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Возврат ТабДок;
КонецФункции
Выясним, почему мы используем именно такие объекты. Объект КомпоновщикМакетаКомпоновкиДанных превращает абстрактную схему и ваши настройки в конкретный «план действий» для процессора. В этот момент 1С анализирует запросы внутри схемы, подставляет туда ваши отборы по складу и организации и формирует итоговый запрос к базе данных.
Важно помнить: если вы используете ПолеКомпоновкиДанных, имя поля должно в точности совпадать с именем поля в наборе данных схемы. Если в схеме поле называется Подразделение, а вы попытаетесь установить отбор по полю Склад, система выдаст ошибку во время выполнения.
Проанализируем ситуацию с текущей датой. В коде автора из примера использовались сложные вычисления: НачалоДня(ТекущаяДата())-60*60*16. Мы рекомендуем использовать стандартные функции языка 1С или возможности самой СКД. В СКД можно настроить параметр как Выражение, например, КонецПериода(ТекущаяДата(), "День"), что сделает отчет более универсальным.
После того как мы получили объект ТабличныйДокумент, его необходимо сохранить и отправить. Поскольку код будет выполняться в фоновом задании на сервере, мы не можем использовать интерактивные формы. Рассмотрим процесс сохранения во временный файл и отправку через системную учетную запись:
Процедура ОтправитьФайлПочтой(ТабДок, АдресПолучателя)
// Сохраняем во временный файл на сервере
ИмяФайла = ПолучитьИмяВременногоФайла("xlsx");
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);
// Получаем системную учетную запись
УчетнаяЗапись = Справочники.УчетныеЗаписиЭлектроннойПочты.СистемнаяУчетнаяЗаписьЭлектроннойПочты;
// Формируем письмо
Письмо = Новый ЭлектронноеПисьмо;
Письмо.Тема = "Актуальный прайс-лист на " + Формат(ТекущаяДата(), "ДЛФ=D");
Письмо.Текст = "Добрый день! Во вложении свежий прайс-лист.";
Письмо.Получатели.Добавить(АдресПолучателя);
Письмо.Вложения.Добавить(Новый ДвоичныеДанные(ИмяФайла), "Price.xlsx");
// Отправляем
Почта = Новый Почта; // Или использовать методы БСП РаботаСЭлектроннойПочтой.ОтправитьПочту
РаботаСЭлектроннойПочтой.ОтправитьПисьмо(УчетнаяЗапись, Письмо);
// Удаляем временный файл
УдалитьФайлы(ИмяФайла);
КонецПроцедуры
Важный момент: при работе в фоновом задании всегда проверяйте наличие прав у пользователя, под которым запущен сервер 1С, на запись в каталог временных файлов. Также убедитесь, что в СистемнаяУчетнаяЗаписьЭлектроннойПочты заполнены настройки SMTP-сервера и пароль.
Чтобы наш код выполнялся автоматически, его нужно поместить в общий модуль (с флагами Сервер и Вызов сервера) и создать объект РегламентноеЗадание в конфигураторе или через консоль заданий. Рассмотрим основные параметры настройки:
МойОбщийМодуль.СформироватьИОтправитьПрайс.Проанализируем возможные ошибки. Если отчет не формируется, первым делом проверьте Журнал регистрации. Часто ошибки возникают из-за того, что в фоновом задании не определен ПараметрыСеанса.ТекущийПользователь, к которому могут обращаться некоторые механизмы УниверсальногоОтчета. В таких случаях перед формированием отчета стоит программно установить пользователя или использовать упрощенные схемы компоновки данных без привязки к интерфейсным механизмам БП 3.0.
Таким образом, мы рассмотрели два надежных способа реализации задачи. Для простых задач идеально подходит Рассылка отчетов, для специфических бизнес-требований — программная работа с СКД и объектами Почты. Выбор за вами, исходя из сложности требуемой логики отборов.