Welcome to the Jose Madrid Salsa developer docs — explore features, APIs, and deployment guides.
Jose Madrid SalsaJMS Docs

Order Lifecycle

Order statuses, transitions, admin actions, notifications, and management throughout the complete order lifecycle

Order Lifecycle

This guide covers order statuses, state transitions, admin actions, notifications, and order management throughout the complete lifecycle.

Overview

Orders track two independent status dimensions:

  • Order status — Fulfillment lifecycle (PENDING through DELIVERED/CANCELLED/REFUNDED)
  • Payment status — Payment state (PENDING through PAID/FAILED/REFUNDED)

Both statuses are stored on the Order model and can be updated independently.

Order Statuses

Defined in lib/validations/orders.ts (mirrors the Prisma OrderStatus enum):

StatusDescriptionAdmin UI Color
PENDINGOrder created, awaiting payment confirmationYellow
CONFIRMEDPayment received, order acceptedBlue
PROCESSINGOrder being prepared for shipmentPurple
SHIPPEDOrder shipped, tracking availableIndigo
DELIVEREDOrder delivered to customerGreen
CANCELLEDOrder cancelled (before or after payment)Red
REFUNDEDFull refund issuedGray

Payment Statuses

Defined in lib/validations/orders.ts (mirrors the Prisma PaymentStatus enum):

StatusDescription
PENDINGAwaiting payment
PAIDPayment successfully processed
FAILEDPayment attempt failed
REFUNDEDFull refund issued
PARTIALLY_REFUNDEDPartial refund issued

Status Flow Diagram

                     +----------+
                     | PENDING  |
                     +----+-----+
                          |
               Payment confirmed
               (checkout/complete or webhook)
                          |
                     +----v-----+
                +--->| CONFIRMED |<---+
                |    +----+-----+    |
                |         |          |
                |    Admin action    |
                |    "Processing"    |
                |         |          |
                |    +----v------+   |
                |    | PROCESSING|   |
                |    +----+------+   |
                |         |          |
                |    Admin action    |
                |    "Ship" +        |
                |    tracking info   |
                |         |          |
                |    +----v---+      |
                |    | SHIPPED|      |
                |    +----+--+      |
                |         |         |
                |    Admin action   |
                |    "Delivered"    |
                |         |         |
                |    +----v----+    |
                |    |DELIVERED|    |
                |    +---------+    |
                |                   |
                |   (Any status     |
                |    can also       |
                |    transition to) |
                |         |         |
          +-----v---+ +--v-------+
          |CANCELLED | | REFUNDED |
          +---------+ +----------+

Payment Status Flow:

PENDING ---> PAID ---> REFUNDED
   |           |
   v           v
 FAILED   PARTIALLY_REFUNDED

Key Transition Rules

  • PENDING → CONFIRMED: Triggered automatically when payment succeeds (via /api/checkout/complete or Stripe webhook payment_intent.succeeded)
  • PENDING → CANCELLED: Triggered by Stripe webhook payment_intent.canceled or admin action
  • CONFIRMED → PROCESSING: Admin manually moves order to processing
  • PROCESSING → SHIPPED: Admin adds tracking information
  • SHIPPED → DELIVERED: Admin confirms delivery
  • Any → CANCELLED: Admin cancellation (order status update)
  • Any → REFUNDED: Full refund via Stripe webhook charge.refunded
  • PAID → PARTIALLY_REFUNDED: Partial refund via Stripe webhook

Admin Actions

Order Detail Page

URL: /admin/orders/[id] Required permission: orders:read to view, orders:write to modify

Available admin actions (when orders:write permission is granted):

ActionComponentDescription
Update StatusUpdateStatusDialogChange order status with optional notes
Add TrackingTrackingDialogAdd tracking number, carrier, and tracking URL
Issue RefundRefundDialogProcess full or partial refund via Stripe
Send EmailSendEmailDialogSend custom email to customer
Print InvoicePrintInvoiceButtonGenerate printable invoice
Packing SlipPackingSlipButtonGenerate packing slip for fulfillment

Refund Eligibility

The admin detail page calculates the refundable amount by:

  1. Checking if a stripePaymentId exists on the order
  2. Verifying payment status is PAID or PARTIALLY_REFUNDED
  3. Retrieving the charge from Stripe to get amount_refunded
  4. Returning max(0, total - totalRefunded)

Order List Page

URL: /admin/orders

Supports filtering by:

  • Order status (enum dropdown)
  • Payment status (enum dropdown)
  • Pagination with configurable page size
  • Sort order (ascending/descending by date)

Order Import

URL: Available via import dialog on orders list page

Supports bulk order creation from CSV or XLSX files. See Order Import section.

Notifications

Notification System

File: lib/notifications/order-notifications.ts

The notification system supports both in-app notifications and email alerts, configurable per admin user via OrderNotificationSetting.

Notification Types

TypeIn-AppEmailTrigger
ORDER_NEWConfigurableConfigurableNew order placed
ORDER_STATUS_CHANGEConfigurableConfigurableOrder status updated
ORDER_HIGH_VALUEConfigurable (with threshold)ConfigurableOrder total exceeds threshold
ORDER_MODIFIEDAlwaysNeverOrder items or details changed
SYSTEMAlwaysNeverSystem-generated notification

Notification Settings

Each admin user has an OrderNotificationSetting record controlling:

