Refactor workflow closure logic and enhance API

Updated `CloseWorkflowCommand` to use nullable `Code` and `Message` properties for better result representation. Refactored `CloseWorkflowCommandHandler` to use a capitalized `Repo` and improved exception handling with `InvalidWorkflowPayloadException`. Enhanced `WorkflowsController` by implementing the `CloseAsync` method, which now processes `CloseWorkflowReqBody` and returns appropriate HTTP status codes. Updated XML documentation for clarity.
This commit is contained in:
2026-11-04 10:07:33 +01:00
parent 3c3744c0ce
commit 8c6102d161
3 changed files with 47 additions and 23 deletions

View File

@@ -11,5 +11,5 @@ public sealed record CloseWorkflowCommand(
byte? RejectionReasonId) : IRequest<CloseWorkflowResult>;
public sealed record CloseWorkflowResult(
int ResultCode,
string ResultMessage);
int? Code,
string Message);

View File

@@ -1,16 +1,14 @@
using DigitalData.TaskFlow.Application.Common.Exceptions;
using DigitalData.TaskFlow.Application.Common.Interfaces;
using MediatR;
namespace DigitalData.TaskFlow.Application.Features.Workflows.Commands;
public sealed class CloseWorkflowCommandHandler(IWorkflowRepository repo)
: IRequestHandler<CloseWorkflowCommand, CloseWorkflowResult>
public sealed class CloseWorkflowCommandHandler(IWorkflowRepository Repo) : IRequestHandler<CloseWorkflowCommand, CloseWorkflowResult>
{
public async Task<CloseWorkflowResult> Handle(
CloseWorkflowCommand request,
CancellationToken cancellationToken)
public async Task<CloseWorkflowResult> Handle(CloseWorkflowCommand request, CancellationToken cancellationToken)
{
var procedureResult = await repo.CloseAsync(
var procedureResult = await Repo.CloseAsync(
userId: request.WisagId,
source: request.Source,
processId: request.ProcessId,
@@ -19,14 +17,10 @@ public sealed class CloseWorkflowCommandHandler(IWorkflowRepository repo)
rejectionReasonId: request.RejectionReasonId,
cancellationToken: cancellationToken);
if (procedureResult?.Code is null)
{
throw new InvalidOperationException(
"Stored procedure returned an invalid close result.");
}
return new CloseWorkflowResult(
ResultCode: procedureResult.Code.Value,
ResultMessage: procedureResult.Result ?? string.Empty);
return procedureResult is null
? throw new InvalidWorkflowPayloadException("Close workflow closing procedure returned no result.")
: new CloseWorkflowResult(
Code: procedureResult.Code,
Message: procedureResult.Result ?? string.Empty);
}
}

View File

@@ -1,3 +1,6 @@
using DigitalData.TaskFlow.API.Models;
using DigitalData.TaskFlow.Application.Common.Exceptions;
using DigitalData.TaskFlow.Application.Features.Workflows.Commands;
using DigitalData.TaskFlow.Application.Features.Workflows.Queries;
using MediatR;
using Microsoft.AspNetCore.Mvc;
@@ -29,18 +32,45 @@ public sealed class WorkflowsController(ISender sender) : ControllerBase
}
/// <summary>
///
/// Closes a workflow for a WISAG user identifier, source, and process identifier.
/// </summary>
/// <param name="wisagId"></param>
/// <param name="source"></param>
/// <param name="processId"></param>
/// <param name="body"></param>
/// <param name="source"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
[HttpPost("{wisagId:int}/{source}/{processId:long}/closing")]
[ProducesResponseType(StatusCodes.Status501NotImplemented)]
public Task<ActionResult<JsonElement>> CloseAsync([FromRoute] int wisagId, [FromRoute] string source, [FromRoute] long processId, CancellationToken cancellationToken)
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> CloseAsync(
[FromRoute] int wisagId,
[FromRoute] long processId,
[FromBody] CloseWorkflowReqBody body,
[FromRoute] string source = "Ferdinand",
CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
var result = await sender.Send(
new CloseWorkflowCommand(
WisagId: wisagId,
Source: source,
ProcessId: processId,
ClosingMethodId: body.ClosingMethodId,
Comment: body.Comment,
RejectionReasonId: body.RejectionReasonId),
cancellationToken);
var metaResult = new CloseWorkflowReqResponse() { Meta = [result] };
return result.Code switch
{
0 => Ok(metaResult),
4 => BadRequest(metaResult),
6 => NotFound(metaResult),
7 => Conflict(metaResult),
_ => StatusCode(StatusCodes.Status500InternalServerError, metaResult)
};
}
}