feat(kitchen-service): expand kitchen workflow contracts
This commit is contained in:
parent
02cf18a0a6
commit
119f23ca66
@ -4,4 +4,7 @@
|
|||||||
<Project Path="src/Kitchen.Service.Contracts/Kitchen.Service.Contracts.csproj" />
|
<Project Path="src/Kitchen.Service.Contracts/Kitchen.Service.Contracts.csproj" />
|
||||||
<Project Path="src/Kitchen.Service.Grpc/Kitchen.Service.Grpc.csproj" />
|
<Project Path="src/Kitchen.Service.Grpc/Kitchen.Service.Grpc.csproj" />
|
||||||
</Folder>
|
</Folder>
|
||||||
|
<Folder Name="/tests/">
|
||||||
|
<Project Path="tests/Kitchen.Service.Application.UnitTests/Kitchen.Service.Application.UnitTests.csproj" />
|
||||||
|
</Folder>
|
||||||
</Solution>
|
</Solution>
|
||||||
|
|||||||
27
docs/api/internal-kitchen-workflows.md
Normal file
27
docs/api/internal-kitchen-workflows.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Internal Kitchen Workflow Contracts
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
`kitchen-service` now exposes a board-oriented internal workflow surface that the kitchen-ops BFF can consume directly.
|
||||||
|
|
||||||
|
## Endpoint Surface
|
||||||
|
|
||||||
|
- `GET /internal/kitchen/queue?queueName=<name>&limit=<n>`
|
||||||
|
- `POST /internal/kitchen/orders/transition`
|
||||||
|
- `GET /internal/kitchen/board?contextId=<id>`
|
||||||
|
- `POST /internal/kitchen/work-items/claim`
|
||||||
|
- `POST /internal/kitchen/work-items/priority`
|
||||||
|
|
||||||
|
## Contract Depth Added In Stage 41
|
||||||
|
|
||||||
|
The new kitchen workflow contracts add enough shape for downstream BFF and SPA work:
|
||||||
|
|
||||||
|
- board lanes with per-item station, claim, ETA, and priority details
|
||||||
|
- explicit claim/release-ready work-item ownership responses
|
||||||
|
- dedicated priority update responses separate from generic state transitions
|
||||||
|
- existing transition contract kept in place for order-state changes
|
||||||
|
|
||||||
|
## Current Runtime Shape
|
||||||
|
|
||||||
|
- The default implementation remains deterministic and in-memory.
|
||||||
|
- This repo still focuses on orchestration and contract shape, not kitchen persistence realism.
|
||||||
@ -13,6 +13,7 @@ kitchen-service
|
|||||||
- Kitchen queue and dispatch optimization hooks.
|
- Kitchen queue and dispatch optimization hooks.
|
||||||
- Operations control-plane policies (flags, service windows, overrides).
|
- Operations control-plane policies (flags, service windows, overrides).
|
||||||
- POS closeout and settlement summary alignment.
|
- POS closeout and settlement summary alignment.
|
||||||
|
- Kitchen board lanes, claim ownership, and priority updates aligned to operator workflows.
|
||||||
|
|
||||||
## Documentation Contract
|
## Documentation Contract
|
||||||
Any code change in this repository must include docs updates in the same branch.
|
Any code change in this repository must include docs updates in the same branch.
|
||||||
|
|||||||
@ -23,6 +23,7 @@ docker run --rm -p 8080:8080 --name kitchen-service agilewebs/kitchen-service:de
|
|||||||
## Runtime Notes
|
## Runtime Notes
|
||||||
|
|
||||||
- Exposes internal queue and order state transition endpoints.
|
- Exposes internal queue and order state transition endpoints.
|
||||||
|
- Also exposes board, work-item claim, and priority update endpoints for the kitchen-ops BFF flow.
|
||||||
|
|
||||||
## Health Endpoint Consistency
|
## Health Endpoint Consistency
|
||||||
|
|
||||||
@ -38,3 +39,4 @@ docker run --rm -p 8080:8080 --name kitchen-service agilewebs/kitchen-service:de
|
|||||||
|
|
||||||
- Current runtime adapters are still predominantly in-memory for deterministic local/demo behavior.
|
- Current runtime adapters are still predominantly in-memory for deterministic local/demo behavior.
|
||||||
- Demo PostgreSQL seeds validate integration contracts and smoke determinism, but do not yet imply full persistence implementation parity.
|
- Demo PostgreSQL seeds validate integration contracts and smoke determinism, but do not yet imply full persistence implementation parity.
|
||||||
|
- Stage 41 adds kitchen workflow contract depth first; downstream BFFs still need to adopt these endpoints before richer board behavior reaches the web app.
|
||||||
|
|||||||
@ -0,0 +1,88 @@
|
|||||||
|
using Kitchen.Service.Contracts.Contracts;
|
||||||
|
using Kitchen.Service.Contracts.Requests;
|
||||||
|
using Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Application.Ports;
|
||||||
|
|
||||||
|
public sealed class DefaultKitchenWorkflowPort : IKitchenWorkflowPort
|
||||||
|
{
|
||||||
|
public Task<GetKitchenBoardResponse> GetKitchenBoardAsync(GetKitchenBoardRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var lanes = new[]
|
||||||
|
{
|
||||||
|
new KitchenBoardLaneContract(
|
||||||
|
"queued",
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new KitchenBoardItemContract("WK-1001", "CO-1001", "KT-1001", "T-08", "hot-line", "Queued", 3, null, 12),
|
||||||
|
new KitchenBoardItemContract("WK-1002", "CO-1003", "KT-1002", "T-12", "expedite", "Queued", 2, null, 8)
|
||||||
|
}),
|
||||||
|
new KitchenBoardLaneContract(
|
||||||
|
"preparing",
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new KitchenBoardItemContract("WK-1003", "CO-1002", "KT-1003", "T-15", "grill", "Preparing", 4, "chef-maya", 5)
|
||||||
|
}),
|
||||||
|
new KitchenBoardLaneContract(
|
||||||
|
"ready",
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new KitchenBoardItemContract("WK-1004", "CO-0999", "KT-0999", "T-21", "pickup", "ReadyForPickup", 1, "expo-noah", 0)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
return Task.FromResult(new GetKitchenBoardResponse(
|
||||||
|
request.ContextId,
|
||||||
|
"Kitchen board shows queued, preparing, and ready lanes for the current service context.",
|
||||||
|
lanes,
|
||||||
|
new[] { "hot-line", "grill", "salad", "pickup", "expedite" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ClaimKitchenWorkItemResponse> ClaimKitchenWorkItemAsync(ClaimKitchenWorkItemRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var claimed = !string.IsNullOrWhiteSpace(request.ContextId) &&
|
||||||
|
!string.IsNullOrWhiteSpace(request.WorkItemId) &&
|
||||||
|
!string.IsNullOrWhiteSpace(request.ClaimedBy);
|
||||||
|
|
||||||
|
return Task.FromResult(new ClaimKitchenWorkItemResponse(
|
||||||
|
request.ContextId,
|
||||||
|
request.WorkItemId,
|
||||||
|
claimed,
|
||||||
|
request.ClaimedBy,
|
||||||
|
claimed
|
||||||
|
? $"Work item {request.WorkItemId} claimed by {request.ClaimedBy}."
|
||||||
|
: "Kitchen work-item claim is incomplete."));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<UpdateKitchenPriorityResponse> UpdateKitchenPriorityAsync(UpdateKitchenPriorityRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var priority = Math.Max(1, request.Priority);
|
||||||
|
return Task.FromResult(new UpdateKitchenPriorityResponse(
|
||||||
|
request.ContextId,
|
||||||
|
request.WorkItemId,
|
||||||
|
priority,
|
||||||
|
$"Priority for {request.WorkItemId} updated to {priority} by {request.RequestedBy}."));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<TransitionKitchenOrderStateResponse> TransitionKitchenOrderStateAsync(TransitionKitchenOrderStateRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var previous = "Queued";
|
||||||
|
var allowed = request.TargetState is "Preparing" or "ReadyForPickup" or "Canceled" or "Plated";
|
||||||
|
|
||||||
|
return Task.FromResult(new TransitionKitchenOrderStateResponse(
|
||||||
|
request.OrderId,
|
||||||
|
request.TicketId,
|
||||||
|
previous,
|
||||||
|
allowed ? request.TargetState : previous,
|
||||||
|
allowed,
|
||||||
|
allowed ? null : "Target state is not allowed by kitchen-service policy."));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using Kitchen.Service.Contracts.Requests;
|
||||||
|
using Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Application.Ports;
|
||||||
|
|
||||||
|
public interface IKitchenWorkflowPort
|
||||||
|
{
|
||||||
|
Task<GetKitchenBoardResponse> GetKitchenBoardAsync(GetKitchenBoardRequest request, CancellationToken cancellationToken);
|
||||||
|
Task<ClaimKitchenWorkItemResponse> ClaimKitchenWorkItemAsync(ClaimKitchenWorkItemRequest request, CancellationToken cancellationToken);
|
||||||
|
Task<UpdateKitchenPriorityResponse> UpdateKitchenPriorityAsync(UpdateKitchenPriorityRequest request, CancellationToken cancellationToken);
|
||||||
|
Task<TransitionKitchenOrderStateResponse> TransitionKitchenOrderStateAsync(TransitionKitchenOrderStateRequest request, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
using Kitchen.Service.Application.Ports;
|
||||||
|
using Kitchen.Service.Contracts.Requests;
|
||||||
|
using Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Application.UseCases;
|
||||||
|
|
||||||
|
public sealed class ClaimKitchenWorkItemUseCase(IKitchenWorkflowPort workflowPort) : IClaimKitchenWorkItemUseCase
|
||||||
|
{
|
||||||
|
public Task<ClaimKitchenWorkItemResponse> HandleAsync(ClaimKitchenWorkItemRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return workflowPort.ClaimKitchenWorkItemAsync(request, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
using Kitchen.Service.Application.Ports;
|
||||||
|
using Kitchen.Service.Contracts.Requests;
|
||||||
|
using Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Application.UseCases;
|
||||||
|
|
||||||
|
public sealed class GetKitchenBoardUseCase(IKitchenWorkflowPort workflowPort) : IGetKitchenBoardUseCase
|
||||||
|
{
|
||||||
|
public Task<GetKitchenBoardResponse> HandleAsync(GetKitchenBoardRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return workflowPort.GetKitchenBoardAsync(request, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using Kitchen.Service.Contracts.Requests;
|
||||||
|
using Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Application.UseCases;
|
||||||
|
|
||||||
|
public interface IClaimKitchenWorkItemUseCase
|
||||||
|
{
|
||||||
|
Task<ClaimKitchenWorkItemResponse> HandleAsync(ClaimKitchenWorkItemRequest request, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using Kitchen.Service.Contracts.Requests;
|
||||||
|
using Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Application.UseCases;
|
||||||
|
|
||||||
|
public interface IGetKitchenBoardUseCase
|
||||||
|
{
|
||||||
|
Task<GetKitchenBoardResponse> HandleAsync(GetKitchenBoardRequest request, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using Kitchen.Service.Contracts.Requests;
|
||||||
|
using Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Application.UseCases;
|
||||||
|
|
||||||
|
public interface IUpdateKitchenPriorityUseCase
|
||||||
|
{
|
||||||
|
Task<UpdateKitchenPriorityResponse> HandleAsync(UpdateKitchenPriorityRequest request, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
using Kitchen.Service.Application.Ports;
|
||||||
|
using Kitchen.Service.Contracts.Requests;
|
||||||
|
using Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Application.UseCases;
|
||||||
|
|
||||||
|
public sealed class UpdateKitchenPriorityUseCase(IKitchenWorkflowPort workflowPort) : IUpdateKitchenPriorityUseCase
|
||||||
|
{
|
||||||
|
public Task<UpdateKitchenPriorityResponse> HandleAsync(UpdateKitchenPriorityRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return workflowPort.UpdateKitchenPriorityAsync(request, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
namespace Kitchen.Service.Contracts.Contracts;
|
||||||
|
|
||||||
|
public sealed record KitchenBoardItemContract(
|
||||||
|
string WorkItemId,
|
||||||
|
string OrderId,
|
||||||
|
string TicketId,
|
||||||
|
string TableId,
|
||||||
|
string Station,
|
||||||
|
string State,
|
||||||
|
int Priority,
|
||||||
|
string? ClaimedBy,
|
||||||
|
int EtaMinutes);
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
namespace Kitchen.Service.Contracts.Contracts;
|
||||||
|
|
||||||
|
public sealed record KitchenBoardLaneContract(
|
||||||
|
string Lane,
|
||||||
|
IReadOnlyCollection<KitchenBoardItemContract> Items);
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace Kitchen.Service.Contracts.Requests;
|
||||||
|
|
||||||
|
public sealed record ClaimKitchenWorkItemRequest(
|
||||||
|
string ContextId,
|
||||||
|
string WorkItemId,
|
||||||
|
string ClaimedBy);
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
namespace Kitchen.Service.Contracts.Requests;
|
||||||
|
|
||||||
|
public sealed record GetKitchenBoardRequest(string ContextId);
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
namespace Kitchen.Service.Contracts.Requests;
|
||||||
|
|
||||||
|
public sealed record UpdateKitchenPriorityRequest(
|
||||||
|
string ContextId,
|
||||||
|
string WorkItemId,
|
||||||
|
int Priority,
|
||||||
|
string RequestedBy);
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
public sealed record ClaimKitchenWorkItemResponse(
|
||||||
|
string ContextId,
|
||||||
|
string WorkItemId,
|
||||||
|
bool Claimed,
|
||||||
|
string ClaimedBy,
|
||||||
|
string Message);
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
using Kitchen.Service.Contracts.Contracts;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
public sealed record GetKitchenBoardResponse(
|
||||||
|
string ContextId,
|
||||||
|
string Summary,
|
||||||
|
IReadOnlyCollection<KitchenBoardLaneContract> Lanes,
|
||||||
|
IReadOnlyCollection<string> AvailableStations);
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
namespace Kitchen.Service.Contracts.Responses;
|
||||||
|
|
||||||
|
public sealed record UpdateKitchenPriorityResponse(
|
||||||
|
string ContextId,
|
||||||
|
string WorkItemId,
|
||||||
|
int Priority,
|
||||||
|
string Message);
|
||||||
@ -4,8 +4,12 @@ using Kitchen.Service.Contracts.Requests;
|
|||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
builder.Services.AddSingleton<IKitchenQueueReadPort, DefaultKitchenQueueReadPort>();
|
builder.Services.AddSingleton<IKitchenQueueReadPort, DefaultKitchenQueueReadPort>();
|
||||||
|
builder.Services.AddSingleton<IKitchenWorkflowPort, DefaultKitchenWorkflowPort>();
|
||||||
builder.Services.AddSingleton<IGetKitchenQueueUseCase, GetKitchenQueueUseCase>();
|
builder.Services.AddSingleton<IGetKitchenQueueUseCase, GetKitchenQueueUseCase>();
|
||||||
builder.Services.AddSingleton<ITransitionKitchenOrderStateUseCase, TransitionKitchenOrderStateUseCase>();
|
builder.Services.AddSingleton<ITransitionKitchenOrderStateUseCase, TransitionKitchenOrderStateUseCase>();
|
||||||
|
builder.Services.AddSingleton<IGetKitchenBoardUseCase, GetKitchenBoardUseCase>();
|
||||||
|
builder.Services.AddSingleton<IClaimKitchenWorkItemUseCase, ClaimKitchenWorkItemUseCase>();
|
||||||
|
builder.Services.AddSingleton<IUpdateKitchenPriorityUseCase, UpdateKitchenPriorityUseCase>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
@ -23,6 +27,30 @@ app.MapPost("/internal/kitchen/orders/transition", async (
|
|||||||
return Results.Ok(await useCase.HandleAsync(request, ct));
|
return Results.Ok(await useCase.HandleAsync(request, ct));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.MapGet("/internal/kitchen/board", async (
|
||||||
|
string contextId,
|
||||||
|
IGetKitchenBoardUseCase useCase,
|
||||||
|
CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
return Results.Ok(await useCase.HandleAsync(new GetKitchenBoardRequest(contextId), ct));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapPost("/internal/kitchen/work-items/claim", async (
|
||||||
|
ClaimKitchenWorkItemRequest request,
|
||||||
|
IClaimKitchenWorkItemUseCase useCase,
|
||||||
|
CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
return Results.Ok(await useCase.HandleAsync(request, ct));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.MapPost("/internal/kitchen/work-items/priority", async (
|
||||||
|
UpdateKitchenPriorityRequest request,
|
||||||
|
IUpdateKitchenPriorityUseCase useCase,
|
||||||
|
CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
return Results.Ok(await useCase.HandleAsync(request, ct));
|
||||||
|
});
|
||||||
|
|
||||||
app.MapGet("/health", () => Results.Ok(new { status = "ok", service = "kitchen-service" }));
|
app.MapGet("/health", () => Results.Ok(new { status = "ok", service = "kitchen-service" }));
|
||||||
app.MapGet("/healthz", () => Results.Ok(new { status = "ok", service = "kitchen-service" }));
|
app.MapGet("/healthz", () => Results.Ok(new { status = "ok", service = "kitchen-service" }));
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../../src/Kitchen.Service.Application/Kitchen.Service.Application.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
using Kitchen.Service.Application.Ports;
|
||||||
|
using Kitchen.Service.Application.UseCases;
|
||||||
|
using Kitchen.Service.Contracts.Requests;
|
||||||
|
|
||||||
|
namespace Kitchen.Service.Application.UnitTests;
|
||||||
|
|
||||||
|
public class KitchenWorkflowUseCasesTests
|
||||||
|
{
|
||||||
|
private readonly DefaultKitchenWorkflowPort workflowPort = new();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetKitchenBoardUseCase_ReturnsLanesAndStations()
|
||||||
|
{
|
||||||
|
var useCase = new GetKitchenBoardUseCase(workflowPort);
|
||||||
|
|
||||||
|
var response = await useCase.HandleAsync(new GetKitchenBoardRequest("demo-context"), CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.Equal("demo-context", response.ContextId);
|
||||||
|
Assert.NotEmpty(response.Lanes);
|
||||||
|
Assert.NotEmpty(response.AvailableStations);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ClaimKitchenWorkItemUseCase_ReturnsClaimedResponse()
|
||||||
|
{
|
||||||
|
var useCase = new ClaimKitchenWorkItemUseCase(workflowPort);
|
||||||
|
|
||||||
|
var response = await useCase.HandleAsync(
|
||||||
|
new ClaimKitchenWorkItemRequest("demo-context", "WK-1001", "chef-maya"),
|
||||||
|
CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.True(response.Claimed);
|
||||||
|
Assert.Equal("chef-maya", response.ClaimedBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UpdateKitchenPriorityUseCase_NormalizesPriority()
|
||||||
|
{
|
||||||
|
var useCase = new UpdateKitchenPriorityUseCase(workflowPort);
|
||||||
|
|
||||||
|
var response = await useCase.HandleAsync(
|
||||||
|
new UpdateKitchenPriorityRequest("demo-context", "WK-1001", 0, "expo-noah"),
|
||||||
|
CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.Equal(1, response.Priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TransitionKitchenOrderStateUseCase_AllowsConfiguredStates()
|
||||||
|
{
|
||||||
|
var useCase = new TransitionKitchenOrderStateUseCase();
|
||||||
|
|
||||||
|
var response = await useCase.HandleAsync(
|
||||||
|
new TransitionKitchenOrderStateRequest("CO-1001", "KT-1001", "Preparing", "chef-maya"),
|
||||||
|
CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.True(response.Applied);
|
||||||
|
Assert.Equal("Preparing", response.CurrentState);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user