feat(backend): implement order state machine with validation
This commit is contained in:
parent
89036d7b39
commit
132fef816c
3 changed files with 40 additions and 0 deletions
|
|
@ -395,7 +395,10 @@ const (
|
||||||
OrderStatusPending OrderStatus = "Pendente"
|
OrderStatusPending OrderStatus = "Pendente"
|
||||||
OrderStatusPaid OrderStatus = "Pago"
|
OrderStatusPaid OrderStatus = "Pago"
|
||||||
OrderStatusInvoiced OrderStatus = "Faturado"
|
OrderStatusInvoiced OrderStatus = "Faturado"
|
||||||
|
OrderStatusShipped OrderStatus = "Enviado"
|
||||||
OrderStatusDelivered OrderStatus = "Entregue"
|
OrderStatusDelivered OrderStatus = "Entregue"
|
||||||
|
OrderStatusCompleted OrderStatus = "Concluído"
|
||||||
|
OrderStatusCancelled OrderStatus = "Cancelado"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PaymentMethod enumerates supported payment types.
|
// PaymentMethod enumerates supported payment types.
|
||||||
|
|
|
||||||
|
|
@ -337,6 +337,37 @@ func (s *Service) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error {
|
func (s *Service) UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error {
|
||||||
|
order, err := s.repo.GetOrder(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// State Machine Logic
|
||||||
|
switch order.Status {
|
||||||
|
case domain.OrderStatusPending:
|
||||||
|
if status != domain.OrderStatusPaid && status != domain.OrderStatusCancelled {
|
||||||
|
return errors.New("invalid transition from Pending")
|
||||||
|
}
|
||||||
|
case domain.OrderStatusPaid:
|
||||||
|
if status != domain.OrderStatusInvoiced && status != domain.OrderStatusShipped && status != domain.OrderStatusCancelled {
|
||||||
|
return errors.New("invalid transition from Paid")
|
||||||
|
}
|
||||||
|
case domain.OrderStatusInvoiced: // Can go to Shipped
|
||||||
|
if status != domain.OrderStatusShipped && status != domain.OrderStatusCancelled {
|
||||||
|
return errors.New("invalid transition from Invoiced")
|
||||||
|
}
|
||||||
|
case domain.OrderStatusShipped:
|
||||||
|
if status != domain.OrderStatusDelivered {
|
||||||
|
return errors.New("invalid transition from Shipped")
|
||||||
|
}
|
||||||
|
case domain.OrderStatusDelivered:
|
||||||
|
if status != domain.OrderStatusCompleted {
|
||||||
|
return errors.New("invalid transition from Delivered")
|
||||||
|
}
|
||||||
|
case domain.OrderStatusCompleted, domain.OrderStatusCancelled:
|
||||||
|
return errors.New("order is in terminal state")
|
||||||
|
}
|
||||||
|
|
||||||
return s.repo.UpdateOrderStatus(ctx, id, status)
|
return s.repo.UpdateOrderStatus(ctx, id, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -646,6 +646,12 @@ func TestUpdateOrderStatus(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to update order status: %v", err)
|
t.Fatalf("failed to update order status: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test invalid transition
|
||||||
|
err = svc.UpdateOrderStatus(ctx, order.ID, domain.OrderStatusDelivered) // Paid -> Delivered is invalid (skip Shipped)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error for invalid transition Paid -> Delivered")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- User Tests ---
|
// --- User Tests ---
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue