Daily Report
report_dailyRetrieve a daily operational report for a store, including orders, revenue, top products, customer metrics, low stock alerts, and anomaly count.
Instructions
Daily operational report: orders, revenue, top products, new vs returning customers, low stock alerts, and anomaly count.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| store_id | Yes | UUID of a connected store (returned by store_connect with action="connect" or visible in store_connect with action="list" / the store_overview resource) | |
| date | No | Calendar date for the report in YYYY-MM-DD (e.g. "2026-04-25"). Defaults to today (UTC). The report is computed against orders whose created_at falls within that calendar day. |
Implementation Reference
- src/index.ts:307-325 (registration)Tool registration for 'report_daily' with input schema (store_id required, date optional) and handler that calls generateDailyReport.
// ── Tool: report_daily ──────────────────────────────────────────── server.registerTool( 'report_daily', { title: 'Daily Report', description: 'Daily operational report: orders, revenue, top products, new vs returning customers, low stock alerts, and anomaly count.', inputSchema: z.object({ store_id: z.string().uuid().describe('UUID of a connected store (returned by store_connect with action="connect" or visible in store_connect with action="list" / the store_overview resource)'), date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be YYYY-MM-DD format').optional().describe('Calendar date for the report in YYYY-MM-DD (e.g. "2026-04-25"). Defaults to today (UTC). The report is computed against orders whose created_at falls within that calendar day.'), }), annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }, }, async ({ store_id, date }) => { try { const result = await generateDailyReport(store_id, date); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }; } catch (e) { return handleToolError(e); } } ); - src/models/store.ts:205-226 (schema)DailyReportSchema and DailyReport type defining the output shape: store_id, date, total_orders, total_revenue, avg_order_value, new_customers, returning_customers, top_products, low_stock_alerts, anomaly_count, and summary.
export const DailyReportSchema = z.object({ store_id: z.string().uuid(), date: z.string(), total_orders: z.number().int(), total_revenue: z.number(), avg_order_value: z.number(), new_customers: z.number().int(), returning_customers: z.number().int(), top_products: z.array(z.object({ title: z.string(), units: z.number().int(), revenue: z.number(), })), low_stock_alerts: z.array(z.object({ title: z.string(), current_stock: z.number().int(), days_left: z.number().nullable(), })), anomaly_count: z.number().int(), summary: z.string(), }); export type DailyReport = z.infer<typeof DailyReportSchema>; - src/tools/reports.ts:10-101 (handler)generateDailyReport function: the core implementation that fetches orders for the given date, computes revenue/avg order value, distinguishes new vs returning customers, finds top 5 products, checks low stock alerts (via forecastAll), counts anomalies (via detectAnomalies), and returns a DailyReport.
export async function generateDailyReport(storeId: string, date?: string): Promise<DailyReport> { validateUUID(storeId, 'store'); const store = await storage.getStoreById(storeId); if (!store) throw new NotFoundError('Store', storeId); const targetDate = date ?? new Date().toISOString().slice(0, 10); const dayStart = new Date(`${targetDate}T00:00:00Z`).getTime(); const dayEnd = dayStart + MS_PER_DAY; const allOrders = await storage.getOrders(storeId); const dayOrders = allOrders.filter((o) => { const ts = new Date(o.created_at).getTime(); return ts >= dayStart && ts < dayEnd && o.status !== 'cancelled' && o.status !== 'refunded'; }); const totalRevenue = dayOrders.reduce((sum, o) => sum + o.total, 0); const avgOrderValue = dayOrders.length > 0 ? totalRevenue / dayOrders.length : 0; // Count new vs returning const customerOrderCounts = new Map<string, number>(); for (const order of allOrders) { if (!order.customer_id || order.status === 'cancelled') continue; const ts = new Date(order.created_at).getTime(); if (ts < dayStart) { customerOrderCounts.set(order.customer_id, (customerOrderCounts.get(order.customer_id) ?? 0) + 1); } } let newCustomers = 0; let returningCustomers = 0; const seenCustomers = new Set<string>(); for (const order of dayOrders) { if (!order.customer_id || seenCustomers.has(order.customer_id)) continue; seenCustomers.add(order.customer_id); if ((customerOrderCounts.get(order.customer_id) ?? 0) > 0) { returningCustomers++; } else { newCustomers++; } } // Top products const productSales = new Map<string, { title: string; units: number; revenue: number }>(); for (const order of dayOrders) { for (const item of order.items) { const existing = productSales.get(item.product_id); if (existing) { existing.units += item.quantity; existing.revenue += item.total; } else { productSales.set(item.product_id, { title: item.title, units: item.quantity, revenue: item.total }); } } } const topProducts = [...productSales.values()] .sort((a, b) => b.revenue - a.revenue) .slice(0, 5) .map((p) => ({ title: p.title, units: p.units, revenue: Math.round(p.revenue * 100) / 100 })); // Low stock alerts const products = await storage.getProducts(storeId); const forecasts = forecastAll(products, allOrders); const lowStockAlerts = forecasts .filter((f) => f.risk_level === 'critical' || f.risk_level === 'high') .slice(0, 5) .map((f) => ({ title: f.product_title, current_stock: f.current_stock, days_left: f.days_of_stock })); // Anomalies const anomalies = detectAnomalies(allOrders); const anomalyCount = anomalies.filter((a) => a.risk_level === 'high' || a.risk_level === 'critical').length; // Summary const summaryParts: string[] = []; summaryParts.push(`${dayOrders.length} orders totaling $${totalRevenue.toFixed(2)}`); if (newCustomers > 0) summaryParts.push(`${newCustomers} new customer(s)`); if (lowStockAlerts.length > 0) summaryParts.push(`${lowStockAlerts.length} product(s) need restocking`); if (anomalyCount > 0) summaryParts.push(`${anomalyCount} order anomaly alert(s)`); return { store_id: storeId, date: targetDate, total_orders: dayOrders.length, total_revenue: Math.round(totalRevenue * 100) / 100, avg_order_value: Math.round(avgOrderValue * 100) / 100, new_customers: newCustomers, returning_customers: returningCustomers, top_products: topProducts, low_stock_alerts: lowStockAlerts, anomaly_count: anomalyCount, summary: summaryParts.join('. ') + '.', }; }