Полезные мелочи при работе с карточками ч.4 (Замещение своими руками)

13 10

На данном форуме уже есть несколько статей по созданию замещений в конкретных организациях (Пример: https://club.directum.ru/award/64706 или https://club.directum.ru/award/64767), только без открытого кода, без должного описания и даже без разработки. Так что я решил заполнить это пробел.

Ни для кого не секрет, что у наших пользователей нет прав на многие технические справочники, в том числе и на справочник "замещения пользователей", в связи с чем - пишутся заявки и нагружаются администраторы и разработчики. Чтобы этого избежать, всю техническую кухню, надо спрятать в подкорку несложного процесса, и вот его уже передать пользователям. Уже не одна компания реализует подобный подход к делу через Мастера действий или маршруты, чтобы минимизировать кол-во заявок в Service-Desk.

И так - начнем:

1. Создадим основу - Функцию "СоздатьЗамещение"

Для этого создадим новую Функцию и наполним ее нужными нам параметрами:

После этого заводим внутрь код:

  Zameshenie = References.ЗМЩ.CreateNew           // Созщдаем новую запись в справочнике "ЗМЩ"  
  Zameshenie.ISBReplaceableUser = Замещаемый      // Пользователь
  Zameshenie.ISBSubstitutingUser = Заместитель    // Заместитель
  Zameshenie.ISBSubstituteStart = ДатаНачала      // Дата Начала замещения
  Zameshenie.ISBSubstituteFinish = ДатаКонца      // Дата Конца замещения
  Zameshenie.КСтрока = Обоснование                // Примичание
  if ТипЗамещения                                 // тип замещения: Полное или Ассистент
    Zameshenie.ISBSubstituteType = 'Полное'
  else
    Zameshenie.ISBSubstituteType = 'Ассистент'
  endif
  Zameshenie.Save                                 // Сохраняем запись
  Result = Zameshenie.SYSREQ_ID                   // Выводим в результат ИД новой записи

Готово. Теперь у нас есть функция создающая запись в справочнике по вводимой информации и не требующую никаких сверх-естественных прав от пользователя.

Справка: В данном коде присутствует параметр "Тип Замещения", который в примере не участвует. Я его не стал убирать, так как он может и пригодиться в другом месте. Например в маршруте по согласованию приказа, где будет возможность не только делегировать какую-либо задачу, но и сразу выдать замещение (полное или на уровне Ассистента), у вас же есть для этого функция. Можно часть кода убрать и оставить только строку "Zameshenie.ISBSubstituteType = 'Полное'" - смотрите сами.

2. Нарисуем маршрут для Создания Замещения

Называем его как угодно и даем новому маршруту уникальный Код:

Теперь заполняем его параметры:

Далее - создаем схему. Нам она сложной и не нужна, так что идем по минимальной тропке:

Собственно на этом этапе можно добавить согласование с руководителем, внести блок с созданием документа по шаблону с просьбой его оформить, передать оповещение в отдел кадров для учета и так далее - все в ваших руках. Я на примере буду уведомлять только 2 заинтересованных лиц: Замещаемого и заместителя (хотя отсюда первого можно и выкинуть, он же и так в курсе, кто его будет замещать)

Далее указываем и запрашиваемые параметры

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

3. Добавляем вычисления!

Тут я делал все под себя, но вы можете сделать и иначе:

Начало выбора: 

Params = Sender.WorkFlowParams
CurrentUser = ServiceFactory.GetUserByName(Application.Connection.UserName)
Params.ValueByName("Инициатор").Value = CurrentUser
Params.ValueByName("НачалоПериода").Value = Today()

Object.Subject = Format("Создается замещение от %s от %s)"; ArrayOf(CurrentUser.FullName; Today()))

Думаю, тут пояснения излишни - все просто.

Возможность старта:

Params = Sender.WorkFlowParams

if Params.ValueByName("НачалоПериода").Value >= Params.ValueByName("КонецПериода").Value
   Raise(СоздатьИсключение('ВНИМАНИЕ!'; 'Конец периода должен быть после начала периода!' &CR&'Можете начинать процедуру заново.'))
endif

if Params.ValueByName("Инициатор").Value == Params.ValueByName("Заместитель").Value
   Raise(СоздатьИсключение('ВНИМАНИЕ!'; 'Неверно выбран заместитель!' &CR& 'Вы выбрали себя!' &CR&'Можете начинать процедуру заново.'))
endif

ИНЗ = ТМПолучитьПараметрЗадачи('Инициатор')
ЗАМ = ТМПолучитьПараметрЗадачи('Заместитель')
Замещаемый = ServiceFactory.GetUserByName(ИНЗ).FullName
Заместитель = ServiceFactory.GetUserByName(ЗАМ).FullName

FullText = 'Создано замещение!' & CR
FullText = FullText & 'Замещаемый: ' & Замещаемый & CR
FullText = FullText & 'Заместитель: ' & Заместитель & CR
FullText = FullText & 'Начало периода замещения: ' & Params.ValueByName("НачалоПериода").Value & CR
FullText = FullText & 'Конец периода замещения: ' & Params.ValueByName("КонецПериода").Value & CR
FullText = FullText & 'Обоснование замещения: ' & Params.ValueByName("Обоснование").Value & CR

Object.ActiveText = FullText

Здесь немного сложнее, так как я посадил в вычисления 2 проверки: Проверка на последовательность дат и выбор замещаемого (здесь же можно сделать проверку на группу выбираемого сотрудника, чтобы никто не смог выбрать высшее руководство, но я это пропустил). Так же в активное поле комментариев выгружается вся полученная информация чтобы было легко все найти и рассмотреть.

Завершение выбора - тут на ваше усмотрение, я вот сделал так:

Sender.Start // Стартуем сразу, зачем кнопки часто нажимать?

Теперь осталось добавить стандартные блоки тем для уведомлений и само вычисление.

Уведомление для Инициатора:

Params = Object.WorkFlowParams
ЗАМ = ТМПолучитьПараметрЗадачи('Заместитель')
Заместитель = ServiceFactory.GetUserByName(ЗАМ).FullName
Начало = Params.ValueByName("НачалоПериода").Value
Конец = Params.ValueByName("КонецПериода").Value
Sender.Properties.ValueByName(JOB_BLOCK_SUBJECT_PROPERTY).Value = Format("Вас замещает %s с %s по %s"; ArrayOf(Заместитель;Начало;Конец))

Object.ActiveText = Params.ValueByName("ИДЗамещения").Value

Тоже все понятно, кроме "ИДЗамещения", его мы как раз получим чуть ранее из блока вычисления:

Вычисления в блоке "Создание Замещения":

Params = Object.WorkFlowParams
  Инициатор = ServiceFactory.GetUserByName(ТМПолучитьПараметрЗадачи('Инициатор')).Code
  Заместитель = ServiceFactory.GetUserByName(ТМПолучитьПараметрЗадачи('Заместитель')).Code
  ДатаНачала = Params.ValueByName('НачалоПериода').Value
  ДатаКонца = Params.ValueByName('КонецПериода').Value
  Обоснование = Params.ValueByName('Обоснование').Value
  
  ИДЗамещения = СоздатьЗамещение(Инициатор;Заместитель;ДатаНачала;ДатаКонца;Обоснование)
  Params.ValueByName('ИДЗамещения').Value = Trim(ИДЗамещения)

Просто как 5 копеек. И наличие полученного ИД, позволит Администратору или Разработчику быстрее найти ошибочное замещение и убить его.

Теперь посмотрим скриншотики по работе этого скрипта)))

