Commit bff8fc17 authored by Barthelet Thibault's avatar Barthelet Thibault
Browse files

added chf

parent 6776bdb6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ def demo_basic_scenario():
    print("\nProducts in simulation:")
    for watch in setup.watches:
        print(f"  • Watch ID {watch.id}: {watch.name} ({watch.category})")
        print(f"    Cost: ${watch.base_cost:.0f}, Price: ${watch.sell_price:.0f}")
        print(f"    Cost: CHF {watch.base_cost:.0f}, Price: CHF {watch.sell_price:.0f}")
    
    # Student makes predictions for each product, each month
    print("\n[PREDICTION PHASE] Student enters predictions...")
+10 −10
Original line number Diff line number Diff line
@@ -68,8 +68,8 @@
                                    {{ product.category|capitalize }}
                                </span>
                            </td>
                            <td class="has-text-right">${{ "%.0f"|format(product.base_cost) }}</td>
                            <td class="has-text-right">${{ "%.0f"|format(product.sell_price) }}</td>
                            <td class="has-text-right">CHF {{ "%.0f"|format(product.base_cost) }}</td>
                            <td class="has-text-right">CHF {{ "%.0f"|format(product.sell_price) }}</td>
                            <td class="has-text-right">{{ "%.0f"|format(product.margin_pct) }}%</td>
                        </tr>
                        {% endfor %}
@@ -192,35 +192,35 @@
<script>
// Helper functions for quick-fill buttons
function fillConstant(productId, nMonths) {
    const baseValue = document.getElementById(`pred_${productId}_1`).value || 10;
    const baseValue = document.getElementById(`pred_CHF {productId}_1`).value || 10;
    for (let month = 1; month <= nMonths; month++) {
        document.getElementById(`pred_${productId}_${month}`).value = baseValue;
        document.getElementById(`pred_CHF {productId}_CHF {month}`).value = baseValue;
    }
}

function fillIncreasing(productId, nMonths) {
    const baseValue = parseFloat(document.getElementById(`pred_${productId}_1`).value) || 10;
    const baseValue = parseFloat(document.getElementById(`pred_CHF {productId}_1`).value) || 10;
    const increment = 2;
    for (let month = 1; month <= nMonths; month++) {
        document.getElementById(`pred_${productId}_${month}`).value = Math.round(baseValue + (month - 1) * increment);
        document.getElementById(`pred_CHF {productId}_CHF {month}`).value = Math.round(baseValue + (month - 1) * increment);
    }
}

function fillDecreasing(productId, nMonths) {
    const baseValue = parseFloat(document.getElementById(`pred_${productId}_1`).value) || 20;
    const baseValue = parseFloat(document.getElementById(`pred_CHF {productId}_1`).value) || 20;
    const decrement = 1.5;
    for (let month = 1; month <= nMonths; month++) {
        const value = Math.max(1, Math.round(baseValue - (month - 1) * decrement));
        document.getElementById(`pred_${productId}_${month}`).value = value;
        document.getElementById(`pred_CHF {productId}_CHF {month}`).value = value;
    }
}

function fillSeasonal(productId, nMonths) {
    const baseValue = parseFloat(document.getElementById(`pred_${productId}_1`).value) || 15;
    const baseValue = parseFloat(document.getElementById(`pred_CHF {productId}_1`).value) || 15;
    for (let month = 1; month <= nMonths; month++) {
        // Simple sine wave pattern
        const seasonal = baseValue + Math.sin(month * Math.PI / 6) * (baseValue * 0.3);
        document.getElementById(`pred_${productId}_${month}`).value = Math.round(Math.max(1, seasonal));
        document.getElementById(`pred_CHF {productId}_CHF {month}`).value = Math.round(Math.max(1, seasonal));
    }
}

+24 −24
Original line number Diff line number Diff line
@@ -176,8 +176,8 @@ class VisualSimulation(SupplyChainSimulation):
            watch_table.add_row(
                f"Watch_{watch.id}",
                watch.category.capitalize(),
                f"${watch.base_cost:.0f}",
                f"${watch.sell_price:.0f}",
                f"CHF {watch.base_cost:.0f}",
                f"CHF {watch.sell_price:.0f}",
                f"{markup:.0f}%",
            )

@@ -329,7 +329,7 @@ class VisualSimulation(SupplyChainSimulation):
                    f"Comp_{order.component_id}",
                    str(current),
                    str(order.quantity),
                    f"${order.cost:.0f}",
                    f"CHF {order.cost:.0f}",
                    f"{order.expected_delivery:.1f}d",
                )

