ЦВД
29 марта 2024 г. • 5 мин

Голосование в задаче согласования Directum RX в 2027: модификация через low-code

Валентин Костюкевич
Валентин Костюкевич

На практике часто возникает необходимость организовать коллегиальное принятие решений — например, при утверждении решений совещания, бюджетов или стратегических инициатив. Стандартные механизмы согласования в Directum RX позволяют настроить маршрут, но не поддерживают полноценное голосование с фиксацией позиций «За», «Против», «Воздержался».

В 2027 году эту задачу можно решить через low-code — без изменения стандартных механизмов системы. В этой статье — как мы реализовали модификацию для голосования в рамках задачи согласования.

Если вы хотите понять, как Directum RX встраивается в общую архитектуру — изучите подробнее о Directum RX. Там описаны технические требования и схемы развёртывания.

Полная цифровая трансформация
Единая платформа для управления всеми бизнес‑процессами компании
Экосистема Directum
Экосистема Directum

Задача: коллегиальное принятие решений

В этой статье — как реализовать модификацию для голосования в рамках задачи согласования, сохранив привычный интерфейс и интегрировав результаты прямо в протокол совещания.

Требования

  • Голосование должно быть доступно на любом этапе согласования.
  • Участники голосуют по каждому решению: «За», «Против», «Воздержался».
  • Нельзя выбрать несколько вариантов.
  • Результаты агрегируются в протоколе.
  • Голосование — опциональная функция, активируемая при необходимости.

Реализация: ключевые компоненты

Модификация включает несколько компонентов:

  1. Настройка вида документа «Протокол совещания».
  2. Создание справочника «Матрицы согласования».
  3. Доработка задачи согласования.
  4. Асинхронный обработчик результатов.
  5. Роль согласования «Участники голосования».

Добавление признака «Требуется голосование»

В перекрытый справочник DocumentKind добавляем логическое свойство:

csharp

/// <summary>

/// Требуется голосование.

/// </summary>

public virtual bool? NeedVoting { get; set; }

На событии Showing формы — показываем только для вида «Протокол совещания»:

csharp

public override void Showing(Sungero.Presentation.FormShowingEventArgs e)

{

    base.Showing(e);

    var isMinutes = _obj.DocumentType?.DocumentTypeGuid == Constants.MeetingMinutesTypeGuid;

    _obj.State.Properties.NeedVoting.IsVisible = isMinutes;

}

Коллекция решений в протоколе

В карточку Minutes добавляем коллекцию Decisions, где каждое решение содержит:

  • Текст решения.
  • Матрицу голосующих.
  • Счётчики голосов.
  • Результат.

csharp

public virtual void DecisionsAdded(Sungero.Domain.Shared.CollectionPropertyAddedEventArgs e)

{

    var added = e.Added as IMinuteDecision;

    added.Number = (_obj.Decisions.Max(d => d.Number) ?? 0) + 1;

    added.Result = Resources.NoResults;

}

Кастомный тип этапа «Голосование»

csharp

/// <summary>

/// Тип этапа.

/// </summary>

public virtual CustomStageType? CustomStageType { get; set; }

Фильтруем отображение — «Голосование» доступно только для этапов типа «Задание»:

csharp

public virtual IEnumerable<Enumeration> CustomStageTypeFiltering(IEnumerable<Enumeration> query)

{

    if (_obj.StageType != StageType.SimpleAgr || _obj.AllowSendToRework == true)

        query = query.Where(q => !Equals(q, CustomStageType.Voting));

    return query;

}

Коллекция голосов в задании

В перекрытое задание ApprovalSimpleAssignment добавляем коллекцию Voting, содержащую:

  • Decision — текст.
  • VoteFor, VoteAgainst, VoteAbstain — выбор.

Обеспечиваем взаимоисключающий выбор:

csharp

public virtual void VotingVoteAgainstValueInput(Sungero.Presentation.BooleanValueInputEventArgs e)

{

    if (e.NewValue == true)

    {

        _obj.VoteFor = false;

        _obj.VoteAbstain = false;

    }

}


