Типовые вычисления в мастерах действий

25 3

В статье За 6 шагов мастер готов рассказано как легко можно создать мастер и запросить у пользователя все необходимые данные. Но теперь с этими данными нужно что-то делать, для этого нужны вычисления в событиях мастера.

События в мастере открываются по кнопке События.  У мастера есть 3 события: До выбора, Начало, Завершение. Также у каждого этапа есть свои события: Начало, Завершение, Previous, Next, Finish, Cancel (у заключительного этапа OK). Назначения этих событий описаны в справке.

Предлагаю посмотреть примеры типовых вычислений и особенности вычислений в мастерах.

1. Заполнение параметров значениями по-умолчанию

Так как мастер предназначен для упрощения работы пользователя, нужно заполнять параметры значениями по-умолчанию, если это возможно. Заполнять параметры можно в событии "Начало" мастера. Самые частые случаи:

Заполнить текущего пользователя (например, параметры Автор, Инициатор):

  Params = Wizard.Params
  Params.ValueByName('Автор').Value = EDocuments.CurrentUser

Заполнить работника текущего пользователя:

  Params = Wizard.Params
  // Найти всех работников для текущего пользователя
  CurrentEmployeeIDList = GetEmployeesByUserID(EDocuments.CurrentUser.ID; ; FALSE)
  if CurrentEmployeeIDList.Count > 0
    // Заполнить параметр первым работником
    Params.ValueByName('Работник').Value = References.РАБ.ObjectInfo(CurrentEmployeeIDList.Values(0))
  endif

Заполнить текущую дату (например, параметры Дата договора, Дата документа):

  // Заполнить дату заявления текущей датой
  Params.ValueByName('ДатаДокумента').Value = Today()

Заполнить редко изменяющийся параметр значением, хранящимся в реестре.

Например, каждый секретарь чаще всего создает заявку на имя определенного руководителя, можно код руководителя записывать в реестр, а при повторном запуске мастера считывать оттуда, таким образом для 90% случаев мы облегчим работу секретарю:

  // Считать из реестра код руководителя - в событии "Начало" мастера
  Params = Wizard.Params
  Register = "HKEY_CURRENT_USER\Software\Computer\DIRECTUM\Параметры мастеров действий\"
  ChiefCode = РеестрЧтение(Register & Wizard.Title; "ЗначПоУмолч")
  if Assigned(ChiefCode)
    Params.ValueByName('Руководитель').Value = References.РАБ.GetObjectByCode(ChiefCode).Info
  endif


  // Если данные изменились, то записать в реестр код руководителя - в событии "Finish" последнего этапа
  // (когда пользователь нажимает кнопку Готово)
  Params = Wizard.Params
  Register = "HKEY_CURRENT_USER\Software\Computer\DIRECTUM\Параметры мастеров действий\"
  ChiefCode = РеестрЧтение(Register & Wizard.Title; "ЗначПоУмолч")
  CurrentChiefCode = Params.ValueByName('Руководитель').Value.Code
  if CurrentChiefCode <<>> ChiefCode
    РеестрЗапись(Register & Wizard.Title; "ЗначПоУмолч"; CurrentChiefCode)     
  endIf 

2. Проверка корректности заполнения параметров и генерация исключения

Корректность введенного значения нельзя проверить сразу после заполнения параметра пользователем на форме, а только после нажатия какой-либо кнопки. Логично проверять при нажатии кнопки Далее. Чтобы работа всего мастера не прерывалась, а прерывался только этап, и при этом работало в веб-доступе, необходимо использовать генерацию исключений.

  // Проверить является ли дата начала отпуска рабочим днем
  Params = Wizards.Params
  DateFrom = Params.ValueByName('C').Value
  // Получить первый рабочий день, включая текущий день
  WorkDay = ServiceFactory.GetRelativeDate(DateFrom; 0; dotDays)
  // Если указанная дата и первый рабочий день отличаются, то сгенерировать исключение
  if DateDiff('D'; WorkDay; DateFrom) <> 0  
    Raise(CreateException('EDIRInvalidUserAction'; 'Отпуск (отгул) не должен начинаться с выходного дня.'; ecWarning))   
  endif

3. Переходы с этапа на этап

Переходы можно задавать в зависимости от определенных условий, например, если пользователь установил флажок Отправить задачу по ТМ, то нужно перейти на этап с запросом параметров для ТМ, иначе пропустить этот этап. Если в вычислениях не указан этап для перехода, то переходит на следующий этап. Переходы нужно задавать с событиях "Next" и "Previous" этапов:

  Params = Wizard.Params
  // Если нужно отправить задачу, то перейти на этап Параметры ТМ, иначе сразу на этап проверка данных
  if Params.ValueByName('Отправить задачу по ТМ').Value
    Wizard.NextStep = Wizard.Steps.ValueByName('Параметры ТМ')
  else
    Wizard.NextStep = Wizard.Steps.ValueByName('Проверка данных')  
  endif

