В нашем "Календаре" отображаются стандартные "Задачи исполнителя" и элементы собственного справочника "События".
На основании справочника "События" можно стартовать бизнес-процессы, кроме того, для них доступна настройка повторения по расписанию. Нужно отметить, что повторяются события только в календаре, новые элементы справочника при этом не создаются. А вот бизнес-процессы на основании этих виртуальных повторяемых событий должны создаваться вполне реальные, с реальными датами. Рассмотрим пример реализации данной задачи.
Справочник "События" выглядит следующим образом:
Форма:
В режиме "Предприятие":
Расписание - реквизит формы с типом значения "Произвольный". При его редактировании свойства расписания записываются в реквизиты события, а при создании формы события - наооборот.
&НаКлиенте
Процедура ПослеИзмененияРасписания(РасписаниеРезультат, ДополнительныеПараметры) Экспорт
Если РасписаниеРезультат <> Неопределено Тогда
Модифицированность = Истина;
Расписание = РасписаниеРезультат;
ЗаполнитьЗначенияСвойств(Объект, Расписание);
//дни недели
Объект.ПовторениеПоДнямНедели.Очистить();
Для Каждого Элемент из Расписание.ДниНедели Цикл
Строка = Объект.ПовторениеПоДнямНедели.Добавить();
Строка.День = Элемент;
КонецЦикла;
//месяцы
Объект.ПовторениеПоМесяцам.Очистить();
Для Каждого Элемент из Расписание.Месяцы Цикл
Строка = Объект.ПовторениеПоМесяцам.Добавить();
Строка.Месяц = Элемент;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура РасписаниеНажатие(Элемент, СтандартнаяОбработка)
СтандартнаяОбработка = ложь;
Обработчик = Новый ОписаниеОповещения("ПослеИзмененияРасписания", ЭтотОбъект);
ДиалогРасписания = Новый ДиалогРасписанияЭлементаПланировщика(?(НЕ ТипЗнч(Расписание) = Тип("РасписаниеЭлементаПланировщика"), Новый РасписаниеЭлементаПланировщика, Расписание));
ДиалогРасписания.Показать(Обработчик);
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьРасписание()
Элементы.Расписание.Видимость = Объект.Повторять;
Если Объект.Повторять Тогда
Расписание = Новый РасписаниеЭлементаПланировщика;
ЗаполнитьЗначенияСвойств(Расписание, Объект);
Расписание.ДниНедели = Объект.ПовторениеПоДнямНедели.Выгрузить().ВыгрузитьКолонку("День");
Расписание.Месяцы = Объект.ПовторениеПоМесяцам.Выгрузить().ВыгрузитьКолонку("Месяц");
Если Расписание.ПериодЛет=0 И Расписание.ПериодМесяцев=0 И Расписание.ПериодНедель=0 И Расписание.ПериодПовтораДней=0 Тогда
Расписание = "настроить расписание...";
КонецЕсли;
КонецЕсли;
КонецПроцедуры
При заполнении календаря расписание элементов заполняется сходным образом:
//{Заполняем текст запроса по событиям}
Выборка = Запрос.Выполнить().Выбрать();
ДанныеКалендаря.Элементы.Очистить();
Пока Выборка.Следующий() Цикл
Элемент = ДанныеКалендаря.Элементы.Добавить(НачалоДня(Выборка.ДатаНачала), КонецДня(Выборка.ДатаОкончания));
Элемент.Текст = Выборка.Наименование;
Элемент.Значение = Выборка.Ссылка;
Если Выборка.Ссылка.Повторять Тогда
Элемент.Расписание = Новый РасписаниеЭлементаПланировщика;
ЗаполнитьЗначенияСвойств(Элемент.Расписание, Выборка.Ссылка);
Элемент.Расписание.ДниНедели = Объект.ПовторениеПоДнямНедели.Выгрузить().ВыгрузитьКолонку("День");
Элемент.Расписание.Месяцы = Объект.ПовторениеПоМесяцам.Выгрузить().ВыгрузитьКолонку("Месяц");
КонецЕсли;
КонецЦикла;
Планировщик 1С обрабатывает элементы с заполненным расписанием следующим образом: на каждый период повтора создаётся элемент планировщика с датами начала и окончания, соответствующими периоду повтора, и значением единственного реального элемента, который мы добавили при обходе выборки.
Выглядит это так:
Обработка "ПередНачаломРедактирования" элемента планировщика у нас нестандартная и вызывает открытие формы задачи/события в зависимости от типа значения. Но какой бы элемент из повторяющихся мы не открывали, даты начала и окончания в форме будут исходные, в данном случае 18.08.2017 и 19.08.2017.
Значит, из календаря будем открывать форму с параметрами, и обрабатывать их при создании на сервере.
&НаСервере
Функция ПолучитьПараметрыФормыСобытия(Событие, Начало, Конец)
ПараметрыФормы = Новый Структура("Ключ, ПовторяемыйЭлемент, ДатаНачалаЭлементаПовторения, ДатаОкончанияЭлементаПовторения", Событие, Событие.Повторять, Начало, Конец);
Возврат ПараметрыФормы;
КонецФункции
&НаКлиенте
Процедура ДанныеКалендаряПередНачаломРедактирования(Элемент, НовыйЭлемент, СтандартнаяОбработка)
СтандартнаяОбработка = ложь;
Если НЕ НовыйЭлемент Тогда
ВыбранныйЭлемент = Элемент.ВыделенныеЭлементы[0];
ЗначениеЭлемента = ВыбранныйЭлемент.Значение;
Если ТипЗнч(ЗначениеЭлемента) = Тип("ЗадачаСсылка.ЗадачаИсполнителя") Тогда
ПоказатьЗначение(,ЗначениеЭлемента);
ИначеЕсли ТипЗнч(ЗначениеЭлемента) = Тип("СправочникСсылка.События") Тогда
ПараметрыФормы = ПолучитьПараметрыФормыСобытия(ЗначениеЭлемента, ВыбранныйЭлемент.Начало, ВыбранныйЭлемент.Конец);
ОткрытьФорму("Справочник.События.ФормаОбъекта", ПараметрыФормы);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Обработчик при создании формы события:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЗаполнитьРасписание();
ДатаНачалаЭлементаПовторения = Параметры.ДатаНачалаЭлементаПовторения;
ДатаОкончанияЭлементаПовторения = Параметры.ДатаОкончанияЭлементаПовторения;
ПовторяемыйЭлемент = Параметры.ПовторяемыйЭлемент;
КонецПроцедуры
Если присмотреться, на размещённом в начале статьи скриншоте с формой события по два элемента с заголовками "Дата начала" и "Дата окончания". В зависимости от того, повторяемый это элемент или основной, видны либо реальные "Дата начала" и "Дата окончания", либо реквизиты формы "Дата начала элемента повторения" и "Дата окончания элемента повторения".
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Элементы.ДатаНачала.Видимость = НЕ ПовторяемыйЭлемент;
Элементы.ДатаНачалаЭлементаПовторения.Видимость = ПовторяемыйЭлемент;
Элементы.ДатаОкончания.Видимость = НЕ ПовторяемыйЭлемент;
Элементы.ДатаОкончанияЭлементаПовторения.Видимость = ПовторяемыйЭлемент;
Элементы.ФормаКоманднаяПанель.ПодчиненныеЭлементы["ФормаСоздатьНаОсновании"].Видимость = НЕ ПовторяемыйЭлемент;
Элементы.ФормаГруппаСоздатьНаОсновании.Видимость = ПовторяемыйЭлемент;
КонецПроцедуры
Стандартный ввод на основании для повторяемых элементов тоже пришлось переписать:
&НаКлиенте
Процедура ВводНаОсновании(Команда)
Основание = Новый Структура("Ссылка, Начало, Конец", Объект.Ссылка, ДатаНачалаЭлементаПовторения, ДатаОкончанияЭлементаПовторения);
ПараметрыФормы = Новый Структура("Основание", Основание);
ОткрытьФорму("БизнесПроцесс.СложноеЗадание.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры
Разумеется, все запущенные на основании повторяемых элементов бизнес-процессы будут подчинены единственному реальному событию.
А теперь о реализации так полюбившейся пользователям функции - перемещения элементов календаря мышкой с сохранением изменений. Планировщик позволяет перемещать элементы и изменять их границы мышью "из коробки". При этом у элементов планировщика меняются даты начала и окончания. Осталось только записать их в реальные объекты.
&НаКлиенте
Процедура ДанныеКалендаряПриОкончанииРедактирования(Элемент, НовыйЭлемент, ОтменаРедактирования)
Для Каждого ВыделенныйЭлемент Из Элемент.ВыделенныеЭлементы Цикл
ОбновитьДатыЗаписиКалендаря(ВыделенныйЭлемент.Значение, ВыделенныйЭлемент.Начало, ВыделенныйЭлемент.Конец);
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура ОбновитьДатыЗаписиКалендаря(ЗаписьКалендаря, ДатаНачала, ДатаОкончания)
ЗаписьКалендаряОбъект = ЗаписьКалендаря.ПолучитьОбъект();
Если ТипЗнч(ЗаписьКалендаря) = Тип("СправочникСсылка.События") Тогда
ЗаписьКалендаряОбъект.ДатаНачала = ДатаНачала;
ЗаписьКалендаряОбъект.ДатаОкончания = ДатаОкончания;
ИначеЕсли ТипЗнч(ЗаписьКалендаря) = Тип("ЗадачаСсылка.ЗадачаИсполнителя") Тогда
Если ЗначениеЗаполнено(ЗаписьКалендаряОбъект.ДатаПринятияКИсполнению) Тогда
ЗаписьКалендаряОбъект.ДатаПринятияКИсполнению = ДатаНачала;
ИначеЕсли ЗначениеЗаполнено(ЗаписьКалендаряОбъект.ДатаНачала) Тогда
ЗаписьКалендаряОбъект.ДатаНачала = ДатаНачала;
Иначе
ЗаписьКалендаряОбъект.Дата = ДатаНачала;
КонецЕсли;
ЗаписьКалендаряОбъект.СрокИсполнения = ДатаОкончания;
КонецЕсли;
ЗаписьКалендаряОбъект.Записать();
КонецПроцедуры
Удобно выделять элементы планировщика разных видов цветом. У элемента есть свойства "ЦветФона", "ЦветТекста" и "ЦветРамки". В зависимости от тех или иных условий можно выбирать какие угодно их сочетания. Планировщик сам позаботится о том, чтобы элементы остались видимыми. В нашей конфигурации задачи, не принятые к исполнению, выделяются одним цветом, принятые - другим, а для каждого события цвет выбирается пользователем и сохраняется в справочнике в реквизите типа "ХранилищеЗначений". При заполнении планировщика данными цвет события устанавливается так:
//получим цвет события
СобытиеОбъект = Выборка.Ссылка.ПолучитьОбъект();
СохранённыйЦвет = СобытиеОбъект.Цвет.Получить();
Если Не СохранённыйЦвет = неопределено Тогда
ЦветСобытия = СохранённыйЦвет;
Иначе
ЦветСобытия = ЦветаСтиля.СобытиеКалендаря;
КонецЕсли;
Элемент.ЦветФона = ЦветСобытия;
Вот и всё самое интересное, что мне удалось выяснить в процессе работы с планировщиком. Возможно, кому-нибудь эта информация будет полезна.