The getOrders tool retrieves order records from the Firebase/Firestore database with support for pagination, sorting, and automatic population of nested data (customer, contact, and staff references).
tools/getOrders.js
Retrieves orders for the authenticated account with cursor-based pagination support. This tool automatically fetches and embeds related customer, contact, technician, and responsible staff data. Orders are retrieved from the Firestore path: /Accounts/{accountId}/Orders.
{
limit?: number; // Number of records to retrieve (1-100, default: 50)
cursor?: string; // Document ID for cursor-based pagination
orderBy?: string; // Field to order by (default: "orderId")
orderDirection?: "asc" | "desc"; // Sort direction (default: "asc")
cursorDirection?: "next" | "previous"; // Direction for pagination (default: "next")
includeTotal?: boolean; // Include total count of all orders (default: false)
}
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
limit |
number | No | 50 | Maximum number of orders to return (1-100) |
cursor |
string | No | - | Document ID to start pagination from |
orderBy |
string | No | “orderId” | Field name to sort by |
orderDirection |
enum | No | “asc” | Sort direction: “asc” or “desc” |
cursorDirection |
enum | No | “next” | Pagination direction: “next” or “previous” |
includeTotal |
boolean | No | false | Whether to include total count (expensive) |
{
orders: Order[];
pagination: PaginationMetadata;
}
{
id: string; // Firestore document ID
path: string; // Full Firestore path
bcc: string[]; // BCC email addresses
closed: boolean; // Whether order is closed
pinned?: boolean; // Whether order is pinned
type?: string; // Order type
deadline?: string | Date; // Order deadline (converted to locale string)
location?: string; // Order location
createdAt: string | Date; // Creation timestamp (converted to locale string)
createdBy: string; // Creator user ID
lastCommentAt: string | Date | null; // Last comment timestamp
orderId: number; // Unique order ID
orderNumber: string; // Order number
ownedBy: string; // Owner user ID
stage: number | null; // Current stage number
stages: Stage[]; // Available stages
ticketNumber: string; // Ticket number
title: string; // Order title
users: User[]; // Associated users
customer: Customer | null; // Embedded customer data
contact: Contact | null; // Embedded contact data
technician_staff: Staff | null; // Embedded technician data
responsible_staff: Staff | null; // Embedded responsible staff data
}
{
id: string;
path: string;
address: string;
city: string;
country: string;
createdAt: string | Date;
createdBy: string;
customerId: number;
metadata: Record<string, any>;
name: string;
ownedBy: string;
zip: string;
}
{
id: string;
path: string;
contactId: number;
createdAt: string | Date;
createdBy: string;
customer: string;
email: string;
firstName: string;
greeting: string;
imported: boolean;
lastName: string;
mailchimp: { id: string | null };
metadata: Record<string, any>;
mobilePhone: string;
opt_out_email?: boolean;
opt_out_letter?: boolean;
ownedBy: string;
tags: any[];
telePhone: string;
}
{
id: string;
path: string;
name?: string;
email?: string;
}
{
color: string;
label: Record<string, string>; // Localized labels
stage: number;
}
{
email?: string;
name?: string;
}
{
limit: number; // Applied limit
hasMore: boolean; // Whether more results exist
nextCursor: string | null; // Cursor for next page
previousCursor: string | null; // Cursor for previous page
total?: number | null; // Total count (if includeTotal was true)
}
// Get first 10 orders with all nested data
const result = await getOrders(context, {
limit: 10
});
console.log(result.orders); // Array of 10 orders with nested data
console.log(result.orders[0].customer); // Embedded customer object
console.log(result.orders[0].contact); // Embedded contact object
// First page
const page1 = await getOrders(context, {
limit: 20,
orderBy: "orderId",
orderDirection: "desc" // Get newest orders first
});
// Next page
const page2 = await getOrders(context, {
limit: 20,
cursor: page1.pagination.nextCursor,
cursorDirection: "next"
});
// Note: Filtering by stage requires custom implementation
// Current tool returns all orders; filtering can be done client-side
const result = await getOrders(context, { limit: 100 });
const openOrders = result.orders.filter(order => !order.closed);
const stage1Orders = openOrders.filter(order => order.stage === 1);
// Get orders and filter for open ones
const result = await getOrders(context, {
limit: 50,
orderBy: "lastCommentAt",
orderDirection: "desc"
});
const openOrders = result.orders.filter(order => !order.closed);
The tool performs automatic data population for referenced documents:
customer reference pathcontact reference path/Accounts/{accountId}/Staff/{technician_staff}/Accounts/{accountId}/Staff/{responsible_staff}const customer = await getDocument(db, orderData.customer);
const contact = await getDocument(db, orderData.contact);
const technician = await getDocumentById(db, `Accounts/${accountId}/Staff`, orderData.technician_staff);
const responsible = await getDocumentById(db, `Accounts/${accountId}/Staff`, orderData.responsible_staff);
The tool uses a two-phase approach to handle async transforms:
// Phase 1: Get paginated results
const result = await executePaginatedQuery(ordersRef, options, (doc) => ({ doc }));
// Phase 2: Transform with nested data
const orders = await Promise.all(
result.items.map((item) => transformOrder(item.doc))
);
createdAt: Converted to locale string (de-DE format)lastCommentAt: Converted to locale string (de-DE format)deadline: Converted to locale string if presentIf any referenced document (customer, contact, staff) is not found or fails to load, it returns null instead of throwing an error. This ensures orders can still be retrieved even if references are broken.
| Error | Cause | Solution |
|---|---|---|
| “Error fetching orders: [message]” | Firestore query failed | Check Firebase connection and permissions |
| “Error fetching document at path [path]: [error]” | Referenced document not found | Document may have been deleted; returns null |
| Validation error | Invalid input parameters | Ensure parameters match the input schema |
Main query errors are logged and re-thrown:
catch (error) {
console.error("Error fetching orders:", error);
throw new Error(error.message);
}
Nested document errors are logged but return null:
catch (error) {
console.error(`Error fetching document at path ${path}:`, error);
return null;
}
Promise.allincludeTotal: true adds additional overhead/Accounts/{accountId}/Orders/{orderId}
- bcc: string[]
- closed: boolean
- pinned: boolean
- type: string
- deadline: timestamp
- location: string
- createdAt: timestamp
- createdBy: string
- lastCommentAt: timestamp
- orderId: number
- orderNumber: string
- ownedBy: string
- stage: number
- stages: array of stage objects
- ticketNumber: string
- title: string
- users: array of user objects
- customer: string (reference path)
- contact: string (reference path)
- technician_staff: string (document ID)
- responsible_staff: string (document ID)