feat(operations-service): add lifecycle-backed restaurant detail reads
This commit is contained in:
parent
d19167e3ea
commit
1e86d2f05b
@ -11,7 +11,10 @@
|
||||
- `GET /internal/operations/waiter/assignments?contextId=<id>`
|
||||
- `POST /internal/operations/orders`
|
||||
- `GET /internal/operations/customer/status?contextId=<id>`
|
||||
- `GET /internal/operations/customer/orders/<orderId>?contextId=<id>`
|
||||
- `GET /internal/operations/customer/history?contextId=<id>`
|
||||
- `GET /internal/operations/pos/summary?contextId=<id>`
|
||||
- `GET /internal/operations/pos/transactions/<transactionId>?contextId=<id>`
|
||||
- `POST /internal/operations/pos/payments`
|
||||
- `GET /internal/operations/admin/config?contextId=<id>`
|
||||
- `POST /internal/operations/admin/service-window`
|
||||
@ -23,16 +26,19 @@ This repo now orchestrates restaurant workflow over the shared lifecycle store e
|
||||
That means:
|
||||
- submitted orders are persisted as shared order/check records
|
||||
- customer status reads come from persisted restaurant state rather than static arrays
|
||||
- customer detail and history no longer need to be projected from the status summary payload
|
||||
- POS summary reads only served checks that remain payable
|
||||
- POS detail can resolve a specific check directly from the shared lifecycle store
|
||||
- payment capture updates persisted check state and appends lifecycle events
|
||||
|
||||
## Contract Intent
|
||||
|
||||
- waiter assignments surface floor-facing table attention derived from shared order/check state
|
||||
- customer order status reflects the same lifecycle that waiter and POS flows observe
|
||||
- customer status, detail, and history all reflect the same lifecycle that waiter and POS flows observe
|
||||
- POS payment only opens for served orders with outstanding balance
|
||||
- POS detail stays lifecycle-backed even when the check is not yet payable, which keeps downstream error handling honest
|
||||
- restaurant-admin configuration remains control-plane oriented and intentionally separate from order persistence
|
||||
|
||||
## Remaining Limitation
|
||||
|
||||
- Kitchen ticket creation and kitchen state feedback are not owned by this repo; they will be linked in the Stage 46 kitchen-service task.
|
||||
- Kitchen ticket creation and kitchen state feedback still depend on `kitchen-service` propagation alignment in the Stage 50 companion task.
|
||||
|
||||
@ -128,14 +128,7 @@ public sealed class DefaultOperationsWorkflowPort : IOperationsWorkflowPort
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var orders = await lifecycleStore.ListOrdersAsync(request.ContextId, cancellationToken);
|
||||
var contracts = orders
|
||||
.Select(order => new CustomerOrderStatusContract(
|
||||
order.OrderId,
|
||||
order.TableId,
|
||||
MapCustomerStatus(order.OrderState),
|
||||
order.GuestCount,
|
||||
order.ItemIds))
|
||||
.ToArray();
|
||||
var contracts = MapCustomerOrders(orders);
|
||||
|
||||
var events = await BuildRecentActivityAsync(orders, cancellationToken);
|
||||
|
||||
@ -148,6 +141,45 @@ public sealed class DefaultOperationsWorkflowPort : IOperationsWorkflowPort
|
||||
events);
|
||||
}
|
||||
|
||||
public async Task<GetCustomerOrderDetailResponse> GetCustomerOrderDetailAsync(
|
||||
GetCustomerOrderDetailRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var order = await lifecycleStore.GetOrderAsync(request.ContextId, request.OrderId, cancellationToken);
|
||||
var recentEvents = order is null
|
||||
? Array.Empty<string>()
|
||||
: await BuildOrderActivityAsync(request.ContextId, request.OrderId, cancellationToken);
|
||||
|
||||
return new GetCustomerOrderDetailResponse(
|
||||
request.ContextId,
|
||||
order is null
|
||||
? $"Order {request.OrderId} is not visible in the shared restaurant lifecycle."
|
||||
: $"Order {request.OrderId} is currently {MapCustomerStatus(order.OrderState)} in the shared restaurant lifecycle.",
|
||||
order is null ? null : MapCustomerOrder(order),
|
||||
recentEvents);
|
||||
}
|
||||
|
||||
public async Task<GetCustomerOrderHistoryResponse> GetCustomerOrderHistoryAsync(
|
||||
GetCustomerOrderHistoryRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var orders = await lifecycleStore.ListOrdersAsync(request.ContextId, cancellationToken);
|
||||
var contracts = MapCustomerOrders(orders);
|
||||
var recentEvents = await BuildRecentActivityAsync(orders, cancellationToken);
|
||||
|
||||
return new GetCustomerOrderHistoryResponse(
|
||||
request.ContextId,
|
||||
contracts.Length == 0
|
||||
? "No customer order history is currently visible for the active context."
|
||||
: $"{contracts.Length} customer orders are currently available through lifecycle-backed history.",
|
||||
contracts,
|
||||
recentEvents);
|
||||
}
|
||||
|
||||
public async Task<GetPosTransactionSummaryResponse> GetPosTransactionSummaryAsync(
|
||||
GetPosTransactionSummaryRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
@ -156,15 +188,7 @@ public sealed class DefaultOperationsWorkflowPort : IOperationsWorkflowPort
|
||||
|
||||
var payableOrders = await lifecycleStore.ListPayableOrdersAsync(request.ContextId, cancellationToken);
|
||||
var openBalance = payableOrders.Sum(order => order.OutstandingBalance);
|
||||
var payments = payableOrders
|
||||
.Select(order => new PosPaymentActivityContract(
|
||||
order.CheckId,
|
||||
"check",
|
||||
order.OutstandingBalance,
|
||||
order.Currency,
|
||||
string.Equals(order.CheckState, "AwaitingPayment", StringComparison.Ordinal) ? "partial-payment" : "awaiting-payment",
|
||||
order.UpdatedAtUtc))
|
||||
.ToArray();
|
||||
var payments = MapPayments(payableOrders);
|
||||
|
||||
return new GetPosTransactionSummaryResponse(
|
||||
request.ContextId,
|
||||
@ -176,6 +200,26 @@ public sealed class DefaultOperationsWorkflowPort : IOperationsWorkflowPort
|
||||
payments);
|
||||
}
|
||||
|
||||
public async Task<GetPosTransactionDetailResponse> GetPosTransactionDetailAsync(
|
||||
GetPosTransactionDetailRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var record = await ResolveTransactionAsync(request.ContextId, request.TransactionId, cancellationToken);
|
||||
var payableOrders = await lifecycleStore.ListPayableOrdersAsync(request.ContextId, cancellationToken);
|
||||
var openBalance = payableOrders.Sum(order => order.OutstandingBalance);
|
||||
|
||||
return new GetPosTransactionDetailResponse(
|
||||
request.ContextId,
|
||||
record is null
|
||||
? $"Transaction {request.TransactionId} is not visible in the shared restaurant lifecycle."
|
||||
: $"Transaction {request.TransactionId} maps to check {record.CheckId} and is currently {MapPaymentStatus(record)}.",
|
||||
openBalance,
|
||||
record?.Currency ?? payableOrders.FirstOrDefault()?.Currency ?? "USD",
|
||||
record is null ? null : MapPayment(record));
|
||||
}
|
||||
|
||||
public async Task<CapturePosPaymentResponse> CapturePosPaymentAsync(
|
||||
CapturePosPaymentRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
@ -317,6 +361,16 @@ public sealed class DefaultOperationsWorkflowPort : IOperationsWorkflowPort
|
||||
return orders.FirstOrDefault(order => string.Equals(order.CheckId, transactionId, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyCollection<string>> BuildOrderActivityAsync(string contextId, string orderId, CancellationToken cancellationToken)
|
||||
{
|
||||
var events = await lifecycleStore.ListEventsAsync(contextId, orderId, cancellationToken);
|
||||
return events
|
||||
.OrderByDescending(record => record.OccurredAtUtc)
|
||||
.Select(record => record.Description)
|
||||
.Take(6)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyCollection<string>> BuildRecentActivityAsync(IEnumerable<PersistedRestaurantLifecycleRecord> orders, CancellationToken cancellationToken)
|
||||
{
|
||||
var activity = new List<PersistedRestaurantLifecycleEvent>();
|
||||
@ -333,6 +387,41 @@ public sealed class DefaultOperationsWorkflowPort : IOperationsWorkflowPort
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static CustomerOrderStatusContract[] MapCustomerOrders(IEnumerable<PersistedRestaurantLifecycleRecord> orders)
|
||||
{
|
||||
return orders
|
||||
.Select(MapCustomerOrder)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static CustomerOrderStatusContract MapCustomerOrder(PersistedRestaurantLifecycleRecord order)
|
||||
{
|
||||
return new CustomerOrderStatusContract(
|
||||
order.OrderId,
|
||||
order.TableId,
|
||||
MapCustomerStatus(order.OrderState),
|
||||
order.GuestCount,
|
||||
order.ItemIds);
|
||||
}
|
||||
|
||||
private static PosPaymentActivityContract[] MapPayments(IEnumerable<PersistedRestaurantLifecycleRecord> payableOrders)
|
||||
{
|
||||
return payableOrders
|
||||
.Select(MapPayment)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static PosPaymentActivityContract MapPayment(PersistedRestaurantLifecycleRecord order)
|
||||
{
|
||||
return new PosPaymentActivityContract(
|
||||
order.CheckId,
|
||||
"check",
|
||||
order.OutstandingBalance,
|
||||
order.Currency,
|
||||
MapPaymentStatus(order),
|
||||
order.UpdatedAtUtc);
|
||||
}
|
||||
|
||||
private static bool IsPayable(PersistedRestaurantLifecycleRecord record)
|
||||
{
|
||||
return string.Equals(record.OrderState, "Served", StringComparison.Ordinal)
|
||||
@ -343,6 +432,23 @@ public sealed class DefaultOperationsWorkflowPort : IOperationsWorkflowPort
|
||||
|
||||
private static string MapCustomerStatus(string orderState) => orderState.ToLowerInvariant();
|
||||
|
||||
private static string MapPaymentStatus(PersistedRestaurantLifecycleRecord record)
|
||||
{
|
||||
if (string.Equals(record.CheckState, "Paid", StringComparison.Ordinal))
|
||||
{
|
||||
return "captured";
|
||||
}
|
||||
|
||||
if (!IsPayable(record))
|
||||
{
|
||||
return "not-payable";
|
||||
}
|
||||
|
||||
return string.Equals(record.CheckState, "AwaitingPayment", StringComparison.Ordinal)
|
||||
? "partial-payment"
|
||||
: "awaiting-payment";
|
||||
}
|
||||
|
||||
private static string MapWaiterStatus(PersistedRestaurantLifecycleRecord record)
|
||||
{
|
||||
if (string.Equals(record.OrderState, "Served", StringComparison.Ordinal)
|
||||
|
||||
@ -8,7 +8,10 @@ public interface IOperationsWorkflowPort
|
||||
Task<GetWaiterAssignmentsResponse> GetWaiterAssignmentsAsync(GetWaiterAssignmentsRequest request, CancellationToken cancellationToken);
|
||||
Task<SubmitRestaurantOrderResponse> SubmitRestaurantOrderAsync(SubmitRestaurantOrderRequest request, CancellationToken cancellationToken);
|
||||
Task<GetCustomerOrderStatusResponse> GetCustomerOrderStatusAsync(GetCustomerOrderStatusRequest request, CancellationToken cancellationToken);
|
||||
Task<GetCustomerOrderDetailResponse> GetCustomerOrderDetailAsync(GetCustomerOrderDetailRequest request, CancellationToken cancellationToken);
|
||||
Task<GetCustomerOrderHistoryResponse> GetCustomerOrderHistoryAsync(GetCustomerOrderHistoryRequest request, CancellationToken cancellationToken);
|
||||
Task<GetPosTransactionSummaryResponse> GetPosTransactionSummaryAsync(GetPosTransactionSummaryRequest request, CancellationToken cancellationToken);
|
||||
Task<GetPosTransactionDetailResponse> GetPosTransactionDetailAsync(GetPosTransactionDetailRequest request, CancellationToken cancellationToken);
|
||||
Task<CapturePosPaymentResponse> CapturePosPaymentAsync(CapturePosPaymentRequest request, CancellationToken cancellationToken);
|
||||
Task<GetRestaurantAdminConfigResponse> GetRestaurantAdminConfigAsync(GetRestaurantAdminConfigRequest request, CancellationToken cancellationToken);
|
||||
Task<SetServiceWindowResponse> SetServiceWindowAsync(SetServiceWindowRequest request, CancellationToken cancellationToken);
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
using Operations.Service.Application.Ports;
|
||||
using Operations.Service.Contracts.Requests;
|
||||
using Operations.Service.Contracts.Responses;
|
||||
|
||||
namespace Operations.Service.Application.UseCases;
|
||||
|
||||
public sealed class GetCustomerOrderDetailUseCase(IOperationsWorkflowPort workflowPort) : IGetCustomerOrderDetailUseCase
|
||||
{
|
||||
public Task<GetCustomerOrderDetailResponse> HandleAsync(GetCustomerOrderDetailRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
return workflowPort.GetCustomerOrderDetailAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
using Operations.Service.Application.Ports;
|
||||
using Operations.Service.Contracts.Requests;
|
||||
using Operations.Service.Contracts.Responses;
|
||||
|
||||
namespace Operations.Service.Application.UseCases;
|
||||
|
||||
public sealed class GetCustomerOrderHistoryUseCase(IOperationsWorkflowPort workflowPort) : IGetCustomerOrderHistoryUseCase
|
||||
{
|
||||
public Task<GetCustomerOrderHistoryResponse> HandleAsync(GetCustomerOrderHistoryRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
return workflowPort.GetCustomerOrderHistoryAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
using Operations.Service.Application.Ports;
|
||||
using Operations.Service.Contracts.Requests;
|
||||
using Operations.Service.Contracts.Responses;
|
||||
|
||||
namespace Operations.Service.Application.UseCases;
|
||||
|
||||
public sealed class GetPosTransactionDetailUseCase(IOperationsWorkflowPort workflowPort) : IGetPosTransactionDetailUseCase
|
||||
{
|
||||
public Task<GetPosTransactionDetailResponse> HandleAsync(GetPosTransactionDetailRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
return workflowPort.GetPosTransactionDetailAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using Operations.Service.Contracts.Requests;
|
||||
using Operations.Service.Contracts.Responses;
|
||||
|
||||
namespace Operations.Service.Application.UseCases;
|
||||
|
||||
public interface IGetCustomerOrderDetailUseCase
|
||||
{
|
||||
Task<GetCustomerOrderDetailResponse> HandleAsync(GetCustomerOrderDetailRequest request, CancellationToken cancellationToken);
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using Operations.Service.Contracts.Requests;
|
||||
using Operations.Service.Contracts.Responses;
|
||||
|
||||
namespace Operations.Service.Application.UseCases;
|
||||
|
||||
public interface IGetCustomerOrderHistoryUseCase
|
||||
{
|
||||
Task<GetCustomerOrderHistoryResponse> HandleAsync(GetCustomerOrderHistoryRequest request, CancellationToken cancellationToken);
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using Operations.Service.Contracts.Requests;
|
||||
using Operations.Service.Contracts.Responses;
|
||||
|
||||
namespace Operations.Service.Application.UseCases;
|
||||
|
||||
public interface IGetPosTransactionDetailUseCase
|
||||
{
|
||||
Task<GetPosTransactionDetailResponse> HandleAsync(GetPosTransactionDetailRequest request, CancellationToken cancellationToken);
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
namespace Operations.Service.Contracts.Requests;
|
||||
|
||||
public sealed record GetCustomerOrderDetailRequest(
|
||||
string ContextId,
|
||||
string OrderId);
|
||||
@ -0,0 +1,3 @@
|
||||
namespace Operations.Service.Contracts.Requests;
|
||||
|
||||
public sealed record GetCustomerOrderHistoryRequest(string ContextId);
|
||||
@ -0,0 +1,5 @@
|
||||
namespace Operations.Service.Contracts.Requests;
|
||||
|
||||
public sealed record GetPosTransactionDetailRequest(
|
||||
string ContextId,
|
||||
string TransactionId);
|
||||
@ -0,0 +1,9 @@
|
||||
using Operations.Service.Contracts.Contracts;
|
||||
|
||||
namespace Operations.Service.Contracts.Responses;
|
||||
|
||||
public sealed record GetCustomerOrderDetailResponse(
|
||||
string ContextId,
|
||||
string Summary,
|
||||
CustomerOrderStatusContract? Order,
|
||||
IReadOnlyCollection<string> RecentEvents);
|
||||
@ -0,0 +1,9 @@
|
||||
using Operations.Service.Contracts.Contracts;
|
||||
|
||||
namespace Operations.Service.Contracts.Responses;
|
||||
|
||||
public sealed record GetCustomerOrderHistoryResponse(
|
||||
string ContextId,
|
||||
string Summary,
|
||||
IReadOnlyCollection<CustomerOrderStatusContract> Orders,
|
||||
IReadOnlyCollection<string> RecentEvents);
|
||||
@ -0,0 +1,10 @@
|
||||
using Operations.Service.Contracts.Contracts;
|
||||
|
||||
namespace Operations.Service.Contracts.Responses;
|
||||
|
||||
public sealed record GetPosTransactionDetailResponse(
|
||||
string ContextId,
|
||||
string Summary,
|
||||
decimal OpenBalance,
|
||||
string Currency,
|
||||
PosPaymentActivityContract? Transaction);
|
||||
@ -17,7 +17,10 @@ builder.Services.AddSingleton<IEvaluateOperationalDecisionUseCase, EvaluateOpera
|
||||
builder.Services.AddSingleton<IGetWaiterAssignmentsUseCase, GetWaiterAssignmentsUseCase>();
|
||||
builder.Services.AddSingleton<ISubmitRestaurantOrderUseCase, SubmitRestaurantOrderUseCase>();
|
||||
builder.Services.AddSingleton<IGetCustomerOrderStatusUseCase, GetCustomerOrderStatusUseCase>();
|
||||
builder.Services.AddSingleton<IGetCustomerOrderDetailUseCase, GetCustomerOrderDetailUseCase>();
|
||||
builder.Services.AddSingleton<IGetCustomerOrderHistoryUseCase, GetCustomerOrderHistoryUseCase>();
|
||||
builder.Services.AddSingleton<IGetPosTransactionSummaryUseCase, GetPosTransactionSummaryUseCase>();
|
||||
builder.Services.AddSingleton<IGetPosTransactionDetailUseCase, GetPosTransactionDetailUseCase>();
|
||||
builder.Services.AddSingleton<ICapturePosPaymentUseCase, CapturePosPaymentUseCase>();
|
||||
builder.Services.AddSingleton<IGetRestaurantAdminConfigUseCase, GetRestaurantAdminConfigUseCase>();
|
||||
builder.Services.AddSingleton<ISetServiceWindowUseCase, SetServiceWindowUseCase>();
|
||||
@ -62,6 +65,23 @@ app.MapGet("/internal/operations/customer/status", async (
|
||||
return Results.Ok(await useCase.HandleAsync(new GetCustomerOrderStatusRequest(contextId), ct));
|
||||
});
|
||||
|
||||
app.MapGet("/internal/operations/customer/orders/{orderId}", async (
|
||||
string contextId,
|
||||
string orderId,
|
||||
IGetCustomerOrderDetailUseCase useCase,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
return Results.Ok(await useCase.HandleAsync(new GetCustomerOrderDetailRequest(contextId, orderId), ct));
|
||||
});
|
||||
|
||||
app.MapGet("/internal/operations/customer/history", async (
|
||||
string contextId,
|
||||
IGetCustomerOrderHistoryUseCase useCase,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
return Results.Ok(await useCase.HandleAsync(new GetCustomerOrderHistoryRequest(contextId), ct));
|
||||
});
|
||||
|
||||
app.MapGet("/internal/operations/pos/summary", async (
|
||||
string contextId,
|
||||
IGetPosTransactionSummaryUseCase useCase,
|
||||
@ -70,6 +90,15 @@ app.MapGet("/internal/operations/pos/summary", async (
|
||||
return Results.Ok(await useCase.HandleAsync(new GetPosTransactionSummaryRequest(contextId), ct));
|
||||
});
|
||||
|
||||
app.MapGet("/internal/operations/pos/transactions/{transactionId}", async (
|
||||
string contextId,
|
||||
string transactionId,
|
||||
IGetPosTransactionDetailUseCase useCase,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
return Results.Ok(await useCase.HandleAsync(new GetPosTransactionDetailRequest(contextId, transactionId), ct));
|
||||
});
|
||||
|
||||
app.MapPost("/internal/operations/pos/payments", async (
|
||||
CapturePosPaymentRequest request,
|
||||
ICapturePosPaymentUseCase useCase,
|
||||
|
||||
@ -57,6 +57,36 @@ public class OperationsWorkflowUseCasesTests
|
||||
Assert.Contains(response.Orders, order => order.OrderId == "ORD-1001");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCustomerOrderDetailUseCase_ReturnsSpecificLifecycleOrder()
|
||||
{
|
||||
var useCase = new GetCustomerOrderDetailUseCase(workflowPort);
|
||||
|
||||
var response = await useCase.HandleAsync(
|
||||
new GetCustomerOrderDetailRequest("demo-context", "ORD-1001"),
|
||||
CancellationToken.None);
|
||||
|
||||
Assert.Equal("demo-context", response.ContextId);
|
||||
Assert.NotNull(response.Order);
|
||||
Assert.Equal("ORD-1001", response.Order!.OrderId);
|
||||
Assert.NotEmpty(response.RecentEvents);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCustomerOrderHistoryUseCase_ReturnsLifecycleBackedHistory()
|
||||
{
|
||||
var useCase = new GetCustomerOrderHistoryUseCase(workflowPort);
|
||||
|
||||
var response = await useCase.HandleAsync(
|
||||
new GetCustomerOrderHistoryRequest("demo-context"),
|
||||
CancellationToken.None);
|
||||
|
||||
Assert.Equal("demo-context", response.ContextId);
|
||||
Assert.NotEmpty(response.Orders);
|
||||
Assert.NotEmpty(response.RecentEvents);
|
||||
Assert.Contains("lifecycle-backed history", response.Summary);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPosTransactionSummaryUseCase_ReturnsOnlyPayableChecks()
|
||||
{
|
||||
@ -69,6 +99,21 @@ public class OperationsWorkflowUseCasesTests
|
||||
Assert.All(response.RecentPayments, payment => Assert.Equal("check", payment.PaymentMethod));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPosTransactionDetailUseCase_ReturnsLifecycleBackedCheck()
|
||||
{
|
||||
var useCase = new GetPosTransactionDetailUseCase(workflowPort);
|
||||
|
||||
var response = await useCase.HandleAsync(
|
||||
new GetPosTransactionDetailRequest("demo-context", "CHK-1002"),
|
||||
CancellationToken.None);
|
||||
|
||||
Assert.Equal("demo-context", response.ContextId);
|
||||
Assert.NotNull(response.Transaction);
|
||||
Assert.Equal("CHK-1002", response.Transaction!.TransactionId);
|
||||
Assert.Equal("awaiting-payment", response.Transaction.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CapturePosPaymentUseCase_WhenOrderServed_ReturnsCapturedStatus()
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user