4.2 KiB
Order Void Status Improvement
Overview
This document describes the improved approach for handling order void status when all items are voided.
Problem with Previous Approach
The previous implementation only set the is_void flag to true when voiding orders, but kept the original order status (e.g., "pending", "preparing", etc.). This approach had several issues:
- Poor Semantic Meaning: Orders with status "pending" but
is_void = truewere confusing - Difficult Querying: Hard to filter voided orders by status alone
- Inconsistent State: Order status didn't reflect the actual business state
- Audit Trail Issues: No clear indication of when and why orders were voided
Improved Approach
1. Status Update Strategy
When an order is voided (either entirely or when all items are voided), the system now:
- Sets
is_void = true(for audit trail and void-specific operations) - Updates
status = 'cancelled'(for business logic and semantic clarity) - Records void metadata (reason, timestamp, user who voided)
2. Benefits
Clear Semantic Meaning
- Voided orders have status "cancelled" which clearly indicates they are no longer active
- Business logic can rely on status for workflow decisions
- Frontend can easily display voided orders with appropriate styling
Better Querying
-- Find all cancelled/voided orders
SELECT * FROM orders WHERE status = 'cancelled';
-- Find all active orders (excluding voided)
SELECT * FROM orders WHERE status != 'cancelled';
-- Find voided orders with audit info
SELECT * FROM orders WHERE is_void = true;
Consistent State Management
- Order status always reflects the current business state
- No conflicting states (e.g., "pending" but voided)
- Easier to implement business rules and validations
Enhanced Audit Trail
is_voidflag for void-specific operationsvoid_reason,voided_at,voided_byfor detailed auditstatus = 'cancelled'for business workflow
3. Implementation Details
New Repository Method
VoidOrderWithStatus(ctx context.Context, id uuid.UUID, status entities.OrderStatus, reason string, voidedBy uuid.UUID) error
This method updates both status and void flags in a single atomic transaction.
Updated Processor Logic
// For "ALL" void type
if err := p.orderRepo.VoidOrderWithStatus(ctx, req.OrderID, entities.OrderStatusCancelled, req.Reason, voidedBy); err != nil {
return fmt.Errorf("failed to void order: %w", err)
}
// For "ITEM" void type when all items are voided
if allItemsVoided {
if err := p.orderRepo.VoidOrderWithStatus(ctx, req.OrderID, entities.OrderStatusCancelled, req.Reason, voidedBy); err != nil {
return fmt.Errorf("failed to void order after all items voided: %w", err)
}
}
Database Migration
Added migration 000021_add_paid_status_to_orders.up.sql to include "paid" status in the constraint.
4. Status Flow
Order Created → pending
↓
Items Added/Modified → pending
↓
Order Processing → preparing → ready → completed
↓
Order Voided → cancelled (with is_void = true)
5. Backward Compatibility
- Existing
is_voidflag is preserved for backward compatibility - New approach is additive, not breaking
- Existing queries using
is_voidcontinue to work - New queries can use
status = 'cancelled'for better performance
6. Best Practices
For Queries
- Use
status = 'cancelled'for business logic and filtering - Use
is_void = truefor void-specific operations and audit trails - Combine both when you need complete void information
For Business Logic
- Check
status != 'cancelled'before allowing modifications - Use
is_voidflag for void-specific validations - Always include void reason and user for audit purposes
For Frontend
- Display cancelled orders with appropriate styling
- Show void reason and timestamp when available
- Disable actions on cancelled orders
Conclusion
This improved approach provides better semantic meaning, easier querying, and more consistent state management while maintaining backward compatibility. The combination of status updates and void flags creates a robust system for handling order cancellations.