При адаптации типовой конфигурации 1С:Управление торговлей 11 (ПРОФ) под специфические задачи бизнеса (например, учет аренды, предоставление услуг проживания или абонентского обслуживания) часто возникает необходимость автоматизировать регулярные операции. Одной из таких задач является ежемесячное начисление по долгосрочным договорам проживания, когда документ начисления должен создаваться автоматически при условии, что гость еще не выехал, а начисление в текущем месяце по нему еще не производилось.
В этой статье мы подробно разберем, как спроектировать и реализовать этот функционал, не снимая типовую конфигурацию с поддержки. Мы создадим внешнюю обработку на базе Библиотеки стандартных подсистем (БСП), напишем оптимальный запрос для выборки данных и организуем безопасное проведение документов в фоновом режиме.
При работе с конфигурацией УТ 11 ПРОФ крайне важно сохранять возможность её простого и малозатратного обновления. Прямое изменение метаданных (добавление регламентных заданий в саму конфигурацию) усложнит последующую поддержку системы. Наиболее правильным решением является использование механизма Дополнительных отчетов и обработок, который входит в состав БСП.
Этот подход дает нам следующие преимущества:
Для реализации задачи нам потребуется создать внешнюю обработку, которая будет выбирать незакрытые проживания и программно формировать документы начисления.
Прежде чем приступать к программной логике, спроектируем 핵심-запрос. Нам необходимо выбрать только те документы Проживание, по которым выполняются два условия:
ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)).Для исключения повторных начислений мы используем конструкцию ЛЕВОЕ СОЕДИНЕНИЕ с регистром накопления (или регистром сведений, куда вы записываете начисления) и отбор по значению NULL. Проанализируем схему связи:
ВЫБРАТЬ
Проживание.Ссылка КАК ПроживаниеСсылка,
Проживание.Контрагент КАК Контрагент,
Проживание.Договор КАК Договор,
Проживание.СтоимостьМесяц КАК Сумма
ИЗ
Документ.Проживание КАК Проживание
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.НачисленияПоПроживанию КАК Начисления
ПО Начисления.Проживание = Проживание.Ссылка
И Начисления.Период МЕЖДУ &НачалоМесяца И &КонецМесяца
ГДЕ
Проживание.Проведен = ИСТИНА
И Проживание.ДатаВыезда = ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)
И Начисления.Проживание ЕСТЬ NULL
Обратите внимание на то, что ограничение по периоду начислений МЕЖДУ &НачалоМесяца И &КонецМесяца вынесено непосредственно в условие связи ПО. Если перенести это условие в секцию ГДЕ, левое соединение превратится во внутреннее, и мы потеряем те проживания, по которым вообще никогда не было начислений.
Создадим новую внешнюю обработку в конфигураторе. В модуле объекта обработки обязательно определим экспортную функцию СведенияОВнешнейОбработке(), которая позволит системе распознать нашу обработку и добавить её в список регламентных задач.
Рассмотрим структуру описания интеграции с БСП:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
ПараметрыРегистрации.Версия = "1.0";
ПараметрыРегистрации.Наименование = "Автоматическое начисление за проживание (ежемесячно)";
ПараметрыРегистрации.Информация = "Выполняет автоматическое формирование документов начисления по активным проживаниям раз в месяц.";
ПараметрыРегистрации.БезопасныйРежим = Ложь;
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = "Выполнить начисление за проживание";
НоваяКоманда.Идентификатор = "ВыполнитьНачисление";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
НоваяКоманда.ПоказыватьОповещение = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
После регистрации этой команды система предоставит интерфейс для настройки расписания. Команда будет запускаться на сервере через общий модуль интеграции БСП.
Теперь напишем обработчик команды. При автоматическом выполнении регламентного задания нам важно предусмотреть обработку исключительных ситуаций. Недопустимо проводить все документы в рамках одной общей транзакции: если при проведении одного документа возникнет ошибка (например, из-за нехватки прав или блокировки данных), вся транзакция откатится, и начисления не запишутся ни по одному клиенту. Мы должны обрабатывать каждое проживание индивидуально в блоке Попытка ... Исключение.
Посмотрим на пример реализации метода выполнения команды в модуле объекта внешней обработки:
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения) Экспорт
Если ИдентификаторКоманды = "ВыполнитьНачисление" Тогда
ВыполнитьАвтоматическоеНачисление();
КонецЕсли;
КонецПроцедуры
Процедура ВыполнитьАвтоматическоеНачисление()
// Включаем привилегированный режим для обхода ограничений RLS при фоновом запуске
УстановитьПривилегированныйРежим(Истина);
ТекущаяДатаСеанса = ТекущаяДатаСеанса();
НачалоМесяца = НачалоПериода(ТекущаяДатаСеанса, ЧастиДаты.Месяц);
КонецМесяца = КонецПериода(ТекущаяДатаСеанса, ЧастиДаты.Месяц);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Проживание.Ссылка КАК ПроживаниеСсылка,
| Проживание.Контрагент КАК Контрагент,
| Проживание.Договор КАК Договор,
| Проживание.СтоимостьМесяц КАК Сумма
|ИЗ
| Документ.Проживание КАК Проживание
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.НачисленияПоПроживанию КАК Начисления
| ПО Начисления.Проживание = Проживание.Ссылка
| И Начисления.Период МЕЖДУ &НачалоМесяца И &КонецМесяца
|ГДЕ
| Проживание.Проведен = ИСТИНА
| И Проживание.ДатаВыезда = ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)
| И Начисления.Проживание ЕСТЬ NULL";
Запрос.УстановитьПараметр("НачалоМесяца", НачалоМесяца);
Запрос.УстановитьПараметр("КонецМесяца", КонецМесяца);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Попытка
СоздатьИПровестиДокументНачисления(Выборка, ТекущаяДатаСеанса);
Исключение
// Поскольку задание выполняется на сервере, интерактивные сообщения Сообщить() не сработают.
// Записываем ошибку в системный Журнал регистрации.
ИнформацияОбОшибке = ИнформацияОбОшибке();
ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
ЗаписатьВЖурналРегистрации(
"АвтоматическоеНачислениеПроживания",
УровеньЖурналаРегистрации.Ошибка,
Выборка.ПроживаниеСсылка.Метаданные(),
Выборка.ПроживаниеСсылка,
"Не удалось создать документ начисления для проживания: " + Выборка.ПроживаниеСсылка + Символы.ПС + ТекстОшибки
);
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Процедура СоздатьИПровестиДокументНачисления(ДанныеВыборки, ДатаДокумента)
// Предполагаем, что у вас создан документ "НачислениеУслуг"
ДокНачисление = Документы.НачислениеУслуг.СоздатьДокумент();
ДокНачисление.Дата = ДатаДокумента;
ДокНачисление.Контрагент = ДанныеВыборки.Контрагент;
ДокНачисление.Договор = ДанныеВыборки.Договор;
ДокНачисление.Проживание = ДанныеВыборки.ПроживаниеСсылка;
ДокНачисление.СуммаДокумента = ДанныеВыборки.Сумма;
// Заполняем табличную часть или другие реквизиты при необходимости
// ...
// Записываем документ с проведением
ДокНачисление.Записать(РежимЗаписиДокумента.Проведение);
КонецПроцедуры
После создания обработки сохраните её как внешний файл с расширением .epf. Настройка автоматического запуска выполняется следующим образом:
.epf.Проанализируем технические особенности выполнения фонового кода, которые необходимо учитывать при запуске:
УстановитьПривилегированныйРежим(Истина). При запуске регламентного задания от имени системной службы у фонового сеанса могут отсутствовать права доступа на чтение или запись определенных объектов базы данных, обусловленные настроенными политиками RLS (ограничение доступа на уровне записей). Привилегированный режим позволяет выполнить операции без проверки прав текущего пользователя.Используя данный подход, вы сможете эффективно решить задачу автоматизации начислений, сохранив при этом конфигурацию «1С:Управление торговлей 11» чистой и легко обновляемой.