4. Формирование данных для проверки пользователем

В мастерах рекомендуется делать специальный этап для проверки введенных данных пользователем перед тем, как он нажмет кнопку Готово. Эти данные формируются ввиде текста и записывают в текстовый параметр, которые размещен на форме этапа. Я предлагаю вычисления, которые выводят все значения параметров всех типов с заданных этапов, без привязки к именам параметров. Этот способ удобно использовать, когда на этапе проверки нужно выводить именно введенные данные, а не сформированные на их основе. Преимущество способа в том, что при добавлении\удалении с этапа параметра, он появится\удалится на этапе проверки данных автоматически. Вычисления пишем в событие "Начало" этапа с проверкой данных:

  STEP_NAME_INDEX = 0
  TITLE_INDEX = 1
  Params = Wizard.Params
  // Массив в формате: Имя параметра, Заголовок для вывода информации для проверки
  StepNameArray = ArrayOf(
    ArrayOf('Основные параметры'; 'Основные параметры');
    ArrayOf('Параметры ТМ'; 'Параметры согласования'))
  foreach StepName in CArrayElement(StepNameArray)
    // Проверить, что этап существует
    if Wizard.Steps.IndexOfName(StepName[STEP_NAME_INDEX]) <> -1
      // Добавить заголовок в данные для проверки 
      Result = AddSubString(StepName[TITLE_INDEX]; Result; CR & CR) 
      // Получить все элементы формы этапа 
      Elements = Wizard.Steps.ValueByName(StepName[STEP_NAME_INDEX]).Elements
      ElementCount = Elements.Count
      Index = 0
      // Пройтись по каждому элементу
      while Index < ElementCount
        Element = Elements.Values(Index)
        Index = Index + 1
        // Если элемент формы связан с параметром
        if Element.ElementType = wfetQueryParameter
          // Получить параметр
          Param = Element.Parameter
          // Если элемент связан с параметром, то получить его значение
          if in(ArrayOf(wptReferenceRecordInfo; wptUser); Param.ParamType)
            ParamValue = ''
            if Assigned(Param.Value)
              if Param.ParamType = wptUser
                ParamValue = Param.Value.FullName
              else
                ParamValue = Param.Value.Name
              endif
            endif
          else
            // Если параметр типа Логическое значение, то заменить TRUE\FALSE на Да\Нет
            if Param.ParamType = wptBoolean
              ParamValue = IfThen(Param.Value; 'Да'; 'Нет')
            else
              // Для параметров типа Список записей справочников сформировать список
              if in(ArrayOf(wptReferenceRecordInfoList; wptUserList; wptEDocumentInfoList); Param.ParamType) 
                ParamValue = ''
                if Assigned(Param.Value)
                  ParamValue = TAB & TAB
                  foreach Record in Param.Value
                    if Param.ParamType = wptUserList
                      ParamValue = AddSubString(Format('%s%s'; ArrayOf(TAB & TAB; Record.FullName)); ParamValue; CR) 
                    else
                      ParamValue = AddSubString(Format('%s%s'; ArrayOf(TAB & TAB; Record.Name)); ParamValue; CR)
                    endif
                  endforeach
                endif 
              else
                // Иначе просто получить значение параметра
                ParamValue = Param.Value
              endif
            endif
          endif
          // Добавить заголовок параметра на форме и значения параметра в данные для проверки
          Result = AddSubString(Format('%s: %s'; ArrayOf(Element.Caption; ParamValue)); Result; CR & Tab)
        endif
      endwhile
    endif
  endforeach
  Params.ValueByName('Данные для проверки').Value = Result

5. Создание записи справочника

Результатом работы мастера может быть новая запись справочника. Очень часто возникает вопрос: в записях справочника бывают табличные части, которые нужно заполнять, как это организовать в мастере? Рекомендуется 3 варианта:

  • Параметр типа «Список записей справочника\объектов\электронных документов\пользователей», но тогда можно запросить только один столбец в табличной части.
  • Выбрать максимальное количество записей в табличной части (например, 5) и разместить соответствующее количество параметров на форме. Если пользователю потребуется в исключительной ситуации ввести больше, то он может сделать это в самой записи справочника.
  • Использовать этап типа «Запись справочника», чтобы пользователь вводил данные в самой записи. Но нужно помнить, что вводить данные в записи справочника будет невозможно в веб-доступе. 

