New alert system and panel de control page 2

This commit is contained in:
Urtzi Alfaro
2025-11-27 16:28:44 +01:00
parent e902419b6e
commit 2d9fc01515
4 changed files with 106 additions and 289 deletions

View File

@@ -164,137 +164,137 @@
}, },
"alerts": { "alerts": {
"critical_stock_shortage": { "critical_stock_shortage": {
"title": "🚨 Critical Stock: {{ingredient_name}}", "title": "🚨 Critical Stock: {ingredient_name}",
"message_with_po_pending": "Only {{current_stock}}kg of {{ingredient_name}} (need {{required_stock}}kg). Already created {{po_id}} for delivery on {{delivery_day_name}}. Please approve €{{po_amount}}.", "message_with_po_pending": "Only {current_stock}kg of {ingredient_name} (need {required_stock}kg). Already created {po_id} for delivery on {delivery_day_name}. Please approve €{po_amount}.",
"message_with_po_created": "Only {{current_stock}}kg of {{ingredient_name}} (need {{required_stock}}kg). Already created {{po_id}}. Review and approve €{{po_amount}}.", "message_with_po_created": "Only {current_stock}kg of {ingredient_name} (need {required_stock}kg). Already created {po_id}. Review and approve €{po_amount}.",
"message_with_hours": "Only {{current_stock}}kg of {{ingredient_name}} available (need {{required_stock}}kg in {{hours_until}} hours).", "message_with_hours": "Only {current_stock}kg of {ingredient_name} available (need {required_stock}kg in {hours_until} hours).",
"message_with_date": "Only {{current_stock}}kg of {{ingredient_name}} available (need {{required_stock}}kg for production on {{production_day_name}}).", "message_with_date": "Only {current_stock}kg of {ingredient_name} available (need {required_stock}kg for production on {production_day_name}).",
"message_generic": "Only {{current_stock}}kg of {{ingredient_name}} available (need {{required_stock}}kg)." "message_generic": "Only {current_stock}kg of {ingredient_name} available (need {required_stock}kg)."
}, },
"low_stock": { "low_stock": {
"title": "⚠️ Low Stock: {{ingredient_name}}", "title": "⚠️ Low Stock: {ingredient_name}",
"message_with_po": "{{ingredient_name}} stock: {{current_stock}}kg (minimum: {{minimum_stock}}kg). Already scheduled PO for replenishment.", "message_with_po": "{ingredient_name} stock: {current_stock}kg (minimum: {minimum_stock}kg). Already scheduled PO for replenishment.",
"message_generic": "{{ingredient_name}} stock: {{current_stock}}kg (minimum: {{minimum_stock}}kg). Consider placing an order." "message_generic": "{ingredient_name} stock: {current_stock}kg (minimum: {minimum_stock}kg). Consider placing an order."
}, },
"stock_depleted": { "stock_depleted": {
"title": "📦 Stock Depleted by Order", "title": "📦 Stock Depleted by Order",
"message_with_supplier": "Order #{{order_id}} requires {{ingredient_name}} but it's depleted. Contact {{supplier_name}} ({{supplier_phone}}).", "message_with_supplier": "Order #{order_id} requires {ingredient_name} but it's depleted. Contact {supplier_name} ({supplier_phone}).",
"message_generic": "Order #{{order_id}} requires {{ingredient_name}} but it's depleted. Immediate action required." "message_generic": "Order #{order_id} requires {ingredient_name} but it's depleted. Immediate action required."
}, },
"ingredient_shortage": { "ingredient_shortage": {
"title": "⚠️ Ingredient Shortage in Production", "title": "⚠️ Ingredient Shortage in Production",
"message_with_customers": "{{ingredient_name}} insufficient for batches in progress. {{affected_orders}} orders affected ({{customer_names}}). Current stock: {{current_stock}}kg, required: {{required_stock}}kg.", "message_with_customers": "{ingredient_name} insufficient for batches in progress. {affected_orders} orders affected ({customer_names}). Current stock: {current_stock}kg, required: {required_stock}kg.",
"message_generic": "{{ingredient_name}} insufficient for batches in progress. Current stock: {{current_stock}}kg, required: {{required_stock}}kg." "message_generic": "{ingredient_name} insufficient for batches in progress. Current stock: {current_stock}kg, required: {required_stock}kg."
}, },
"expired_products": { "expired_products": {
"title": "🚫 Expired or Expiring Products", "title": "🚫 Expired or Expiring Products",
"message_with_names": "{{count}} products expiring: {{product_names}}. Total value: €{{total_value}}.", "message_with_names": "{count} products expiring: {product_names}. Total value: €{total_value}.",
"message_generic": "{{count}} products expiring. Total value: €{{total_value}}." "message_generic": "{count} products expiring. Total value: €{total_value}."
}, },
"production_delay": { "production_delay": {
"title": "⏰ Production Delay: {{batch_name}}", "title": "⏰ Production Delay: {batch_name}",
"message_with_customers": "Batch {{batch_name}} delayed {{delay_minutes}} minutes. Affected customers: {{customer_names}}. Original delivery time: {{scheduled_time}}.", "message_with_customers": "Batch {batch_name} delayed {delay_minutes} minutes. Affected customers: {customer_names}. Original delivery time: {scheduled_time}.",
"message_with_orders": "Batch {{batch_name}} delayed {{delay_minutes}} minutes. {{affected_orders}} orders affected. Original delivery time: {{scheduled_time}}.", "message_with_orders": "Batch {batch_name} delayed {delay_minutes} minutes. {affected_orders} orders affected. Original delivery time: {scheduled_time}.",
"message_generic": "Batch {{batch_name}} delayed {{delay_minutes}} minutes. Original delivery time: {{scheduled_time}}." "message_generic": "Batch {batch_name} delayed {delay_minutes} minutes. Original delivery time: {scheduled_time}."
}, },
"equipment_failure": { "equipment_failure": {
"title": "🔧 Equipment Failure: {{equipment_name}}", "title": "🔧 Equipment Failure: {equipment_name}",
"message_with_batches": "{{equipment_name}} failed. {{affected_batches}} batches in production affected ({{batch_names}}).", "message_with_batches": "{equipment_name} failed. {affected_batches} batches in production affected ({batch_names}).",
"message_generic": "{{equipment_name}} failed. Requires immediate repair." "message_generic": "{equipment_name} failed. Requires immediate repair."
}, },
"maintenance_required": { "maintenance_required": {
"title": "🔧 Maintenance Required: {{equipment_name}}", "title": "🔧 Maintenance Required: {equipment_name}",
"message_with_hours": "{{equipment_name}} requires maintenance in {{hours_until}} hours. Schedule now to prevent disruptions.", "message_with_hours": "{equipment_name} requires maintenance in {hours_until} hours. Schedule now to prevent disruptions.",
"message_with_days": "{{equipment_name}} requires maintenance in {{days_until}} days. Schedule before {{maintenance_date}}." "message_with_days": "{equipment_name} requires maintenance in {days_until} days. Schedule before {maintenance_date}."
}, },
"low_equipment_efficiency": { "low_equipment_efficiency": {
"title": "📉 Low Efficiency: {{equipment_name}}", "title": "📉 Low Efficiency: {equipment_name}",
"message": "{{equipment_name}} operating at {{efficiency_percent}}% efficiency (expected: >{{threshold_percent}}%). Consider maintenance." "message": "{equipment_name} operating at {efficiency_percent}% efficiency (expected: >{threshold_percent}%). Consider maintenance."
}, },
"order_overload": { "order_overload": {
"title": "📊 Order Overload", "title": "📊 Order Overload",
"message_with_orders": "Capacity overloaded by {{overload_percent}}%. {{total_orders}} orders scheduled, capacity: {{capacity_orders}}. Consider adjusting schedule.", "message_with_orders": "Capacity overloaded by {overload_percent}%. {total_orders} orders scheduled, capacity: {capacity_orders}. Consider adjusting schedule.",
"message_generic": "Capacity overloaded by {{overload_percent}}%. Consider adjusting production schedule." "message_generic": "Capacity overloaded by {overload_percent}%. Consider adjusting production schedule."
}, },
"supplier_delay": { "supplier_delay": {
"title": "🚚 Supplier Delay: {{supplier_name}}", "title": "🚚 Supplier Delay: {supplier_name}",
"message": "{{supplier_name}} delayed delivery of {{ingredient_name}} (PO: {{po_id}}). New date: {{new_delivery_date}}. Original: {{original_delivery_date}}." "message": "{supplier_name} delayed delivery of {ingredient_name} (PO: {po_id}). New date: {new_delivery_date}. Original: {original_delivery_date}."
}, },
"temperature_breach": { "temperature_breach": {
"title": "🌡️ Temperature Breach", "title": "🌡️ Temperature Breach",
"message": "Temperature {{location}}: {{current_temp}}°C (range: {{min_temp}}°C-{{max_temp}}°C). Duration: {{duration_minutes}} minutes." "message": "Temperature {location}: {current_temp}°C (range: {min_temp}°C-{max_temp}°C). Duration: {duration_minutes} minutes."
}, },
"demand_surge_weekend": { "demand_surge_weekend": {
"title": "📈 Demand Surge: Weekend", "title": "📈 Demand Surge: Weekend",
"message": "Expected demand {{surge_percent}}% higher for {{weekend_date}}. Affected products: {{products}}. Consider increasing production." "message": "Expected demand {surge_percent}% higher for {weekend_date}. Affected products: {products}. Consider increasing production."
}, },
"weather_impact_alert": { "weather_impact_alert": {
"title": "🌦️ Expected Weather Impact", "title": "🌦️ Expected Weather Impact",
"message": "{{weather_condition}} expected {{date}}. Demand impact: {{impact_percent}}%. Affected products: {{products}}." "message": "{weather_condition} expected {date}. Demand impact: {impact_percent}%. Affected products: {products}."
}, },
"holiday_preparation": { "holiday_preparation": {
"title": "🎉 Holiday Preparation: {{holiday_name}}", "title": "🎉 Holiday Preparation: {holiday_name}",
"message": "{{holiday_name}} in {{days_until}} days ({{holiday_date}}). Expected demand {{expected_increase}}% higher. Key products: {{products}}." "message": "{holiday_name} in {days_until} days ({holiday_date}). Expected demand {expected_increase}% higher. Key products: {products}."
}, },
"severe_weather_impact": { "severe_weather_impact": {
"title": "⛈️ Severe Weather Impact", "title": "⛈️ Severe Weather Impact",
"message": "Severe {{weather_condition}} expected {{date}}. Demand impact: {{impact_percent}}%. Consider adjusting delivery schedules." "message": "Severe {weather_condition} expected {date}. Demand impact: {impact_percent}%. Consider adjusting delivery schedules."
}, },
"unexpected_demand_spike": { "unexpected_demand_spike": {
"title": "📊 Unexpected Demand Spike", "title": "📊 Unexpected Demand Spike",
"message": "Demand increased {{spike_percent}}% for {{products}}. Current stock may run out in {{hours_until_stockout}} hours." "message": "Demand increased {spike_percent}% for {products}. Current stock may run out in {hours_until_stockout} hours."
}, },
"demand_pattern_optimization": { "demand_pattern_optimization": {
"title": "💡 Demand Pattern Optimization", "title": "💡 Demand Pattern Optimization",
"message": "Pattern detected: {{pattern_description}}. Recommend adjusting production of {{products}} to optimize efficiency." "message": "Pattern detected: {pattern_description}. Recommend adjusting production of {products} to optimize efficiency."
}, },
"inventory_optimization": { "inventory_optimization": {
"title": "📦 Inventory Optimization", "title": "📦 Inventory Optimization",
"message": "{{ingredient_name}} consistently over-stocked by {{excess_percent}}%. Recommend reducing order to {{recommended_amount}}kg." "message": "{ingredient_name} consistently over-stocked by {excess_percent}%. Recommend reducing order to {recommended_amount}kg."
}, },
"production_efficiency": { "production_efficiency": {
"title": "⚡ Production Efficiency Opportunity", "title": "⚡ Production Efficiency Opportunity",
"message": "{{product_name}} more efficient at {{suggested_time}}. Production time {{time_saved}} minutes shorter ({{savings_percent}}% savings)." "message": "{product_name} more efficient at {suggested_time}. Production time {time_saved} minutes shorter ({savings_percent}% savings)."
}, },
"sales_opportunity": { "sales_opportunity": {
"title": "💰 Sales Opportunity", "title": "💰 Sales Opportunity",
"message": "High demand for {{products}} detected. Consider additional production. Potential revenue: €{{potential_revenue}}." "message": "High demand for {products} detected. Consider additional production. Potential revenue: €{potential_revenue}."
}, },
"seasonal_adjustment": { "seasonal_adjustment": {
"title": "🍂 Seasonal Adjustment Recommended", "title": "🍂 Seasonal Adjustment Recommended",
"message": "{{season}} season approaching. Adjust production of {{products}} based on historical trends ({{adjustment_percent}}% {{adjustment_direction}})." "message": "{season} season approaching. Adjust production of {products} based on historical trends ({adjustment_percent}% {adjustment_direction})."
}, },
"cost_reduction": { "cost_reduction": {
"title": "💵 Cost Reduction Opportunity", "title": "💵 Cost Reduction Opportunity",
"message": "Switching to {{alternative_ingredient}} can save €{{savings_amount}}/month. Similar quality, lower cost." "message": "Switching to {alternative_ingredient} can save €{savings_amount}/month. Similar quality, lower cost."
}, },
"waste_reduction": { "waste_reduction": {
"title": "♻️ Waste Reduction Opportunity", "title": "♻️ Waste Reduction Opportunity",
"message": "{{product_name}} waste high ({{waste_percent}}%). Recommend reducing batch to {{recommended_quantity}} units." "message": "{product_name} waste high ({waste_percent}%). Recommend reducing batch to {recommended_quantity} units."
}, },
"quality_improvement": { "quality_improvement": {
"title": "⭐ Quality Improvement Recommended", "title": "⭐ Quality Improvement Recommended",
"message": "{{issue_description}} detected in {{product_name}}. Recommended action: {{recommended_action}}." "message": "{issue_description} detected in {product_name}. Recommended action: {recommended_action}."
}, },
"customer_satisfaction": { "customer_satisfaction": {
"title": "😊 Customer Satisfaction Opportunity", "title": "😊 Customer Satisfaction Opportunity",
"message": "Customer {{customer_name}} consistently orders {{product_name}}. Consider special offer or loyalty program." "message": "Customer {customer_name} consistently orders {product_name}. Consider special offer or loyalty program."
}, },
"energy_optimization": { "energy_optimization": {
"title": "⚡ Energy Optimization", "title": "⚡ Energy Optimization",
"message": "Energy usage for {{equipment_name}} peaks at {{peak_time}}. Shifting to {{off_peak_start}}-{{off_peak_end}} can save €{{savings_amount}}/month." "message": "Energy usage for {equipment_name} peaks at {peak_time}. Shifting to {off_peak_start}-{off_peak_end} can save €{savings_amount}/month."
}, },
"staff_optimization": { "staff_optimization": {
"title": "👥 Staff Optimization", "title": "👥 Staff Optimization",
"message": "{{shift_name}} over-staffed by {{excess_percent}}%. Consider adjusting staff levels to reduce labor costs." "message": "{shift_name} over-staffed by {excess_percent}%. Consider adjusting staff levels to reduce labor costs."
}, },
"po_approval_needed": { "po_approval_needed": {
"title": "Purchase Order #{po_number} requires approval", "title": "Purchase Order #{po_number} requires approval",
"message": "Purchase order for {supplier_name} totaling {currency} {total_amount} is pending approval. Delivery required by {required_delivery_date}." "message": "Purchase order for {supplier_name} totaling {currency} {total_amount} is pending approval. Delivery required by {required_delivery_date}."
}, },
"production_batch_start": { "production_batch_start": {
"title": "Production Batch Ready: {{product_name}}", "title": "Production Batch Ready: {product_name}",
"message": "Batch #{{batch_number}} ({{quantity_planned}} {{unit}} of {{product_name}}) is ready to start. Priority: {{priority}}." "message": "Batch #{batch_number} ({quantity_planned} {unit} of {product_name}) is ready to start. Priority: {priority}."
} }
} }
} }