public virtual void VotingVoteForValueInput(Sungero.Presentation.BooleanValueInputEventArgs e)

{

    if (e.NewValue == true)

    {

        _obj.VoteAgainst = false;

        _obj.VoteAbstain = false;

    }

}

Проверка голосования перед завершением задания

На событии BeforeComplete убеждаемся, что по всем решениям проголосовано:

csharp

public override void BeforeComplete(Sungero.Workflow.Server.BeforeCompleteEventArgs e)

{

    base.BeforeComplete(e);

    if (_obj.CustomStageType != CustomStageType.Voting)

        return;

    var emptyVotes = _obj.Voting.Where(v => !v.VoteFor && !v.VoteAgainst && !v.VoteAbstain);

    if (emptyVotes.Any())

    {

        e.AddError("Проголосуйте по всем решениям.");

        return;

    }

}

Асинхронный обработчик результатов

После завершения задания — агрегируем голоса в протоколе:

csharp

public void AddVotingResults(long assignmentId, long minutesId)

{

    var assignment = ApprovalSimpleAssignment.GetAll().Where(a => a.Id == assignmentId).FirstOrDefault();

    var minutes = Minutes.GetAll().Where(m => m.Id == minutesId).FirstOrDefault();

    if (assignment == null || minutes == null) return;


    foreach (var vote in assignment.Voting)

    {

        var decision = minutes.Decisions.FirstOrDefault(d => d.Id == vote.MinutedDecisionId);

        if (decision != null)

        {

            if (vote.VoteFor) decision.VoteFor = (decision.VoteFor ?? 0) + 1;

            if (vote.VoteAgainst) decision.VoteAgainst = (decision.VoteAgainst ?? 0) + 1;

            if (vote.VoteAbstain) decision.VoteAbstain = (decision.VoteAbstain ?? 0) + 1;

            decision.Result = $"За: {decision.VoteFor}, Против: {decision.VoteAgainst}, Воздержались: {decision.VoteAbstain}";

        }

    }

    minutes.Save();

}

Роль согласования «Участники голосования»

Ограничиваем доступ роли только для протоколов:

csharp

public override List<IDocumentKind> Filter(List<IDocumentKind> kinds)

{

    var query = base.Filter(kinds);

    if (_obj.Type == RoleType.MinutesVoters)

        query = query.Where(k => k.DocumentType.DocumentTypeGuid == Constants.MeetingMinutesTypeGuid);

    return query.ToList();

}

Как это связано с автоматизацией договоров

Голосование в задаче согласования — частный случай коллегиального принятия решений. Но тот же подход используется и для согласования договоров, когда нужно собрать визы нескольких участников.

Если хотите понять, как автоматизировать работу с договорами в целом — изучите как автоматизировать работу с договорами. Там разобраны типовые сценарии.

А если нужна настройка маршрутов согласования договоров — посмотрите согласование договоров.

Итог

Модификация позволяет:

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

Решение реализовано через low-code подход, без изменения стандартных механизмов Directum RX, что упрощает сопровождение и обновление.

Что делать дальше

Если нужна помощь с внедрением

Если хотите заказать внедрение Directum RX с подобными доработками — посмотрите заказать внедрение. Мы поможем с настройкой и кастомизацией.

Если нужна техподдержка

Если система уже работает, но нужна помощь с доработками — посмотрите техподдержка Directum. Мы поможем с обновлениями и кастомизацией.

Если хотите посмотреть кейс

Посмотрите кейс: Интеррос — как инвестиционный гигант перешёл на Directum RX за 3 месяца с кастомизацией под свои процессы.

FAQ: частые вопросы

Можно ли реализовать голосование без доработок?

Нет. Стандартные механизмы Directum RX не поддерживают полноценное голосование с фиксацией позиций. Требуется модификация, но её можно реализовать через low-code.

Подбор решения за 60 секунд
Ответьте на 4 коротких вопроса, и мы бесплатно подберём для вас оптимальное решение на базе Directum RX