Checkout Workflow Documentation¶
This document describes the createOrderAtomicWorkflow that processes customer orders in the AzharStore system.
Overview¶
The checkout workflow is an atomic transaction that processes orders through 8 sequential steps. Each step validates data, performs operations, and defines compensation logic for rollback in case of failure.
Workflow Steps¶
Step 1: validateStockStep¶
Purpose: Validates that all requested product variants have sufficient inventory.
Input
Process - Queries Medusa inventory service for each variant - Compares requested quantity with available quantity - Throws error if any variant has insufficient stock
Output - Returns the validated items array
Error Handling
- Throws structured error: { code: "INSUFFICIENT_STOCK", variant_id, requested, available }
- No compensation (validation step)
Example Error
Step 2: createCartStep¶
Purpose: Creates a new Medusa cart with synthetic email from phone number.
Input
Process
- Creates a cart in Medusa
- Uses synthetic email format: {phone_number}@azharstore.local
- Associates cart with the specified region
Output - Returns the created cart object
Compensation - Deletes the created cart if workflow fails
Step 3: addLineItemsStep¶
Purpose: Adds all line items to the cart.
Input
Process - Iterates through items array - Adds each item to the cart using Medusa cart service
Output - Returns the cart ID
Compensation - Handled by cart deletion in Step 2
Step 4: updateCartAddressStep¶
Purpose: Maps customer address fields to Medusa address format and updates cart.
Input
{
cart_id: string
customer: {
name: string
phone_number: string
town: string
address_road: string
address_home: string
address_block: string
}
}
Field Mapping | Frontend Field | Medusa Field | |----------------|--------------| | name | first_name, last_name (split on space) | | phone_number | phone | | town | city | | address_road | address_1 | | address_home | address_2 | | address_block | postal_code | | (hardcoded) | country_code = "BH" |
Process - Splits customer name into first_name and last_name - Maps all address fields - Updates both shipping_address and billing_address
Output - Returns the cart ID
Compensation - None (address update is part of cart state)
Step 5: addShippingMethodStep¶
Purpose: Adds appropriate shipping method based on delivery type.
Input
Process
- If shipping_method === "pick_up":
- Finds shipping option with price = 0
- Adds that option to cart
- If shipping_method === "delivery":
- Uses delivery_area_id as shipping option ID
- Adds that option to cart
Output - Returns the cart ID
Compensation - Removes shipping method from cart if workflow fails
Step 6: createPaymentSessionStep¶
Purpose: Creates a payment session using the manual payment provider.
Input
Process - Calls Medusa cart service to create payment session - Uses manual provider (cash on delivery)
Output - Returns the cart ID
Compensation - Deletes payment session if workflow fails
Step 7: completeCartStep¶
Purpose: Completes the cart, converting it to an order.
Input
Process - Calls Medusa cart completion - Converts cart to order - Captures payment (for manual provider)
Output - Returns the created order object
Compensation - Cancels and archives the created order - Restores stock (if applicable)
Step 8: capturePaymentStep¶
Purpose: Captures the payment (for manual provider, this is automatic on completion).
Input
Process - For manual payment provider, capture happens automatically on cart completion - This step is a placeholder for custom capture logic if needed
Output - Returns the order ID
Compensation - Voids the captured payment if workflow fails
Workflow Diagram¶
┌─────────────────────────────────────────────────────────────┐
│ createOrderAtomicWorkflow │
└─────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────┐
│ validateStock │
│ (Step 1) │
└──────────────────┘
│
▼
┌──────────────────┐
│ createCart │
│ (Step 2) │
└──────────────────┘
│
▼
┌──────────────────┐
│ addLineItems │
│ (Step 3) │
└──────────────────┘
│
▼
┌──────────────────┐
│ updateCartAddr │
│ (Step 4) │
└──────────────────┘
│
▼
┌──────────────────┐
│addShippingMethod │
│ (Step 5) │
└──────────────────┘
│
▼
┌──────────────────┐
│createPaymentSess │
│ (Step 6) │
└──────────────────┘
│
▼
┌──────────────────┐
│ completeCart │
│ (Step 7) │
└──────────────────┘
│
▼
┌──────────────────┐
│ capturePayment │
│ (Step 8) │
└──────────────────┘
│
▼
┌──────────────────┐
│ Return Order │
└──────────────────┘
Usage¶
Running the Workflow¶
The workflow is called from the POST /store/orders endpoint:
const { result: order } = await createOrderAtomicWorkflow(req.scope).run({
input: {
region_id,
phone_number,
customer,
items,
delivery_area_id,
shipping_method,
},
})
Input Schema¶
{
region_id: string // Medusa region ID
phone_number: string // Customer phone number
customer: {
name: string // Full name
phone_number: string // Phone number
town: string // City/town
address_road: string // Street address line 1
address_home: string // Street address line 2
address_block: string // Block/area code
}
items: Array<{
variant_id: string // Product variant ID
quantity: number // Quantity (>= 1)
}>
delivery_area_id: string // Shipping option ID
shipping_method: string // "delivery" or "pick_up"
}
Output Schema¶
{
order: {
id: string
email: string
status: string
items: Array<{
id: string
variant_id: string
quantity: number
unit_price: number
total: number
}>
shipping_address: {
first_name: string
last_name: string
phone: string
city: string
address_1: string
address_2: string
postal_code: string
country_code: string
}
billing_address: {...}
total: number
created_at: string
}
}
Debugging¶
Common Issues¶
1. Insufficient Stock Error - Symptom: Workflow fails with INSUFFICIENT_STOCK error - Cause: Requested quantity exceeds available inventory - Fix: Check inventory levels in Medusa admin dashboard
2. Cart Creation Failure - Symptom: Workflow fails at Step 2 - Cause: Invalid region_id or database connection issue - Fix: Verify region exists in Medusa, check database connection
3. Shipping Method Not Found - Symptom: Workflow fails at Step 5 - Cause: Invalid delivery_area_id or no pickup option available - Fix: Check shipping options in Medusa admin dashboard
4. Payment Session Failure - Symptom: Workflow fails at Step 6 - Cause: Manual payment provider not configured - Fix: Ensure manual payment provider is enabled in medusa-config.ts
Debugging in Medusa Dashboard¶
- Navigate to
http://localhost:9000/app - Go to Orders section
- Check for failed orders or incomplete carts
- Review order details for error messages
Checking Workflow Logs¶
Workflow errors are logged to the Medusa backend logs:
Testing the Workflow¶
Use the POST /store/orders endpoint with test data:
curl -X POST http://localhost:9000/store/orders \
-H "Content-Type: application/json" \
-d '{
"region_id": "reg_123",
"phone_number": "+97312345678",
"customer": {
"name": "Test Customer",
"phone_number": "+97312345678",
"town": "Manama",
"address_road": "Test Street",
"address_home": "Building 1",
"address_block": "123"
},
"items": [
{
"variant_id": "variant_123",
"quantity": 1
}
],
"delivery_area_id": "ship_123",
"shipping_method": "delivery"
}'
Compensation Strategy¶
The workflow uses Medusa's compensation mechanism to ensure data consistency:
- Step 2: Deletes cart on failure
- Step 5: Removes shipping method on failure
- Step 6: Deletes payment session on failure
- Step 7: Cancels order and restores stock on failure
- Step 8: Voids payment on failure
If any step fails, the compensation functions for previous successful steps are executed in reverse order, ensuring the system returns to its original state.
Performance Considerations¶
- The workflow is atomic and runs synchronously
- Each step makes database calls
- Total execution time depends on database latency
- Consider adding caching for inventory checks if performance issues arise
Security Notes¶
- Phone numbers are used to generate synthetic emails
- No sensitive customer data is stored beyond what Medusa requires
- All operations are validated by Medusa's built-in services
- Manual payment provider does not process actual payments