@@ -344,7 +344,7 @@ class VisualSimulation(SupplyChainSimulation):
                )
            )
            log_to_file(
                f"Generated {len(supply_orders)} supply orders, total cost: ${sum(o.cost for o in supply_orders):.0f}"
                f"Generated {len(supply_orders)} supply orders, total cost: CHF {sum(o.cost for o in supply_orders):.0f}"
            )
            phase_results.append(("Orders", len(supply_orders)))
        else:
@@ -518,15 +518,15 @@ class VisualSimulation(SupplyChainSimulation):
            console.print(
                f"  [green]✓ {len(new_sales)} sales from {len(sampled_customers)} visitors (conversion: {conversion:.1f}%)[/green]"
            )
            console.print(f"  [green]✓ Revenue: ${total_revenue:,.0f}[/green]")
            console.print(f"  [green]✓ Revenue: CHF {total_revenue:,.0f}[/green]")
            log_to_file(
                f"{len(new_sales)} sales from {len(sampled_customers)} visitors (conversion: {conversion:.1f}%), Revenue: ${total_revenue:,.0f}"
                f"{len(new_sales)} sales from {len(sampled_customers)} visitors (conversion: {conversion:.1f}%), Revenue: CHF {total_revenue:,.0f}"
            )

            sales_breakdown = []
            for cat, data in sales_by_category.items():
                sales_breakdown.append(
                    f"{cat}: {data['count']} (${data['revenue']:,.0f})"
                    f"{cat}: {data['count']} (CHF {data['revenue']:,.0f})"
                )
            breakdown_str = ", ".join(sales_breakdown)
            console.print(f"  [dim]Sales by category: {breakdown_str}[/dim]")