View File

@@ -133,14 +133,14 @@
"trend": { "trend": {
"near_threshold": "Atalasearen ondoan" "near_threshold": "Atalasearen ondoan"
}, },
"action_preview": { "action_preview": {
"title": "Ekintzaren Aurrebista", "title": "Ekintzaren Aurrebista",
"outcome": "Zer gertatuko da", "outcome": "Zer gertatuko da",
"financial_impact": "Finantza Eragina", "financial_impact": "Finantza Eragina",
"affected_systems": "Sistema Eragindak", "affected_systems": "Sistema Eragindak",
"reversible": "Ekintza hau desegin daiteke", "reversible": "Ekintza hau desegin daiteke",
"not_reversible": "Ekintza hau ezin da desegin", "not_reversible": "Ekintza hau ezin da desegin",
"confidence": "AIaren Konfiantza: {{confidence}}%", "confidence": "AIaren Konfiantza: {confidence}%",
"cancel": "Ezeztatu", "cancel": "Ezeztatu",
"confirm": "Berretsi Ekintza" "confirm": "Berretsi Ekintza"
}, },
@@ -161,137 +161,137 @@
}, },
"alerts": { "alerts": {
"critical_stock_shortage": { "critical_stock_shortage": {
"title": "🚨 Stock Kritikoa: {{ingredient_name}}", "title": "🚨 Stock Kritikoa: {ingredient_name}",
"message_with_po_pending": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik ({{required_stock}}kg behar dituzu). Dagoeneko {{po_id}} sortu dut {{delivery_day_name}}rako entregarako. Mesedez onartu €{{po_amount}}.", "message_with_po_pending": "{ingredient_name}-ren {current_stock}kg bakarrik ({required_stock}kg behar dituzu). Dagoeneko {po_id} sortu dut {delivery_day_name}rako entregarako. Mesedez onartu €{po_amount}.",
"message_with_po_created": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik ({{required_stock}}kg behar dituzu). Dagoeneko {{po_id}} sortu dut. Berrikusi eta onartu €{{po_amount}}.", "message_with_po_created": "{ingredient_name}-ren {current_stock}kg bakarrik ({required_stock}kg behar dituzu). Dagoeneko {po_id} sortu dut. Berrikusi eta onartu €{po_amount}.",
"message_with_hours": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik eskuragarri ({{required_stock}}kg behar dituzu {{hours_until}} ordutan).", "message_with_hours": "{ingredient_name}-ren {current_stock}kg bakarrik eskuragarri ({required_stock}kg behar dituzu {hours_until} ordutan).",
"message_with_date": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik eskuragarri ({{required_stock}}kg behar dituzu {{production_day_name}}ko ekoizpenerako).", "message_with_date": "{ingredient_name}-ren {current_stock}kg bakarrik eskuragarri ({required_stock}kg behar dituzu {production_day_name}ko ekoizpenerako).",
"message_generic": "{{ingredient_name}}-ren {{current_stock}}kg bakarrik eskuragarri ({{required_stock}}kg behar dituzu)." "message_generic": "{ingredient_name}-ren {current_stock}kg bakarrik eskuragarri ({required_stock}kg behar dituzu)."
}, },
"low_stock": { "low_stock": {
"title": "⚠️ Stock Baxua: {{ingredient_name}}", "title": "⚠️ Stock Baxua: {ingredient_name}",
"message_with_po": "{{ingredient_name}} stocka: {{current_stock}}kg (gutxienekoa: {{minimum_stock}}kg). Dagoeneko PO programatu dut osatzeko.", "message_with_po": "{ingredient_name} stocka: {current_stock}kg (gutxienekoa: {minimum_stock}kg). Dagoeneko PO programatu dut osatzeko.",
"message_generic": "{{ingredient_name}} stocka: {{current_stock}}kg (gutxienekoa: {{minimum_stock}}kg). Eskaera egitea kontuan hartu." "message_generic": "{ingredient_name} stocka: {current_stock}kg (gutxienekoa: {minimum_stock}kg). Eskaera egitea kontuan hartu."
}, },
"stock_depleted": { "stock_depleted": {
"title": "📦 Eskaeragatik Stocka Agortu Da", "title": "📦 Eskaeragatik Stocka Agortu Da",
"message_with_supplier": "#{{order_id}} eskaerak {{ingredient_name}} behar du baina agortu da. Jarri harremanetan {{supplier_name}}rekin ({{supplier_phone}}).", "message_with_supplier": "#{order_id} eskaerak {ingredient_name} behar du baina agortu da. Jarri harremanetan {supplier_name}rekin ({supplier_phone}).",
"message_generic": "#{{order_id}} eskaerak {{ingredient_name}} behar du baina agortu da. Berehala ekintza behar da." "message_generic": "#{order_id} eskaerak {ingredient_name} behar du baina agortu da. Berehala ekintza behar da."
}, },
"ingredient_shortage": { "ingredient_shortage": {
"title": "⚠️ Osagaien Falta Ekoizpenean", "title": "⚠️ Osagaien Falta Ekoizpenean",
"message_with_customers": "{{ingredient_name}} nahikoa ez abian dauden loteentzat. {{affected_orders}} eskabide eraginda ({{customer_names}}). Oraingo stocka: {{current_stock}}kg, beharrezkoa: {{required_stock}}kg.", "message_with_customers": "{ingredient_name} nahikoa ez abian dauden loteentzat. {affected_orders} eskabide eraginda ({customer_names}). Stock orain: {current_stock}kg, beharrezkoa: {required_stock}kg.",
"message_generic": "{{ingredient_name}} nahikoa ez abian dauden loteentzat. Oraingo stocka: {{current_stock}}kg, beharrezkoa: {{required_stock}}kg." "message_generic": "{ingredient_name} nahikoa ez abian dauden loteentzat. Stock orain: {current_stock}kg, beharrezkoa: {required_stock}kg."
}, },
"expired_products": { "expired_products": {
"title": "🚫 Iraungitako edo Iraungitzear Dauden Produktuak", "title": "🚫 Iraungitako edo Iraungitzear Dauden Produktuak",
"message_with_names": "{{count}} produktu iraungitzen: {{product_names}}. Balio osoa: €{{total_value}}.", "message_with_names": "{count} produktu iraungitzen: {product_names}. Balio osoa: €{total_value}.",
"message_generic": "{{count}} produktu iraungitzen. Balio osoa: €{{total_value}}." "message_generic": "{count} produktu iraungitzen. Balio osoa: €{total_value}."
}, },
"production_delay": { "production_delay": {
"title": "⏰ Ekoizpen Atzerapena: {{batch_name}}", "title": "⏰ Ekoizpen Atzerapena: {batch_name}",
"message_with_customers": "{{batch_name}} lotea {{delay_minutes}} minutu atzeratu da. Bezeroak eraginda: {{customer_names}}. Jatorrizko entrega ordua: {{scheduled_time}}.", "message_with_customers": "{batch_name} lotea {delay_minutes} minutu atzeratu da. Bezeroak eraginda: {customer_names}. Jatorrizko entrega ordua: {scheduled_time}.",
"message_with_orders": "{{batch_name}} lotea {{delay_minutes}} minutu atzeratu da. {{affected_orders}} eskabide eraginda. Jatorrizko entrega ordua: {{scheduled_time}}.", "message_with_orders": "{batch_name} lotea {delay_minutes} minutu atzeratu da. {affected_orders} eskabide eraginda. Jatorrizko entrega ordua: {scheduled_time}.",
"message_generic": "{{batch_name}} lotea {{delay_minutes}} minutu atzeratu da. Jatorrizko entrega ordua: {{scheduled_time}}." "message_generic": "{batch_name} lotea {delay_minutes} minutu atzeratu da. Jatorrizko entrega ordua: {scheduled_time}."
}, },
"equipment_failure": { "equipment_failure": {
"title": "🔧 Ekipamendu Matxura: {{equipment_name}}", "title": "🔧 Ekipamendu Matxura: {equipment_name}",
"message_with_batches": "{{equipment_name}} huts egin du. {{affected_batches}} ekoizpeneko lote eraginda ({{batch_names}}).", "message_with_batches": "{equipment_name} huts egin du. {affected_batches} ekoizpeneko lote eraginda ({batch_names}).",
"message_generic": "{{equipment_name}} huts egin du. Berehala konponketa behar du." "message_generic": "{equipment_name} huts egin du. Berehala konponketa behar du."
}, },
"maintenance_required": { "maintenance_required": {
"title": "🔧 Mantentze-lanak Behar Dira: {{equipment_name}}", "title": "🔧 Mantentze-lanak Behar Dira: {equipment_name}",
"message_with_hours": "{{equipment_name}}(e)k mantentze-lanak behar ditu {{hours_until}} ordutan. Programatu orain etetenak saihesteko.", "message_with_hours": "{equipment_name}(e)k mantentze-lanak behar ditu {hours_until} ordutan. Programatu orain etetenak saihesteko.",
"message_with_days": "{{equipment_name}}(e)k mantentze-lanak behar ditu {{days_until}} egunetan. Programatu {{maintenance_date}} baino lehen." "message_with_days": "{equipment_name}(e)k mantentze-lanak behar ditu {days_until} egunetan. Programatu {maintenance_date} baino lehen."
}, },
"low_equipment_efficiency": { "low_equipment_efficiency": {
"title": "📉 Eraginkortasun Baxua: {{equipment_name}}", "title": "📉 Eraginkortasun Baxua: {equipment_name}",
"message": "{{equipment_name}} %{{efficiency_percent}} eraginkortasunarekin funtzionatzen (esperoa: >{{threshold_percent}}%). Mantentze-lanak kontuan hartu." "message": "{equipment_name} %{efficiency_percent} eraginkortasunarekin funtzionatzen (esperoa: >{threshold_percent}%). Mantentze-lanak kontuan hartu."
}, },
"order_overload": { "order_overload": {
"title": "📊 Eskabideen Gainzama", "title": "📊 Eskabideen Gainzama",
"message_with_orders": "Gaitasuna %{{overload_percent}}z gainzamatuta. {{total_orders}} eskabide programatuta, gaitasuna: {{capacity_orders}}. Egutegia doitzea kontuan hartu.", "message_with_orders": "Gaitasuna %{overload_percent}z gainzamatuta. {total_orders} eskabide programatuta, gaitasuna: {capacity_orders}. Egutegia doitzea kontuan hartu.",
"message_generic": "Gaitasuna %{{overload_percent}}z gainzamatuta. Ekoizpen egutegia doitzea kontuan hartu." "message_generic": "Gaitasuna %{overload_percent}z gainzamatuta. Ekoizpen egutegia doitzea kontuan hartu."
}, },
"supplier_delay": { "supplier_delay": {
"title": "🚚 Hornitzaile Atzerapena: {{supplier_name}}", "title": "🚚 Hornitzaile Atzerapena: {supplier_name}",
"message": "{{supplier_name}}(e)k {{ingredient_name}} entrega atzeratu du (PO: {{po_id}}). Data berria: {{new_delivery_date}}. Jatorrizkoa: {{original_delivery_date}}." "message": "{supplier_name}(e)k {ingredient_name} entrega atzeratu du (PO: {po_id}). Data berria: {new_delivery_date}. Jatorrizkoa: {original_delivery_date}."
}, },
"temperature_breach": { "temperature_breach": {
"title": "🌡️ Tenperatura Haustea", "title": "🌡️ Tenperatura Haustea",
"message": "Tenperatura {{location}}: {{current_temp}}°C (tartea: {{min_temp}}°C-{{max_temp}}°C). Iraupena: {{duration_minutes}} minutu." "message": "Tenperatura {location}: {current_temp}°C (tartea: {min_temp}°C-{max_temp}°C). Iraupena: {duration_minutes} minutu."
}, },
"demand_surge_weekend": { "demand_surge_weekend": {
"title": "📈 Eskariaren Igoera: Asteburua", "title": "📈 Eskariaren Igoera: Asteburua",
"message": "Eskatutako eskaria %{{surge_percent}} handiagoa {{weekend_date}}rako. Produktu eragindak: {{products}}. Ekoizpena handitzea kontuan hartu." "message": "Eskatutako eskaria %{surge_percent} handiagoa {weekend_date}rako. Produktu eragindak: {products}. Ekoizpena handitzea kontuan hartu."
}, },
"weather_impact_alert": { "weather_impact_alert": {
"title": "🌦️ Espero den Eguraldiaren Eragina", "title": "🌦️ Espero den Eguraldiaren Eragina",
"message": "{{weather_condition}} esperotzen da {{date}}. Eskarian eragina: %{{impact_percent}}. Produktu eragindak: {{products}}." "message": "{weather_condition} esperotzen da {date}. Eskarian eragina: %{impact_percent}. Produktu eragindak: {products}."
}, },
"holiday_preparation": { "holiday_preparation": {
"title": "🎉 Jai Prestaketa: {{holiday_name}}", "title": "🎉 Jai Prestaketa: {holiday_name}",
"message": "{{holiday_name}} {{days_until}} egunetan ({{holiday_date}}). Eskatutako eskaria %{{expected_increase}} handiagoa. Funtsezko produktuak: {{products}}." "message": "{holiday_name} {days_until} egunetan ({holiday_date}). Eskatutako eskaria %{expected_increase} handiagoa. Produktu gakoak: {products}."
}, },
"severe_weather_impact": { "severe_weather_impact": {
"title": "⛈️ Eguraldi Larriaren Eragina", "title": "⛈️ Eguraldi Larriaren Eragina",
"message": "{{weather_condition}} larria esperotzen da {{date}}. Eskarian eragina: %{{impact_percent}}. Entrega ordutegiak doitzea kontuan hartu." "message": "{weather_condition} larria esperotzen da {date}. Eskarian eragina: %{impact_percent}. Entrega ordutegiak doitzea kontuan hartu."
}, },
"unexpected_demand_spike": { "unexpected_demand_spike": {
"title": "📊 Ustekabeko Eskariaren Igoera", "title": "📊 Ustekabeko Eskariaren Igoera",
"message": "Eskaria %{{spike_percent}} igo da {{products}}entzat. Oraingo stocka agor daiteke {{hours_until_stockout}} ordutan." "message": "Eskaria %{spike_percent} igo da {products}entzat. Oraingo stocka agor daiteke {hours_until_stockout} ordutan."
}, },
"demand_pattern_optimization": { "demand_pattern_optimization": {
"title": "💡 Eskari Ereduaren Optimizazioa", "title": "💡 Eskari Ereduaren Optimizazioa",
"message": "Eredua detektatua: {{pattern_description}}. Gomendatzen da {{products}} ekoizpena doitzea eraginkortasuna optimizatzeko." "message": "Eredua detektatua: {pattern_description}. Gomendatzen da {products} ekoizpena doitzea eraginkortasuna optimizatzeko."
}, },
"inventory_optimization": { "inventory_optimization": {
"title": "📦 Inbentarioaren Optimizazioa", "title": "📦 Inbentarioaren Optimizazioa",
"message": "{{ingredient_name}} etengabe gehiegizko stockarekin %{{excess_percent}}z. Gomendatzen da eskaera {{recommended_amount}}kg-ra murriztea." "message": "{ingredient_name} etengabe gehiegizko stockarekin %{excess_percent}z. Gomendatzen da eskaera {recommended_amount}kg-ra murriztea."
}, },
"production_efficiency": { "production_efficiency": {
"title": "⚡ Ekoizpen Eraginkortasunaren Aukera", "title": "⚡ Ekoizpen Eraginkortasunaren Aukera",
"message": "{{product_name}} eraginkorragoa da {{suggested_time}}etan. Ekoizpen denbora {{time_saved}} minutu laburragoa (%{{savings_percent}} aurrezkia)." "message": "{product_name} eraginkorragoa da {suggested_time}etan. Ekoizpen denbora {time_saved} minutu laburragoa (%{savings_percent} aurrezkia)."
}, },
"sales_opportunity": { "sales_opportunity": {
"title": "💰 Salmenten Aukera", "title": "💰 Salmenten Aukera",
"message": "{{products}}entzako eskari handia detektatuta. Ekoizpen gehigarria kontuan hartu. Sarrera potentziala: €{{potential_revenue}}." "message": "{products}entzako eskari handia detektatuta. Ekoizpen gehigarria kontuan hartu. Sarrera potentziala: €{potential_revenue}."
}, },
"seasonal_adjustment": { "seasonal_adjustment": {
"title": "🍂 Sasoiko Doikuntza Gomendatua", "title": "🍂 Sasoiko Doikuntza Gomendatua",
"message": "{{season}} sasoia hurbiltzen. Doitu {{products}} ekoizpena historia joerei oinarrituta (%{{adjustment_percent}} {{adjustment_direction}})." "message": "{season} sasoia hurbiltzen. Doitu {products} ekoizpena historia joerei oinarrituta (%{adjustment_percent} {adjustment_direction})."
}, },
"cost_reduction": { "cost_reduction": {
"title": "💵 Kostu Murrizketa Aukera", "title": "💵 Kostu Murrizketa Aukera",
"message": "{{alternative_ingredient}}ra aldatzeak €{{savings_amount}}/hilabetean aurreztu dezake. Antzeko kalitatea, kostu txikiagoa." "message": "{alternative_ingredient}ra aldatzeak €{savings_amount}/hilabetean aurreztu dezake. Antzeko kalitatea, kostu txikiagoa."
}, },
"waste_reduction": { "waste_reduction": {
"title": "♻️ Hondakin Murrizketa Aukera", "title": "♻️ Hondakin Murrizketa Aukera",
"message": "{{product_name}} hondakin handia (%{{waste_percent}}). Gomendatzen da lotea {{recommended_quantity}} unitatetara murriztea." "message": "{product_name} hondakin handia (%{waste_percent}). Gomendatzen da lotea {recommended_quantity} unitatetara murriztea."
}, },
"quality_improvement": { "quality_improvement": {
"title": "⭐ Kalitate Hobekuntza Gomendatua", "title": "⭐ Kalitate Hobekuntza Gomendatua",
"message": "{{issue_description}} detektatuta {{product_name}}n. Gomendatutako ekintza: {{recommended_action}}." "message": "{issue_description} detektatuta {product_name}n. Gomendatutako ekintza: {recommended_action}."
}, },
"customer_satisfaction": { "customer_satisfaction": {
"title": "😊 Bezeroaren Gogobetetasun Aukera", "title": "😊 Bezeroaren Gogobetetasun Aukera",
"message": "{{customer_name}} bezeroak etengabe eskatzen du {{product_name}}. Eskaintza berezia edo leialtasun programa kontuan hartu." "message": "{customer_name} bezeroak etengabe eskatzen du {product_name}. Eskaintza berezia edo leialtasun programa kontuan hartu."
}, },
"energy_optimization": { "energy_optimization": {
"title": "⚡ Energia Optimizazioa", "title": "⚡ Energia Optimizazioa",
"message": "{{equipment_name}}rako energia erabilera gailurra {{peak_time}}etan. {{off_peak_start}}-{{off_peak_end}}ra aldatzeak €{{savings_amount}}/hilabetean aurreztu dezake." "message": "{equipment_name}rako energia erabilera gailurra {peak_time}etan. {off_peak_start}-{off_peak_end}ra aldatzeak €{savings_amount}/hilabetean aurreztu dezake."
}, },
"staff_optimization": { "staff_optimization": {
"title": "👥 Langile Optimizazioa", "title": "👥 Langile Optimizazioa",
"message": "{{shift_name}} langileak gehiegi %{{excess_percent}}z. Langile mailak doitzea kontuan hartu lan kostuak murrizteko." "message": "{shift_name} langileak gehiegi %{excess_percent}z. Langile mailak doitzea kontuan hartu lan kostuak murrizteko."
}, },
"po_approval_needed": { "po_approval_needed": {
"title": "Erosketa Agindua #{po_number} onarpenaren beharra", "title": "Erosketa Agindua #{po_number} onarpenaren beharra",
"message": "{supplier_name}-(r)entzako erosketa agindua {currency} {total_amount} onarpenaren zain. Entreaga {required_delivery_date}-(e)rako behar da." "message": "Erosketa agindua {supplier_name}-(r)entzako {currency} {total_amount} onarpenaren zain. Entreaga {required_delivery_date}-(e)rako behar da."
}, },
"production_batch_start": { "production_batch_start": {
"title": "Ekoizpen Lote Prest: {{product_name}}", "title": "Ekoizpen Lote Prest: {product_name}",
"message": "#{{batch_number}} lotea ({{quantity_planned}} {{unit}} {{product_name}}) hasteko prest. Lehentasuna: {{priority}}." "message": "Lote #{batch_number} ({quantity_planned} {unit} {product_name}) hasierarako prest dago. Lehentasuna: {priority}."
} }
} }
} }

