Skip to main content

Cart to Order Flow

This guide walks you through implementing the complete shopping cart to order conversion process.

Overview

The cart-to-order flow involves several steps:
  1. Add items to cart
  2. Validate cart contents
  3. Calculate totals and fees
  4. Process payment
  5. Create order
  6. Update inventory
  7. Send notifications

Step-by-Step Implementation

1. Add Items to Cart

// Add product to cart
const addToCart = async (productId: string, quantity: number) => {
  await convex.mutation(api.customers.cart.addToCart, {
    productId,
    quantity,
    customerId: "user_123"
  });
};

2. Validate Cart for Checkout

// Validate cart before checkout
const validation = await convex.query(api.customers.cartToOrder.validateCartForCheckout, {
  customerId: "user_123"
});

if (!validation.isValid) {
  console.error("Cart validation failed:", validation.errors);
  return;
}

3. Create Payment Intent

// Create Stripe payment intent
const paymentIntent = await convex.mutation(api.customers.payments.createPaymentIntent, {
  amount: validation.totalAmount,
  currency: "AED",
  customerId: "user_123"
});

4. Process Payment

// Use Stripe client to confirm payment
const { error } = await stripe.confirmPayment({
  clientSecret: paymentIntent.clientSecret,
  elements,
  confirmParams: {
    return_url: "https://yourapp.com/return"
  }
});

5. Create Order from Cart

// Convert cart to order after successful payment
const order = await convex.mutation(api.customers.cartToOrder.createOrderFromCart, {
  customerId: "user_123",
  paymentIntentId: paymentIntent.id,
  shippingAddress: {
    street: "123 Main St",
    city: "Dubai",
    emirate: "Dubai",
    postalCode: "12345"
  }
});

Complete Flow Example

const completeCheckout = async () => {
  try {
    // 1. Validate cart
    const validation = await convex.query(api.customers.cartToOrder.validateCartForCheckout, {
      customerId: currentUser.id
    });

    if (!validation.isValid) {
      throw new Error(`Cart validation failed: ${validation.errors.join(", ")}`);
    }

    // 2. Create payment intent
    const paymentIntent = await convex.mutation(api.customers.payments.createPaymentIntent, {
      amount: validation.totalAmount,
      currency: "AED",
      customerId: currentUser.id
    });

    // 3. Process payment with Stripe
    const { error } = await stripe.confirmPayment({
      clientSecret: paymentIntent.clientSecret,
      elements,
      confirmParams: {
        return_url: `${window.location.origin}/checkout/success`
      }
    });

    if (error) {
      throw new Error(`Payment failed: ${error.message}`);
    }

    // 4. Create order
    const order = await convex.mutation(api.customers.cartToOrder.createOrderFromCart, {
      customerId: currentUser.id,
      paymentIntentId: paymentIntent.id,
      shippingAddress: shippingAddress
    });

    // 5. Clear cart
    await convex.mutation(api.customers.cart.clearCart, {
      customerId: currentUser.id
    });

    return order;
  } catch (error) {
    console.error("Checkout failed:", error);
    throw error;
  }
};

Error Handling

Common Validation Errors

  • Out of stock: Product no longer available
  • Price changes: Product price updated
  • Invalid quantities: Quantity exceeds available stock
  • Store unavailable: Store is not accepting orders

Payment Errors

  • Insufficient funds: Card declined
  • Invalid card: Card details incorrect
  • Network error: Payment processing failed

Best Practices

  1. Always validate cart before payment
  2. Handle errors gracefully with user-friendly messages
  3. Clear cart only after successful order creation
  4. Send confirmations via email and push notifications
  5. Update inventory immediately after order creation
The cart-to-order flow is designed to be atomic - either all steps succeed or none do, ensuring data consistency.