← back to Designer Wallcoverings
DW-Agents/dw-agents/auto-reorder-ai.ts
228 lines
/**
* Auto-Reorder AI - Intelligent Predictions
* Analyzes usage patterns and predicts when to reorder
*/
import * as fs from 'fs';
interface InventoryItem {
item: string;
quantity: number;
reorderLevel: number;
lastOrdered: Date | null;
}
interface Order {
id: string;
item: string;
vendor: string;
price: number;
status: string;
timestamp: Date;
}
interface ReorderPrediction {
item: string;
currentQuantity: number;
reorderLevel: number;
daysUntilReorder: number;
urgency: 'critical' | 'high' | 'medium' | 'low';
suggestedQuantity: number;
estimatedCost: number;
reasoning: string;
bulkOpportunity?: {
savings: number;
quantity: number;
description: string;
};
}
/**
* Calculate usage rate based on order history
*/
function calculateUsageRate(item: string, orders: Order[], inventory: InventoryItem[]): number {
// Find all orders for this item
const itemOrders = orders.filter(o =>
o.item.toLowerCase().includes(item.toLowerCase().split(' ')[0])
).sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
if (itemOrders.length < 2) {
// Default usage rate if not enough data
return 0.1; // Assume 10% per month
}
// Calculate average time between orders
let totalDays = 0;
for (let i = 1; i < itemOrders.length; i++) {
const days = (new Date(itemOrders[i].timestamp).getTime() - new Date(itemOrders[i-1].timestamp).getTime()) / (1000 * 60 * 60 * 24);
totalDays += days;
}
const avgDaysBetweenOrders = totalDays / (itemOrders.length - 1);
// Find current inventory item
const invItem = inventory.find(inv => inv.item.toLowerCase().includes(item.toLowerCase()));
if (!invItem) return 0.1;
// Calculate daily usage rate
const dailyUsage = invItem.reorderLevel / avgDaysBetweenOrders;
return dailyUsage;
}
/**
* Generate AI-powered reorder predictions
*/
export async function generateReorderPredictions(): Promise<ReorderPrediction[]> {
console.log('🤖 Analyzing inventory and generating AI predictions...\n');
// Load data
const ordersPath = '/root/Projects/Designer-Wallcoverings/DW-Agents/data/amazon-orders.json';
const inventoryPath = '/root/Projects/Designer-Wallcoverings/DW-Agents/data/office-inventory.json';
if (!fs.existsSync(ordersPath) || !fs.existsSync(inventoryPath)) {
console.log('❌ Data files not found');
return [];
}
const orders: Order[] = JSON.parse(fs.readFileSync(ordersPath, 'utf-8'));
const inventory: InventoryItem[] = JSON.parse(fs.readFileSync(inventoryPath, 'utf-8'));
const predictions: ReorderPrediction[] = [];
for (const item of inventory) {
// Calculate usage rate
const dailyUsage = calculateUsageRate(item.item, orders, inventory);
// Calculate days until reorder needed
const quantityAboveReorder = item.quantity - item.reorderLevel;
const daysUntilReorder = Math.max(0, Math.floor(quantityAboveReorder / dailyUsage));
// Determine urgency
let urgency: 'critical' | 'high' | 'medium' | 'low';
if (daysUntilReorder <= 0) urgency = 'critical';
else if (daysUntilReorder <= 7) urgency = 'high';
else if (daysUntilReorder <= 30) urgency = 'medium';
else urgency = 'low';
// Suggested quantity (order enough for 60 days)
const suggestedQuantity = Math.ceil(dailyUsage * 60);
// Find last price
const lastOrder = orders
.filter(o => o.item.toLowerCase().includes(item.item.toLowerCase().split(' ')[0]))
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())[0];
const estimatedCost = lastOrder ? lastOrder.price * suggestedQuantity : 0;
// Generate reasoning
let reasoning = '';
if (urgency === 'critical') {
reasoning = `⚠️ URGENT: At or below reorder level. Order immediately!`;
} else if (urgency === 'high') {
reasoning = `Will need reorder in ${daysUntilReorder} days. Order within this week.`;
} else if (urgency === 'medium') {
reasoning = `Good stock for now. Plan to reorder in ~${daysUntilReorder} days.`;
} else {
reasoning = `Well stocked. No action needed for ${daysUntilReorder}+ days.`;
}
// Bulk opportunity detection
let bulkOpportunity = undefined;
if (suggestedQuantity >= 10 && estimatedCost > 50) {
bulkOpportunity = {
savings: estimatedCost * 0.15, // Assume 15% bulk savings
quantity: suggestedQuantity * 2, // Buy 2x for bigger discount
description: `Buy ${suggestedQuantity * 2} units and save ~15% with bulk pricing`
};
}
predictions.push({
item: item.item,
currentQuantity: item.quantity,
reorderLevel: item.reorderLevel,
daysUntilReorder,
urgency,
suggestedQuantity,
estimatedCost,
reasoning,
bulkOpportunity
});
}
// Sort by urgency
const urgencyOrder = { critical: 0, high: 1, medium: 2, low: 3 };
predictions.sort((a, b) => urgencyOrder[a.urgency] - urgencyOrder[b.urgency]);
return predictions;
}
/**
* Display reorder predictions
*/
export async function displayReorderPredictions(): Promise<void> {
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('🤖 AI Auto-Reorder Predictions');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
const predictions = await generateReorderPredictions();
// Group by urgency
const critical = predictions.filter(p => p.urgency === 'critical');
const high = predictions.filter(p => p.urgency === 'high');
const medium = predictions.filter(p => p.urgency === 'medium');
const low = predictions.filter(p => p.urgency === 'low');
if (critical.length > 0) {
console.log('🚨 CRITICAL - ORDER NOW:\n');
critical.forEach(p => {
console.log(`${p.item}`);
console.log(` Current: ${p.currentQuantity} | Reorder: ${p.reorderLevel}`);
console.log(` ${p.reasoning}`);
console.log(` Suggested: Order ${p.suggestedQuantity} units (~$${p.estimatedCost.toFixed(2)})\n`);
});
}
if (high.length > 0) {
console.log('⚠️ HIGH PRIORITY - ORDER THIS WEEK:\n');
high.forEach(p => {
console.log(`${p.item}`);
console.log(` Current: ${p.currentQuantity} | Reorder: ${p.reorderLevel}`);
console.log(` ${p.reasoning}`);
console.log(` Suggested: Order ${p.suggestedQuantity} units (~$${p.estimatedCost.toFixed(2)})`);
if (p.bulkOpportunity) {
console.log(` 💰 BULK DEAL: ${p.bulkOpportunity.description}`);
console.log(` Save ~$${p.bulkOpportunity.savings.toFixed(2)}`);
}
console.log('');
});
}
if (medium.length > 0) {
console.log('📋 MEDIUM - PLAN AHEAD:\n');
medium.slice(0, 5).forEach(p => {
console.log(`${p.item} - Reorder in ${p.daysUntilReorder} days`);
});
console.log('');
}
console.log(`✅ LOW PRIORITY: ${low.length} items well stocked\n`);
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
}
// Save predictions to file for agent to use
export async function saveReorderPredictions(): Promise<void> {
const predictions = await generateReorderPredictions();
const outputPath = '/root/Projects/Designer-Wallcoverings/DW-Agents/data/reorder-predictions.json';
fs.writeFileSync(outputPath, JSON.stringify(predictions, null, 2));
console.log(`✅ Predictions saved to: ${outputPath}`);
}
// Run if called directly
if (require.main === module) {
displayReorderPredictions().catch(console.error);
}
export { ReorderPrediction };