> ## Documentation Index
> Fetch the complete documentation index at: https://twigz.arqqin.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Orders Admin

> Administrative order management, analytics, and bulk operations

## Overview

Orders Admin API provides comprehensive order management tools for platform administrators. Includes order listing with filtering, status management, revenue analytics, store performance rankings, and bulk delete operations. All functions require admin authorization.

**Location:** `convex/admins/ordersAdmin.ts`

***

## Get All Orders

Fetches all orders with filtering and cursor-based pagination. Orders are returned newest first, enriched with customer name, store name, and item count. Supports filtering by status, store, customer, date range, and text search (searches customer name, store name, and order ID).

<ParamField path="status" type="string">
  Filter by order status: `pending`, `preparing`, `ready`, `out_for_delivery`, `delivered`, `cancelled`
</ParamField>

<ParamField path="storeId" type="Id<'stores'>">
  Filter orders by store. Uses the `by_store` index for efficient lookup.
</ParamField>

<ParamField path="customerId" type="Id<'customers'>">
  Filter orders by customer
</ParamField>

<ParamField path="searchQuery" type="string">
  Text search across customer name, store name, and order ID (case-insensitive)
</ParamField>

<ParamField path="startDate" type="number">
  Filter orders created on or after this timestamp (milliseconds)
</ParamField>

<ParamField path="endDate" type="number">
  Filter orders created on or before this timestamp (milliseconds)
</ParamField>

