Перейти к содержанию

Изменение состояния карточки, которое было добавлено в таблицу-перечисление KrDocState

Изменение состояния карточки, которое было добавлено в таблицу-перечисление KrDocState

Состояния карточки, которые использует типовое решение, содержатся в таблице KrDocState. Чтобы добавить новые состояния карточки (например, “В архиве”, “На доработке” и пр.), нужно добавить записи в эту таблицу с опциональной локализацией. Для этого в редакторе схемы данных надо выбрать таблицу, перейти на узел “Записи” и вставить строки с состояниями. Тогда все представления и правила доступа типового решения получат возможность использовать это состояние для фильтрации и разделения прав.

Для того, чтобы перевести карточку в новое состояние в расширениях (например, в бизнес-процессах Workflow API), требуется написать и вызвать метод SetKrStateAsync.

Задание состояния необходимо выполнять с помощью объекта IKrDocumentStateManager. Это позволяет обеспечить единообразие при задании состояния. В типовой реализации интерфейса IKrDocumentStateManager, объект KrDocumentStateManager копирует информацию о состоянии в поля DocumentCommonInfo.StateID и DocumentCommonInfo.StateName, если сответствующие поля включены в пакет карточки. Это позволяет оптимизировать запросы. Например:

SELECT [dci].[ID], [aci].[StateID], [aci].[StateName] FROM [DocumentCommonInfo] AS [dci] WITH (NOLOCK) LEFT JOIN [KrApprovalCommonInfo] AS [aci] WITH (NOLOCK) ON [aci].[MainCardID] = [dci].[ID] WHERE [dci].[CardTypeID] = '335F86A1-D009-012C-8B45-1F43C2382C2D' AND [aci].[StateID] IN (0, 1, 2, 3);

Следующим образом:

SELECT [dci].[ID], [dci].[StateID], [dci].[StateName] FROM [DocumentCommonInfo] AS [dci] WITH (NOLOCK) WHERE [dci].[CardTypeID] = '335F86A1-D009-012C-8B45-1F43C2382C2D' AND [dci].[StateID] IN (0, 1, 2, 3);

Примеры изменения состояния карточки

using System; using System.Threading; using System.Threading.Tasks; using Tessa.Cards; using Tessa.Extensions.Default.Server.Cards; using Tessa.Extensions.Default.Server.Workflow.KrProcess.Scope; using Tessa.Extensions.Default.Shared; using Tessa.Extensions.Default.Shared.Workflow.KrProcess; using Tessa.Platform; using Tessa.Platform.Validation;

namespace Tessa.Extensions.Server { public static class SetKrStateExamples { /// <summary> /// Устанавливает состояние документа. /// /// Данный способ следует использовать, если выполнение происходит вне транзакции на сохранение /// (CardStoreExtension AfterBeginTransaction/BeforeCommitTransaction). /// </summary> /// <param name="cardRepository"> /// Репозиторий для управления карточками с расширениями /// (<see cref="CardRepositoryNames.Extended"/> или <see cref="CardRepositoryNames.ExtendedWithoutTransaction"/>). /// </param> /// <param name="krDocumentStateManager">Объект управляющий состоянием карточки документа.</param> /// <param name="mainCard">Карточка документа.</param> /// <param name="state">Состояние документа.</param> /// <param name="validationResult">Реультат валидации.</param> /// <param name="cancellationToken">Объект, посредством которого можно отменить асинхронную задачу.</param> /// <returns>Асинхронная задача.</returns> public static async Task SetKrStateAsync( ICardRepository cardRepository, IKrDocumentStateManager krDocumentStateManager, Card mainCard, KrState state, IValidationResultBuilder validationResult, CancellationToken cancellationToken = default) { Check.ArgumentNotNull(cardRepository, nameof(cardRepository)); Check.ArgumentNotNull(krDocumentStateManager, nameof(krDocumentStateManager)); Check.ArgumentNotNull(mainCard, nameof(mainCard)); Check.ArgumentNotNull(validationResult, nameof(validationResult));

// Карточка-сателлит будет автоматически создана, если она отсутствовала при загрузке. Card satellite = await GetKrSatelliteCardAsync( cardRepository, mainCard.ID, validationResult, cancellationToken);

if (satellite is null) { return; }

(_, bool hasMainSatelliteChanges, _) = await krDocumentStateManager.SetStateAsync( mainCard, satellite, state, cancellationToken);

if (!hasMainSatelliteChanges) { return; }

satellite.RemoveAllButChanged();

CardStoreRequest storeRequest = new CardStoreRequest { Card = satellite }; CardStoreResponse storeResponse = await cardRepository.StoreAsync(storeRequest, cancellationToken); validationResult.Add(storeResponse.ValidationResult); }

/// <summary> /// Возвращает карточку основного сателлита карточки документа. /// </summary> /// <param name="cardRepository">Репозиторий для управления карточками.</param> /// <param name="mainCardID">Идентификатор карточки документа.</param> /// <param name="validationResult">Результат валидации.</param> /// <param name="cancellationToken">Объект, посредством которого можно отменить асинхронную задачу.</param> /// <returns>Асинхронная задача содержащая карточку основного сателлита /// или значение <see langword="null"/>, если при выполнении произошла ошибка.</returns> public static async Task<Card> GetKrSatelliteCardAsync( ICardRepository cardRepository, Guid mainCardID, IValidationResultBuilder validationResult, CancellationToken cancellationToken = default) { Check.ArgumentNotNull(cardRepository, nameof(cardRepository)); Check.ArgumentNotNull(validationResult, nameof(validationResult));

CardGetRequest getRequest = new CardGetRequest { CardID = mainCardID, CardTypeID = DefaultCardTypes.KrSatelliteTypeID, RestrictionFlags = CardGetRestrictionValues.Satellite, };

// Если мы внутри Workflow API, то необходимо добавить строку, // чтобы блокировка на основную карточку не бралась: getRequest.SetNoLockingMainCard(true);

CardGetResponse response = await cardRepository.GetAsync( getRequest, cancellationToken); validationResult.Add(response.ValidationResult); return response.ValidationResult.IsSuccessful() ? response.Card : null; }

