Задача
Запретить некоторым пользователям возможность старта задачи по свободному маршруту, но оставить возможность старта задачи по типовому.
Решение
Сложность задачи заключается в том, что её нельзя решить стандартными средствами: в Директуме нет механизма, который бы запретил нажатие кнопки "Маршрут" (именно с её помощью создаются задачи по свободным маршрутам) или каким-то другим способом запретил создание
задач по свободным маршрутам.
Тем не менее, решение есть и сводится оно к созданию триггер SQL, который будет срабатывать каждый раз, когда пользователь пытается стартовать задачу по свободному маршруту и прекращать старт задачи, если этому пользователю задачи можно создавать только по ТМ.
Внимание! Все описанные ниже действия необходимо сначала выполнять на тестовой базе и, в случае удачного завершения, выполнять на рабочей. Также хочется отметить, что все изменения, которые вносятся в базу данных, необходимо вручную переносить при последующих обновлениях версии системы.
Шаг 1. В DIRECTUM создаем группу пользователей, которым запрещено создавать задачи по свободным маршрутам.
Имя: StandardRouteOnlyUsersGroup
Полное имя: Стартуют задачи только по типовым маршрутам
Запоминаем её ИД (пригодится дальше).
Шаг 2. Заполняем группу нужными пользователями
Шаг 3. Создаем константу, в которой указываем ИД только что созданной группы пользователей.
Имя: StandardRouteOnlyUsersGroup
Значение: ИД только что созданной группы пользователей
Примечание: ИД группы пользователей, которые могут стартовать задачи только по типовым маршрутам
Шаг 4. SQL-запросом создаем сообщение, которое будет выводиться пользователям при попытке старта задачи по свободному маршруту (2000 в запросе - код ошибки, который используется в триггере). Сообщение об ошибке можно написать любое.
insert XErrors(ErrCode, ErrGroup, Description, SrvCode, ErrType, Sost)
values(20000, 'XMBMSG', 'Нельзя создавать задачи по свободным маршрутам. Для создания задачи воспользуйтесь кнопкой Типовой маршрут', null, 16, 'Н')
update XErrors
set Sost='З'
where ErrCode=20000 and Sost='Н'
Шаг 5. SQL-запросом создаем триггер StandardRouteOnly для таблицы SBTask (сердце решения), который будет срабатывать в момент старта задачи и будет проверять, может ли текущий пользователь стартовать задачи по указанному маршруту.
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE TRIGGER [dbo].[StandardRouteOnly] ON [dbo].[SBTask] AFTER UPDATE
AS
DECLARE
@Route VARCHAR(1), — маршрут задчи (NULL - свободный)
@State VARCHAR(1), — состояние задачи (W - "В работе")
@Author INT, — автор задачи (для получения пользователя)
@UserID INT, — ИД пользователя автора
@UsersGroup NVARCHAR(255) — группа пользователей, которым запрещено стартовать задачи по свободным маршрутам
-- получить маршрут задачи
SET @Route = (SELECT StandardRoute FROM Inserted)
-- получить состояние задачи
SET @State = (SELECT State FROM Inserted)
-- получить автора задачи
SET @Author = (SELECT Author FROM Inserted)
-- получить ИД пользователя автора
SET @UserID = (SELECT MBUser.UserID
FROM MBUser
INNER JOIN MBAnalit ON MBuser.Userkod = MBAnalit.Dop
WHERE Analit = @Author)
-- получить группу пользователей из константы StandardRouteOnlyUsersGroup
SET @UsersGroup = (SELECT VALUE FROM MBConst WHERE Const = 'StandardRouteOnlyUsersGroup')
IF @Route IS NULL AND @State = 'W'
-- идет попытка старта задачи по свободному маршруту
BEGIN
IF @UsersGroup IN (SELECT GroupID FROM MBUserLinkFull WHERE UserID = @UserID)
-- пользователь входит в группу StandardRouteOnlyUsersGroup
BEGIN
-- откатить действие и выдать сообщение об ошибке
ROLLBACK TRANSACTION
EXEC XRaisError @ErrCode = 20000
RETURN
END
END
GO
Теперь каждый раз, когда пользователь, входящий в группу StandardRouteOnlyUsersGroup попытается стартовать задачу по свободному маршруту, он получит вот такое сообщение:
Огромное спасибо Артуру за подсказку решения, Мохаммеду за красивый триггер и Антону за задачу.
Комментарий для привлечения внимания (материал почему-то не попал в RSS-ленту).
А не слетит ли этот триггер при каждой перегенерации серверной части? В том числе при переносе базы с одного сервера на другой, при обновлении системы... Триггеры, насколько я помню, удаляются и создаются заново при этом.
Слетит. И сообщение об ошибке слетит (которое в таблицу XErrors добавляется).
Поэтому и написал, что все манипуляции с базой - создание сообщения об ошибке и создание триггера - необходимо выполнять каждый раз, при обновлении системы (в том числе и про активации системы с помощью SASystemActivator).
Для удобства можно объединить операцию по созданию сообщения и созданию триггера в один запрос и выполнять его после активации/конвертации/переноса базы.
А, ведь такую задачу ставило передо мной руководство и сказано было технарями- нельзя запретить. Пойду обрадую. Спасибо!
Отличный материал! Нужно предусмотреть такую группу и триггер в базовой поставке DIRECTUM.
И сразу вопрос: воможен ли аналогичный механизм при такой постановке задачи: "Нельзя отправлять задачу по свободному маршруту конкретному исполнителю". Например: чтоб генеральному директору (или губернатору области) ФИЗИЧЕСКИ никто никогда "свободные" задачи отсылать не мог - только через ТМ по строго определенным процессам (после всех необходимых согласований). А то сейчас для этого только механизм правил используем (чистим его папку "Входящие" от "свободных" заданий и перекидываем их в папку, которая у помошника - для дальнейшего разбирательства.
Материал без сомнений полезный, убеждён не малое количество компаний нуждается в подобном.
Я думаю есть смысл всё тонкости триггера обсуждать на одноимённой теме форума:
http://club.directum.ru/forum/topic1152-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D1%82%D0%B8%D0%BF%D0%BE%D0%B2%D1%8B%D1%85-%D0%BC%D0%B0%D1%80%D1%88%D1%80%D1%83%D1%82%D0%BE%D0%B2-.aspx
Дмитрий, возможен. Для этого:
1. Создаете константу с нужным названием.
2. В неё записываете ИД пользователя, которому нельзя стартовать задачи по свободным маршрутам.
3. Создаете нужное сообщение в таблице XErrors.
4. Меняете триггер таким образом, чтобы вместо автора задачи получался список пользователей, которые указаны в маршруте, а затем проверяете, входит ли указанный в константе пользователей в список этих пользователей. Делается это примерно так:
А лучше не константу, а справочник, чтоб указывать в справочнике ИД пользователей :)
Иван, добрый день. Очень хороший материал, помог в решении задачи. Возникла единственная проблема, может поможете с решением. Задача на запрет ручных задач, поставилась не с самого момента внедрения системы, то есть накопилось много уже стартованных ручных задач, в том числе и сейчас в работе их очень много.
Если создаю триггер, то у всех пользователей существующие задачи прекращаются с ошибкой
"IS-Builder System User (ISBuilderSystem) за ПОЛЬЗОВАТЕЛЯ [26.08.2013 16:26:55] :
Выполнение задачи прервано по причине: "Вам нельзя создавать задачи по свободным маршрутам. Для создания задачи выберите Типовой маршрут Розница - Постановка задач|SQL State: 42000, SQL Error Code: 50349"."
Может подскажете как можно ее избежать? Спасибо большое.
Как вариант, в триггере дополнительно проверять дату старта задачи (чтобы позволить рестартовать старые задачи, еще и историю можно дополнительно проверить).
Кстати так же тем кому необходимо запретить запуск задачи по свободному маршруту, но разрешить запуск подзадач - необходимо в триггер добавить следующие параметры:
В современных реалиях надо код ошибки указывать более 50 000. Предлагаю автору чуть откорректировать статью.
Кстати возможно следует учесть и последнее замечание про подзадачи и также внести их в текст статьи.
SQL State: 42000, SQL Error Code: 52654
как быть? кто что делал?
Константин, а сама ошибка как звучит(поле с текстом ошибки из таблицы XErrors)?
Большое спасибо. все получилось. Рестартнул сервак и все норм встало
Есть вопрос по выводу сообщений об ошибке.
Добавили строку в таблицу XErrors, но при попытке вывести - идёт просто ошибка SQL, без вывода нашего сообщения. Или вывод идёт только Англоязычного сообщения.
Это на SQL 2005, на SQL 2008 R2 - всё хорошо.
Есть ли вариант какой-то работы функции XRaisError без использования дополнительной таблицы XErrors с текстом? Как еще можно вывести ошибку на экран пользователя.
Опа похоже ошибка то похожая же как и в прошлом сообщении...
Рестартовать скул похоже... надо.
Перезагрузка не помогла.
Такое ощущение, что какая-то нестыковка сообщений с сообщениями в master.dbo.sysmessages.
Подскажите как всё же вывести нормальное сообщение об ошибке с текстом?
Попробуйте вместо
вот так
подробнее можно глянуть в справку по функции raiserror по SQL Server
Да, я RAISERROR и использую в итоге для вывода.
В общем, если кому интересно, придумал такой вариант.
Создавать спец.группы людей, между которыми разрешены свободные маршруты.
Например Бухгалтерия_маршрут, Юристы_маршрут, Кассиры_маршрут
Теперь все кто включен в одну и ту же группу - могут друг другу писать, а если общей группы нет, то писать не могут.
Одновременно человек может быть сразу в нескольких группах.
Для начальников создал группу StandardRouteAlwaysUsersGroup - они могут писать кому угодно.
В итоге получился навороченный триггер. Его конечно еще можно дорабатывать, например, не учитывается получатели "Наблюдатели", а так же если идёт отправка сразу нескольким сотрудникам у которых нет общей группы между собой (а есть только общие с отправителем) - то отправку тоже запрещает.
Пришлось правда еще использовать функцию преобразования текста, в таблицу и переводить ID пользователей к одному типу. Но в целом работает.
Понимаю, что основной запрос получился несколько запутанным для понимания... Возможно, зная структуру точнее можно его упростить... Но если просить у специалистов реализацию этой функции, то стоимость вызывает желание сделать всё самому...
Еще доработочка:
Проверку производить через "if not exists (", а не через "if () is null"
И дописать DISTINCT в строку:
HAVING COUNT(MBUser.UserName) = (select COUNT(DISTINCT item) from Split(@ParticipantsIDs, ','))
===========
В общем дорабатывать есть куда, думаю после тестирования вылезет еще что-нибудь.
лучше оформите в виде отдельной статьи! думаю многие пропустят ваш полезный триггер в этих комментариях
Те, кому интересно - найдут исходный вариант, и исходя из комментариев - додумают свой... как собственно я и сделал, просто кому-то поможет этот код, чтобы не придумывать алгоритм и реализацию.
К тому же, у меня не идеально законченный вариант.
Смысл его в том, что анализируются отправитель и получатели, и если они все имеют общую группу с определенным типом называния, то маршрут разрешается. Технические особенности же в том, чтобы выцепить IDшники участников, запросом получить необходимые типы групп и посмотреть есть ли группа, которая встречается столько же раз, сколько участников.
Вариант типовыми средставми на скорую руку: Создаем закольцованный типовой маршрут, который раз в минуту или чаще, в зависимости от нагрузки на Workflow, находит все незавершенные задачи запущенные по свободному маршруту и принудительно завершает их, отправляя уведомление инициатору. Если необходимо оставить кому-то возможность отправлять по свободному маршруту - добавляем еще одно условие перед тем как завершить задачу.
А можно ли это сделать не для группы пользователей, а для определенных типов карточек эл. документов?
т.е. если есть во сложении задачи этот тип карточки то выдавать сообщение, что данные документы можно отправлять только по типовому маршруту.
А если в поле инициатор выбрать пользователя которому не запрещен старт по свободному маршруту?
Авторизуйтесь, чтобы написать комментарий