<ParamField path="paginationOpts" type="PaginationOptions" required>
  Pagination options (numItems, cursor)
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const orders = await convex.query(api.admins.ordersAdmin.getAllOrders, {
    paginationOpts: { numItems: 20, cursor: null },
    status: "pending",
    searchQuery: "Pizza"
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "page": [
      {
        "_id": "o123456789",
        "_creationTime": 1700000000000,
        "status": "pending",
        "totalAmount": 125.50,
        "customerId": "c111",
        "storeId": "s222",
        "customerName": "Ahmed Ali",
        "storeName": "Pizza Palace",
        "itemsCount": 3,
        "orderItems": [...]
      }
    ],
    "continueCursor": "abc123",
    "isDone": false
  }
  ```
</ResponseExample>

***

## Get Store Orders

Fetches orders for a specific store with pagination. Returns enriched orders with customer name, phone number, and item count, plus the store name and total order count.

<ParamField path="storeId" type="Id<'stores'>" required>
  Store ID to fetch orders for
</ParamField>

<ParamField path="status" type="string">
  Filter by order status: `pending`, `preparing`, `ready`, `out_for_delivery`, `delivered`, `cancelled`
</ParamField>

<ParamField path="paginationOpts" type="PaginationOptions" required>
  Pagination options (numItems, cursor)
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const storeOrders = await convex.query(api.admins.ordersAdmin.getStoreOrders, {
    storeId: "s222",
    status: "delivered",
    paginationOpts: { numItems: 20, cursor: null }
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "page": [
      {
        "_id": "o123456789",
        "_creationTime": 1700000000000,
        "status": "delivered",
        "totalAmount": 85.00,
        "customerName": "Ahmed Ali",
        "customerPhone": "+971501234567",
        "itemsCount": 2
      }
    ],
    "continueCursor": "abc123",
    "isDone": true,
    "storeName": "Pizza Palace",
    "totalOrders": 156
  }
  ```
</ResponseExample>

***

## Get Order Status Counts

Returns live order counts grouped by status. Used for dashboard cards showing per-status totals.

*No arguments required.*

<CodeGroup>
  ```typescript TypeScript theme={null}
  const counts = await convex.query(api.admins.ordersAdmin.getOrderStatusCounts, {});
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "pending": 12,
    "preparing": 8,
    "ready": 5,
    "out_for_delivery": 15,
    "delivered": 1240,
    "cancelled": 42,
    "total": 1322
  }
  ```
</ResponseExample>

***

## Get Order Statistics

Returns order statistics from the pre-computed `adminOrderStats` aggregate table. Supports daily or all-time views.

<ParamField path="date" type="string">
  Date in `YYYY-MM-DD` format for daily stats. Omit for all-time statistics.
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  // All-time stats
  const allTime = await convex.query(api.admins.ordersAdmin.getOrderStatistics, {});

  // Daily stats
  const daily = await convex.query(api.admins.ordersAdmin.getOrderStatistics, {
    date: "2026-03-09"
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "totalOrders": 1322,
    "completedOrders": 1240,
    "cancelledOrders": 42,
    "totalRevenue": 156000.50,
    "averageOrderValue": 125.81,
    "lastUpdated": 1700000000000
  }
  ```
</ResponseExample>

<Note>
  When no stats exist for the requested date, all values return as zero. The `averageOrderValue` is calculated as `totalRevenue / completedOrders`.
</Note>

***

## Get Order Details

Fetches full details for a single order, including enriched customer info, store info, order items, and status history timeline.

<ParamField path="orderId" type="Id<'orders'>" required>
  Order ID to retrieve
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const details = await convex.query(api.admins.ordersAdmin.getOrderDetails, {
    orderId: "o123456789"
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "_id": "o123456789",
    "_creationTime": 1700000000000,
    "status": "delivered",
    "totalAmount": 125.50,
    "customer": {
      "_id": "c111",
      "name": "Ahmed Ali",
      "email": "ahmed@example.com",
      "phoneNumber": "+971501234567"
    },
    "store": {
      "_id": "s222",
      "name": "Pizza Palace",
      "phoneNumber": "+971509876543"
    },
    "enrichedItems": [...],
    "statusHistory": [
      {
        "_id": "h111",
        "_creationTime": 1700000000000,
        "orderId": "o123456789",
        "previousStatus": "pending",
        "newStatus": "preparing",
        "changedBy": { "userId": "u111", "userType": "store", "userName": "Store Owner" },
        "notes": "Order accepted"
      }
    ]
  }
  ```
</ResponseExample>

<Note>
  Status history is sorted chronologically (oldest first). Order items already contain `productName` and `productImage` from the original order.
</Note>

***

## Update Order Status

Admin override to update an order's status. Records the change in the `orderStatusHistory` table with the admin marked as a `system` user type.

<ParamField path="orderId" type="Id<'orders'>" required>
  Order ID to update
</ParamField>

<ParamField path="status" type="string" required>
  New status: `pending`, `preparing`, `ready`, `out_for_delivery`, `delivered`, `cancelled`
</ParamField>

<ParamField path="adminNotes" type="string">
  Optional notes explaining the status change. Defaults to a generated message.
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  await convex.mutation(api.admins.ordersAdmin.updateOrderStatus, {
    orderId: "o123456789",
    status: "cancelled",
    adminNotes: "Customer requested cancellation via support"
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  null
  ```
</ResponseExample>

***

## Get Revenue Analytics

Returns revenue analytics grouped by time period. Only counts delivered (completed) orders.

<ParamField path="startDate" type="number" required>
  Start of date range (timestamp in milliseconds)
</ParamField>

<ParamField path="endDate" type="number" required>
  End of date range (timestamp in milliseconds)
</ParamField>

<ParamField path="groupBy" type="string">
  Grouping period: `day`, `week`, or `month`. Defaults to `day`.
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const revenue = await convex.query(api.admins.ordersAdmin.getRevenueAnalytics, {
    startDate: 1700000000000,
    endDate: 1702600000000,
    groupBy: "week"
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  [
    {
      "period": "2024-11-12",
      "totalOrders": 85,
      "totalRevenue": 10625.00,
      "averageOrderValue": 125.00
    },
    {
      "period": "2024-11-19",
      "totalOrders": 92,
      "totalRevenue": 11500.00,
      "averageOrderValue": 125.00
    }
  ]
  ```
</ResponseExample>

<Note>
  For `week` grouping, the period key is the Sunday (start of week) date. For `month` grouping, the format is `YYYY-MM`. Results are sorted chronologically.
</Note>

***

## Get Top Stores By Orders

Returns the top performing stores ranked by number of completed (delivered) orders, with revenue metrics.

<ParamField path="limit" type="number">
  Maximum number of stores to return. Defaults to 10.
</ParamField>

<ParamField path="startDate" type="number">
  Filter orders created on or after this timestamp (milliseconds)
</ParamField>

<ParamField path="endDate" type="number">
  Filter orders created on or before this timestamp (milliseconds)
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const topStores = await convex.query(api.admins.ordersAdmin.getTopStoresByOrders, {
    limit: 5,
    startDate: 1700000000000,
    endDate: 1702600000000
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  [
    {
      "storeId": "s222",
      "storeName": "Pizza Palace",
      "totalOrders": 320,
      "totalRevenue": 40000.00,
      "averageOrderValue": 125.00
    },
    {
      "storeId": "s333",
      "storeName": "Burger Hub",
      "totalOrders": 280,
      "totalRevenue": 33600.00,
      "averageOrderValue": 120.00
    }
  ]
  ```
</ResponseExample>

***

## Bulk Delete Orders

Permanently deletes multiple orders and their associated status history records. Processes in batches of 50 using internal mutations.

<ParamField path="orderIds" type="Id<'orders'>[]" required>
  Array of order IDs to delete
</ParamField>

<CodeGroup>
  ```typescript TypeScript theme={null}
  const result = await convex.action(api.admins.ordersAdmin.bulkDeleteOrders, {
    orderIds: ["o111", "o222", "o333"]
  });
  ```
</CodeGroup>

<ResponseExample>
  ```json Response theme={null}
  {
    "ordersDeleted": 3,
    "historyDeleted": 12
  }
  ```
</ResponseExample>

<Note>
  This is a Convex action that delegates to internal mutations in batches of 50. Each order's status history entries from `orderStatusHistory` are deleted before the order itself. Returns zero counts if an empty array is passed.
</Note>