/// <summary> /// Устанавливает состояние документа. /// /// Данный способ следует использовать, если выполнение происходит в транзакции на сохранение /// (CardStoreExtension AfterBeginTransaction/BeforeCommitTransaction). /// </summary> /// <param name="krScope">Объект предоставляющий методы для работы с текущим контекстом расширений /// типового решения и использования разделяемых объектов карточек.</param> /// <param name="krDocumentStateManager">Объект управляющий состоянием карточки документа.</param> /// <param name="mainCard">Карточка документа.</param> /// <param name="state">Состояние документа.</param> /// <param name="validationResult">Реультат валидации.</param> /// <param name="cancellationToken">Объект, посредством которого можно отменить асинхронную задачу.</param> /// <returns>Асинхронная задача.</return public static async Task SetKrStateAsync( IKrScope krScope, IKrDocumentStateManager krDocumentStateManager, Card mainCard, KrState state, IValidationResultBuilder validationResult, CancellationToken cancellationToken = default) { Check.ArgumentNotNull(krScope, nameof(krScope)); Check.ArgumentNotNull(krDocumentStateManager, nameof(krDocumentStateManager)); Check.ArgumentNotNull(mainCard, nameof(mainCard)); Check.ArgumentNotNull(validationResult, nameof(validationResult));

// Сателлит будет сохранён автоматически при выходе из уровня контекста KrScopeContext // в Tessa.Extensions.Default.Server.Workflow.KrProcess.Scope.KrLifecycleScopeStoreExtension. Card satellite = await krScope.GetKrSatelliteAsync( mainCard.ID, validationResult, cancellationToken);

await krDocumentStateManager.SetStateAsync( mainCard, satellite, state, cancellationToken); } } }

Important

В сборке 2.2 и более ранних при использовании метода GetSatelliteCard внутри Workflow API карточка-сателлит уже должна быть создана. В противном случае будет отброшена транзакция Workflow, и будет создана транзакция на создание сателлита. Это можно сделать, вызвав метод GetSatelliteCard в запросе BeforeRequest перед запуском бизнес-процесса.

Чтобы состояние карточки отображалось в блоке KrBlockForDocStatus даже в том случае, когда не используется типовой процесс согласования и регистрации, следует изменить расширение KrHideApprovalTabOrDocStateBlockUIExtension в типовом решении в проекте Tessa.Extensions.Default.Client, убрав вызов метода CollapseSpecialBlock.

// Удалить строки ниже: // скрываем специальный блок с состоянием документа, если нет согласования и регистрации //if (usedComponents.HasNot(KrComponents.Routes) // && usedComponents.HasNot(KrComponents.Registration)) //{ // CollapseSpecialBlock(model); //}

Back to top