# Orders API

The Orders API allows you to manage orders created from baskets. Track order status, update order data, and retrieve order history.

## Import

```typescript
import { Orders, OrderStatus } from 'lua-cli';
```

## Overview

The Orders API enables:
- Retrieve user orders with optional status filtering
- Get specific orders by ID
- Update order status (pending → processing → shipped → delivered)
- Update order data (shipping info, tracking, notes)
- Track order lifecycle
- Save changes to orders

## Methods

| Method | Description |
|--------|-------------|
| `Orders.get(status?)` | Get all user orders, optionally filtered by status |
| `Orders.getById(orderId)` | Get a specific order by ID |

## Order Status

```typescript
enum OrderStatus {
  PENDING = 'pending',
  PROCESSING = 'processing',
  SHIPPED = 'shipped',
  DELIVERED = 'delivered',
  CANCELLED = 'cancelled',
  REFUNDED = 'refunded'
}
```

## OrderInstance Methods

Once you have an order instance, you can call these methods:

### `order.updateStatus(status)`

Updates the order's status.

**Parameters:**
- `status` (OrderStatus) - New order status

**Returns:** `Promise<Order>` - Updated order data

**Example:**
```typescript
await order.updateStatus(OrderStatus.SHIPPED);
```

### `order.update(data)`

Updates the order's data fields.

**Parameters:**
- `data` (object) - Data fields to update
  - `trackingNumber` (string, optional)
  - `shippingCarrier` (string, optional)
  - `notes` (string, optional)
  - `estimatedDelivery` (string, optional)
  - Any custom fields

**Returns:** `Promise<Order>` - Updated order data

**Example:**
```typescript
await order.update({
  trackingNumber: 'TRACK123456',
  shippingCarrier: 'FedEx',
  estimatedDelivery: '2025-02-10'
});
```

### `order.save()`

Saves the current order data.

**Returns:** `Promise<boolean>` - True if save was successful

**Example:**
```typescript
order.notes = 'Customer requested gift wrap';
await order.save();
```

## Complete Examples

### Track Order Tool

```typescript
import { LuaTool, Orders } from 'lua-cli';
import { z } from 'zod';

export default class TrackOrderTool implements LuaTool {
  name = 'track_order';
  description = 'Track an order by order ID';

  inputSchema = z.object({
    orderId: z.string().describe('Order ID to track')
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    try {
      const order = await Orders.getById(input.orderId);

      return {
        success: true,
        orderId: order.orderId,
        status: order.status,
        trackingNumber: order.trackingNumber || 'Not available yet',
        shippingCarrier: order.shippingCarrier || 'N/A',
        estimatedDelivery: order.estimatedDelivery || 'TBD',
        items: order.items,
        totalAmount: order.totalAmount
      };
    } catch (error) {
      return {
        success: false,
        error: 'Order not found'
      };
    }
  }
}
```

### Order History Tool

```typescript
import { LuaTool, Orders, OrderStatus } from 'lua-cli';
import { z } from 'zod';

export default class OrderHistoryTool implements LuaTool {
  name = 'order_history';
  description = 'View order history';

  inputSchema = z.object({
    status: z.nativeEnum(OrderStatus).optional()
      .describe('Filter by order status')
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const orders = await Orders.get(input.status);

    if (orders.length === 0) {
      return {
        success: true,
        message: input.status
          ? `No ${input.status} orders found`
          : 'No orders found',
        orders: []
      };
    }

    return {
      success: true,
      orderCount: orders.length,
      orders: orders.map(order => ({
        orderId: order.orderId,
        status: order.status,
        totalAmount: order.totalAmount,
        itemCount: order.items?.length || 0,
        createdAt: order.createdAt,
        trackingNumber: order.trackingNumber
      }))
    };
  }
}
```

### Cancel Order Tool

