Как показала практика, рассылка типового агента входящих заданий уведомляет только о новых заданиях поступивших сотруднику, на которое иногда пользователь не обращает внимания, а повторного напоминания о том, что таких задач уже много - не поступает. До написания данного прикладного решения, Инициаторы сами писали письма Исполнителям и прикладывали к ним ссылки на зависшие задания (Не мне рассказывать о том, что некоторые пользователи не могут самостоятельно находить задания в работе, или быть может просто не хотят этого делать). А после ввода данного сценария, напоминания ускорили время реакции на невыполненные задания.
Для начала нам надо создать сценарий - назовите его как вам будет угодно, не суть важно это. Далее создаем вычисления:
Email = "" //Объявляем переменные
Ссылки = "" //Объявляем переменные
Users = CreateReference('ПОЛ') //Создаем объект типа справочник "Пользователи"
Users.Open() //Открываем его
Users.First //Ставим указатель на первый элемент
While (Not Users.EOF) //Пока пользователи в списки есть, работаем:
if Users.Состояние == "Действующая" //Выбираем только действующих пользователей
Perfomer = Users.Код //Получаем Код пользователя
Search = Searches.CreateNew(ckJob) //Начинаем поиск по критериям Исполнителя и статусу задания
Criteria = Search.SearchCriteria
CriterionPerformer = Criteria.Add('Performer')
CriterionPerformer.Add(Perfomer)
CriterionJobState = Criteria.Add('JobState')
CriterionJobState.Add('В работе')
SearchResult = Searches.Execute(Search) //Получили результаты
if SearchResult.count > 0 //Если результаты вообще есть, работаем:
User = ServiceFactory.GetUserByCode(Perfomer) //Получаем Пользователя
Email = НайтиРеквизитПоФИО(User.FullName;"Email") //Об этой функции мы поговорим отдельно!!!
foreach ReqName in SearchResult //Получаем ID заданий для генерации ссылок
Ссылки = Ссылки & ГиперссылкаСоздать(ReqName.ID; "Задание") & CR
endforeach
Theme = Format("Для: " & User.FullName & "." & CR & " У вас есть невыполненные задания. Всего: %s."; SearchResult.count) //Генерируем тему
Body= Format("Для: " & User.FullName & "." & CR & " У вас есть невыполненные задания. Всего: %s." & CR & "%s"; ArrayOf(SearchResult.count;Ссылки)) //Генерируем Тело письма
//Предусматриваем вариант работы с заместителем -- начало
Зам = CreateReference('ЗМЩ')
Зам.open()
Зам.first()
if Зам.Locate('ISBReplaceableUser';Perfomer)
if Зам.requisites('ISBSubstituteType').value == "Полное"
and Зам.requisites('ISBSubstituteStart').value <<>> ""
and Зам.requisites('ISBSubstituteFinish').value <<>> ""
and Today() >= Зам.requisites('ISBSubstituteStart').value
and Today() <= Зам.requisites('ISBSubstituteFinish').value
Заместитель = ServiceFactory.GetUserByCode(Зам.requisites('ISBSubstitutingUser').value)
Email = НайтиРеквизитПоФИО(Заместитель.FullName;"Email")
Theme = Format("У сотрудника " & User.FullName & ", которого вы замещаете, есть невыполненные задания. Всего: %s."; SearchResult.count) //Генерируем тему
Body= Format("У сотрудника " & User.FullName & ", которого вы замещаете, есть невыполненные задания. Всего: %s." & CR & "%s"; ArrayOf(SearchResult.count;Ссылки)) //Генерируем Тело письма
endif
endif
Зам.close()
//Предусматриваем вариант работы с заместителем -- конец
Shapka = "Добрый день!" & CR & CR //Объявляем шапку
Podwal = "Данное сообщение сформировано автоматически, просьба не отвечать на него." //Объявляем Подвал
if Assigned(Email) // Если email не пустой - шлем письмо
ПЧТОтправитьПисьмо(Email;;;Theme; Shapka & Body & CR & Podwal;;;)
endif
endif
SearchResult = NIL //Убираемся
CriterionPerformer = NIL //Убираемся
CriterionJobState = NIL //Убираемся
Criteria = NIL //Убираемся
Search = NIL //Убираемся
Ссылки = "" //Убираемся
endif
Users.Next() //Следующий пользователь
endwhile
Пример входящего сообщения:
Кстати пример удачный - пользователь не из самых оперативных.
По сути это все. Но перед завершением темы, раскрываем функцию:
Давно написал эту функцию, надоело постоянно искать все подряд и как попало. Можете написать свою или использовать несколько базовых функций. Мой код вот:
FIO = ФИО
Reference = References.РАБ.GetComponent
Podrazd = ''
AddWhere = Reference.AddWhere(Format("%0:s.%1:s = '%2:s'"; ArrayOf(Reference.TableName;
Reference.Requisites('Дополнение').FieldName; FIO)))
Reference.Open
if Вариант == "Подразделение"
if Reference.RecordCount > 0
Code = Reference.Requisites('Подразделение').AsString
Podrazd = ReferenceRequisiteValue('ПОД';Code;'Наименование')
endif
Reference.Close
Reference.DelWhere(AddWhere)
Reference = nil
Result = Podrazd
endif
if Вариант == "Пользователь"
UserCod = ''
if Reference.RecordCount > 0
Code = Reference.Requisites('Пользователь').AsString
UserCod = ReferenceRequisiteValue('ПОЛ';Code;'Код')
endif
Reference.Close
Reference.DelWhere(AddWhere)
Reference = nil
Result = UserCod
endif
if Вариант == "Подразделение_GUID"
PodrazdGUID = ''
if Reference.RecordCount > 0
Code = Reference.Requisites('Подразделение').AsString
PodrazdGUID = ReferenceRequisiteValue('ПОД';Code;'GUID')
endif
Reference.Close
Reference.DelWhere(AddWhere)
Reference = nil
Result = PodrazdGUID
endif
if Вариант == "Email"
Email = ''
if Reference.RecordCount > 0
Email = Reference.Requisites('Email').AsString
endif
Reference.Close
Reference.DelWhere(AddWhere)
Reference = nil
Result = Email
endif
По сути все - Сценарий работает неспеша, но если он включен всего 2 раза в день в 9 и в 15 - его "неторопливость" совершенно незаметна, а эффект от такой рассылки видно практически сразу - Задания начинают выполняться немного оперативнее.
--------------------------
Вне темы:
Текст вы можете изменить, причем это иногда даже бывает полезно. У меня в одном маршруте так же ведется отправка писем, чтобы оперативнее было выполнение задания, там текст немного иной:
Theme = 'Новая заявка: ' & Params.ValueByName("ТемаЗадачи").Value
MailText = 'Добрый день!' & CR & CR & 'Сожалею, Сэр, но похоже в СЭД Директум на Вас опять упала какая-то заявка:'& CR &
Theme & CR & CreateHyperlink(Object.ID;'Задание';'Ссылка на задание') & CR & 'Спасибо, Сэр. Удачного дня, Сэр.'
ПЧТОтправитьПисьмо('Адресат@Доменопочта.com';;;Theme;MailText;;;)
Как говорят ответственные сотрудники, такой текст им нравится куда больше, чем сухие факты, и они идут "на задание" с приподнятым настроением.
Всем удачного дня!
Может работать неверно
1. при несовпадении users.Fullname с РАБ.Дополнение
2. при наличии полных тезок
3. при наличии нескольких записей (и закрытых тоже) в справочнике работники для одного сотрудника, если, допустим, было увольнение и снова прием (адреса электропочты могут вполне различаться)
зы нет необходимости получать весь набор данных, используя объектную модель. можно обойтись парой запросов, получив только необходимую информацию с последующим разбором.
Сергей Шишканов, Так это уже вопрос необходимости и самодеятельности. Я не претендую на идеальный вариант - он работает при текущих условиях, плюс у нас синхронизация сотрудников проходит автоматическая и вариант Уволен/Принят как правило просто восстанавливает закрытую запись, а вот при смене фамилии - да, может возникнуть проблема, так как там могут возникнуть разночтения. Но это надо задаться целью - нет ничего невозможного.
1. Справочники ПОЛ и ЗМЩ — кэшируемые. Почему решили не использовать кэш?
2. Зачем всех пользователей загружаете с сервера, если закрытых не обрабатываете? С течением времени закрытых пользователей будет все больше, агент будет работать все дольше, работая при этом большей частью вхолостую.
3. Справочник ЗМЩ у вас тоже открывается без серверной фильтрации, хотя нужны в нем вполне конкретные записи. Хуже того, открытие всего ЗМЩ у вас происходит для каждого обрабатываемого пользователя...
Сколько у вас записей в справочнике пользователей? Сколько работает сценарий?
Алексей Семакин, есть над чем поработать)))
Вместо не говорящих ссылок можно прописывать названия ссылок из наименования в DIR.
У нас другая метода. На корп. сайте в личном кабинете есть опция "отправка уведомлений о заданиях", а на SQL сервере хранимочка, которая обрабатывает данный списочек и рассылает письма средствами SQL. Производительность высокая, нагрузка крайне низкая.
Первая Замена "Долой вычисления в цикле":
Теперь условие "if Users.Состояние == "Действующая"" - ненужное!
С ссылками смог доработать только до этого варианта:
Для получения ссылки на объект можно использовать свойство Hyperlink
Юлия Литвинюк, В условиях настройки нашей политики безопасности, все сообщения ЭП по-умолчанию создаются обычным текстом с запретом на html. Так что я пробовал - не выходит. Но возможно другим этот метод подойдет. Спасибо!
Не вижу связи между созданием гиперссылки и форматом текста эл. почты.
Свойство Hyperlink в отличие от функции CreateHyperlink() или ГиперссылкаСоздать() возвращает гиперссылку на объект в 3х форматах: текстовом, RTF и HTML. Т.е.
Юлия Литвинюк, ну собственно вот в чем связь, если пойти вашим путем:
0 - >> Доступ к серверу СКУД для просмотра видеонаблюдения КОНКОРД (http://directum/job.asp?sys=DIRECTUM&id=2572798)
1 - >> Доступ к серверу СКУД для просмотра видеонаблюдения КОНКОРД ({\field{\*\fldinst{HYPERLINK "http://directum/job.asp?sys=DIRECTUM&id=2572798"}}{\fldrslt{\cf1\ul>> \u1044?\u1086?\u1089?\u1090?\u1091?\u1087? \u1082? \u1089?\u1077?\u1088?\u1074?\u1077?\u1088?\u1091? \u1057?\u1050?\u1059?\u1044? \u1076?\u1083?\u1103? \u1087?\u1088?\u1086?\u1089?\u1084?\u1086?\u1090?\u1088?\u1072? \u1074?\u1080?\u1076?\u1077?\u1086?\u1085?\u1072?\u1073?\u1083?\u1102?\u1076?\u1077?\u1085?\u1080?\u1103? \u1050?\u1054?\u1053?\u1050?\u1054?\u1056?\u1044?}}})
2 - >> Доступ к серверу СКУД для просмотра видеонаблюдения КОНКОРД (http://directum/job.asp?sys=DIRECTUM&id=2572798">>> Доступ к серверу СКУД для просмотра видеонаблюдения КОНКОРД)
Чувствуется, что все должно быть иначе, но политика все же сильнее...
Конструктивные правки по подсказке Алексея Семакина:
Что стало с неторопливостью сценария после правок? Удалось ли сократить время его работы?
Боюсь давать сравнительную характеристику, но процентов 30% сбросилось точно. Хотя нас и до этого процесс не особо тревожил - 2 раза в сутки, это не тот случай когда время критично.
Авторизуйтесь, чтобы написать комментарий