feat(orders): implement QA audit fixes — return flow, refund webhook, TS cleanup
Convex backend (AUDIT-5–10): - schema: add returnLabelUrl, returnTrackingNumber, returnCarrier fields + by_return_tracking_number_and_carrier and by_stripe_payment_intent_id indexes - orders: markReturnReceived now sets status="completed"; add getOrderByPaymentIntent and applyReturnAccepted internal helpers - returnActions: add acceptReturn action — creates Shippo return label (is_return:true), persists label data, sends return label email to customer - stripeActions: handle refund.updated webhook to auto-mark orders refunded via Stripe Dashboard - shippoWebhook: add getOrderByReturnTracking; applyTrackingUpdate extended with isReturnTracking flag (return events use return_tracking_update type, skip delivered transition) - emails: add sendReturnLabelEmail; fulfillmentActions: createShippingLabel action Admin UI (AUDIT-1–6): - OrderActionsBar: full rewrite per authoritative action matrix; remove UpdateStatusDialog; add AcceptReturnButton for delivered+returnRequested state - AcceptReturnButton: new action component matching CreateLabelButton pattern - FulfilmentCard: add returnLabelUrl prop; show "Return label" row; rename outbound label to "Outbound label" when both are present - statusConfig: add return_accepted to OrderEventType and EVENT_TYPE_LABELS - orders detail page and all supporting cards/components Storefront & shared (TS fixes): - checkout/success, CheckoutErrorState, OrderReviewStep, PaymentStep: replace Button as/color/isLoading/variant="flat" with HeroUI v3-compatible props - ReviewList: isLoading → isPending for HeroUI v3 Button - packages/utils: add return and completed entries to ORDER_STATUS_LABELS/COLORS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -167,6 +167,8 @@ export default defineSchema({
|
||||
v.literal("delivered"),
|
||||
v.literal("cancelled"),
|
||||
v.literal("refunded"),
|
||||
v.literal("return"),
|
||||
v.literal("completed"),
|
||||
),
|
||||
paymentStatus: v.union(
|
||||
v.literal("pending"),
|
||||
@@ -209,6 +211,8 @@ export default defineSchema({
|
||||
carrier: v.string(),
|
||||
trackingNumber: v.optional(v.string()),
|
||||
trackingUrl: v.optional(v.string()),
|
||||
labelUrl: v.optional(v.string()),
|
||||
trackingStatus: v.optional(v.string()),
|
||||
estimatedDelivery: v.optional(v.number()),
|
||||
actualDelivery: v.optional(v.number()),
|
||||
notes: v.optional(v.string()),
|
||||
@@ -216,6 +220,11 @@ export default defineSchema({
|
||||
updatedAt: v.number(),
|
||||
paidAt: v.optional(v.number()),
|
||||
shippedAt: v.optional(v.number()),
|
||||
returnRequestedAt: v.optional(v.number()),
|
||||
returnReceivedAt: v.optional(v.number()),
|
||||
returnLabelUrl: v.optional(v.string()),
|
||||
returnTrackingNumber: v.optional(v.string()),
|
||||
returnCarrier: v.optional(v.string()),
|
||||
})
|
||||
.index("by_user", ["userId"])
|
||||
.index("by_status", ["status"])
|
||||
@@ -223,7 +232,10 @@ export default defineSchema({
|
||||
.index("by_order_number", ["orderNumber"])
|
||||
.index("by_email", ["email"])
|
||||
.index("by_created_at", ["createdAt"])
|
||||
.index("by_stripe_checkout_session_id", ["stripeCheckoutSessionId"]),
|
||||
.index("by_stripe_checkout_session_id", ["stripeCheckoutSessionId"])
|
||||
.index("by_tracking_number_and_carrier", ["trackingNumber", "carrier"])
|
||||
.index("by_return_tracking_number_and_carrier", ["returnTrackingNumber", "returnCarrier"])
|
||||
.index("by_stripe_payment_intent_id", ["stripePaymentIntentId"]),
|
||||
|
||||
orderItems: defineTable({
|
||||
orderId: v.id("orders"),
|
||||
@@ -237,6 +249,19 @@ export default defineSchema({
|
||||
imageUrl: v.optional(v.string()),
|
||||
}).index("by_order", ["orderId"]),
|
||||
|
||||
orderTimelineEvents: defineTable({
|
||||
orderId: v.id("orders"),
|
||||
eventType: v.string(), // "status_change" | "customer_cancel" | "return_requested" | "return_received" | "refund" | "tracking_update" | "label_created"
|
||||
source: v.string(), // "stripe_webhook" | "fulfillment" | "admin" | "shippo_webhook" | "customer_cancel" | "customer_return"
|
||||
fromStatus: v.optional(v.string()),
|
||||
toStatus: v.optional(v.string()),
|
||||
payload: v.optional(v.string()), // JSON string for Shippo/Stripe payloads
|
||||
createdAt: v.number(),
|
||||
userId: v.optional(v.id("users")),
|
||||
})
|
||||
.index("by_order", ["orderId"])
|
||||
.index("by_order_and_created_at", ["orderId", "createdAt"]),
|
||||
|
||||
// ─── Reviews ───────────────────────────────────────────────────────────
|
||||
reviews: defineTable({
|
||||
productId: v.id("products"),
|
||||
|
||||
Reference in New Issue
Block a user