```typescript
import { LuaTool, Orders, OrderStatus } from 'lua-cli';
import { z } from 'zod';

export default class CancelOrderTool implements LuaTool {
  name = 'cancel_order';
  description = 'Cancel a pending order';

  inputSchema = z.object({
    orderId: z.string().describe('Order ID to cancel'),
    reason: z.string().optional().describe('Cancellation reason')
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    try {
      const order = await Orders.getById(input.orderId);

      // Only allow cancellation of pending/processing orders
      if (order.status === OrderStatus.SHIPPED ||
          order.status === OrderStatus.DELIVERED) {
        return {
          success: false,
          error: 'Cannot cancel orders that are already shipped or delivered'
        };
      }

      if (order.status === OrderStatus.CANCELLED) {
        return {
          success: false,
          error: 'Order is already cancelled'
        };
      }

      // Update order
      await order.updateStatus(OrderStatus.CANCELLED);
      await order.update({
        cancellationReason: input.reason || 'Customer request',
        cancelledAt: new Date().toISOString()
      });

      return {
        success: true,
        message: 'Order cancelled successfully',
        orderId: order.orderId,
        refundAmount: order.totalAmount
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Failed to cancel order'
      };
    }
  }
}
```

### Update Shipping Tool

```typescript
import { LuaTool, Orders, OrderStatus } from 'lua-cli';
import { z } from 'zod';

export default class UpdateShippingTool implements LuaTool {
  name = 'update_shipping';
  description = 'Update order shipping information';

  inputSchema = z.object({
    orderId: z.string(),
    trackingNumber: z.string(),
    carrier: z.string().optional(),
    estimatedDelivery: z.string().optional()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    try {
      const order = await Orders.getById(input.orderId);

      // Update status to shipped if not already
      if (order.status === OrderStatus.PENDING ||
          order.status === OrderStatus.PROCESSING) {
        await order.updateStatus(OrderStatus.SHIPPED);
      }

      // Update shipping details
      await order.update({
        trackingNumber: input.trackingNumber,
        shippingCarrier: input.carrier || 'Standard',
        estimatedDelivery: input.estimatedDelivery,
        shippedAt: new Date().toISOString()
      });

      return {
        success: true,
        message: 'Shipping information updated',
        orderId: order.orderId,
        trackingNumber: input.trackingNumber,
        status: order.status
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Update failed'
      };
    }
  }
}
```

### Recent Orders Tool

```typescript
import { LuaTool, Orders } from 'lua-cli';
import { z } from 'zod';

export default class RecentOrdersTool implements LuaTool {
  name = 'recent_orders';
  description = 'Get recent orders (last 5)';

  inputSchema = z.object({});

  async execute() {
    const orders = await Orders.get();

    // Sort by creation date (most recent first)
    const sortedOrders = orders
      .sort((a, b) =>
        new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
      )
      .slice(0, 5);

    if (sortedOrders.length === 0) {
      return {
        success: true,
        message: 'No orders found',
        orders: []
      };
    }

    return {
      success: true,
      orderCount: sortedOrders.length,
      orders: sortedOrders.map(order => ({
        orderId: order.orderId,
        status: order.status,
        totalAmount: order.totalAmount,
        itemCount: order.items?.length || 0,
        createdAt: order.createdAt
      }))
    };
  }
}
```

### Mark as Delivered Tool

```typescript
import { LuaTool, Orders, OrderStatus, User } from 'lua-cli';
import { z } from 'zod';

export default class MarkDeliveredTool implements LuaTool {
  name = 'mark_delivered';
  description = 'Mark order as delivered';

  inputSchema = z.object({
    orderId: z.string(),
    signature: z.string().optional(),
    deliveredTo: z.string().optional()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    try {
      const order = await Orders.getById(input.orderId);

      // Verify order was shipped
      if (order.status !== OrderStatus.SHIPPED) {
        return {
          success: false,
          error: 'Only shipped orders can be marked as delivered'
        };
      }

      // Update status
      await order.updateStatus(OrderStatus.DELIVERED);

      // Update delivery details
      await order.update({
        deliveredAt: new Date().toISOString(),
        deliveredTo: input.deliveredTo,
        signature: input.signature
      });

      // Notify user
      const user = await User.get();
      await user.send([{
        type: 'text',
        text: `✅ Your order #${order.orderId} has been delivered!`
      }]);

      return {
        success: true,
        message: 'Order marked as delivered',
        orderId: order.orderId,
        deliveredAt: new Date().toISOString()
      };
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Update failed'
      };
    }
  }
}
```

## Order Properties

Order instances provide direct access to properties:

```typescript
const order = await Orders.getById('order_123');

