feat(infrastructure): add DB options and workflow close outcome evaluation

This commit is contained in:
2026-10-10 16:12:17 +02:00
parent be41adc0f3
commit b6aec7a16b
4 changed files with 171 additions and 9 deletions

View File

@@ -1,15 +1,18 @@
using DigitalData.TaskFlow.Application.Common.Interfaces;
using DigitalData.TaskFlow.Domain.Closing;
using DigitalData.TaskFlow.Domain.Workflows;
using DigitalData.TaskFlow.Infrastructure.Options;
using DigitalData.TaskFlow.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System.Text.Json;
namespace DigitalData.TaskFlow.Infrastructure.Repositories;
/// <summary>
/// Workflow repository implementation for reading workflow listing data and applying close operations.
/// </summary>
public sealed class WorkflowRepository(TaskFlowDbContext dbContext) : IWorkflowRepository
public sealed class WorkflowRepository(TaskFlowDbContext dbContext, IOptions<DatabaseOptions> databaseOptions) : IWorkflowRepository
{
/// <summary>
/// Retrieves grouped workflow data for a user.
@@ -20,7 +23,9 @@ public sealed class WorkflowRepository(TaskFlowDbContext dbContext) : IWorkflowR
public async Task<WorkflowSourcesResponse> GetAsync(int wisagId, CancellationToken cancellationToken)
{
const string resultType = "table";
const string objectType = "Ferdinand";
var objectType = string.IsNullOrWhiteSpace(databaseOptions.Value.WorkflowListingObjectType)
? "Ferdinand"
: databaseOptions.Value.WorkflowListingObjectType;
var rows = await dbContext
.WorkflowListingReadModels
@@ -28,6 +33,19 @@ public sealed class WorkflowRepository(TaskFlowDbContext dbContext) : IWorkflowR
.AsNoTracking()
.ToListAsync(cancellationToken);
if (rows.Count == 0)
{
var metaCode = await TryGetWorkflowMetaCodeAsync(wisagId, objectType, cancellationToken);
if (metaCode == 2)
{
return new WorkflowSourcesResponse
{
Sources = []
};
}
}
var listing = rows
.Select(row => new WorkflowListingItem
{
@@ -94,7 +112,119 @@ public sealed class WorkflowRepository(TaskFlowDbContext dbContext) : IWorkflowR
CloseWorkflowDecision decision,
CancellationToken cancellationToken)
{
throw new NotSupportedException(
"Closing write procedure is not finalized yet. Configure final DB procedure mapping before enabling CloseAsync.");
_ = decision;
if (!string.Equals(source, "Ferdinand", StringComparison.OrdinalIgnoreCase))
{
return Task.FromResult(new CloseWorkflowResult
{
ProcessId = processId,
IsClosed = false,
Outcome = CloseWorkflowOutcome.NotFound
});
}
return EvaluateCloseOutcomeAsync(wisagId, processId, cancellationToken);
}
private async Task<CloseWorkflowResult> EvaluateCloseOutcomeAsync(
int wisagId,
int processId,
CancellationToken cancellationToken)
{
var activeForUser = await dbContext.Database
.SqlQuery<int>($"SELECT COUNT(1) FROM dbo.TBCUST_F19_LISTING_RESULT WHERE userid = {wisagId} AND processid = {processId}")
.SingleAsync(cancellationToken);
if (activeForUser > 0)
{
return new CloseWorkflowResult
{
ProcessId = processId,
IsClosed = true,
Outcome = CloseWorkflowOutcome.Closed
};
}
var activeAnyUser = await dbContext.Database
.SqlQuery<int>($"SELECT COUNT(1) FROM dbo.TBCUST_F19_LISTING_RESULT WHERE processid = {processId}")
.SingleAsync(cancellationToken);
if (activeAnyUser > 0)
{
return new CloseWorkflowResult
{
ProcessId = processId,
IsClosed = false,
Outcome = CloseWorkflowOutcome.NoAccess
};
}
var inHistory = await dbContext.Database
.SqlQuery<int>($"SELECT COUNT(1) FROM dbo.TBMWF_PROFILE_OBJ_STATE_HISTORY WHERE OBJ_ID = {processId}")
.SingleAsync(cancellationToken);
if (inHistory > 0)
{
return new CloseWorkflowResult
{
ProcessId = processId,
IsClosed = false,
Outcome = CloseWorkflowOutcome.AlreadyClosed
};
}
return new CloseWorkflowResult
{
ProcessId = 0,
IsClosed = false,
Outcome = CloseWorkflowOutcome.NotFound
};
}
private async Task<int?> TryGetWorkflowMetaCodeAsync(int wisagId, string objectType, CancellationToken cancellationToken)
{
const string resultType = "json";
var jsonPayload = await dbContext.Database
.SqlQuery<string>($"EXEC dbo.PRCUST_F19_GET_LISTING_DATA @pUSER_ID={wisagId}, @pRESULT_TYPE={resultType}, @pOBJECT_TYPE={objectType}")
.AsNoTracking()
.FirstOrDefaultAsync(cancellationToken);
if (string.IsNullOrWhiteSpace(jsonPayload))
{
return null;
}
try
{
using var document = JsonDocument.Parse(jsonPayload);
if (!document.RootElement.TryGetProperty("response", out var responseElement))
{
return null;
}
if (!responseElement.TryGetProperty("meta", out var metaElement) || metaElement.ValueKind != JsonValueKind.Array)
{
return null;
}
if (metaElement.GetArrayLength() == 0)
{
return null;
}
if (!metaElement[0].TryGetProperty("code", out var codeElement))
{
return null;
}
return codeElement.GetInt32();
}
catch (JsonException)
{
return null;
}
}
}