Как реализовать автоматическое ежемесячное начисление за проживание в 1С:Управление торговлей 11?

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

При адаптации типовой конфигурации 1С:Управление торговлей 11 (ПРОФ) под специфические задачи бизнеса (например, учет аренды, предоставление услуг проживания или абонентского обслуживания) часто возникает необходимость автоматизировать регулярные операции. Одной из таких задач является ежемесячное начисление по долгосрочным договорам проживания, когда документ начисления должен создаваться автоматически при условии, что гость еще не выехал, а начисление в текущем месяце по нему еще не производилось.

В этой статье мы подробно разберем, как спроектировать и реализовать этот функционал, не снимая типовую конфигурацию с поддержки. Мы создадим внешнюю обработку на базе Библиотеки стандартных подсистем (БСП), напишем оптимальный запрос для выборки данных и организуем безопасное проведение документов в фоновом режиме.

Архитектурное решение: почему внешняя обработка лучше изменения конфигурации

При работе с конфигурацией УТ 11 ПРОФ крайне важно сохранять возможность её простого и малозатратного обновления. Прямое изменение метаданных (добавление регламентных заданий в саму конфигурацию) усложнит последующую поддержку системы. Наиболее правильным решением является использование механизма Дополнительных отчетов и обработок, который входит в состав БСП.

Этот подход дает нам следующие преимущества:

  1. Конфигурация остается на полной поддержке.
  2. Регистрация обработки и настройка расписания её запуска выполняются администратором в пользовательском режиме предприятия.
  3. Код выполняется на сервере в фоновом задании, не блокируя работу пользователей.

Для реализации задачи нам потребуется создать внешнюю обработку, которая будет выбирать незакрытые проживания и программно формировать документы начисления.

Шаг 1. Разработка запроса для выбора проживаний без начислений

Прежде чем приступать к программной логике, спроектируем 핵심-запрос. Нам необходимо выбрать только те документы Проживание, по которым выполняются два условия:

  1. Дата выезда не заполнена (равна пустой дате ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)).
  2. В текущем календарном месяце по этому проживанию еще не было зарегистрировано начислений.

Для исключения повторных начислений мы используем конструкцию ЛЕВОЕ СОЕДИНЕНИЕ с регистром накопления (или регистром сведений, куда вы записываете начисления) и отбор по значению NULL. Проанализируем схему связи:


ВЫБРАТЬ
	Проживание.Ссылка КАК ПроживаниеСсылка,
	Проживание.Контрагент КАК Контрагент,
	Проживание.Договор КАК Договор,
	Проживание.СтоимостьМесяц КАК Сумма
ИЗ
	Документ.Проживание КАК Проживание
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.НачисленияПоПроживанию КАК Начисления
		ПО Начисления.Проживание = Проживание.Ссылка
		И Начисления.Период МЕЖДУ &НачалоМесяца И &КонецМесяца
ГДЕ
	Проживание.Проведен = ИСТИНА
	И Проживание.ДатаВыезда = ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)
	И Начисления.Проживание ЕСТЬ NULL

Обратите внимание на то, что ограничение по периоду начислений МЕЖДУ &НачалоМесяца И &КонецМесяца вынесено непосредственно в условие связи ПО. Если перенести это условие в секцию ГДЕ, левое соединение превратится во внутреннее, и мы потеряем те проживания, по которым вообще никогда не было начислений.

Шаг 2. Создание модуля внешней обработки БСП

Создадим новую внешнюю обработку в конфигураторе. В модуле объекта обработки обязательно определим экспортную функцию СведенияОВнешнейОбработке(), которая позволит системе распознать нашу обработку и добавить её в список регламентных задач.

Рассмотрим структуру описания интеграции с БСП:


Функция СведенияОВнешнейОбработке() Экспорт
	
	ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2");
	
	ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
	ПараметрыРегистрации.Версия = "1.0";
	ПараметрыРегистрации.Наименование = "Автоматическое начисление за проживание (ежемесячно)";
	ПараметрыРегистрации.Информация = "Выполняет автоматическое формирование документов начисления по активным проживаниям раз в месяц.";
	ПараметрыРегистрации.БезопасныйРежим = Ложь;
	
	НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
	НоваяКоманда.Представление = "Выполнить начисление за проживание";
	НоваяКоманда.Идентификатор = "ВыполнитьНачисление";
	НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
	НоваяКоманда.ПоказыватьОповещение = Истина;
	
	Возврат ПараметрыРегистрации;
	
КонецФункции

После регистрации этой команды система предоставит интерфейс для настройки расписания. Команда будет запускаться на сервере через общий модуль интеграции БСП.

Шаг 3. Реализация алгоритма проведения документов

Теперь напишем обработчик команды. При автоматическом выполнении регламентного задания нам важно предусмотреть обработку исключительных ситуаций. Недопустимо проводить все документы в рамках одной общей транзакции: если при проведении одного документа возникнет ошибка (например, из-за нехватки прав или блокировки данных), вся транзакция откатится, и начисления не запишутся ни по одному клиенту. Мы должны обрабатывать каждое проживание индивидуально в блоке Попытка ... Исключение.

Посмотрим на пример реализации метода выполнения команды в модуле объекта внешней обработки:


Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения) Экспорт
	
	Если ИдентификаторКоманды = "ВыполнитьНачисление" Тогда
		ВыполнитьАвтоматическоеНачисление();
	КонецЕсли;
	
КонецПроцедуры

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

Процедура СоздатьИПровестиДокументНачисления(ДанныеВыборки, ДатаДокумента)
	
	// Предполагаем, что у вас создан документ "НачислениеУслуг"
	ДокНачисление = Документы.НачислениеУслуг.СоздатьДокумент();
	ДокНачисление.Дата = ДатаДокумента;
	ДокНачисление.Контрагент = ДанныеВыборки.Контрагент;
	ДокНачисление.Договор = ДанныеВыборки.Договор;
	ДокНачисление.Проживание = ДанныеВыборки.ПроживаниеСсылка;
	ДокНачисление.СуммаДокумента = ДанныеВыборки.Сумма;
	
	// Заполняем табличную часть или другие реквизиты при необходимости
	// ...
	
	// Записываем документ с проведением
	ДокНачисление.Записать(РежимЗаписиДокумента.Проведение);
	
КонецПроцедуры

Шаг 4. Настройка расписания в режиме «1С:Предприятие»

После создания обработки сохраните её как внешний файл с расширением .epf. Настройка автоматического запуска выполняется следующим образом:

  1. Откройте информационную базу под учетной записью администратора.
  2. Перейдите в раздел НСИ и администрирование — Печатные формы, отчеты и обработки — Дополнительные отчеты и обработки.
  3. Нажмите кнопку «Добавить из файла» и выберите созданный файл .epf.
  4. В карточке обработки в колонке «Расписание» нажмите на ссылку «Не установлено».
  5. Настройте требуемую периодичность. Например, для запуска первого числа каждого месяца в 01:00 настройте расписание на вкладке «Месячное» или настройте ежедневный запуск для оперативного контроля пропущенных начислений (благодаря нашему запросу повторные документы создаваться не будут).

Важные нюансы выполнения регламентных заданий

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

Используя данный подход, вы сможете эффективно решить задачу автоматизации начислений, сохранив при этом конфигурацию «1С:Управление торговлей 11» чистой и легко обновляемой.

← На главную