Как видно - задача уже стартована! Это из-за моей строки "Sender.Start"

И проверяем создание записи в справочнике:

Вот по сути и все - больше не надо получать письма с просьбой создать замещение - бросайтесь в людей инструкциями и да познаете вы Дзэн... 

Павел Березин

Почему подобное в стандартной коробке досихпор не реализовано? Ведь потребность оперативного назначения "зама" на период резкого отбытия по служебным/прочим делам, - довольно частая практическая задача.

Фёдор Сироткин

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

А так идея интересная и актуальная. Спасибо! 

Тарас Асачёв

Прикреплен файл: Wizards.rar
И сама разработка

Ольга Салифанова

Добрый вечер!

Судя по коду "Raise(СоздатьИсключение('ВНИМАНИЕ!'; 'Конец периода должен быть после начала периода!' &CR&'Можете начинать процедуру заново.'))"

у вас не реализовано создание замещения на 1 день ? 

Тарас Асачёв

Ольга, Верно - мы на это не размениваемся))) Ну а если честно, то мы заметили, что при замещении на 1 день, отказывается работать Подпись документов по праву заместителя, так что мы от этого отказались. Сутки и без зама работа не остановится. 

Тарас Асачёв

Прикреплен файл: Замещение.rar
Обновляю разработку (МД, Маршрут, Функция)

Дмитрий Зайцев

А на какой версии Вы писали разработку?  Для мастера действий в событиях выдается ошибка "

Task1 = CreateTaskToEmployees(Theme1; CArrayElement(ArrayOf(НайтиРеквизитПоФИО(ServiceFactory.GetUserByCode(Пользователь.Code).FullName; 'Работник'))); Attachments; Params.ValueByName('ВсяИнформация').Value; 1)//.Form.Show

" - не нравится - "НайтиРеквизитПоФИО"

P.S. Нашел вашу функцию в других сообщениях.

Дмитрий Зайцев: обновлено 26.05.2020 в 17:32
Тарас Асачёв

Дмитрий, "НайтиРеквизитПоФИО", это самописная функция, которую я несколько раз расписывал и в этой статье пренебрег этим знанием. Вы можете создать ее сами:

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
  Result = Podrazd
endif

if Вариант == "Пользователь"
  UserCod = ''
  if Reference.RecordCount > 0
    Code = Reference.Requisites('Пользователь').AsString
    UserCod = ReferenceRequisiteValue('ПОЛ';Code;'Код')
  endif
  Result = UserCod
endif

if Вариант == "Подразделение_GUID"
  PodrazdGUID = ''
  if Reference.RecordCount > 0
    Code = Reference.Requisites('Подразделение').AsString
    PodrazdGUID = ReferenceRequisiteValue('ПОД';Code;'GUID')
  endif
  Result = PodrazdGUID
endif

if Вариант == "Email"
  Email = ''
  if Reference.RecordCount > 0
    Email = Reference.Requisites('Email').AsString
  endif
  Result = Email
endif

  Reference.Close
  Reference.DelWhere(AddWhere)
  Reference = nil

 

Тарас Асачёв: обновлено 26.05.2020 в 15:49
Дмитрий Зайцев

Опробовал работу вашей разработки на версии 5.8. Работоспособно, но есть нюансы:

  1. При  создании задачи по ТМ создается 2 замещения, т.е. 2 записи в справочнике "Замещение"
  2.  В карточке задачи не показывает с каким ИД создано замещение.
Тарас Асачёв

2 года прошло. Для 5.8. я бы использовал Мастер действия и Серверное событие. Тогда и маршрут не нужен и проблем куда меньше)

Авторизуйтесь, чтобы написать комментарий