Loading supply_chain_sim/cmd_visual.py +381 −0 Original line number Diff line number Diff line Loading @@ -607,6 +607,387 @@ class VisualSimulation(SupplyChainSimulation): console.print(product_table) # Supply Chain Summary console.print("\n[bold cyan]📦 SUPPLY CHAIN OPERATIONS[/bold cyan]\n") operations_table = Table(show_header=False, box=None) operations_table.add_column("Metric", style="cyan") operations_table.add_column("Value", style="green", justify="right") operations_table.add_column("Details", style="dim") # Component analysis component_cost = sum(o.cost for o in self.all_orders) avg_lead_time = sum(o.expected_delivery for o in self.all_orders) / len(self.all_orders) if self.all_orders else 0 operations_table.add_row("Component Orders", str(total_orders), f"Total value: ${component_cost:,.0f}") operations_table.add_row("Average Lead Time", f"{avg_lead_time:.1f} days", "From order to delivery") operations_table.add_row("Watches Assembled", str(self.total_assembled), f"Capacity: {self.assembly.assembly_capacity}/day") operations_table.add_row("Distribution Points", str(len(self.distribution.distribution_history)), "Shipments to retailers") # Inventory status warehouse_components = sum(inv.quantity for inv in self.warehouse_inventories if inv.item_type == "component") warehouse_watches = sum(inv.quantity for inv in self.warehouse_inventories if inv.item_type == "watch") retailer_watches = sum(inv.quantity for inv in self.retailer_inventories) operations_table.add_row("Warehouse Components", str(warehouse_components), "Current stock") operations_table.add_row("Warehouse Watches", str(warehouse_watches), "Ready to ship") operations_table.add_row("Retailer Stock", str(retailer_watches), "Available for sale") console.print(Panel(operations_table, title="Operations Summary", border_style="cyan")) # Customer Analytics console.print("\n[bold cyan]👥 CUSTOMER ANALYTICS[/bold cyan]\n") # Sales by wealth class sales_by_wealth = defaultdict(lambda: {'count': 0, 'revenue': 0}) unique_buyers = set() for sale in self.all_sales: customer = next((c for c in self.setup.customers if c.id == sale.customer_id), None) if customer: sales_by_wealth[customer.wealth_class]['count'] += 1 sales_by_wealth[customer.wealth_class]['revenue'] += sale.total_price unique_buyers.add(customer.id) customer_table = Table(show_header=True, header_style="bold magenta") customer_table.add_column("Wealth Class", style="cyan") customer_table.add_column("Customers", justify="right") customer_table.add_column("Buyers", justify="right") customer_table.add_column("Sales", justify="right") customer_table.add_column("Revenue", justify="right", style="green") customer_table.add_column("Avg Ticket", justify="right") # Count customers by wealth class customers_by_wealth = defaultdict(int) buyers_by_wealth = defaultdict(set) for customer in self.setup.customers: customers_by_wealth[customer.wealth_class] += 1 for sale in self.all_sales: customer = next((c for c in self.setup.customers if c.id == sale.customer_id), None) if customer: buyers_by_wealth[customer.wealth_class].add(customer.id) for wc in range(1, 11): if wc in sales_by_wealth or wc in customers_by_wealth: data = sales_by_wealth[wc] n_customers = customers_by_wealth[wc] n_buyers = len(buyers_by_wealth[wc]) avg_ticket = data['revenue'] / data['count'] if data['count'] > 0 else 0 customer_table.add_row( f"Class {wc}", str(n_customers), str(n_buyers), str(data['count']), f"${data['revenue']:,.0f}", f"${avg_ticket:.0f}" ) console.print(customer_table) console.print(f"\n[cyan]Total Unique Buyers: {len(unique_buyers)} ({len(unique_buyers)/len(self.setup.customers)*100:.1f}% penetration)[/cyan]") console.print(f"[cyan]Return Rate: {len(self.customer_behavior.returns)/len(self.all_sales)*100:.1f}% ({len(self.customer_behavior.returns)} returns)[/cyan]") # Model Performance console.print("\n[bold cyan]🤖 AI MODEL PERFORMANCE[/bold cyan]\n") model_summary = self.model_update.get_model_performance_summary() accuracy_metrics = model_summary['forecast_accuracy'] model_table = Table(show_header=False, box=None) model_table.add_column("Metric", style="cyan") model_table.add_column("Value", style="green", justify="right") model_table.add_row("Training Data Points", str(model_summary['total_sales_records'])) model_table.add_row("Customer Segments", str(model_summary['customer_segments'])) model_table.add_row("Forecasts Evaluated", str(model_summary['forecasts_evaluated'])) model_table.add_row("MAPE", f"{accuracy_metrics['mape']:.1f}%") model_table.add_row("RMSE", f"{accuracy_metrics['rmse']:.2f}") model_table.add_row("ML Accuracy", f"{accuracy_metrics['accuracy']*100:.1f}%") console.print(Panel(model_table, title="Machine Learning Metrics", border_style="yellow")) # Final KPIs console.print("\n[bold cyan]💰 FINANCIAL PERFORMANCE[/bold cyan]\n") if self.research_logging.kpi_history: final_kpis = self.research_logging.kpi_history[-1] financial_table = Table(show_header=False, box=None) financial_table.add_column("Metric", style="cyan", width=25) financial_table.add_column("Value", style="bold green", justify="right") financial_table.add_column("Status", justify="center") # GMROI assessment gmroi_status = "🟢" if final_kpis['gmroi'] > 2 else "🟡" if final_kpis['gmroi'] > 1 else "🔴" financial_table.add_row("GMROI", f"{final_kpis['gmroi']:.3f}", gmroi_status) financial_table.add_row("Total Revenue", f"${final_kpis['total_revenue']:,.0f}", "🟢") financial_table.add_row("Gross Margin", f"${final_kpis['gross_margin']:,.0f}", "🟢") financial_table.add_row("COGS", f"${final_kpis['cogs']:,.0f}", "—") financial_table.add_row("Logistics Costs", f"${final_kpis['logistics_costs']:,.0f}", "—") margin_pct = (final_kpis['gross_margin'] / final_kpis['total_revenue'] * 100) if final_kpis['total_revenue'] > 0 else 0 financial_table.add_row("Margin %", f"{margin_pct:.1f}%", "🟢" if margin_pct > 60 else "🟡") financial_table.add_row("", "", "") financial_table.add_row("Warehouse Utilization", f"{final_kpis['warehouse_capacity_utilization']:.1%}", "🟢") financial_table.add_row("Retailer Utilization", f"{final_kpis['retailer_capacity_utilization']:.1%}", "🟢") console.print(Panel(financial_table, title="[bold]Financial KPIs[/bold]", border_style="green")) # Final completion console.print("\n[bold green]✅ Simulation completed successfully![/bold green]\n") log_to_file("Simulation completed successfully!") Loading supply_chain_sim/forecasting.py +5 −6 Original line number Diff line number Diff line Loading @@ -54,14 +54,13 @@ class Forecasting: return forecasts def _calculate_realistic_demand(self, watch, region: str) -> float: """Calculate realistic demand based on watch characteristics.""" # Base demand starts lower and more realistic # Current base demands are too high - reduce by factor of 10 if watch.category == 'luxury': base_demand = np.random.uniform(5, 15) # Luxury has lower volume base_demand = np.random.uniform(0.5, 1.5) # was 5-15 elif watch.category == 'sport': base_demand = np.random.uniform(10, 25) # Sport has medium volume base_demand = np.random.uniform(1, 2.5) # was 10-25 else: # casual base_demand = np.random.uniform(15, 30) # Casual has higher volume base_demand = np.random.uniform(1.5, 3) # was 15-30 # Price sensitivity - higher prices reduce demand price_factor = max(0.3, 1.0 - (watch.base_cost - 200) / 2000) Loading supply_chain_sim/supply_order.py +1 −1 Original line number Diff line number Diff line Loading @@ -132,7 +132,7 @@ class SupplyOrderLogic: remaining_orders = [] for order in self.pending_orders: order.expected_delivery -= time_elapsed max(0, order.expected_delivery - time_elapsed) if order.expected_delivery <= 0: delivered_orders.append(order) Loading Loading
supply_chain_sim/cmd_visual.py +381 −0 Original line number Diff line number Diff line Loading @@ -607,6 +607,387 @@ class VisualSimulation(SupplyChainSimulation): console.print(product_table) # Supply Chain Summary console.print("\n[bold cyan]📦 SUPPLY CHAIN OPERATIONS[/bold cyan]\n") operations_table = Table(show_header=False, box=None) operations_table.add_column("Metric", style="cyan") operations_table.add_column("Value", style="green", justify="right") operations_table.add_column("Details", style="dim") # Component analysis component_cost = sum(o.cost for o in self.all_orders) avg_lead_time = sum(o.expected_delivery for o in self.all_orders) / len(self.all_orders) if self.all_orders else 0 operations_table.add_row("Component Orders", str(total_orders), f"Total value: ${component_cost:,.0f}") operations_table.add_row("Average Lead Time", f"{avg_lead_time:.1f} days", "From order to delivery") operations_table.add_row("Watches Assembled", str(self.total_assembled), f"Capacity: {self.assembly.assembly_capacity}/day") operations_table.add_row("Distribution Points", str(len(self.distribution.distribution_history)), "Shipments to retailers") # Inventory status warehouse_components = sum(inv.quantity for inv in self.warehouse_inventories if inv.item_type == "component") warehouse_watches = sum(inv.quantity for inv in self.warehouse_inventories if inv.item_type == "watch") retailer_watches = sum(inv.quantity for inv in self.retailer_inventories) operations_table.add_row("Warehouse Components", str(warehouse_components), "Current stock") operations_table.add_row("Warehouse Watches", str(warehouse_watches), "Ready to ship") operations_table.add_row("Retailer Stock", str(retailer_watches), "Available for sale") console.print(Panel(operations_table, title="Operations Summary", border_style="cyan")) # Customer Analytics console.print("\n[bold cyan]👥 CUSTOMER ANALYTICS[/bold cyan]\n") # Sales by wealth class sales_by_wealth = defaultdict(lambda: {'count': 0, 'revenue': 0}) unique_buyers = set() for sale in self.all_sales: customer = next((c for c in self.setup.customers if c.id == sale.customer_id), None) if customer: sales_by_wealth[customer.wealth_class]['count'] += 1 sales_by_wealth[customer.wealth_class]['revenue'] += sale.total_price unique_buyers.add(customer.id) customer_table = Table(show_header=True, header_style="bold magenta") customer_table.add_column("Wealth Class", style="cyan") customer_table.add_column("Customers", justify="right") customer_table.add_column("Buyers", justify="right") customer_table.add_column("Sales", justify="right") customer_table.add_column("Revenue", justify="right", style="green") customer_table.add_column("Avg Ticket", justify="right") # Count customers by wealth class customers_by_wealth = defaultdict(int) buyers_by_wealth = defaultdict(set) for customer in self.setup.customers: customers_by_wealth[customer.wealth_class] += 1 for sale in self.all_sales: customer = next((c for c in self.setup.customers if c.id == sale.customer_id), None) if customer: buyers_by_wealth[customer.wealth_class].add(customer.id) for wc in range(1, 11): if wc in sales_by_wealth or wc in customers_by_wealth: data = sales_by_wealth[wc] n_customers = customers_by_wealth[wc] n_buyers = len(buyers_by_wealth[wc]) avg_ticket = data['revenue'] / data['count'] if data['count'] > 0 else 0 customer_table.add_row( f"Class {wc}", str(n_customers), str(n_buyers), str(data['count']), f"${data['revenue']:,.0f}", f"${avg_ticket:.0f}" ) console.print(customer_table) console.print(f"\n[cyan]Total Unique Buyers: {len(unique_buyers)} ({len(unique_buyers)/len(self.setup.customers)*100:.1f}% penetration)[/cyan]") console.print(f"[cyan]Return Rate: {len(self.customer_behavior.returns)/len(self.all_sales)*100:.1f}% ({len(self.customer_behavior.returns)} returns)[/cyan]") # Model Performance console.print("\n[bold cyan]🤖 AI MODEL PERFORMANCE[/bold cyan]\n") model_summary = self.model_update.get_model_performance_summary() accuracy_metrics = model_summary['forecast_accuracy'] model_table = Table(show_header=False, box=None) model_table.add_column("Metric", style="cyan") model_table.add_column("Value", style="green", justify="right") model_table.add_row("Training Data Points", str(model_summary['total_sales_records'])) model_table.add_row("Customer Segments", str(model_summary['customer_segments'])) model_table.add_row("Forecasts Evaluated", str(model_summary['forecasts_evaluated'])) model_table.add_row("MAPE", f"{accuracy_metrics['mape']:.1f}%") model_table.add_row("RMSE", f"{accuracy_metrics['rmse']:.2f}") model_table.add_row("ML Accuracy", f"{accuracy_metrics['accuracy']*100:.1f}%") console.print(Panel(model_table, title="Machine Learning Metrics", border_style="yellow")) # Final KPIs console.print("\n[bold cyan]💰 FINANCIAL PERFORMANCE[/bold cyan]\n") if self.research_logging.kpi_history: final_kpis = self.research_logging.kpi_history[-1] financial_table = Table(show_header=False, box=None) financial_table.add_column("Metric", style="cyan", width=25) financial_table.add_column("Value", style="bold green", justify="right") financial_table.add_column("Status", justify="center") # GMROI assessment gmroi_status = "🟢" if final_kpis['gmroi'] > 2 else "🟡" if final_kpis['gmroi'] > 1 else "🔴" financial_table.add_row("GMROI", f"{final_kpis['gmroi']:.3f}", gmroi_status) financial_table.add_row("Total Revenue", f"${final_kpis['total_revenue']:,.0f}", "🟢") financial_table.add_row("Gross Margin", f"${final_kpis['gross_margin']:,.0f}", "🟢") financial_table.add_row("COGS", f"${final_kpis['cogs']:,.0f}", "—") financial_table.add_row("Logistics Costs", f"${final_kpis['logistics_costs']:,.0f}", "—") margin_pct = (final_kpis['gross_margin'] / final_kpis['total_revenue'] * 100) if final_kpis['total_revenue'] > 0 else 0 financial_table.add_row("Margin %", f"{margin_pct:.1f}%", "🟢" if margin_pct > 60 else "🟡") financial_table.add_row("", "", "") financial_table.add_row("Warehouse Utilization", f"{final_kpis['warehouse_capacity_utilization']:.1%}", "🟢") financial_table.add_row("Retailer Utilization", f"{final_kpis['retailer_capacity_utilization']:.1%}", "🟢") console.print(Panel(financial_table, title="[bold]Financial KPIs[/bold]", border_style="green")) # Final completion console.print("\n[bold green]✅ Simulation completed successfully![/bold green]\n") log_to_file("Simulation completed successfully!") Loading
supply_chain_sim/forecasting.py +5 −6 Original line number Diff line number Diff line Loading @@ -54,14 +54,13 @@ class Forecasting: return forecasts def _calculate_realistic_demand(self, watch, region: str) -> float: """Calculate realistic demand based on watch characteristics.""" # Base demand starts lower and more realistic # Current base demands are too high - reduce by factor of 10 if watch.category == 'luxury': base_demand = np.random.uniform(5, 15) # Luxury has lower volume base_demand = np.random.uniform(0.5, 1.5) # was 5-15 elif watch.category == 'sport': base_demand = np.random.uniform(10, 25) # Sport has medium volume base_demand = np.random.uniform(1, 2.5) # was 10-25 else: # casual base_demand = np.random.uniform(15, 30) # Casual has higher volume base_demand = np.random.uniform(1.5, 3) # was 15-30 # Price sensitivity - higher prices reduce demand price_factor = max(0.3, 1.0 - (watch.base_cost - 200) / 2000) Loading
supply_chain_sim/supply_order.py +1 −1 Original line number Diff line number Diff line Loading @@ -132,7 +132,7 @@ class SupplyOrderLogic: remaining_orders = [] for order in self.pending_orders: order.expected_delivery -= time_elapsed max(0, order.expected_delivery - time_elapsed) if order.expected_delivery <= 0: delivered_orders.append(order) Loading