console.log(order.id);                  // Internal ID
console.log(order.orderId);             // Order ID
console.log(order.status);              // Order status
console.log(order.items);               // Array of order items
console.log(order.totalAmount);         // Total order value
console.log(order.shippingAddress);     // Shipping address
console.log(order.trackingNumber);      // Tracking number
console.log(order.shippingCarrier);     // Carrier name
console.log(order.estimatedDelivery);   // Estimated delivery date
console.log(order.createdAt);           // Creation timestamp
```

## Best Practices

### ✅ DO

- Update order status as it progresses through fulfillment
- Provide tracking information as soon as available
- Use appropriate status values for each stage
- Keep customers informed with notifications
- Validate status transitions (don't skip steps)
- Add tracking numbers when marking as shipped
- Store delivery confirmations

### ❌ DON'T

- Don't skip from pending directly to delivered
- Don't update orders without proper validation
- Don't forget to notify customers of status changes
- Don't lose tracking information
- Don't allow cancellation of shipped/delivered orders
- Don't mark as delivered without confirmation

## Error Handling

```typescript
try {
  const order = await Orders.getById('order_123');
  await order.updateStatus(OrderStatus.SHIPPED);
} catch (error) {
  if (error.message.includes('not found')) {
    console.log('Order not found');
  } else if (error.message.includes('invalid status')) {
    console.log('Invalid status transition');
  } else {
    console.log('Failed to update order:', error.message);
  }
}
```

## Common Patterns

### Status Workflow

```typescript
// Typical order lifecycle
await order.updateStatus(OrderStatus.PENDING);      // Order placed
await order.updateStatus(OrderStatus.PROCESSING);   // Payment confirmed
await order.updateStatus(OrderStatus.SHIPPED);      // Package shipped
await order.updateStatus(OrderStatus.DELIVERED);    // Package delivered

// Alternative flows
await order.updateStatus(OrderStatus.CANCELLED);    // Cancelled by customer
await order.updateStatus(OrderStatus.REFUNDED);     // Refund processed
```

### Send Status Update Notification

```typescript
async function notifyOrderStatus(
  order: OrderInstance,
  newStatus: OrderStatus
): Promise<void> {
  const user = await User.get();

  const messages = {
    [OrderStatus.PROCESSING]: 'Your order is being processed',
    [OrderStatus.SHIPPED]: `Your order has shipped! Tracking: ${order.trackingNumber}`,
    [OrderStatus.DELIVERED]: 'Your order has been delivered!',
    [OrderStatus.CANCELLED]: 'Your order has been cancelled',
  };

  await user.send([{
    type: 'text',
    text: messages[newStatus] || `Order status: ${newStatus}`
  }]);
}
```

### Get Order Summary

```typescript
function getOrderSummary(order: OrderInstance) {
  return {
    orderId: order.orderId,
    status: order.status,
    totalItems: order.items?.length || 0,
    totalAmount: order.totalAmount,
    tracking: order.trackingNumber || 'Not available',
    createdAt: order.createdAt
  };
}
```

## Related APIs

- [Baskets API](./Baskets.md) - Create orders from baskets
- [Products API](./Products.md) - Product information
- [User API](./User.md) - Notify users about orders

## See Also

- [Order Fulfillment Guide](../guides/OrderFulfillment.md)
- [E-commerce Guide](../guides/Ecommerce.md)
