-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Priority: P0 (Critical)
Phase: 1 - E-Commerce Core
Estimate: 3 days
Type: Story
Context
Introduce primitives for refunds and returns to ensure financial integrity, inventory reconciliation, and customer trust. Provides groundwork for future RMA flows and partial refunds.
Scope
- Models: RefundRequest, RefundTransaction, ReturnAuthorization
- State machines (simplified initial):
- RefundRequest: PENDING → APPROVED → EXECUTED / REJECTED
- ReturnAuthorization: ISSUED → RECEIVED → RESTOCKED / DISCARDED
- Refund triggers payment provider API (stub initially) & idempotent recording
- Inventory restock on successful return (link to InventoryReservation & original Order lines)
- Validation: Refund amount ≤ original paid minus prior refunds
Acceptance Criteria
- Create RefundRequest validates amount boundaries
- Executing refund logs structured event & updates PaymentAttempt state (link PaymentAttempt [Phase 1] PaymentAttempt & PaymentTransaction State Machine #63)
- ReturnAuthorization receiving items updates inventory (restock or discard path)
- Partial refunds supported (multiple RefundRequest until total reached)
- Metrics: refund.request.count, refund.executed.amount.total
- Audit log entries for each state transition
Data Model (Draft)
model RefundRequest {
id String @id @default(cuid())
orderId String
paymentAttemptId String?
amount Int
status RefundStatus @default(PENDING)
reason String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum RefundStatus {
PENDING
APPROVED
EXECUTED
REJECTED
}
model ReturnAuthorization {
id String @id @default(cuid())
orderId String
status ReturnStatus @default(ISSUED)
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum ReturnStatus {
ISSUED
RECEIVED
RESTOCKED
DISCARDED
}
model RefundTransaction {
id String @id @default(cuid())
refundRequestId String
externalRef String?
amount Int
createdAt DateTime @default(now())
}Dependencies
- PaymentAttempt state machine ([Phase 1] PaymentAttempt & PaymentTransaction State Machine #63)
- Inventory Reservation ([Phase 1] Inventory Reservation & Hold System #64) for restock logic context
- Idempotency ([Phase 1] Idempotency Key & Request Replay Safety Layer #66) for execution safety
Metrics Targets
- 100% accurate cumulative refund amount tracking
Testing Checklist
- Partial refund sequence doesn't exceed original amount
- ReturnAuthorization restocks inventory correctly
- Duplicate refund execution prevented by idempotency key
Risk
Financial & customer trust impact (score: 17). Required before advanced commerce expansion.
References
- docs/GITHUB_ISSUES_COMPARISON_ANALYSIS.md (refund/return gap)
Copilot