/**
* track_order — Order tracking and fulfillment status for AI agents.
*
* Queries the Shopify Admin API for order details and fulfillment tracking
* information. Returns structured order status, tracking number, carrier,
* and estimated delivery data.
*
* When no Shopify access token is configured (local dev / testing), returns
* a realistic mock order so the tool can be exercised without live API keys.
*/
import type { Order, FulfillmentInfo } from '../types.js';
import { loadConfig } from '../types.js';
import { ShopifyClient } from '../shopify/client.js';
import { AdminAPI } from '../shopify/admin.js';
import { logger } from '../utils/logger.js';
// ─── Parameter / Result Interfaces ───
export interface TrackParams {
order_id: string;
}
export interface TrackingInfo {
status: string;
tracking_number?: string;
tracking_url?: string;
carrier?: string;
last_update?: string;
}
export interface TrackResult {
found: boolean;
order?: Order;
tracking?: TrackingInfo;
estimated_delivery?: string;
}
// ─── Mock Data (for local testing without Shopify keys) ───
function buildMockResult(orderId: string): TrackResult {
const now = new Date().toISOString();
const estimatedDelivery = new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString();
const mockOrder: Order = {
id: orderId,
checkout_id: `mock-checkout-${orderId}`,
status: 'shipped',
line_items: [
{
id: 'gid://shopify/LineItem/mock-1',
product_id: 'gid://shopify/Product/mock-100',
variant_id: 'gid://shopify/ProductVariant/mock-200',
title: 'Mock Product - Default',
quantity: 1,
unit_amount: 2999,
total_amount: 2999,
type: 'product',
sku: 'MOCK-SKU-001',
},
],
totals: {
subtotal: 2999,
tax: 300,
shipping: 500,
discount: 0,
fee: 0,
total: 3799,
currency: 'USD',
},
fulfillment: {
status: 'fulfilled',
tracking_number: '1Z999AA10123456784',
tracking_url: 'https://www.ups.com/track?tracknum=1Z999AA10123456784',
carrier: 'UPS',
estimated_delivery: estimatedDelivery,
},
created_at: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(),
updated_at: now,
};
return {
found: true,
order: mockOrder,
tracking: {
status: 'in_transit',
tracking_number: '1Z999AA10123456784',
tracking_url: 'https://www.ups.com/track?tracknum=1Z999AA10123456784',
carrier: 'UPS',
last_update: now,
},
estimated_delivery: estimatedDelivery,
};
}
// ─── Helpers ───
/**
* Map an Order + FulfillmentInfo into a flat TrackingInfo structure.
*/
function buildTrackingInfo(order: Order, fulfillment: FulfillmentInfo | undefined): TrackingInfo {
if (!fulfillment) {
return { status: 'unfulfilled' };
}
return {
status: fulfillment.status,
tracking_number: fulfillment.tracking_number,
tracking_url: fulfillment.tracking_url,
carrier: fulfillment.carrier,
last_update: order.updated_at,
};
}
// ─── Implementation ───
/**
* Retrieve order status and fulfillment tracking information.
*
* 1. Loads gateway config; if no access token is present, returns mock data
* so the tool is exercisable in local development.
* 2. Creates a ShopifyClient + AdminAPI and fetches the order by GID.
* 3. If the order does not exist, returns `{ found: false }`.
* 4. Extracts fulfillment / tracking info from the order and returns a
* structured result with order details, tracking info, and estimated
* delivery date.
*/
export async function trackOrder(params: TrackParams): Promise<TrackResult> {
try {
// 1. Load config and check for Shopify credentials
const config = loadConfig();
if (!config.shopify.accessToken) {
logger.info('track_order: no accessToken configured, returning mock data', {
order_id: params.order_id,
});
return buildMockResult(params.order_id);
}
// 2. Instantiate Shopify client and Admin API
const client = new ShopifyClient({
storeDomain: config.shopify.storeDomain,
accessToken: config.shopify.accessToken,
storefrontToken: config.shopify.storefrontToken,
});
const adminAPI = new AdminAPI(client);
// 3. Fetch the order
const order = await adminAPI.getOrder(params.order_id);
if (!order) {
return { found: false };
}
// 4. Build tracking info from fulfillment data
const tracking = buildTrackingInfo(order, order.fulfillment);
return {
found: true,
order,
tracking,
estimated_delivery: order.fulfillment?.estimated_delivery,
};
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
logger.error('track_order failed', { error: message, params });
return { found: false };
}
}