@@ -609,13 +609,13 @@ class VisualSimulation(SupplyChainSimulation):
            "GMROI",
            f"{kpis['gmroi']:.2f}",
            "Total Revenue",
            f"${kpis['total_revenue']:,.0f}",
            f"CHF {kpis['total_revenue']:,.0f}",
        )
        kpi_grid.add_row(
            "Gross Margin",
            f"${kpis['gross_margin']:,.0f}",
            f"CHF {kpis['gross_margin']:,.0f}",
            "Logistics Costs",
            f"${kpis['logistics_costs']:,.0f}",
            f"CHF {kpis['logistics_costs']:,.0f}",
        )
        kpi_grid.add_row(
            "Warehouse Util",
@@ -626,7 +626,7 @@ class VisualSimulation(SupplyChainSimulation):

        console.print(Panel(kpi_grid, title="Daily KPIs", border_style="green"))
        log_to_file(
            f"Daily KPIs - GMROI: {kpis['gmroi']:.2f}, Revenue: ${kpis['total_revenue']:,.0f}, Margin: ${kpis['gross_margin']:,.0f}, Warehouse Util: {kpis['warehouse_capacity_utilization']:.1%}, Retailer Util: {kpis['retailer_capacity_utilization']:.1%}"
            f"Daily KPIs - GMROI: {kpis['gmroi']:.2f}, Revenue: CHF {kpis['total_revenue']:,.0f}, Margin: CHF {kpis['gross_margin']:,.0f}, Warehouse Util: {kpis['warehouse_capacity_utilization']:.1%}, Retailer Util: {kpis['retailer_capacity_utilization']:.1%}"
        )

        # Store metrics for final report
@@ -668,7 +668,7 @@ class VisualSimulation(SupplyChainSimulation):
        # Executive Summary
        exec_summary = f"""
[bold cyan]Simulation Period:[/bold cyan] {self.config['simulation_days']} days
[bold cyan]Total Revenue:[/bold cyan] ${total_revenue:,.0f}
[bold cyan]Total Revenue:[/bold cyan] CHF {total_revenue:,.0f}
[bold cyan]Total Sales:[/bold cyan] {total_sales} units
[bold cyan]Customers:[/bold cyan] {len(self.setup.customers)} potential buyers
[bold cyan]Conversion Rate:[/bold cyan] {(len(set(s.customer_id for s in self.all_sales))/len(self.setup.customers)*100):.1f}%
@@ -681,7 +681,7 @@ class VisualSimulation(SupplyChainSimulation):
            )
        )
        log_to_file(
            f"EXECUTIVE SUMMARY - Period: {self.config['simulation_days']} days, Revenue: ${total_revenue:,.0f}, Sales: {total_sales}, Customers: {len(self.setup.customers)}, Conversion: {(len(set(s.customer_id for s in self.all_sales))/len(self.setup.customers)*100):.1f}%"
            f"EXECUTIVE SUMMARY - Period: {self.config['simulation_days']} days, Revenue: CHF {total_revenue:,.0f}, Sales: {total_sales}, Customers: {len(self.setup.customers)}, Conversion: {(len(set(s.customer_id for s in self.all_sales))/len(self.setup.customers)*100):.1f}%"
        )

        # Continue with the rest of the report...
@@ -722,16 +722,16 @@ class VisualSimulation(SupplyChainSimulation):
            product_table.add_row(
                f"Watch_{watch.id}",
                watch.category.capitalize(),
                f"${watch.base_cost:.0f}",
                f"${watch.sell_price:.0f}",
                f"CHF {watch.base_cost:.0f}",
                f"CHF {watch.sell_price:.0f}",
                f"{perf['predicted']:.0f}",
                str(perf["sold"]),
                f"${perf['revenue']:,.0f}",
                f"CHF {perf['revenue']:,.0f}",
                f"{margin:.1f}%",
            )

            log_to_file(
                f"Watch_{watch.id} ({watch.category}): Predicted={perf['predicted']:.0f}, Sold={perf['sold']}, Revenue=${perf['revenue']:,.0f}, Margin={margin:.1f}%"
                f"Watch_{watch.id} ({watch.category}): Predicted={perf['predicted']:.0f}, Sold={perf['sold']}, Revenue=CHF {perf['revenue']:,.0f}, Margin={margin:.1f}%"
            )

        console.print(product_table)
@@ -755,7 +755,7 @@ class VisualSimulation(SupplyChainSimulation):
        operations_table.add_row(
            "Component Orders",
            str(total_orders),
            f"Total value: ${component_cost:,.0f}",
            f"Total value: CHF {component_cost:,.0f}",
        )
        operations_table.add_row(
            "Average Lead Time", f"{avg_lead_time:.1f} days", "From order to delivery"
@@ -845,8 +845,8 @@ class VisualSimulation(SupplyChainSimulation):
                    str(n_customers),
                    str(n_buyers),
                    str(data["count"]),
                    f"${data['revenue']:,.0f}",
                    f"${avg_ticket:.0f}",
                    f"CHF {data['revenue']:,.0f}",
                    f"CHF {avg_ticket:.0f}",
                )

        console.print(customer_table)
@@ -905,14 +905,14 @@ class VisualSimulation(SupplyChainSimulation):
            financial_table.add_row("GMROI", f"{final_kpis['gmroi']:.3f}", gmroi_status)

            financial_table.add_row(
                "Total Revenue", f"${final_kpis['total_revenue']:,.0f}", "🟢"
                "Total Revenue", f"CHF {final_kpis['total_revenue']:,.0f}", "🟢"
            )
            financial_table.add_row(
                "Gross Margin", f"${final_kpis['gross_margin']:,.0f}", "🟢"
                "Gross Margin", f"CHF {final_kpis['gross_margin']:,.0f}", "🟢"
            )
            # financial_table.add_row("COGS", f"${final_kpis['cogs']:,.0f}", "—")
            # financial_table.add_row("COGS", f"CHF {final_kpis['cogs']:,.0f}", "—")
            financial_table.add_row(
                "Logistics Costs", f"${final_kpis['logistics_costs']:,.0f}", ""
                "Logistics Costs", f"CHF {final_kpis['logistics_costs']:,.0f}", ""
            )

            margin_pct = (
+1 −1
Original line number Diff line number Diff line
@@ -150,7 +150,7 @@ class CustomerBehavior:
                        if key in inv_map:
                            inv_map[key].quantity -= 1
                        
                        logger.debug(f"Customer {customer.id} purchased watch {watch_id} for ${retail_price:.0f}")
                        logger.debug(f"Customer {customer.id} purchased watch {watch_id} for CHF {retail_price:.0f}")
                        break  # Customer only buys one watch per visit
        
        logger.info(f"Processed {len(new_sales)} sales")
+1 −1
Original line number Diff line number Diff line
@@ -136,7 +136,7 @@ class RetailDistribution:
    def calculate_distribution_costs(self) -> float:
        """Calculate total distribution/logistics costs."""
        # Simplified cost model
        base_cost_per_unit = 5.0  # $5 per unit shipped
        base_cost_per_unit = 5.0  # CHF 5 per unit shipped
        total_cost = 0
        
        for dist in self.distribution_history:
Loading