View File

@@ -417,7 +417,7 @@
"header": { "header": {
"main_navigation": "Nabigazio nagusia", "main_navigation": "Nabigazio nagusia",
"notifications": "Jakinarazpenak", "notifications": "Jakinarazpenak",
"unread_count": "{{count}} jakinarazpen irakurri gabeak", "unread_count": "{count} jakinarazpen irakurri gabeak",
"login": "Hasi Saioa", "login": "Hasi Saioa",
"start_free": "Hasi Doan", "start_free": "Hasi Doan",
"register": "Erregistratu", "register": "Erregistratu",

View File

@@ -1,183 +0,0 @@
"""
Test script to verify i18n ICU format parameters are properly structured
for PO approval alerts in the bakery-ia system.
"""
import uuid
from datetime import datetime
def test_raw_alert_structure():
"""Test that raw alerts contain proper message_params for ICU format"""
print("Testing Raw Alert Structure...")
# Simulate the structure that should be created by _emit_po_approval_alert
raw_alert_data = {
'id': str(uuid.uuid4()),
'tenant_id': str(uuid.uuid4()),
'service': 'procurement',
'type': 'po_approval_needed',
'alert_type': 'po_approval_needed',
'type_class': 'action_needed',
'severity': 'high',
'title': '', # Empty - will be generated by frontend with i18n
'message': '', # Empty - will be generated by frontend with i18n
'timestamp': datetime.utcnow().isoformat(),
'metadata': {
'po_id': str(uuid.uuid4()),
'po_number': 'PO-12345',
'supplier_id': str(uuid.uuid4()),
'supplier_name': 'ABC Supplier',
'total_amount': 1500.00,
'currency': 'EUR',
'priority': 'high',
'required_delivery_date': '2024-01-15',
'created_at': datetime.utcnow().isoformat(),
'financial_impact': 1500.00,
'urgency_score': 85,
'reasoning_data': {
'type': 'po_creation_approval',
'parameters': {
'po_number': 'PO-12345',
'supplier_name': 'ABC Supplier',
'total_amount': 1500.00,
'currency': 'EUR',
'required_delivery_date': '2024-01-15',
'items_count': 5,
'priority': 'high',
'reason': 'automated_replenishment',
'triggering_event': 'low_stock_detected',
'financial_impact_if_delayed': 2000.00,
'production_batches_affected': ['BATCH-001', 'BATCH-002']
},
'consequence': {
'severity': 'high',
'affects': ['production_delay', 'stockout_risk']
}
}
},
'message_params': {
'po_number': 'PO-12345',
'supplier_name': 'ABC Supplier',
'total_amount': 1500.00,
'currency': 'EUR',
'priority': 'high',
'required_delivery_date': '2024-01-15',
'items_count': 5,
'created_at': datetime.utcnow().isoformat()
},
'actions': ['approve_po', 'reject_po', 'modify_po'],
'item_type': 'alert'
}
print(f"✓ Raw alert contains message_params: {raw_alert_data['message_params']}")
print(f"✓ Message params structure: {list(raw_alert_data['message_params'].keys())}")
# Verify ICU format compatibility
icu_compatible = all(isinstance(v, (str, int, float, bool)) for k, v in raw_alert_data['message_params'].items()
if k != 'created_at') # created_at is datetime string
print(f"✓ ICU format compatible: {icu_compatible}")
return raw_alert_data
def test_enriched_alert_structure(raw_alert_data):
"""Test that enriched alerts preserve and enhance message_params"""
print("\nTesting Enriched Alert Structure...")
# Simulate the enriched alert structure (simplified version)
enriched_alert_data = {
'id': raw_alert_data['id'],
'tenant_id': raw_alert_data['tenant_id'],
'service': raw_alert_data['service'],
'alert_type': raw_alert_data['alert_type'],
'type_class': raw_alert_data['type_class'],
'priority_score': 85,
'priority_level': 'important',
'message_params': raw_alert_data['message_params'], # Preserved from raw alert
'reasoning_data': raw_alert_data['metadata']['reasoning_data'],
'actions': raw_alert_data['actions'],
'business_impact': {'financial_impact_eur': 1500.00},
'urgency_context': {'time_until_consequence_hours': 24},
'user_agency': {'can_user_fix': True},
'created_at': datetime.utcnow(),
'alert_metadata': {
**raw_alert_data['metadata'],
'message_params': raw_alert_data['message_params'], # Preserved in metadata
'i18n': {
'title_key': f'alerts.{raw_alert_data["alert_type"]}.title',
'message_key': f'alerts.{raw_alert_data["alert_type"]}.message',
'message_params': raw_alert_data['message_params'] # ICU format params
}
},
'status': 'active'
}
print(f"✓ Enriched alert preserves message_params: {enriched_alert_data['message_params']}")
print(f"✓ ICU params in metadata: {enriched_alert_data['alert_metadata']['i18n']['message_params']}")
print(f"✓ All ICU params preserved: {set(enriched_alert_data['message_params'].keys()) == set(raw_alert_data['message_params'].keys())}")
return enriched_alert_data
def test_i18n_icu_usage():
"""Test how frontend would use ICU format parameters"""
print("\nTesting ICU Format Usage...")
# Simulate frontend i18n usage
message_params = {
'po_number': 'PO-12345',
'supplier_name': 'ABC Supplier',
'total_amount': 1500.00,
'currency': 'EUR',
'priority': 'high',
'required_delivery_date': '2024-01-15',
'items_count': 5
}
# Simulate ICU format translation strings
title_template = "{po_number} needs approval"
message_template = "Purchase order for {supplier_name} ({currency}{total_amount}) requires your approval. {items_count} items included. Required by {required_delivery_date}."
# Simulate i18n.t() function replacement
title = title_template.format(**message_params)
message = message_template.format(**message_params)
print(f"✓ ICU title: {title}")
print(f"✓ ICU message: {message}")
# Verify ICU format compatibility
expected_title = "PO-12345 needs approval"
expected_message = "Purchase order for ABC Supplier (EUR150.0) requires your approval. 5 items included. Required by 2024-01-15."
print(f"✓ Title matches expected: {title == expected_title}")
print(f"✓ Message matches expected: {message == expected_message}")
return True
def main():
"""Main test function"""
print("Testing i18n ICU Format Implementation for PO Approval Alerts")
print("=" * 60)
# Test 1: Raw alert structure
raw_alert = test_raw_alert_structure()
# Test 2: Enriched alert structure
enriched_alert = test_enriched_alert_structure(raw_alert)
# Test 3: ICU format usage
icu_test = test_i18n_icu_usage()
print("\n" + "=" * 60)
print("All tests passed! ✓")
print("\nSummary:")
print("- Raw alerts now contain structured message_params for ICU format")
print("- Enriched alerts preserve and enhance message_params")
print("- ICU format supports {param} syntax for i18n translation")
print("- Parameters are compatible with frontend i18n libraries")
if __name__ == "__main__":
main()