SettingDescription
newOrderInAppShow in-app notification for new orders
newOrderEmailSend email for new orders
orderStatusInAppShow in-app notification for status changes
orderStatusEmailSend email for status changes
highValueInAppShow in-app notification for high-value orders
highValueEmailSend email for high-value orders
highValueThresholdDollar amount threshold for high-value alerts

Admin Notification Flow

When a new order is placed, notifyAdminsOfNewOrder() is called:

  1. Fetches all users with ADMIN or DEVELOPER role
  2. Creates ORDER_NEW notification for each admin (respecting their settings)
  3. If order total >= $100, also creates ORDER_HIGH_VALUE notification

Notification Delivery

  • In-app: Creates a Notification record in the database (title, message, entity reference)
  • Email: Sends via sendEmail() with a link to the admin order detail page
  • Mark as read: markNotificationAsRead() updates isRead flag and readAt timestamp

Order Modification

File: lib/orders/modify.ts

Admins can modify existing orders. The modifyOrder() function handles:

Modifiable Fields

FieldDescription
itemsReplace order items (deletes existing, creates new)
shippingAddressUpdate shipping address
statusChange order status
shippingCostAdjust shipping cost
notesAdd/update admin notes

Modification Process

  1. Fetch existing order with items and shipping address
  2. If items are updated: delete all existing OrderItem records, create new ones, recalculate subtotal
  3. Recalculate total: subtotal + shippingCost + tax - discountAmount
  4. Append modification to modificationHistory JSON array with timestamp, userId, and changes
  5. Update order record
  6. Create audit log entry (order.modify)

Modification History

Each modification is recorded in the order's modificationHistory JSON field:

{
  "timestamp": "2026-03-31T12:00:00.000Z",
  "userId": "clxxx...",
  "changes": {
    "before": { "items": [...] },
    "after": { "items": [...] }
  }
}

Order Import

File: lib/orders/import.ts

Supports bulk order creation from CSV or XLSX files.

Supported File Formats

  • CSV — Parsed via PapaParse (headers required, empty lines skipped, # comments supported)
  • XLSX/XLS — Parsed via ExcelJS (first worksheet, first row as headers)

Required Columns

ColumnTypeRequiredDescription
customerEmailstringYesValid email address
customerNamestringYesCustomer full name
shippingFirstNamestringYesShipping first name
shippingLastNamestringYesShipping last name
shippingStreetstringYesShipping street address
shippingCitystringYesShipping city
shippingStatestringYesShipping state (2+ chars)
shippingZipstringYesShipping ZIP code
productSkustringYesProduct SKU
productNamestringYesProduct display name
quantitynumberYesOrder quantity (min 1)
unitPricenumberYesUnit price (min 0)

Optional Columns

ColumnDefaultDescription
orderNumberAuto-generatedCustom order number
customerPhone-Customer phone
shippingCountryUSShipping country
shippingPhone-Shipping phone
billingFirstNameUses shippingBilling first name
billingLastNameUses shippingBilling last name
billingStreetUses shippingBilling street
billingCityUses shippingBilling city
billingStateUses shippingBilling state
billingZipUses shippingBilling ZIP
billingCountryUSBilling country
shippingCost0Shipping cost
tax0Tax amount
discountAmount0Discount amount
statusPENDINGOrder status
paymentStatusPENDINGPayment status
paymentMethod-Payment method
customerNotes-Customer notes
adminNotes-Admin notes
createdAtNowOrder creation date

Import Options

OptionDescription
createMissingProductsCreate placeholder products for unknown SKUs
createMissingUsersCreate user accounts for unknown email addresses
skipDuplicatesSkip orders with existing order numbers

Multi-Item Orders

Rows with the same orderNumber are grouped into a single order with multiple line items.

Auto-Generated Order Numbers

Format: ORD-YYYYMM-NNNNN (e.g., ORD-202603-00001), using sequential numbering within each month.

Validation Schemas

File: lib/validations/orders.ts

Zod schemas for all order operations:

SchemaPurpose
OrderItemSchema{ productId: CUID, quantity: positive int }
CustomerInfoSchema{ email, firstName, lastName, phone? }
ShippingAddressSchema{ address1, address2?, city, state, postalCode, country }
CreateOrderSchema{ cartItemIds, shippingAddress, billingAddress?, notes? }
UpdateOrderStatusSchema{ orderId: CUID, status: OrderStatus, notes? }
UpdateOrderPaymentStatusSchema{ orderId: CUID, paymentStatus: PaymentStatus }
OrderQuerySchemaFiltering/pagination: { status?, paymentStatus?, take?, skip, sortOrder }
CancelOrderSchema{ orderId: CUID, reason, refundAmount? }
UpdateOrderTrackingSchema{ orderId: CUID, trackingNumber, carrier, trackingUrl? }

Key Files

FilePurpose
lib/validations/orders.tsOrder status enums, Zod validation schemas
lib/orders/modify.tsOrder modification logic with audit trail
lib/orders/import.tsBulk order import from CSV/XLSX
lib/notifications/order-notifications.tsIn-app and email notification system
app/admin/orders/page.tsxAdmin order list with filtering
app/admin/orders/[id]/page.tsxAdmin order detail with action dialogs
app/admin/orders/[id]/invoice/page.tsxPrintable invoice generation
app/admin/orders/[id]/packing-slip/page.tsxPacking slip generation
app/admin/orders/_components/import-orders-dialog.tsxImport UI dialog
app/api/webhooks/stripe/route.tsAutomatic status updates from Stripe events
lib/stripe/webhooks.tsWebhook handler logic for payment/refund events

How is this guide?

Edit on GitHub

Last updated on

On this page