fix(operations-service): close orders after full payment
This commit is contained in:
parent
1e86d2f05b
commit
4bd088e2b1
@ -29,13 +29,14 @@ That means:
|
|||||||
- customer detail and history no longer need to be projected from the status summary payload
|
- 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 summary reads only served checks that remain payable
|
||||||
- POS detail can resolve a specific check directly from the shared lifecycle store
|
- POS detail can resolve a specific check directly from the shared lifecycle store
|
||||||
- payment capture updates persisted check state and appends lifecycle events
|
- payment capture updates persisted check state, appends lifecycle events, and closes the customer-facing order lifecycle on full payment
|
||||||
|
|
||||||
## Contract Intent
|
## Contract Intent
|
||||||
|
|
||||||
- waiter assignments surface floor-facing table attention derived from shared order/check state
|
- waiter assignments surface floor-facing table attention derived from shared order/check state
|
||||||
- customer status, detail, and history all reflect 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 payment only opens for served orders with outstanding balance
|
||||||
|
- a fully paid check now advances customer-facing order state beyond `served`, which keeps order detail aligned with successful POS capture
|
||||||
- POS detail stays lifecycle-backed even when the check is not yet payable, which keeps downstream error handling honest
|
- 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
|
- restaurant-admin configuration remains control-plane oriented and intentionally separate from order persistence
|
||||||
|
|
||||||
|
|||||||
@ -265,10 +265,12 @@ public sealed class DefaultOperationsWorkflowPort : IOperationsWorkflowPort
|
|||||||
var nowUtc = DateTime.UtcNow;
|
var nowUtc = DateTime.UtcNow;
|
||||||
var remainingBalance = decimal.Max(record.OutstandingBalance - request.Amount, 0m);
|
var remainingBalance = decimal.Max(record.OutstandingBalance - request.Amount, 0m);
|
||||||
var nextCheckState = remainingBalance == 0m ? "Paid" : "AwaitingPayment";
|
var nextCheckState = remainingBalance == 0m ? "Paid" : "AwaitingPayment";
|
||||||
|
var nextOrderState = remainingBalance == 0m ? "Paid" : record.OrderState;
|
||||||
|
|
||||||
// Partial captures keep the check open for the remaining balance; full captures close the check cleanly.
|
// Partial captures keep the check open for the remaining balance; full captures close the check cleanly.
|
||||||
var updated = record with
|
var updated = record with
|
||||||
{
|
{
|
||||||
|
OrderState = nextOrderState,
|
||||||
CheckState = nextCheckState,
|
CheckState = nextCheckState,
|
||||||
OutstandingBalance = remainingBalance,
|
OutstandingBalance = remainingBalance,
|
||||||
UpdatedAtUtc = nowUtc
|
UpdatedAtUtc = nowUtc
|
||||||
|
|||||||
@ -128,10 +128,30 @@ public class OperationsWorkflowUseCasesTests
|
|||||||
Assert.True(response.Succeeded);
|
Assert.True(response.Succeeded);
|
||||||
Assert.Equal("captured", response.Status);
|
Assert.Equal("captured", response.Status);
|
||||||
Assert.NotNull(updated);
|
Assert.NotNull(updated);
|
||||||
|
Assert.Equal("Paid", updated!.OrderState);
|
||||||
Assert.Equal("Paid", updated!.CheckState);
|
Assert.Equal("Paid", updated!.CheckState);
|
||||||
Assert.Equal(0m, updated.OutstandingBalance);
|
Assert.Equal(0m, updated.OutstandingBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CapturePosPaymentUseCase_WhenPaymentIsPartial_KeepsOrderServed()
|
||||||
|
{
|
||||||
|
var useCase = new CapturePosPaymentUseCase(workflowPort);
|
||||||
|
|
||||||
|
var response = await useCase.HandleAsync(
|
||||||
|
new CapturePosPaymentRequest("demo-context", "CHK-1002", 12.50m, "USD", "card"),
|
||||||
|
CancellationToken.None);
|
||||||
|
|
||||||
|
var updated = await lifecycleStore.GetOrderAsync("demo-context", "ORD-1002", CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.True(response.Succeeded);
|
||||||
|
Assert.Equal("partial", response.Status);
|
||||||
|
Assert.NotNull(updated);
|
||||||
|
Assert.Equal("Served", updated!.OrderState);
|
||||||
|
Assert.Equal("AwaitingPayment", updated.CheckState);
|
||||||
|
Assert.Equal(25.00m, updated.OutstandingBalance);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CapturePosPaymentUseCase_WhenOrderNotServed_ReturnsBlockedStatus()
|
public async Task CapturePosPaymentUseCase_WhenOrderNotServed_ReturnsBlockedStatus()
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user