Вычисления пишем в событие "Finish" этапа с проверкой данных:

  // Создать запись справочника Совещания
  MeetingRec = References.СВЩ.CreateNew()
  // Тема 
  MeetingRec.Содержание = Params.ValueByName('Тема').Value
  // Дата и время
  MeetingRec.ДатаВремя = Params.ValueByName('Дата').Value) 
  // Продолжительность
  MeetingRec.Цена1 = Params.ValueByName('Продолжительность').Value
  // Место проведения - запись справочника (значение параметра это IReferenceInfo, для заполнения реквизита нужно получить код)
  MeetingRec.Room = Params.ValueByName('Место').Value.Code
  // Заполнить участников в табличной части из параметра типа Список записей справочников
  if Assigned(Params.ValueByName('Участники').Value)
    ParticipantDataSet = MeetingRec.DetailDataSet(2)
    foreach Participant in Params.ValueByName('Участники').Value 
      ParticipantDataSet.Insert
      ParticipantDataSet.РаботникТ2 = Participant.Code
      ParticipantDataSet.AdditionT2 = Participant.Name
    endforeach 
  endif
  MeetingRec.Save

6. Создание и отправка задачи по ТМ

Для отправки задачи можно воспользоваться специальной функцией. Вычисления пишем в событие "Finish" этапа с проверкой данных:

  // Массив соответствия: параметр задачи - параметр мастера
  // Параметры ТМ и мастера должны быть одинакового типа
  ParamArray = ArrayOf(
      ArrayOf('Participants'; 'Согласующие');
      ArrayOf('MeetingApprovalDeadline'; 'СрокСогласования');
      ArrayOf('NeedNotice'; 'Уведомление')) 
  endif
  TaskMeeting = WizardCreateStandardRouteTask(
    Wizard; 
    Params.ValueByName('ТМ').Value.Code;
    ParamArray;
    ArrayOf('КарточкаСовещания'; 'Вложения'); ; ; FALSE)

7. Формирование результатов работы мастера со ссылками

В мастерах рекомендуется на завершающем этапе выводить результаты работы мастера со ссылками на созданные объекты (записи справочника, документы, задачи и т.д.). Эти данные формируются ввиде текста и записываются в текстовый параметр, который размещен на форме завершающего этапа. Также при созднии этих объектов могут возникать ошибки (например, проблемы со службой WorkFlow и поэтому не удалось отправить задачу), эту ошибку можно запомнить и на завершающем этапе вывести ее.

  Text = ''
  // Создать запись справочника Совещания
  MeetingRec = References.СВЩ.CreateNew()
  // Заполнить реквизиты...
  
  // Перед сохранением записи отключить генерацию исключений
  FreeException()
  ExceptionsOff()
  MeetingRec.Save
  ExceptionsOn()
  if ExceptionExists()
    Exception = GetLastException()
    // Запомнить ошибку
    Text = AddSubString('Не удалось создать запись справочника "Совещания": ' & Exception.Message; Text; CR & CR)
  else
    // Запомнить гиперссылку на запись справочника
    Text = AddSubString('Оформлено совещание: ' & MeetingRec.HyperLink(hltText); Text; CR & CR)  
  endif
  
  // Отправить задачу по ТМ, перед отправкой отключить генерацию исключений
  FreeException()
  ExceptionsOn()
  TaskMeeting = WizardCreateStandardRouteTask(Wizard; 
    Params.ValueByName('ТМ').Value.Code; ParamArray; ArrayOf('КарточкаСовещания'; 'Вложения'); ; ; FALSE)
  ExceptionsOff()
  if ExceptionExists()
     // Запомнить ошибку
    Exception = GetLastException()
    Text = AddSubString(Format('Не удалось отправить задачу по совещанию: %s'; Exception.Message); Text; CR & CR)
  else
    // Запомнить гиперссылку на задачу
    Text = AddSubString(
      Format('Отправлена задача по совещанию: %s'; CreateHyperlink(Task.ID; 'Задача')); Text; CR & CR)
  endif
  Params.ValueByName('Итоговые данные').Value = Text

Примечание: опускаю совсем создание документов, так как этот вопрос будет рассмотрен в следующей статье, в которой будет рассказано про совместное использование мастеров действий и конструктора доументов.

Marina Kobzar

Как можно заполнить программно пустою параметр типа "Список электронных документов"? Метод ADD не работает.

Ксения Останина
Чтобы заполнить пустой параметр типа "Список электронных документов", нужно получить объект IContents. получить его можно, в том числе, в результате поиска. Например, мы знаем ИД документа, который нужно записать в список, значит нужно выполнить программный поиск этого документа и результаты поиска записать в параметр, пример кода:  
  // Выполнить поиск по ИД документа
  Search = Searches.CreateNew(ckEDocument)
  Criteria = Search.SearchCriteria
  EDocTypeCriterion = Criteria.Add("ИД")
  EDocTypeCriterion.AddSingleValue('<ИД документа>'; vtEqual)  
  FindDocs = Search.Execute()
  // Записать найденный документ в параметр
  Wizard.Params.ValueByName('<имя параметра со списком эл. документов>').Value = FindDocs  
Андрей Подкин

Еще обратите внимание на метод Combine - он позволяет гибко собирать IContents по частям.

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