From 3242c8d83719ed4a2f2a033f8c8677906315030e Mon Sep 17 00:00:00 2001 From: Urtzi Alfaro Date: Fri, 21 Nov 2025 16:15:09 +0100 Subject: [PATCH] Improve te panel de control logic --- frontend/src/locales/en/blog.json | 594 +++++++++++++++ frontend/src/locales/en/reasoning.json | 5 +- frontend/src/locales/es/blog.json | 594 +++++++++++++++ frontend/src/locales/es/reasoning.json | 5 +- frontend/src/locales/eu/blog.json | 594 +++++++++++++++ frontend/src/locales/eu/reasoning.json | 65 +- frontend/src/locales/index.ts | 10 +- frontend/src/pages/public/BlogPage.tsx | 689 +++--------------- services/demo_session/app/core/config.py | 1 + .../app/services/clone_orchestrator.py | 6 + .../inventory/scripts/demo/seed_demo_stock.py | 92 ++- services/orchestrator/app/api/dashboard.py | 5 + .../orchestrator/app/api/internal_demo.py | 264 +++++++ services/orchestrator/app/main.py | 4 +- .../app/services/dashboard_service.py | 35 +- services/procurement/app/api/internal_demo.py | 1 + .../scripts/demo/seed_demo_purchase_orders.py | 219 +++++- .../scripts/demo/lotes_produccion_es.json | 99 +++ .../scripts/demo/seed_demo_batches.py | 16 +- shared/clients/production_client.py | 65 +- shared/schemas/reasoning_types.py | 138 +++- 21 files changed, 2805 insertions(+), 696 deletions(-) create mode 100644 frontend/src/locales/en/blog.json create mode 100644 frontend/src/locales/es/blog.json create mode 100644 frontend/src/locales/eu/blog.json create mode 100644 services/orchestrator/app/api/internal_demo.py diff --git a/frontend/src/locales/en/blog.json b/frontend/src/locales/en/blog.json new file mode 100644 index 00000000..414fb64c --- /dev/null +++ b/frontend/src/locales/en/blog.json @@ -0,0 +1,594 @@ +{ + "hero": { + "badge": "Bakery Management Blog", + "title": "Learn to Optimize Your Bakery", + "description": "Articles about management, AI, waste reduction, and sustainable growth for bakeries." + }, + "cta": { + "title": "Ready to Optimize Your Bakery?", + "description": "Join the pilot program and get 3 months free + 20% lifetime discount", + "button": "Request Pilot Spot" + }, + "post": { + "read_more": "Read full article", + "read_time": "{{time}} min" + }, + "categories": { + "management": "Management", + "technology": "Technology", + "production": "Production", + "strategy": "Strategy", + "legal": "Legal" + }, + "posts": { + "waste_reduction": { + "title": "How to Reduce Food Waste in Your Bakery: Complete 2025 Guide", + "excerpt": "Food waste costs bakeries between 15-40% of their production. Discover proven techniques and how AI can help you reduce it by up to 35%.", + "author": "BakeWise AI Team", + "tags": { + "food_waste": "food waste", + "sustainability": "sustainability", + "ai": "AI", + "management": "management" + }, + "content": { + "intro": "Food waste is one of the biggest challenges for bakeries. Every day, thousands of euros in product end up in the trash because they weren't sold. But it doesn't have to be this way.", + "problem_title": "The Real Problem", + "problem_desc": "Bakeries lose between **15% and 40% of their production** due to:", + "problem_reasons": [ + "Overproduction from fear of running out of stock", + "Inaccurate manual predictions", + "Lack of data on demand patterns", + "Unforeseen events (weather, holidays)" + ], + "solutions_title": "Practical Solutions", + "solution_1_title": "1. Historical Data Analysis", + "solution_1_desc": "Analyze your sales from the last 6-12 months to identify:", + "solution_1_points": [ + "Days of highest and lowest demand", + "Best-selling products by day of the week", + "Impact of holidays and local events", + "Weather effect on sales" + ], + "solution_2_title": "2. AI-Powered Prediction", + "solution_2_desc": "Artificial intelligence can:", + "solution_2_points": [ + "Analyze more than 50 variables simultaneously", + "Predict demand with 92% accuracy", + "Automatically adjust to new patterns", + "Alert you to events that will affect sales" + ], + "solution_3_title": "3. Dynamic Inventory Management", + "solution_3_points": [ + "Minimum stock calculated per product", + "Automatic replenishment alerts", + "Expiration tracking", + "Purchase order optimization" + ], + "results_title": "Real Results", + "results_desc": "Bakeries implementing these systems report:", + "results_points": [ + "**35% less waste** in 3 months", + "**€800/month savings** on average", + "**22% more sales** from better availability", + "**8 hours per week** saved in planning" + ], + "first_steps_title": "First Steps", + "first_steps_points": [ + "Start recording daily sales by product", + "Note external factors (weather, events)", + "Analyze weekly and monthly patterns", + "Consider an AI prediction tool", + "Adjust production gradually" + ], + "conclusion": "Food waste doesn't just affect your profitability, it also affects the environment. Every kilo you don't waste is a step towards a more sustainable and profitable bakery." + } + }, + "ai_prediction": { + "title": "How AI Predicts Bakery Demand with 92% Accuracy", + "excerpt": "Artificial intelligence has revolutionized demand prediction. Discover how ML algorithms work when applied to bakeries.", + "author": "Dr. Ana Martínez", + "tags": { + "ai": "AI", + "machine_learning": "machine learning", + "prediction": "prediction", + "technology": "technology" + }, + "content": { + "intro": "Demand prediction has always been more art than science in bakeries. But artificial intelligence is changing that radically.", + "problem_title": "The Intuition Problem", + "problem_desc": "Traditionally, bakers predict based on:", + "problem_points": [ + "Personal experience (\"Mondays sell less\")", + "Previous day's observation", + "Weather feelings", + "Excel with simple averages" + ], + "problem_conclusion": "**The problem:** Intuition fails when multiple variables interact.", + "how_it_works_title": "How AI Works", + "variables_title": "Variables It Analyzes", + "variables_intro": "Modern AI considers more than 50 factors:", + "variables_historical_title": "Historical:", + "variables_historical": [ + "Sales by product, day, hour", + "Weekly and monthly trends", + "Annual seasonality", + "Product growth or decline" + ], + "variables_external_title": "External:", + "variables_external": [ + "Weather (temperature, rain, sun)", + "Day of the week", + "Holidays and local events", + "School holidays", + "Sporting events" + ], + "variables_contextual_title": "Contextual:", + "variables_contextual": [ + "Available stock", + "Active promotions", + "New products", + "Price changes" + ], + "algorithms_title": "Machine Learning Algorithms", + "algorithms_intro": "Most effective for bakeries:", + "algorithms": [ + "**Random Forest**: Excellent for non-linear patterns", + "**LSTM (Neural Networks)**: Captures temporal trends", + "**XGBoost**: High performance with historical data" + ], + "accuracy_title": "Real Accuracy", + "accuracy_desc": "Case studies show:", + "accuracy_points": [ + "**92% accuracy** in daily prediction", + "**95% accuracy** in weekly prediction", + "**Continuous improvement** with more data" + ], + "implementation_title": "Practical Implementation", + "phase_1_title": "Phase 1: Collection (Week 1)", + "phase_1": [ + "Set up the system", + "Import historical data (minimum 3 months)", + "Verify data quality" + ], + "phase_2_title": "Phase 2: Training (Week 2-4)", + "phase_2": [ + "AI learns from your patterns", + "Adjusts to your specific business", + "Begins basic predictions" + ], + "phase_3_title": "Phase 3: Optimization (Month 2-3)", + "phase_3": [ + "Accuracy increases gradually", + "Adapts to changes", + "Predictive alerts active" + ], + "benefits_title": "Measurable Benefits", + "benefits": [ + "**35% less waste** in 90 days", + "**Never run out of stock** of bestsellers", + "**Automatic planning** of production", + "**Save 8 hours/week** in planning" + ], + "worth_it_title": "Is It Worth It?", + "worth_it_desc": "For bakeries that:", + "worth_it_points": [ + "Produce more than 20 different products", + "Sell more than 100 units daily", + "Have waste >15%", + "Want to scale the business" + ], + "worth_it_conclusion": "**The answer is YES.**", + "conclusion": "The technology is already here. The question is not whether AI works, but how much you're losing by not using it." + } + }, + "production_optimization": { + "title": "Production Optimization Guide for Bakeries", + "excerpt": "Learn to optimize your production without losing quality. Proven techniques that increase profitability by up to 30% whether you produce locally or manage a central bakery.", + "author": "Carlos Ruiz", + "tags": { + "optimization": "optimization", + "production": "production", + "artisan": "artisan", + "management": "management" + }, + "content": { + "intro": "Optimizing doesn't mean losing quality. It's about working smarter, not faster.", + "challenge_title": "The Modern Bakery Challenge", + "challenge_desc": "Bakeries, whether local or with central facilities, face:", + "challenge_points": [ + "**Varied products** with different preparation times", + "**Manual production** requiring detailed planning", + "**Narrow margin** where every mistake costs", + "**Competition** with low-price industrial bakeries" + ], + "principles_title": "Optimization Principles", + "principle_1_title": "1. Data-Driven Planning", + "principle_1_before": "**Before:** \"I make 50 loaves because I sold 45 yesterday\"", + "principle_1_after": "**After:** \"The system predicts 52 loaves considering it's Friday and the weather is good\"", + "principle_1_impact": "**Impact:** -30% waste, +15% sales", + "principle_2_title": "2. Intelligent Batch Production", + "principle_2_desc": "Group products by:", + "principle_2_points": [ + "Similar baking temperature", + "Compatible fermentation time", + "Common base dough" + ], + "principle_2_result": "**Result:** -25% production time, same quality", + "principle_3_title": "3. Timing Management", + "principle_3_desc": "Use visual schedules:", + "principle_3_points": [ + "Starter dough initiation (18-24h before)", + "Kneading and shaping (sequenced)", + "Baking (optimizing oven use)", + "Cooling and packaging" + ], + "principle_3_result": "**Specialized software reduces planning from 2 hours to 15 minutes.**", + "principle_4_title": "4. Efficient Staff", + "principle_4_points": [ + "Clear tasks by role", + "Production checklist", + "Continuous training", + "Smart shift rotation" + ], + "technology_title": "Technology That Helps (Without Losing Quality)", + "tech_ai_title": "AI for Prediction", + "tech_ai": [ + "How much to produce of each product", + "Which days are peak sales", + "Alerts for events affecting demand" + ], + "tech_automation_title": "Admin Automation", + "tech_automation": [ + "Automatic purchase orders", + "Real-time inventory control", + "Digital production records" + ], + "tech_apps_title": "Team Apps", + "tech_apps": [ + "Daily task list", + "Critical timing notifications", + "Problem/improvement logging" + ], + "dont_automate_title": "What NOT to Automate", + "dont_automate_desc": "Keep manual what adds value:", + "dont_automate": [ + "✅ Kneading and shaping (product quality)", + "✅ Fermentation control (expert eye)", + "✅ Decoration and finishing", + "✅ Final quality control" + ], + "implementation_title": "Step-by-Step Implementation", + "month_1_title": "Month 1: Analysis", + "month_1": [ + "Record actual production times", + "Identify bottlenecks", + "Measure current waste" + ], + "month_2_title": "Month 2: Basic Optimization", + "month_2": [ + "Implement intelligent batching", + "Improve workflow", + "Train team" + ], + "month_3_title": "Month 3: Technology", + "month_3": [ + "Integrate prediction system", + "Automate inventory", + "Digitalize planning" + ], + "results_title": "Expected Results (3-6 months)", + "results": [ + "**30% more profitability**", + "**25% less time on admin**", + "**20% more production** (same team)", + "**Quality maintained or improved**" + ], + "conclusion_title": "Conclusion", + "conclusion": "Optimizing your bakery doesn't mean losing quality. It means freeing up time to focus on what you do best: creating exceptional products and serving your customers better.\n\nTechnology is your ally, not your enemy." + } + }, + "central_vs_local": { + "title": "Central Bakery vs Local Production: How AI Optimizes Both Models", + "excerpt": "Two business models, same technology. Discover how our AI platform adapts to both local bakeries and central facilities with multiple points of sale.", + "author": "BakeWise AI Team", + "tags": { + "business_models": "business models", + "central_bakery": "central bakery", + "local_production": "local production", + "scalability": "scalability" + }, + "content": { + "intro": "In the bakery world, there is no one-size-fits-all model. Two main forms dominate the market, each with its own challenges and advantages.", + "models_title": "The Two Business Models", + "model_1_title": "Model 1: Local Production (All in One Place)", + "model_1_characteristics_title": "Characteristics:", + "model_1_characteristics": [ + "Production and sales in the same location", + "Maximum freshness: from oven to counter", + "Total process control", + "Direct customer relationships", + "Flexibility to adjust production in real-time" + ], + "model_1_advantages_title": "Advantages:", + "model_1_advantages": [ + "✅ Ultra-fresh product", + "✅ Quick response to demand", + "✅ Simple operation", + "✅ Strong local identity" + ], + "model_1_challenges_title": "Challenges:", + "model_1_challenges": [ + "⚠️ Limited capacity by space", + "⚠️ Difficulty scaling", + "⚠️ High fixed costs per location", + "⚠️ Dependence on local traffic" + ], + "model_2_title": "Model 2: Central Bakery + Points of Sale", + "model_2_characteristics_title": "Characteristics:", + "model_2_characteristics": [ + "Centralized production in a bakery", + "Distribution to multiple points of sale", + "Production economies of scale", + "Critical logistics coordination", + "Multi-location management" + ], + "model_2_advantages_title": "Advantages:", + "model_2_advantages": [ + "✅ Economies of scale", + "✅ Consistency across locations", + "✅ Staff specialization", + "✅ Greater market reach" + ], + "model_2_challenges_title": "Challenges:", + "model_2_challenges": [ + "⚠️ Logistics complexity", + "⚠️ Coordination between locations", + "⚠️ Aggregate demand prediction", + "⚠️ Freshness management in distribution" + ], + "ai_solutions_title": "How AI Solves Each Model's Challenges", + "local_title": "For Local Production", + "local_solution_1_title": "1. Hyper-Local Prediction", + "local_solution_1_desc": "AI analyzes patterns specific to your location:", + "local_solution_1_points": [ + "Local weather (rain reduces foot traffic)", + "Nearby events (weekly market, games)", + "Local holidays", + "Historical foot traffic" + ], + "local_solution_1_result": "**Result:** Predicts demand with 92% accuracy for your specific location.", + "local_solution_2_title": "2. Space Optimization", + "local_solution_2_desc": "With limited space, every batch counts:", + "local_solution_2_points": [ + "Optimal product sequencing", + "Oven use maximization", + "Fermentation management in reduced spaces" + ], + "local_solution_2_result": "**Result:** +20% capacity without expanding premises.", + "local_solution_3_title": "3. Simple Inventory Management", + "local_solution_3_desc": "Single stock point:", + "local_solution_3_points": [ + "Automatic replenishment alerts", + "Optimized purchase orders", + "Expiration tracking" + ], + "local_solution_3_result": "**Result:** -30% in immobilized stock.", + "central_title": "For Central Bakery + Points of Sale", + "central_solution_1_title": "1. Aggregate and Granular Prediction", + "central_solution_1_desc": "AI predicts at two levels:", + "central_solution_1_levels": [ + "**Aggregate level:** Total bakery production", + "**Granular level:** Demand per point of sale" + ], + "central_solution_1_example": "Real example:", + "central_solution_1_example_points": [ + "Bakery must produce 500 baguettes", + "POS 1 (office area): 200 (morning peak)", + "POS 2 (residential): 150 (afternoon peak)", + "POS 3 (tourist): 150 (midday peak)" + ], + "central_solution_1_result": "**Result:** Optimized distribution, -25% total waste.", + "central_solution_2_title": "2. Logistics Coordination", + "central_solution_2_desc": "AI manages multi-location complexity:", + "central_solution_2_points": [ + "Optimized delivery routes", + "Delivery timing by demand peak", + "Intraday restocking if necessary" + ], + "central_solution_2_result": "**Result:** Each point receives what it needs, when it needs it.", + "central_solution_3_title": "3. Centralized Visibility", + "central_solution_3_desc": "A unified dashboard:", + "central_solution_3_points": [ + "Performance per point of sale", + "Comparison between locations", + "Best practice identification", + "Anomaly detection" + ], + "central_solution_3_result": "**Result:** Informed decisions, continuous improvement.", + "central_solution_4_title": "4. Freshness Management", + "central_solution_4_desc": "Time tracking:", + "central_solution_4_points": [ + "From baking to point of sale", + "Time on counter per product", + "Freshness alerts by location" + ], + "central_solution_4_result": "**Result:** Quality guarantee at all locations.", + "comparison_title": "Results Comparison", + "comparison_local_title": "Metrics: Local Production", + "comparison_local": [ + "Waste: 25% → 12% (-13%)", + "Stockouts: 18% → 5% (-13%)", + "Planning time: 2h/day → 15min/day (-85%)", + "Net margin: 22% → 32% (+10%)" + ], + "comparison_central_title": "Metrics: Central Bakery (3 POS)", + "comparison_central": [ + "Total waste: 30% → 15% (-15%)", + "Optimal distribution: 60% → 95% (+35%)", + "Restocking: 12/week → 3/week (-75%)", + "Logistics ROI: +40%" + ], + "which_better_title": "Which Model Is Better?", + "which_better_desc": "**There's no universal answer.** It depends on:", + "choose_local_title": "Choose Local Production If:", + "choose_local": [ + "You value maximum control and flexibility", + "Your market is hyperlocal", + "You want to start with lower investment", + "Instant freshness is your competitive advantage" + ], + "choose_central_title": "Choose Central Bakery If:", + "choose_central": [ + "You want to scale to multiple locations", + "You seek economies of scale", + "You have capital to invest in logistics", + "You want presence in multiple neighborhoods/cities" + ], + "important_title": "What's Important: Technology Adapts", + "important_desc": "What's revolutionary about modern AI platforms is their **adaptability**:", + "important_points": [ + "✅ Same system, two configurations", + "✅ Grow from local to central without changing platform", + "✅ A/B testing between models", + "✅ Hybrids possible (some products local, others central)" + ], + "case_study_title": "Real Case: Bakery in Transition", + "case_study_desc": "**Bakery X** started as local production:", + "case_study_points": [ + "Year 1-2: One location, AI predicts local demand", + "Year 3: Opens 2nd location, same system now manages both", + "Year 4: Migrates to central bakery + 4 POS, AI scales seamlessly" + ], + "case_study_result": "**Result:** 300% growth without losing operational control.", + "conclusion_title": "Conclusion", + "conclusion": "You don't need to choose your technology based on your business model. You need technology that **evolves with you**.\n\nWhether you bake 50 or 5000 loaves daily, in one place or in ten, AI can optimize your operation.\n\n**The question is not \"What model am I?\"**\n**The question is \"How do I optimize the model I have?\"**\n\nAnd the answer is: with data, with AI, with the right tool." + } + }, + "gdpr": { + "title": "GDPR and Data Protection in Bakeries: What You Need to Know", + "excerpt": "GDPR affects all businesses in Spain, including bakeries. Practical guide to comply with the law without complications.", + "author": "María López (Digital Lawyer)", + "tags": { + "gdpr": "GDPR", + "rgpd": "RGPD", + "privacy": "privacy", + "legal": "legal", + "security": "security" + }, + "content": { + "intro": "If you use software to manage your bakery, you need to know about GDPR.", + "data_title": "What Data Does Your Bakery Handle?", + "customer_data_title": "Customer data:", + "customer_data": [ + "Name and contact (loyalty programs)", + "Purchase history", + "Food preferences (allergies, vegans)", + "Payment data (cards)" + ], + "employee_data_title": "Employee data:", + "employee_data": [ + "Personal information", + "Schedules and shifts", + "Payroll", + "Performance evaluations" + ], + "operational_data_title": "Operational data:", + "operational_data": [ + "Suppliers and contacts", + "Recipes and formulas", + "Sales and inventory", + "Business analytics" + ], + "obligations_title": "Legal Obligations (GDPR)", + "obligation_1_title": "1. Explicit Consent", + "obligation_1_desc": "Customers must **actively accept** that you use their data:", + "obligation_1_points": [ + "❌ Pre-checked box", + "✅ Box they must check themselves", + "✅ Clear explanation of use" + ], + "obligation_2_title": "2. Right to be Forgotten", + "obligation_2_desc": "Customers can request:", + "obligation_2_points": [ + "View their data (portability)", + "Correct incorrect data", + "Completely delete their data" + ], + "obligation_2_deadline": "**You must respond within 30 days.**", + "obligation_3_title": "3. Data Security", + "obligation_3_desc": "Obligations:", + "obligation_3_points": [ + "Encryption of sensitive data", + "Restricted access (passwords)", + "Regular backups", + "Breach procedures" + ], + "obligation_4_title": "4. Data Transfer", + "obligation_4_desc": "If you use cloud software:", + "obligation_4_points": [ + "Servers must be in EU", + "Or with valid GDPR agreements", + "Never in countries without adequate protection" + ], + "fines_title": "Fines for Non-Compliance", + "fines_desc": "GDPR fines can be:", + "fines_points": [ + "Up to **€20 million**", + "Or **4% of annual turnover**", + "**Whichever is greater**" + ], + "fines_note": "Although for small businesses they rarely reach these amounts, actual fines range **€5,000 - €50,000**.", + "software_title": "How to Choose Safe Software", + "checklist_title": "✅ GDPR Checklist", + "checklist": [ + "[ ] Servers in Spain/EU", + "[ ] AES-256 encryption or higher", + "[ ] ISO 27001 certification", + "[ ] Regular security audits", + "[ ] Clear privacy policy", + "[ ] Spanish language support", + "[ ] Data processor contract" + ], + "warning_signs_title": "❌ Warning Signs", + "warning_signs": [ + "⚠️ Servers in USA/Asia without agreements", + "⚠️ Doesn't mention GDPR/RGPD", + "⚠️ \"We share data with partners\"", + "⚠️ No security certifications" + ], + "case_title": "Case: BakeWise AI", + "case_desc": "Our GDPR commitment:", + "case_points": [ + "✅ **100% servers in Spain**", + "✅ **AES-256 encryption**", + "✅ **Quarterly audits**", + "✅ **Guaranteed GDPR compliance**", + "✅ **Your data is NEVER shared**", + "✅ **You control EVERYTHING**" + ], + "practical_steps_title": "Practical Steps", + "today_title": "Today", + "today": [ + "Review what personal data you store", + "Verify where it's stored", + "Read your current software terms" + ], + "this_week_title": "This Week", + "this_week": [ + "Update privacy policy", + "Obtain explicit consents", + "Implement regular backups" + ], + "this_month_title": "This Month", + "this_month": [ + "Train team on data protection", + "Document security procedures", + "Consider switching to GDPR-compliant software" + ], + "conclusion_title": "Conclusion", + "conclusion": "GDPR is not optional. But it's not complicated either if you use the right tools.\n\n**Your priority:** software that takes GDPR seriously, so you can focus on making bread." + } + } + } +} diff --git a/frontend/src/locales/en/reasoning.json b/frontend/src/locales/en/reasoning.json index f4e7f642..3a660ca4 100644 --- a/frontend/src/locales/en/reasoning.json +++ b/frontend/src/locales/en/reasoning.json @@ -1,6 +1,7 @@ { "purchaseOrder": { "low_stock_detection": "Low stock for {supplier_name}. Current stock of {product_names_joined} will run out in {days_until_stockout} days.", + "low_stock_detection_detailed": "{critical_product_count, plural, =1 {{critical_products_0} will deplete in {min_depletion_hours} hours} other {{critical_product_count} critical items running low}}. With {supplier_name}'s {supplier_lead_time_days}-day delivery, we must order {order_urgency, select, critical {IMMEDIATELY} urgent {TODAY} important {soon} other {now}} to prevent {affected_batches_count, plural, =0 {production delays} =1 {disruption to {affected_batches_0}} other {{affected_batches_count} batch disruptions}}{potential_loss_eur, select, 0 {} other { (€{potential_loss_eur} at risk)}}.", "forecast_demand": "Order scheduled based on {forecast_period_days}-day demand forecast for {product_names_joined} from {supplier_name}.", "safety_stock_replenishment": "Replenishing safety stock for {product_names_joined} from {supplier_name}.", "supplier_contract": "Scheduled order per contract with {supplier_name}.", @@ -108,8 +109,8 @@ "title": "Last Night I Planned Your Day", "ready_to_plan": "Ready to Plan Your Bakery Day", "run_planning": "Run Daily Planning", - "run_info": "Orchestration run #{{runNumber}}", - "took": "Took {{seconds}}s", + "run_info": "Orchestration run #{runNumber}", + "took": "Took {seconds}s", "created_pos": "Created {count} purchase order{count, plural, one {} other {s}}", "scheduled_batches": "Scheduled {count} production batch{count, plural, one {} other {es}}", "show_more": "Show {count} more", diff --git a/frontend/src/locales/es/blog.json b/frontend/src/locales/es/blog.json new file mode 100644 index 00000000..c3543971 --- /dev/null +++ b/frontend/src/locales/es/blog.json @@ -0,0 +1,594 @@ +{ + "hero": { + "badge": "Blog de Gestión para Panaderías", + "title": "Aprende a Optimizar tu Panadería", + "description": "Artículos sobre gestión, IA, reducción de desperdicios y crecimiento sostenible para panaderías." + }, + "cta": { + "title": "¿Listo para Optimizar tu Panadería?", + "description": "Únete al programa piloto y obtén 3 meses gratis + 20% descuento de por vida", + "button": "Solicitar Plaza en el Piloto" + }, + "post": { + "read_more": "Leer artículo completo", + "read_time": "{{time}} min" + }, + "categories": { + "management": "Gestión", + "technology": "Tecnología", + "production": "Producción", + "strategy": "Estrategia", + "legal": "Legal" + }, + "posts": { + "waste_reduction": { + "title": "Cómo Reducir el Desperdicio Alimentario en tu Panadería: Guía Completa 2025", + "excerpt": "El desperdicio alimentario cuesta a las panaderías entre 15-40% de su producción. Descubre técnicas probadas y cómo la IA puede ayudarte a reducirlo hasta un 35%.", + "author": "Equipo Panadería IA", + "tags": { + "food_waste": "desperdicio alimentario", + "sustainability": "sostenibilidad", + "ai": "IA", + "management": "gestión" + }, + "content": { + "intro": "El desperdicio alimentario es uno de los mayores desafíos para las panaderías. Cada día, miles de euros en producto terminan en la basura porque no se vendieron. Pero no tiene que ser así.", + "problem_title": "El Problema Real", + "problem_desc": "Las panaderías pierden entre **15% y 40% de su producción** por:", + "problem_reasons": [ + "Sobreproducción por miedo a quedarse sin stock", + "Predicciones manuales inexactas", + "Falta de datos sobre patrones de demanda", + "Eventos imprevistos (clima, festividades)" + ], + "solutions_title": "Soluciones Prácticas", + "solution_1_title": "1. Análisis de Datos Históricos", + "solution_1_desc": "Analiza tus ventas de los últimos 6-12 meses para identificar:", + "solution_1_points": [ + "Días de mayor y menor demanda", + "Productos más vendidos por día de la semana", + "Impacto de festividades y eventos locales", + "Efecto del clima en las ventas" + ], + "solution_2_title": "2. Predicción con IA", + "solution_2_desc": "La inteligencia artificial puede:", + "solution_2_points": [ + "Analizar más de 50 variables simultáneamente", + "Predecir demanda con 92% de precisión", + "Ajustarse automáticamente a nuevos patrones", + "Alertarte de eventos que afectarán ventas" + ], + "solution_3_title": "3. Gestión Dinámica de Inventario", + "solution_3_points": [ + "Stock mínimo calculado por producto", + "Alertas automáticas de reposición", + "Seguimiento de caducidades", + "Optimización de órdenes de compra" + ], + "results_title": "Resultados Reales", + "results_desc": "Panaderías que implementan estos sistemas reportan:", + "results_points": [ + "**35% menos desperdicio** en 3 meses", + "**€800/mes de ahorro** promedio", + "**22% más ventas** por mejor disponibilidad", + "**8 horas semanales** ahorradas en planificación" + ], + "first_steps_title": "Primeros Pasos", + "first_steps_points": [ + "Empieza registrando ventas diarias por producto", + "Anota factores externos (clima, eventos)", + "Analiza patrones semanales y mensuales", + "Considera una herramienta de predicción con IA", + "Ajusta producción gradualmente" + ], + "conclusion": "El desperdicio alimentario no solo afecta tu rentabilidad, también el medioambiente. Cada kilo que no desperdicias es un paso hacia una panadería más sostenible y rentable." + } + }, + "ai_prediction": { + "title": "Cómo la IA Predice la Demanda en Panaderías con 92% de Precisión", + "excerpt": "La inteligencia artificial ha revolucionado la predicción de demanda. Descubre cómo funcionan los algoritmos de ML aplicados a panaderías.", + "author": "Dr. Ana Martínez", + "tags": { + "ai": "IA", + "machine_learning": "machine learning", + "prediction": "predicción", + "technology": "tecnología" + }, + "content": { + "intro": "La predicción de demanda siempre ha sido más arte que ciencia en panaderías. Pero la inteligencia artificial está cambiando eso radicalmente.", + "problem_title": "El Problema de la Intuición", + "problem_desc": "Tradicionalmente, los panaderos predicen basándose en:", + "problem_points": [ + "Experiencia personal (\"los lunes se vende menos\")", + "Observación del día anterior", + "Sensaciones sobre el clima", + "Excel con promedios simples" + ], + "problem_conclusion": "**El problema:** La intuición falla cuando hay múltiples variables interactuando.", + "how_it_works_title": "Cómo Funciona la IA", + "variables_title": "Variables que Analiza", + "variables_intro": "La IA moderna considera más de 50 factores:", + "variables_historical_title": "Históricos:", + "variables_historical": [ + "Ventas por producto, día, hora", + "Tendencias semanales y mensuales", + "Estacionalidad anual", + "Crecimiento o declive de productos" + ], + "variables_external_title": "Externos:", + "variables_external": [ + "Clima (temperatura, lluvia, sol)", + "Día de la semana", + "Festividades y eventos locales", + "Vacaciones escolares", + "Eventos deportivos" + ], + "variables_contextual_title": "Contextuales:", + "variables_contextual": [ + "Stock disponible", + "Promociones activas", + "Nuevos productos", + "Cambios de precio" + ], + "algorithms_title": "Algoritmos de Machine Learning", + "algorithms_intro": "Los más efectivos para panaderías:", + "algorithms": [ + "**Random Forest**: Excelente para patrones no lineales", + "**LSTM (Redes Neuronales)**: Captura tendencias temporales", + "**XGBoost**: Alto rendimiento con datos históricos" + ], + "accuracy_title": "Precisión Real", + "accuracy_desc": "Casos de estudio muestran:", + "accuracy_points": [ + "**92% de precisión** en predicción diaria", + "**95% de precisión** en predicción semanal", + "**Mejora continua** con más datos" + ], + "implementation_title": "Implementación Práctica", + "phase_1_title": "Fase 1: Recopilación (Semana 1)", + "phase_1": [ + "Configura el sistema", + "Importa datos históricos (mínimo 3 meses)", + "Verifica calidad de datos" + ], + "phase_2_title": "Fase 2: Entrenamiento (Semana 2-4)", + "phase_2": [ + "La IA aprende de tus patrones", + "Se ajusta a tu negocio específico", + "Comienza predicciones básicas" + ], + "phase_3_title": "Fase 3: Optimización (Mes 2-3)", + "phase_3": [ + "Precisión aumenta gradualmente", + "Se adapta a cambios", + "Alertas predictivas activas" + ], + "benefits_title": "Beneficios Medibles", + "benefits": [ + "**35% menos desperdicio** en 90 días", + "**Nunca quedarse sin stock** de bestsellers", + "**Planificación automática** de producción", + "**Ahorro de 8 horas/semana** en planificación" + ], + "worth_it_title": "¿Vale la Pena?", + "worth_it_desc": "Para panaderías que:", + "worth_it_points": [ + "Producen más de 20 productos diferentes", + "Venden más de 100 unidades diarias", + "Tienen desperdicio >15%", + "Quieren escalar el negocio" + ], + "worth_it_conclusion": "**La respuesta es SÍ.**", + "conclusion": "La tecnología ya está aquí. La pregunta no es si la IA funciona, sino cuánto estás perdiendo al no usarla." + } + }, + "production_optimization": { + "title": "Guía de Optimización de Producción para Panaderías", + "excerpt": "Aprende a optimizar tu producción sin perder la calidad. Técnicas probadas que aumentan rentabilidad hasta 30% ya sea que produzcas localmente o gestiones un obrador central.", + "author": "Carlos Ruiz", + "tags": { + "optimization": "optimización", + "production": "producción", + "artisan": "artesanal", + "management": "gestión" + }, + "content": { + "intro": "Optimizar no significa perder calidad. Se trata de trabajar más inteligente, no más rápido.", + "challenge_title": "El Desafío de la Panadería Moderna", + "challenge_desc": "Las panaderías, ya sean locales o con obradores centrales, enfrentan:", + "challenge_points": [ + "**Productos variados** con tiempos de preparación diferentes", + "**Producción manual** que requiere planificación detallada", + "**Margen estrecho** donde cada error cuesta", + "**Competencia** con panaderías industriales de bajo precio" + ], + "principles_title": "Principios de Optimización", + "principle_1_title": "1. Planificación Basada en Datos", + "principle_1_before": "**Antes:** \"Hago 50 barras porque ayer vendí 45\"", + "principle_1_after": "**Después:** \"El sistema predice 52 barras considerando que es viernes y hay buen clima\"", + "principle_1_impact": "**Impacto:** -30% desperdicio, +15% ventas", + "principle_2_title": "2. Batch Inteligente de Producción", + "principle_2_desc": "Agrupa productos por:", + "principle_2_points": [ + "Temperatura de horneado similar", + "Tiempo de fermentación compatible", + "Masa base común" + ], + "principle_2_result": "**Resultado:** -25% tiempo de producción, misma calidad", + "principle_3_title": "3. Gestión de Timing", + "principle_3_desc": "Usa cronogramas visuales:", + "principle_3_points": [ + "Inicio de masas madres (18-24h antes)", + "Amasados y formados (secuenciados)", + "Horneados (optimizando uso de hornos)", + "Enfriado y empaquetado" + ], + "principle_3_result": "**Software especializado reduce planificación de 2 horas a 15 minutos.**", + "principle_4_title": "4. Personal Eficiente", + "principle_4_points": [ + "Tareas claras por rol", + "Checklist de producción", + "Capacitación continua", + "Rotación inteligente de turnos" + ], + "technology_title": "Tecnología que Ayuda (Sin Perder Calidad)", + "tech_ai_title": "IA para Predicción", + "tech_ai": [ + "Cuánto producir de cada producto", + "Qué días son picos de venta", + "Alertas de eventos que afectan demanda" + ], + "tech_automation_title": "Automatización de Admin", + "tech_automation": [ + "Órdenes de compra automáticas", + "Control de inventario en tiempo real", + "Registro de producción digital" + ], + "tech_apps_title": "Apps para Equipo", + "tech_apps": [ + "Lista de tareas del día", + "Notificaciones de timing crítico", + "Registro de problemas/mejoras" + ], + "dont_automate_title": "Lo Que NO Debes Automatizar", + "dont_automate_desc": "Mantén manual lo que da valor:", + "dont_automate": [ + "✅ Amasado y formado (calidad del producto)", + "✅ Control de fermentación (ojo experto)", + "✅ Decoración y acabados", + "✅ Control de calidad final" + ], + "implementation_title": "Implementación Paso a Paso", + "month_1_title": "Mes 1: Análisis", + "month_1": [ + "Registra tiempos reales de producción", + "Identifica cuellos de botella", + "Mide desperdicio actual" + ], + "month_2_title": "Mes 2: Optimización Básica", + "month_2": [ + "Implementa batch inteligente", + "Mejora flujo de trabajo", + "Capacita equipo" + ], + "month_3_title": "Mes 3: Tecnología", + "month_3": [ + "Integra sistema de predicción", + "Automatiza inventario", + "Digitaliza planificación" + ], + "results_title": "Resultados Esperados (3-6 meses)", + "results": [ + "**30% más rentabilidad**", + "**25% menos tiempo en admin**", + "**20% más producción** (mismo equipo)", + "**Calidad mantenida o mejorada**" + ], + "conclusion_title": "Conclusión", + "conclusion": "Optimizar tu panadería no significa perder calidad. Significa liberar tiempo para enfocarte en lo que haces mejor: crear productos excepcionales y servir mejor a tus clientes.\n\nLa tecnología es tu aliada, no tu enemiga." + } + }, + "central_vs_local": { + "title": "Obrador Central vs Producción Local: Cómo la IA Optimiza Ambos Modelos", + "excerpt": "Dos modelos de negocio, misma tecnología. Descubre cómo nuestra plataforma de IA se adapta tanto a panaderías locales como a obradores centrales con múltiples puntos de venta.", + "author": "Equipo Panadería IA", + "tags": { + "business_models": "modelos de negocio", + "central_bakery": "obrador central", + "local_production": "producción local", + "scalability": "escalabilidad" + }, + "content": { + "intro": "En el mundo de la panadería, no existe un modelo único. Dos formas principales dominan el mercado, cada una con sus propios desafíos y ventajas.", + "models_title": "Los Dos Modelos de Negocio", + "model_1_title": "Modelo 1: Producción Local (Todo en un Lugar)", + "model_1_characteristics_title": "Características:", + "model_1_characteristics": [ + "Producción y venta en la misma ubicación", + "Frescura máxima: del horno al mostrador", + "Control total del proceso", + "Relación directa con clientes", + "Flexibilidad para ajustar producción en tiempo real" + ], + "model_1_advantages_title": "Ventajas:", + "model_1_advantages": [ + "✅ Producto ultrafresco", + "✅ Respuesta rápida a demanda", + "✅ Operación simple", + "✅ Identidad local fuerte" + ], + "model_1_challenges_title": "Desafíos:", + "model_1_challenges": [ + "⚠️ Capacidad limitada por espacio", + "⚠️ Dificultad para escalar", + "⚠️ Costos fijos altos por ubicación", + "⚠️ Dependencia de tráfico local" + ], + "model_2_title": "Modelo 2: Obrador Central + Puntos de Venta", + "model_2_characteristics_title": "Características:", + "model_2_characteristics": [ + "Producción centralizada en un obrador", + "Distribución a múltiples puntos de venta", + "Economías de escala en producción", + "Coordinación logística crítica", + "Gestión multi-ubicación" + ], + "model_2_advantages_title": "Ventajas:", + "model_2_advantages": [ + "✅ Economías de escala", + "✅ Consistencia entre ubicaciones", + "✅ Especialización de personal", + "✅ Mayor alcance de mercado" + ], + "model_2_challenges_title": "Desafíos:", + "model_2_challenges": [ + "⚠️ Complejidad logística", + "⚠️ Coordinación entre ubicaciones", + "⚠️ Predicción de demanda agregada", + "⚠️ Gestión de frescura en distribución" + ], + "ai_solutions_title": "Cómo la IA Resuelve los Desafíos de Cada Modelo", + "local_title": "Para Producción Local", + "local_solution_1_title": "1. Predicción Hiper-Local", + "local_solution_1_desc": "La IA analiza patrones específicos de tu ubicación:", + "local_solution_1_points": [ + "Clima local (lluvia reduce tráfico peatonal)", + "Eventos cercanos (mercado semanal, partidos)", + "Días festivos locales", + "Tráfico peatonal histórico" + ], + "local_solution_1_result": "**Resultado:** Predice demanda con 92% precisión para tu ubicación específica.", + "local_solution_2_title": "2. Optimización de Espacio", + "local_solution_2_desc": "Con espacio limitado, cada hornada cuenta:", + "local_solution_2_points": [ + "Secuenciación óptima de productos", + "Maximización de uso de horno", + "Gestión de fermentación en espacios reducidos" + ], + "local_solution_2_result": "**Resultado:** +20% capacidad sin ampliar local.", + "local_solution_3_title": "3. Gestión de Inventario Simple", + "local_solution_3_desc": "Un solo punto de stock:", + "local_solution_3_points": [ + "Alertas automáticas de reposición", + "Órdenes de compra optimizadas", + "Seguimiento de caducidad" + ], + "local_solution_3_result": "**Resultado:** -30% en stock inmovilizado.", + "central_title": "Para Obrador Central + Puntos de Venta", + "central_solution_1_title": "1. Predicción Agregada y Granular", + "central_solution_1_desc": "La IA predice a dos niveles:", + "central_solution_1_levels": [ + "**Nivel agregado:** Producción total del obrador", + "**Nivel granular:** Demanda por cada punto de venta" + ], + "central_solution_1_example": "Ejemplo real:", + "central_solution_1_example_points": [ + "Obrador debe producir 500 baguettes", + "POS 1 (zona oficinas): 200 (pico mañana)", + "POS 2 (residencial): 150 (pico tarde)", + "POS 3 (turística): 150 (pico mediodía)" + ], + "central_solution_1_result": "**Resultado:** Distribución optimizada, -25% desperdicio total.", + "central_solution_2_title": "2. Coordinación Logística", + "central_solution_2_desc": "La IA gestiona complejidad multi-ubicación:", + "central_solution_2_points": [ + "Rutas de distribución optimizadas", + "Timing de entregas por pico de demanda", + "Reabastecimientos intraday si necesario" + ], + "central_solution_2_result": "**Resultado:** Cada punto recibe lo que necesita, cuando lo necesita.", + "central_solution_3_title": "3. Visibilidad Centralizada", + "central_solution_3_desc": "Un dashboard unificado:", + "central_solution_3_points": [ + "Performance por punto de venta", + "Comparación entre ubicaciones", + "Identificación de mejores prácticas", + "Detección de anomalías" + ], + "central_solution_3_result": "**Resultado:** Decisiones informadas, mejora continua.", + "central_solution_4_title": "4. Gestión de Frescura", + "central_solution_4_desc": "Tracking de tiempos:", + "central_solution_4_points": [ + "Desde horneado hasta punto de venta", + "Tiempo en mostrador por producto", + "Alertas de frescura por ubicación" + ], + "central_solution_4_result": "**Resultado:** Garantía de calidad en todas las ubicaciones.", + "comparison_title": "Comparación de Resultados", + "comparison_local_title": "Métricas: Producción Local", + "comparison_local": [ + "Desperdicio: 25% → 12% (-13%)", + "Stockouts: 18% → 5% (-13%)", + "Tiempo planificación: 2h/día → 15min/día (-85%)", + "Margen neto: 22% → 32% (+10%)" + ], + "comparison_central_title": "Métricas: Obrador Central (3 POS)", + "comparison_central": [ + "Desperdicio total: 30% → 15% (-15%)", + "Distribución óptima: 60% → 95% (+35%)", + "Reabastecimientos: 12/sem → 3/sem (-75%)", + "ROI logística: +40%" + ], + "which_better_title": "¿Cuál Modelo Es Mejor?", + "which_better_desc": "**No hay respuesta universal.** Depende de:", + "choose_local_title": "Elige Producción Local Si:", + "choose_local": [ + "Valoras máximo control y flexibilidad", + "Tu mercado es hiperlocal", + "Quieres empezar con menor inversión", + "La frescura instantánea es tu ventaja competitiva" + ], + "choose_central_title": "Elige Obrador Central Si:", + "choose_central": [ + "Quieres escalar a múltiples ubicaciones", + "Buscas economías de escala", + "Tienes capital para invertir en logística", + "Quieres presencia en múltiples barrios/ciudades" + ], + "important_title": "Lo Importante: La Tecnología Se Adapta", + "important_desc": "Lo revolucionario de las plataformas de IA modernas es su **adaptabilidad**:", + "important_points": [ + "✅ Mismo sistema, dos configuraciones", + "✅ Creces de local a central sin cambiar plataforma", + "✅ Pruebas A/B entre modelos", + "✅ Híbridos posibles (algunos productos locales, otros centrales)" + ], + "case_study_title": "Caso Real: Panadería en Transición", + "case_study_desc": "**Bakery X** empezó como producción local:", + "case_study_points": [ + "Año 1-2: Un local, IA predice demanda local", + "Año 3: Abre 2do local, mismo sistema ahora gestiona ambos", + "Año 4: Migra a obrador central + 4 POS, IA escala sin problemas" + ], + "case_study_result": "**Resultado:** Crecimiento 300% sin perder control operativo.", + "conclusion_title": "Conclusión", + "conclusion": "No necesitas elegir tu tecnología según tu modelo de negocio. Necesitas tecnología que **evolucione contigo**.\n\nYa sea que hornees 50 o 5000 panes diarios, en un lugar o en diez, la IA puede optimizar tu operación.\n\n**La pregunta no es \"¿Qué modelo soy?\"**\n**La pregunta es \"¿Cómo optimizo el modelo que tengo?\"**\n\nY la respuesta es: con datos, con IA, con la herramienta correcta." + } + }, + "gdpr": { + "title": "GDPR y Protección de Datos en Panaderías: Lo Que Debes Saber", + "excerpt": "El RGPD afecta a todas las empresas en España, incluidas panaderías. Guía práctica para cumplir con la ley sin complicaciones.", + "author": "María López (Abogada Digital)", + "tags": { + "gdpr": "GDPR", + "rgpd": "RGPD", + "privacy": "privacidad", + "legal": "legal", + "security": "seguridad" + }, + "content": { + "intro": "Si usas software para gestionar tu panadería, necesitas conocer el RGPD (GDPR en inglés).", + "data_title": "¿Qué Datos Maneja tu Panadería?", + "customer_data_title": "Datos de clientes:", + "customer_data": [ + "Nombre y contacto (programas de fidelidad)", + "Historial de compras", + "Preferencias alimentarias (alergias, veganos)", + "Datos de pago (tarjetas)" + ], + "employee_data_title": "Datos de empleados:", + "employee_data": [ + "Información personal", + "Horarios y turnos", + "Nóminas", + "Evaluaciones de desempeño" + ], + "operational_data_title": "Datos operativos:", + "operational_data": [ + "Proveedores y contactos", + "Recetas y fórmulas", + "Ventas e inventario", + "Analíticas de negocio" + ], + "obligations_title": "Obligaciones Legales (RGPD)", + "obligation_1_title": "1. Consentimiento Explícito", + "obligation_1_desc": "Los clientes deben **aceptar activamente** que uses sus datos:", + "obligation_1_points": [ + "❌ Casilla pre-marcada", + "✅ Casilla que deben marcar ellos", + "✅ Explicación clara del uso" + ], + "obligation_2_title": "2. Derecho al Olvido", + "obligation_2_desc": "Clientes pueden solicitar:", + "obligation_2_points": [ + "Ver sus datos (portabilidad)", + "Corregir datos incorrectos", + "Eliminar completamente sus datos" + ], + "obligation_2_deadline": "**Debes responder en 30 días.**", + "obligation_3_title": "3. Seguridad de Datos", + "obligation_3_desc": "Obligaciones:", + "obligation_3_points": [ + "Cifrado de datos sensibles", + "Acceso restringido (contraseñas)", + "Backups regulares", + "Procedimientos ante brechas" + ], + "obligation_4_title": "4. Transferencia de Datos", + "obligation_4_desc": "Si usas software en la nube:", + "obligation_4_points": [ + "Servidores deben estar en UE", + "O con acuerdos GDPR válidos", + "Nunca en países sin protección adecuada" + ], + "fines_title": "Multas por Incumplimiento", + "fines_desc": "Las multas RGPD pueden ser:", + "fines_points": [ + "Hasta **€20 millones**", + "O **4% de facturación anual**", + "**Lo que sea mayor**" + ], + "fines_note": "Aunque para pequeñas empresas raramente llegan a estas cantidades, las multas reales rondan **€5,000 - €50,000**.", + "software_title": "Cómo Elegir Software Seguro", + "checklist_title": "✅ Checklist GDPR", + "checklist": [ + "[ ] Servidores en España/UE", + "[ ] Cifrado AES-256 o superior", + "[ ] Certificación ISO 27001", + "[ ] Auditorías de seguridad regulares", + "[ ] Política de privacidad clara", + "[ ] Soporte en español", + "[ ] Contrato de procesador de datos" + ], + "warning_signs_title": "❌ Señales de Alerta", + "warning_signs": [ + "⚠️ Servidores en EEUU/Asia sin acuerdos", + "⚠️ No menciona GDPR/RGPD", + "⚠️ \"Compartimos datos con partners\"", + "⚠️ Sin certificaciones de seguridad" + ], + "case_title": "Caso: Panadería IA", + "case_desc": "Nuestro compromiso GDPR:", + "case_points": [ + "✅ **100% servidores en España**", + "✅ **Cifrado AES-256**", + "✅ **Auditorías trimestrales**", + "✅ **Cumplimiento RGPD garantizado**", + "✅ **Tus datos NUNCA se comparten**", + "✅ **Tú controlas TODO**" + ], + "practical_steps_title": "Pasos Prácticos", + "today_title": "Hoy", + "today": [ + "Revisa qué datos personales guardas", + "Verifica dónde están almacenados", + "Lee términos de tu software actual" + ], + "this_week_title": "Esta Semana", + "this_week": [ + "Actualiza política de privacidad", + "Obtén consentimientos explícitos", + "Implementa backups regulares" + ], + "this_month_title": "Este Mes", + "this_month": [ + "Capacita equipo en protección de datos", + "Documenta procedimientos de seguridad", + "Considera cambiar a software GDPR-compliant" + ], + "conclusion_title": "Conclusión", + "conclusion": "El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas correctas.\n\n**Tu prioridad:** software que tome el GDPR en serio, para que tú puedas enfocarte en hacer pan." + } + } + } +} diff --git a/frontend/src/locales/es/reasoning.json b/frontend/src/locales/es/reasoning.json index 4630345d..f7fb0df3 100644 --- a/frontend/src/locales/es/reasoning.json +++ b/frontend/src/locales/es/reasoning.json @@ -1,6 +1,7 @@ { "purchaseOrder": { "low_stock_detection": "Stock bajo para {supplier_name}. El stock actual de {product_names_joined} se agotará en {days_until_stockout} días.", + "low_stock_detection_detailed": "{critical_product_count, plural, =1 {{critical_products_0} se agotará en {min_depletion_hours} horas} other {{critical_product_count} productos críticos escasos}}. Con entrega de {supplier_lead_time_days} días de {supplier_name}, debemos pedir {order_urgency, select, critical {INMEDIATAMENTE} urgent {HOY} important {pronto} other {ahora}} para evitar {affected_batches_count, plural, =0 {retrasos en producción} =1 {interrupción del lote {affected_batches_0}} other {interrupción de {affected_batches_count} lotes}}{potential_loss_eur, select, 0 {} other { (€{potential_loss_eur} en riesgo)}}.", "forecast_demand": "Pedido programado basado en pronóstico de demanda de {forecast_period_days} días para {product_names_joined} de {supplier_name}.", "safety_stock_replenishment": "Reposición de stock de seguridad para {product_names_joined} de {supplier_name}.", "supplier_contract": "Pedido programado según contrato con {supplier_name}.", @@ -108,8 +109,8 @@ "title": "Anoche Planifiqué Tu Día", "ready_to_plan": "Listo Para Planificar Tu Día en la Panadería", "run_planning": "Ejecutar Planificación Diaria", - "run_info": "Ejecución de orquestación #{{runNumber}}", - "took": "Duró {{seconds}}s", + "run_info": "Ejecución de orquestación #{runNumber}", + "took": "Duró {seconds}s", "created_pos": "{count} orden{count, plural, one {} other {es}} de compra creada{count, plural, one {} other {s}}", "scheduled_batches": "{count} lote{count, plural, one {} other {s}} de producción programado{count, plural, one {} other {s}}", "show_more": "Mostrar {count} más", diff --git a/frontend/src/locales/eu/blog.json b/frontend/src/locales/eu/blog.json new file mode 100644 index 00000000..4c28191a --- /dev/null +++ b/frontend/src/locales/eu/blog.json @@ -0,0 +1,594 @@ +{ + "hero": { + "badge": "Okindegien Kudeaketarako Bloga", + "title": "Ikasi Zure Okindegi Optimizatzen", + "description": "Artikuluak kudeaketari, IAri, hondakinen murrizketari eta hazkunde jasangarriari buruzkoak." + }, + "cta": { + "title": "Prest Zaude Zure Okindegi Optimizatzeko?", + "description": "Batu pilotu programara eta lortu 3 hilabete doan + % 20ko beherapena betiko", + "button": "Eskatu Pilotuko Plaza" + }, + "post": { + "read_more": "Irakurri artikulu osoa", + "read_time": "{{time}} min" + }, + "categories": { + "management": "Kudeaketa", + "technology": "Teknologia", + "production": "Ekoizpena", + "strategy": "Estrategia", + "legal": "Legala" + }, + "posts": { + "waste_reduction": { + "title": "Nola Murriztu Elikagaien Hondakina Zure Okindegian: 2025 Gida Osoa", + "excerpt": "Elikagaien hondakinak okindegiei % 15-40 kostatzen die euren ekoizpenean. Aurkitu teknika frobatuak eta IAk nola lagun dezakeen % 35era arte murrizten.", + "author": "Okindegi IA Taldea", + "tags": { + "food_waste": "elikagaien hondakina", + "sustainability": "iraunkortasuna", + "ai": "IA", + "management": "kudeaketa" + }, + "content": { + "intro": "Elikagaien hondakina okindegien erronka handienetako bat da. Egunero, milaka euro produktutan zaborrean amaitzen dira saldu ez direlako. Baina ez du horrela izan behar.", + "problem_title": "Benetako Arazoa", + "problem_desc": "Okindegiek euren ekoizpenaren **% 15 eta 40** artean galtzen dute hau dela eta:", + "problem_reasons": [ + "Gehiegizko ekoizpena stocka agortzeko bildurragatik", + "Eskuzko iragarpen ez-zehatzak", + "Eskariaren ereduei buruzko datuen falta", + "Aurreikusi gabeko gertaerak (eguraldia, jaiak)" + ], + "solutions_title": "Irtenbide Praktikoak", + "solution_1_title": "1. Datu Historikoen Analisia", + "solution_1_desc": "Aztertu azken 6-12 hilabeteen salmentak identifikatzeko:", + "solution_1_points": [ + "Eskari handiena eta txikiena duten egunak", + "Asteko egun bakoitzean gehien saltzen diren produktuak", + "Jaien eta tokiko gertaeren eragina", + "Eguraldiaren eragina salmentetan" + ], + "solution_2_title": "2. IArekin Iragarpena", + "solution_2_desc": "Adimen artifiziala gai da:", + "solution_2_points": [ + "50 aldagai baino gehiago aldi berean aztertzeko", + "Eskaria % 92ko zehaztasunarekin iragartzeko", + "Automatikoki eredu berrietara egokitzeko", + "Salmentak eragingo dituzten gertaerak abisutzeko" + ], + "solution_3_title": "3. Inbentario Kudeaketa Dinamikoa", + "solution_3_points": [ + "Produktu bakoitzeko gutxieneko stock kalkulatua", + "Berrosteko alerta automatikoak", + "Iraungitzeen jarraipena", + "Erosketa aginduen optimizazioa" + ], + "results_title": "Emaitza Errealak", + "results_desc": "Sistema hauek ezartzen dituzten okindegiek jakinarazten dute:", + "results_points": [ + "**% 35 hondakin gutxiago** 3 hilabetetan", + "**€800/hilabete batez beste aurreztea**", + "**% 22 salmenta gehiago** eskuragarritasun hobea dela eta", + "**8 ordu astean** plangintzaren aurreztea" + ], + "first_steps_title": "Lehen Urratsak", + "first_steps_points": [ + "Hasi produktu bakoitzeko eguneko salmentak erregistratzen", + "Idatzi kanpoko faktoreak (eguraldia, gertaerak)", + "Aztertu asteko eta hileko ereduak", + "Aztertu IArekin iragarpenerako tresna bat", + "Egokitu ekoizpena pixkanaka" + ], + "conclusion": "Elikagaien hondakinak ez du soilik zure errentagarritasuna eragiten, ingurumena ere bai. Ez duzun kilo bakoitza okindegi jasangarriago eta errentagarriago baterako urrats bat da." + } + }, + "ai_prediction": { + "title": "Nola Iragartzen du IAk Okindegien Eskaria % 92ko Zehaztasunarekin", + "excerpt": "Adimen artifiziala eskariaren iragarpena iraultzen ari da. Aurkitu nola funtzionatzen duten ML algoritmoak okindegiei aplikatuta.", + "author": "Dr. Ana Martínez", + "tags": { + "ai": "IA", + "machine_learning": "machine learning", + "prediction": "iragarpena", + "technology": "teknologia" + }, + "content": { + "intro": "Eskariaren iragarpena beti izan da zientzia baino gehiago artea okindegiei dagokienez. Baina adimen artifiziala erradikalki aldatzen ari da hori.", + "problem_title": "Intuitziaren Arazoa", + "problem_desc": "Tradizionalki, okindegiek honetan oinarrituta iragartzen dute:", + "problem_points": [ + "Esperientzia pertsonala (\"astelehena gutxiago saltzen da\")", + "Aurreko egunaren behaketa", + "Eguraldiaren sentsazioak", + "Excel batezbesteko sinpleekin" + ], + "problem_conclusion": "**Arazoa:** Intuizioa huts egiten du aldagai anitz elkarreragiten dutenean.", + "how_it_works_title": "Nola Funtzionatzen du IAk", + "variables_title": "Aztertzen dituen Aldagaiak", + "variables_intro": "IA modernak 50 faktore baino gehiago hartzen ditu kontuan:", + "variables_historical_title": "Historikoak:", + "variables_historical": [ + "Produktu, egun, orduko salmentak", + "Asteko eta hileko joerak", + "Urteko denboraldiak", + "Produktuen hazkundea edo beherakada" + ], + "variables_external_title": "Kanpokoak:", + "variables_external": [ + "Eguraldia (tenperatura, euria, eguzkia)", + "Asteko eguna", + "Jaiak eta tokiko gertaerak", + "Eskola oporrak", + "Kirol gertaerak" + ], + "variables_contextual_title": "Testuinguruzkoak:", + "variables_contextual": [ + "Eskuragarri dagoen stocka", + "Promozio aktiboak", + "Produktu berriak", + "Prezio aldaketak" + ], + "algorithms_title": "Machine Learning Algoritmoak", + "algorithms_intro": "Okindegientzat eraginkorreenak:", + "algorithms": [ + "**Random Forest**: Bikaina eredu ez-linealetarako", + "**LSTM (Sare Neuronalak)**: Denbora joera kapturatzen du", + "**XGBoost**: Errendimendu altua datu historikoekin" + ], + "accuracy_title": "Zehaztasun Erreala", + "accuracy_desc": "Kasu azterketak erakusten dute:", + "accuracy_points": [ + "**% 92ko zehaztasuna** eguneko iragarpenenean", + "**% 95eko zehaztasuna** asteko iragarpenenean", + "**Hobekuntza jarraitu** datu gehiagorekin" + ], + "implementation_title": "Ezarpen Praktikoa", + "phase_1_title": "1. Fasea: Bilketa (1. astea)", + "phase_1": [ + "Konfiguratu sistema", + "Inportatu datu historikoak (gutxienez 3 hilabete)", + "Egiaztatu datuen kalitatea" + ], + "phase_2_title": "2. Fasea: Entrenamentua (2-4 asteak)", + "phase_2": [ + "IAk zure ereduetatik ikasten du", + "Zure negozio espezifikora egokitzen da", + "Oinarrizko iragarpenekin hasten da" + ], + "phase_3_title": "3. Fasea: Optimizazioa (2-3 hilabeteak)", + "phase_3": [ + "Zehaztasuna pixkanaka handitzen da", + "Aldaketara egokitzen da", + "Alerta iragartzaileak aktiboak" + ], + "benefits_title": "Onura Neugarriak", + "benefits": [ + "**% 35 hondakin gutxiago** 90 egunetan", + "**Ez gelditu inoiz stockik gabe** salerosoenetan", + "**Ekoizpen plangintza automatikoa**", + "**8 ordu/astean aurreztu** plangintzan" + ], + "worth_it_title": "Merezi al du?", + "worth_it_desc": "Okindegientzat:", + "worth_it_points": [ + "20 produktu desberdin baino gehiago ekoizten dituztenak", + "100 unitate baino gehiago egunero saltzen dituztenak", + "% 15 baino gehiago hondakina dutenak", + "Negozioa eskalatu nahi dutenak" + ], + "worth_it_conclusion": "**Erantzuna BAI da.**", + "conclusion": "Teknologia hemen dago dagoeneko. Galdera ez da IAk funtzionatzen duen ala ez, baizik eta zenbat galtzen ari zaren erabiltzen ez duzulako." + } + }, + "production_optimization": { + "title": "Okindegientzako Ekoizpen Optimizazio Gida", + "excerpt": "Ikasi zure ekoizpena kalitatea galdu gabe optimizatzen. Teknika frobatuak errentagarritasuna % 30era arte handitzen dutenak, tokian ekoizten duzun edo obrador zentrala kudeatzen.", + "author": "Carlos Ruiz", + "tags": { + "optimization": "optimizazioa", + "production": "ekoizpena", + "artisan": "artisautza", + "management": "kudeaketa" + }, + "content": { + "intro": "Optimizatzeak ez du esan nahi kalitatea galtzea. Adimentsuago lan egitea da, azkarrago ez.", + "challenge_title": "Okindegi Modernoaren Erronka", + "challenge_desc": "Okindegiek, lokalak edo obrador zentralekin, honako hauei aurre egiten diete:", + "challenge_points": [ + "**Produktu anitzak** prestaketa denbora desberdinekin", + "**Eskuzko ekoizpena** plangintza zehatza behar duena", + "**Marjina estua** non akats bakoitzak kostatzen duen", + "**Lehia** prezioak baxuko okindegi industrialekin" + ], + "principles_title": "Optimizazio Printzipioak", + "principle_1_title": "1. Datuetan Oinarritutako Plangintza", + "principle_1_before": "**Aurretik:** \"50 barra egiten ditut atzo 45 saldu nuelako\"", + "principle_1_after": "**Ondoren:** \"Sistemak 52 barra iragartzen ditu ostirala dela eta eguraldia ona dela kontuan hartuz\"", + "principle_1_impact": "**Eragina:** % -30 hondakina, % +15 salmentak", + "principle_2_title": "2. Ekoizpen Batch Adimentsua", + "principle_2_desc": "Taldekatu produktuak honela:", + "principle_2_points": [ + "Labe tenperatura antzekoa", + "Fermentazio denbora bateragarria", + "Oinarri masa komuna" + ], + "principle_2_result": "**Emaitza:** % -25 ekoizpen denbora, kalitate bera", + "principle_3_title": "3. Denbora Kudeaketa", + "principle_3_desc": "Erabili egutegi bisualak:", + "principle_3_points": [ + "Ama masen hasiera (18-24 ordu lehenago)", + "Irabiketak eta moldaketak (sekuentziatuak)", + "Labetuak (labeen erabilera optimizatuz)", + "Hoztea eta ontziratzea" + ], + "principle_3_result": "**Software espezializatuak plangintza 2 orutatik 15 minutura murrizten du.**", + "principle_4_title": "4. Langile Eraginkorrak", + "principle_4_points": [ + "Eginkizun argiak rolaren arabera", + "Ekoizpen checklist", + "Prestakuntz jarraitua", + "Txanden erroteazio adimentsua" + ], + "technology_title": "Laguntzen duen Teknologia (Kalitatea Galdu gabe)", + "tech_ai_title": "IA Iragarpenerako", + "tech_ai": [ + "Produktu bakoitzean zenbat ekoiztu", + "Zein egun diren salmenta gailurrak", + "Eskaria eragingo duten gertaeren alertak" + ], + "tech_automation_title": "Admin Automatizazioa", + "tech_automation": [ + "Erosketa agindu automatikoak", + "Denbora errealeko inbentario kontrola", + "Ekoizpen erregistro digitala" + ], + "tech_apps_title": "Talderako Appak", + "tech_apps": [ + "Eguneko zereginen zerrenda", + "Denbora kritikoko jakinarazpenak", + "Arazo/hobekuntza erregistroa" + ], + "dont_automate_title": "Zer EZ Automatizatu", + "dont_automate_desc": "Mantendu eskuz balioa ematen duena:", + "dont_automate": [ + "✅ Irabiketa eta moldaketa (produktuaren kalitatea)", + "✅ Fermentazio kontrola (adituen begia)", + "✅ Apainketa eta akabera", + "✅ Azken kalitate kontrola" + ], + "implementation_title": "Urrats Urratsko Ezarpena", + "month_1_title": "1. hilabetea: Analisia", + "month_1": [ + "Erregistratu benetako ekoizpen denborak", + "Identifikatu leku estuak", + "Neurtu gaur egungo hondakina" + ], + "month_2_title": "2. hilabetea: Oinarrizko Optimizazioa", + "month_2": [ + "Ezarri batch adimentsua", + "Hobetu lan fluxua", + "Prestatu taldea" + ], + "month_3_title": "3. hilabetea: Teknologia", + "month_3": [ + "Integratu iragarpena sistema", + "Automatizatu inbentarioa", + "Digitalizatu plangintza" + ], + "results_title": "Espero diren Emaitzak (3-6 hilabete)", + "results": [ + "**% 30 errentagarritasun gehiago**", + "**% 25 denbora gutxiago administrazioan**", + "**% 20 ekoizpen gehiago** (talde bera)", + "**Kalitatea mantendu edo hobetu**" + ], + "conclusion_title": "Ondorioa", + "conclusion": "Zure okindegi optimizatzeak ez du esan nahi kalitatea galtzea. Hoberen egiten duzunean zentratzeko denbora askatzea da: produktu bikainak sortzea eta zure bezeroei hobeto zerbitzua ematea.\n\nTeknologia zure aliatua da, ez zure etsaia." + } + }, + "central_vs_local": { + "title": "Obrador Zentrala vs Tokiko Ekoizpena: Nola Optimizatzen ditu IAk Bi Ereduak", + "excerpt": "Bi negozio eredu, teknologia bera. Aurkitu gure IA plataforma nola egokitzen den tokiko okindegiei eta salmenta puntu anitzeko obrador zentralei.", + "author": "Okindegi IA Taldea", + "tags": { + "business_models": "negozio ereduak", + "central_bakery": "obrador zentrala", + "local_production": "tokiko ekoizpena", + "scalability": "eskalabilitatea" + }, + "content": { + "intro": "Okindegi munduan, ez dago eredu bakar bat. Bi forma nagusi nagusitzen dira merkatua, bakoitzak bere erronka eta abantailak dituena.", + "models_title": "Bi Negozio Ereduak", + "model_1_title": "1. Eredua: Tokiko Ekoizpena (Guztia Leku Berean)", + "model_1_characteristics_title": "Ezaugarriak:", + "model_1_characteristics": [ + "Ekoizpena eta salmenta leku berean", + "Freskotasun maximoa: labetatik mostradoreraino", + "Prozesuaren kontrol osoa", + "Bezeroekin harreman zuzena", + "Malgutasuna ekoizpena denbora errealean egokitzeko" + ], + "model_1_advantages_title": "Abantailak:", + "model_1_advantages": [ + "✅ Produktu ultra-freskoa", + "✅ Eskari azkarreko erantzuna", + "✅ Operazio sinplea", + "✅ Tokiko identitate sendoa" + ], + "model_1_challenges_title": "Erronkak:", + "model_1_challenges": [ + "⚠️ Espazio mugatuko ahalmena", + "⚠️ Eskalatzeko zailtasuna", + "⚠️ Kostu finko altuak kokapeneko", + "⚠️ Tokiko trafikoaren menpekotasuna" + ], + "model_2_title": "2. Eredua: Obrador Zentrala + Salmenta Puntuak", + "model_2_characteristics_title": "Ezaugarriak:", + "model_2_characteristics": [ + "Ekoizpen zentralizatua obrador batean", + "Banaketa salmenta puntu anitzera", + "Ekoizpeneko eskala ekonomiak", + "Logistika koordinazio kritikoa", + "Kokapen anitzeko kudeaketa" + ], + "model_2_advantages_title": "Abantailak:", + "model_2_advantages": [ + "✅ Eskala ekonomiak", + "✅ Kokapenen arteko koherentzia", + "✅ Langileen espezializazioa", + "✅ Merkatuaren irismen handiagoa" + ], + "model_2_challenges_title": "Erronkak:", + "model_2_challenges": [ + "⚠️ Logistika konplexutasuna", + "⚠️ Kokapenen arteko koordinazioa", + "⚠️ Eskari agregatuaren iragarpena", + "⚠️ Banaketan freskotasun kudeaketa" + ], + "ai_solutions_title": "Nola Konpontzen ditu IAk Eredu Bakoitzaren Erronkak", + "local_title": "Tokiko Ekoizpenerako", + "local_solution_1_title": "1. Hiper-Tokiko Iragarpena", + "local_solution_1_desc": "IAk zure kokapenaren eredu espezifikoak aztertzen ditu:", + "local_solution_1_points": [ + "Tokiko eguraldia (euriak oinezko trafikoa murrizten du)", + "Hurbileko gertaerak (asteko merkatua, partiduak)", + "Tokiko jaiak", + "Oinezko trafiko historikoa" + ], + "local_solution_1_result": "**Emaitza:** Eskaria % 92ko zehaztasunarekin iragartzen du zure kokapen espezifikorako.", + "local_solution_2_title": "2. Espazio Optimizazioa", + "local_solution_2_desc": "Espazio mugatuarekin, labe bakoitza kontuan hartzen da:", + "local_solution_2_points": [ + "Produktuen sekuentziazio optimoa", + "Labearen erabileraren maximizazioa", + "Fermentazio kudeaketa espazio murriztuetan" + ], + "local_solution_2_result": "**Emaitza:** % +20 ahalmena lokala zabaldu gabe.", + "local_solution_3_title": "3. Inbentario Kudeaketa Sinplea", + "local_solution_3_desc": "Stock puntu bakarra:", + "local_solution_3_points": [ + "Berrosteko alerta automatikoak", + "Erosketa agindu optimizatuak", + "Iraungitzeen jarraipena" + ], + "local_solution_3_result": "**Emaitza:** % -30 immobilizatutako stockean.", + "central_title": "Obrador Zentrala + Salmenta Puntuetarako", + "central_solution_1_title": "1. Iragarpena Agregatua eta Zehatza", + "central_solution_1_desc": "IAk bi mailatan iragartzen du:", + "central_solution_1_levels": [ + "**Maila agregatua:** Obradoraren ekoizpen osoa", + "**Maila zehatza:** Salmenta puntu bakoitzeko eskaria" + ], + "central_solution_1_example": "Adibide erreala:", + "central_solution_1_example_points": [ + "Obradorak 500 baguette ekoiztu behar ditu", + "POS 1 (bulego gunea): 200 (goizeko gailurra)", + "POS 2 (bizilekua): 150 (arratsaldeko gailurra)", + "POS 3 (turistikoa): 150 (eguerdiko gailurra)" + ], + "central_solution_1_result": "**Emaitza:** Banaketa optimizatua, % -25 hondakin osoa.", + "central_solution_2_title": "2. Logistika Koordinazioa", + "central_solution_2_desc": "IAk kokapen anitzeko konplexutasuna kudeatzen du:", + "central_solution_2_points": [ + "Banaketa ibilbide optimizatuak", + "Eskari gailurraren araberako entrega timing", + "Beharrezkoa bada eguneko berrirosteaketak" + ], + "central_solution_2_result": "**Emaitza:** Puntu bakoitzak behar duena jasotzen du, behar duenean.", + "central_solution_3_title": "3. Ikuspegi Zentralizatua", + "central_solution_3_desc": "Dashboard bateratua:", + "central_solution_3_points": [ + "Salmenta puntuaren errendimendua", + "Kokapenen arteko konparaketa", + "Praktika hoberenen identifikazioa", + "Anomalien detekzioa" + ], + "central_solution_3_result": "**Emaitza:** Erabaki informatuak, hobekuntza jarraitu.", + "central_solution_4_title": "4. Freskotasun Kudeaketa", + "central_solution_4_desc": "Denbora jarraipena:", + "central_solution_4_points": [ + "Labetatik salmenta puntuaraino", + "Mostradorearen denbora produktu bakoitzeko", + "Freskotasun alertak kokapenaren arabera" + ], + "central_solution_4_result": "**Emaitza:** Kalitate bermea kokapen guztietan.", + "comparison_title": "Emaitzen Konparaketa", + "comparison_local_title": "Metrikak: Tokiko Ekoizpena", + "comparison_local": [ + "Hondakina: % 25 → % 12 (% -13)", + "Stockouts: % 18 → % 5 (% -13)", + "Plangintza denbora: 2o/eguna → 15min/eguna (% -85)", + "Marjina garbia: % 22 → % 32 (% +10)" + ], + "comparison_central_title": "Metrikak: Obrador Zentrala (3 POS)", + "comparison_central": [ + "Hondakin osoa: % 30 → % 15 (% -15)", + "Banaketa optimoa: % 60 → % 95 (% +35)", + "Berrirosteaketak: 12/astea → 3/astea (% -75)", + "Logistikaren ROI: % +40" + ], + "which_better_title": "Zein Eredu da Hobea?", + "which_better_desc": "**Ez dago erantzun unibertsalik.** Honetatik dago:", + "choose_local_title": "Aukeratu Tokiko Ekoizpena baldin:", + "choose_local": [ + "Kontrol eta malgutasun maximoa baloratzen baduzu", + "Zure merkatua hiperlokala bada", + "Inbertsio txikiagoarekin hasi nahi baduzu", + "Berehalako freskotasuna zure lehiakortasun abantaila bada" + ], + "choose_central_title": "Aukeratu Obrador Zentrala baldin:", + "choose_central": [ + "Kokapen anitzera eskalatu nahi baduzu", + "Eskala ekonomiak bilatzen badituzu", + "Logistikan inbertitzeko kapitala baduzu", + "Auzune/hiri anitzetan presentzia nahi baduzu" + ], + "important_title": "Garrantzitsua: Teknologia Egokitzen da", + "important_desc": "IA plataforma modernoen iraultzazkoa da haien **egokitzeko gaitasuna**:", + "important_points": [ + "✅ Sistema bera, bi konfigurazio", + "✅ Lokaletik zentralera haztea plataforma aldatu gabe", + "✅ A/B probak ereduen artean", + "✅ Hibridoak posible (produktu batzuk lokalak, besteak zentralak)" + ], + "case_study_title": "Kasu Erreala: Trantsizio Okindegi", + "case_study_desc": "**Okindegi X** tokiko ekoizpen bezala hasi zen:", + "case_study_points": [ + "1-2. urtea: Lokal bat, IAk tokiko eskaria iragartzen du", + "3. urtea: 2. lokala irekitzen du, sistema berak bi kudeatzen ditu orain", + "4. urtea: Obrador zentral + 4 POSera migratzen da, IAk arazorik gabe eskalatzen du" + ], + "case_study_result": "**Emaitza:** % 300eko hazkundea kontrol operatiboa galdu gabe.", + "conclusion_title": "Ondorioa", + "conclusion": "Ez duzu zure teknologia zure negozio ereduaren arabera aukeratu behar. **Zurekin ebolutzionatzen duen** teknologia behar duzu.\n\nEgunero 50 edo 5000 ogi egiten dituzun, leku batean edo hamarretan, IAk zure operazioa optimizatu dezake.\n\n**Galdera ez da \"Zer eredu naiz?\"**\n**Galdera da \"Nola optimizatzen dut dudan eredua?\"**\n\nEta erantzuna da: datuekin, IArekin, tresna egokirarekin." + } + }, + "gdpr": { + "title": "GDPR eta Datuak Babestea Okindegian: Jakin Behar Duzuna", + "excerpt": "RGPDak Espainiako enpresa guztiei eragiten die, okindegiak barne. Gida praktikoa legearekin betetza zailtasunik gabe.", + "author": "María López (Abokatu Digitala)", + "tags": { + "gdpr": "GDPR", + "rgpd": "RGPD", + "privacy": "pribatutasuna", + "legal": "legala", + "security": "segurtasuna" + }, + "content": { + "intro": "Zure okindegi kudeatzeko softwarea erabiltzen baduzu, RGPD (ingelesez GDPR) ezagutu behar duzu.", + "data_title": "Zer Datu Kudeatzen ditu Zure Okindegiak?", + "customer_data_title": "Bezeroen datuak:", + "customer_data": [ + "Izena eta kontaktua (leialtasun programak)", + "Erosketa historiala", + "Elikadura lehentasunak (alergiak, beganoak)", + "Ordainketa datuak (txartelak)" + ], + "employee_data_title": "Langileen datuak:", + "employee_data": [ + "Informazio pertsonala", + "Ordutegiak eta txandak", + "Nomina", + "Errendimendu ebaluazioak" + ], + "operational_data_title": "Datu operatiboak:", + "operational_data": [ + "Hornitzaileak eta kontaktuak", + "Errezetak eta formulak", + "Salmentak eta inbentarioa", + "Negozio analitikak" + ], + "obligations_title": "Betebehar Legalak (RGPD)", + "obligation_1_title": "1. Baimena Esplizitua", + "obligation_1_desc": "Bezeroek **aktiboki onartu behar dute** euren datuak erabiltzen dituzula:", + "obligation_1_points": [ + "❌ Kutxa aurrez markatua", + "✅ Beraiek markatu behar duten kutxa", + "✅ Erabileraren azalpen argia" + ], + "obligation_2_title": "2. Ahazteko Eskubidea", + "obligation_2_desc": "Bezeroek eskatu dezakete:", + "obligation_2_points": [ + "Euren datuak ikusi (eramgarritasuna)", + "Datu okerrak zuzendu", + "Euren datuak osorik ezabatu" + ], + "obligation_2_deadline": "**30 eguneko epean erantzun behar duzu.**", + "obligation_3_title": "3. Datuen Segurtasuna", + "obligation_3_desc": "Betebeharrak:", + "obligation_3_points": [ + "Datu sentikoen enkriptatzea", + "Sarbide murriztua (pasahitzak)", + "Backup erregularrak", + "Haustura aurreko prozedurak" + ], + "obligation_4_title": "4. Datuen Transferentzia", + "obligation_4_desc": "Hodeiko softwarea erabiltzen baduzu:", + "obligation_4_points": [ + "Zerbitzariak EBn egon behar dute", + "Edo GDPR akordio baliodunekin", + "Inoiz ez babesa egokia ez duten herrialdeetan" + ], + "fines_title": "Bete ez izateagatiko Isunak", + "fines_desc": "RGPD isunak izan daitezke:", + "fines_points": [ + "**20 milioi €**ra arte", + "Edo urteko **fakturazioareren % 4**", + "**Handiena dena**" + ], + "fines_note": "Nahiz eta enpresa txikientzat zenbateko hauetara iritsi ez, isun errealak **€5,000 - €50,000** inguruan daude.", + "software_title": "Nola Aukeratu Software Segurua", + "checklist_title": "✅ GDPR Checklist", + "checklist": [ + "[ ] Zerbitzariak Espainian/EBn", + "[ ] AES-256 enkriptatzea edo handiagoa", + "[ ] ISO 27001 ziurtagiria", + "[ ] Segurtasun auditoretzak erregularrak", + "[ ] Pribatutasun politika argia", + "[ ] Euskarazko laguntza", + "[ ] Datuen prozesatzailearen kontratua" + ], + "warning_signs_title": "❌ Alerta Seinaleak", + "warning_signs": [ + "⚠️ AEBetako/Asiako zerbitzariak akordioak gabe", + "⚠️ Ez du GDPR/RGPDri buruz aipatzen", + "⚠️ \"Datuak bazkideekin partekatzen ditugu\"", + "⚠️ Segurtasun ziurtagiririk gabe" + ], + "case_title": "Kasua: Okindegi IA", + "case_desc": "Gure GDPR konpromisoa:", + "case_points": [ + "✅ **Espainiako zerbitzariak % 100**", + "✅ **AES-256 enkriptatzea**", + "✅ **Hiruhilekoko auditoretzak**", + "✅ **RGPD betetze bermea**", + "✅ **Zure datuak INOIZ EZ dira partekatzen**", + "✅ **GUZTIA kontrolatzen duzu**" + ], + "practical_steps_title": "Urrats Praktikoak", + "today_title": "Gaur", + "today": [ + "Berrikusi zer datu pertsonalak gordetzen dituzun", + "Egiaztatu non dauden gordetuta", + "Irakurri zure gaur egungo softwarearen baldintzak" + ], + "this_week_title": "Aste Honetan", + "this_week": [ + "Eguneratu pribatutasun politika", + "Lortu baimen esplizituak", + "Ezarri backup erregularrak" + ], + "this_month_title": "Hilabete Honetan", + "this_month": [ + "Prestatu taldea datuen babesa buruz", + "Dokumentatu segurtasun prozedurak", + "Aztertu GDPR-compliant softwarera aldatzea" + ], + "conclusion_title": "Ondorioa", + "conclusion": "RGPDa ez da aukerakoa. Baina ez da ere korapilatsua tresna egokiak erabiltzen badituzu.\n\n**Zure lehentasuna:** GDPRa benetan hartzen duen softwarea, zuk ogia egitean zentratzen ahal izateko." + } + } + } +} diff --git a/frontend/src/locales/eu/reasoning.json b/frontend/src/locales/eu/reasoning.json index 4c923788..ddac79f9 100644 --- a/frontend/src/locales/eu/reasoning.json +++ b/frontend/src/locales/eu/reasoning.json @@ -1,6 +1,7 @@ { "purchaseOrder": { "low_stock_detection": "{supplier_name}-rentzat stock baxua. {product_names_joined}-ren egungo stocka {days_until_stockout} egunetan amaituko da.", + "low_stock_detection_detailed": "{critical_product_count, plural, =1 {{critical_products_0} {min_depletion_hours} ordutan amaituko da} other {{critical_product_count} produktu kritiko urri}}. {supplier_name}-ren {supplier_lead_time_days} eguneko entregarekin, {order_urgency, select, critical {BEREHALA} urgent {GAUR} important {laster} other {orain}} eskatu behar dugu {affected_batches_count, plural, =0 {ekoizpen atzerapenak} =1 {{affected_batches_0} lotearen etetea} other {{affected_batches_count} loteen etetea}} saihesteko{potential_loss_eur, select, 0 {} other { (€{potential_loss_eur} arriskuan)}}.", "forecast_demand": "{supplier_name}-ren {product_names_joined}-rentzat {forecast_period_days} eguneko eskaera aurreikuspenean oinarritutako eskaera programatua.", "safety_stock_replenishment": "{supplier_name}-ren {product_names_joined}-rentzat segurtasun stockaren birjartzea.", "supplier_contract": "{supplier_name}-rekin kontratuaren arabera programatutako eskaera.", @@ -18,12 +19,12 @@ "regular_schedule": "{product_name}-ren ohiko ekoizpen programatua." }, "consequence": { - "stockout_risk": "Stock amaitzeko arriskua {{impact_days}} egunetan. Produktu kaltetuak: {{affected_products_joined}}.", - "insufficient_supply": "{{impact_days}} eguneko aldirako hornidura ez nahikoa.", - "production_delay": "{{delay_hours}} orduko ekoizpen atzerapena posiblea.", + "stockout_risk": "Stock amaitzeko arriskua {impact_days} egunetan. Produktu kaltetuak: {affected_products_joined}.", + "insufficient_supply": "{impact_days} eguneko aldirako hornidura ez nahikoa.", + "production_delay": "{delay_hours} orduko ekoizpen atzerapena posiblea.", "customer_commitment": "Bezeroari entregatzeko konpromisoa arriskuan.", "quality_issue": "Kalitate estandarrak arriskuan egon daitezke.", - "cost_increase": "Materialen kostuak %{{percentage}} gehitu daitezke." + "cost_increase": "Materialen kostuak %{percentage} gehitu daitezke." }, "severity": { "critical": "Kritikoa", @@ -45,27 +46,27 @@ "NO_DEMAND_DATA": "Ez dago eskaeraren datu historikorik eskuragarri (gutxienez 2 datu puntu behar dira)" }, "safetyStock": { - "statistical_z_score": "Segurtasun-stock kalkulatua metodo estatistikoarekin (zerbitzu-maila {{service_level}}%, z-score {{z_score}}). Eskaeraren desbideratze estandarrean {{demand_std_dev}} eta {{lead_time_days}} eguneko entrega-denboran oinarrituta. Emaitza: {{safety_stock}} unitate.", - "advanced_variability": "Segurtasun-stock kalkulatua aldakortasun-analisi aurreratuarekin. Eskaeraren aldakortasuna (σ={{demand_std_dev}}) eta entrega-denboraren ziurgabetasuna (σ={{lead_time_std_dev}} egun) kontuan hartzen ditu. Emaitza: {{safety_stock}} unitate.", - "fixed_percentage": "Segurtasun-stock ezarri da {{lead_time_days}} eguneko eskaeraren {{percentage}}%n ({{lead_time_demand}} unitate). Emaitza: {{safety_stock}} unitate.", - "error_lead_time_invalid": "Ezin da segurtasun-stock kalkulatu: entrega-denbora ({{lead_time_days}} egun) edo eskaeraren desbideratze estandarra ({{demand_std_dev}}) ez dira baliodunak.", - "error_insufficient_data": "Eskaeraren historiala ez da nahikoa segurtasun-stock kalkulatzeko ({{data_points}} datu puntu, {{min_required}} behar dira)." + "statistical_z_score": "Segurtasun-stock kalkulatua metodo estatistikoarekin (zerbitzu-maila {service_level}%, z-score {z_score}). Eskaeraren desbideratze estandarrean {demand_std_dev} eta {lead_time_days} eguneko entrega-denboran oinarrituta. Emaitza: {safety_stock} unitate.", + "advanced_variability": "Segurtasun-stock kalkulatua aldakortasun-analisi aurreratuarekin. Eskaeraren aldakortasuna (σ={demand_std_dev}) eta entrega-denboraren ziurgabetasuna (σ={lead_time_std_dev} egun) kontuan hartzen ditu. Emaitza: {safety_stock} unitate.", + "fixed_percentage": "Segurtasun-stock ezarri da {lead_time_days} eguneko eskaeraren {percentage}%n ({lead_time_demand} unitate). Emaitza: {safety_stock} unitate.", + "error_lead_time_invalid": "Ezin da segurtasun-stock kalkulatu: entrega-denbora ({lead_time_days} egun) edo eskaeraren desbideratze estandarra ({demand_std_dev}) ez dira baliodunak.", + "error_insufficient_data": "Eskaeraren historiala ez da nahikoa segurtasun-stock kalkulatzeko ({data_points} datu puntu, {min_required} behar dira)." }, "priceForecaster": { - "decrease_expected": "Espero da prezioa {{change_pct}}% jaitsiko dela hurrengo {{forecast_days}} egunetan. Oraingoa: €{{current_price}}, aurreikuspena: €{{forecast_mean}}. Gomendio: Itxaron prezio hobeago baterako.", - "increase_expected": "Espero da prezioa {{change_pct}}% igoko dela hurrengo {{forecast_days}} egunetan. Oraingoa: €{{current_price}}, aurreikuspena: €{{forecast_mean}}. Gomendio: Erosi orain oraingo prezioa ziurtatzeko.", - "high_volatility": "Prezio-aldakortasun altua detektatu da (CV={{coefficient}}). Prezioaren eguneko batez besteko aldaketa: {{avg_daily_change_pct}}%. Gomendio: Itxaron prezioaren jaitsierara.", - "below_average": "Oraingo prezioa €{{current_price}} batez besteko historikoaren (€{{mean_price}}) {{below_avg_pct}}% azpitik dago. Erosketa-aukera egokia.", - "stable": "Prezioa egonkorra da. Oraingoa: €{{current_price}}, aurreikuspena: €{{forecast_mean}} ({{expected_change_pct}}% aldaketa espero da). Ohiko erosketa-denbora gomendatzen da.", - "insufficient_data": "Prezioen historiala ez da nahikoa aurreikuspen fidagarrirako ({{history_days}} egun eskuragarri, {{min_required_days}} egun behar dira)." + "decrease_expected": "Espero da prezioa {change_pct}% jaitsiko dela hurrengo {forecast_days} egunetan. Oraingoa: €{current_price}, aurreikuspena: €{forecast_mean}. Gomendio: Itxaron prezio hobeago baterako.", + "increase_expected": "Espero da prezioa {change_pct}% igoko dela hurrengo {forecast_days} egunetan. Oraingoa: €{current_price}, aurreikuspena: €{forecast_mean}. Gomendio: Erosi orain oraingo prezioa ziurtatzeko.", + "high_volatility": "Prezio-aldakortasun altua detektatu da (CV={coefficient}). Prezioaren eguneko batez besteko aldaketa: {avg_daily_change_pct}%. Gomendio: Itxaron prezioaren jaitsierara.", + "below_average": "Oraingo prezioa €{current_price} batez besteko historikoaren (€{mean_price}) {below_avg_pct}% azpitik dago. Erosketa-aukera egokia.", + "stable": "Prezioa egonkorra da. Oraingoa: €{current_price}, aurreikuspena: €{forecast_mean} ({expected_change_pct}% aldaketa espero da). Ohiko erosketa-denbora gomendatzen da.", + "insufficient_data": "Prezioen historiala ez da nahikoa aurreikuspen fidagarrirako ({history_days} egun eskuragarri, {min_required_days} egun behar dira)." }, "optimization": { - "eoq_base": "Eskaera Kantitate Ekonomikoa kalkulatu da: {{eoq}} unitate (beharrezkoa: {{required_quantity}}, urteko eskaera: {{annual_demand}}). {{optimal_quantity}} unitatetan optimizatuta.", - "moq_applied": "Gutxieneko eskaera-kantitatearen murrizketa aplikatu da: {{moq}} unitate.", - "max_applied": "Gehienezko eskaera-kantitatearen murrizketa aplikatu da: {{max_qty}} unitate.", - "no_tiers": "Ez dago prezio-mailarik eskuragarri produktu honetarako. Oinarrizko kantitatea: {{base_quantity}} unitate €{{unit_price}} unitateko.", - "current_tier": "Oraingo prezio-maila: €{{current_tier_price}} unitateko {{base_quantity}} unitateko (guztira: €{{base_cost}}).", - "tier_upgraded": "Prezio-maila hobea lortu da! {{tier_min_qty}} unitate eskatzeak ({{additional_qty}} gehiago) €{{tier_price}} unitateko €{{savings}} aurrezten ditu {{base_quantity}} unitateri €{{base_price}}n konparatuta." + "eoq_base": "Eskaera Kantitate Ekonomikoa kalkulatu da: {eoq} unitate (beharrezkoa: {required_quantity}, urteko eskaera: {annual_demand}). {optimal_quantity} unitatetan optimizatuta.", + "moq_applied": "Gutxieneko eskaera-kantitatearen murrizketa aplikatu da: {moq} unitate.", + "max_applied": "Gehienezko eskaera-kantitatearen murrizketa aplikatu da: {max_qty} unitate.", + "no_tiers": "Ez dago prezio-mailarik eskuragarri produktu honetarako. Oinarrizko kantitatea: {base_quantity} unitate €{unit_price} unitateko.", + "current_tier": "Oraingo prezio-maila: €{current_tier_price} unitateko {base_quantity} unitateko (guztira: €{base_cost}).", + "tier_upgraded": "Prezio-maila hobea lortu da! {tier_min_qty} unitate eskatzeak ({additional_qty} gehiago) €{tier_price} unitateko €{savings} aurrezten ditu {base_quantity} unitateri €{base_price}n konparatuta." }, "jtbd": { "health_status": { @@ -75,8 +76,8 @@ "last_updated": "Azken eguneratzea", "next_check": "Hurrengo egiaztapena", "never": "Inoiz ez", - "critical_issues": "{{count}} arazo kritiko", - "actions_needed": "{{count}} ekintza behar" + "critical_issues": "{count} arazo kritiko", + "actions_needed": "{count} ekintza behar" }, "action_queue": { "title": "Zer Behar Du Zure Arreta", @@ -108,19 +109,19 @@ "title": "Bart Gauean Zure Eguna Planifikatu Nuen", "ready_to_plan": "Zure Okindegiko Eguna Planifikatzeko Prest", "run_planning": "Exekutatu Eguneko Plangintza", - "run_info": "Orkestazio exekuzioa #{{runNumber}}", - "took": "{{seconds}}s behar izan zituen", - "created_pos": "{{count}} erosketa agindu sortu", - "scheduled_batches": "{{count}} ekoizpen lote programatu", - "show_more": "Erakutsi {{count}} gehiago", + "run_info": "Orkestazio exekuzioa #{runNumber}", + "took": "{seconds}s behar izan zituen", + "created_pos": "{count} erosketa agindu sortu", + "scheduled_batches": "{count} ekoizpen lote programatu", + "show_more": "Erakutsi {count} gehiago", "show_less": "Erakutsi gutxiago", "no_actions": "Ez dira ekintza berriak behar - dena bidean dago!", "based_on": "Oinarrituta:", - "customer_orders": "{{count}} bezero eskaera", + "customer_orders": "{count} bezero eskaera", "historical_demand": "Eskaera historikoa", "inventory_levels": "Inbentario mailak", "ai_optimization": "IA optimizazioa", - "actions_required": "{{count}} elementuk zure onespena behar du aurrera jarraitu aurretik", + "actions_required": "{count} elementuk zure onespena behar du aurrera jarraitu aurretik", "no_tenant_error": "Ez da inquilino ID aurkitu. Mesedez, ziurtatu saioa hasi duzula.", "planning_started": "Plangintza behar bezala hasi da", "planning_failed": "Errorea plangintza hastean", @@ -159,9 +160,9 @@ } }, "types": { - "low_stock_detection": "Stock baxua detektatu da {{product_name}}-(e)rako. Stocka {{days_until_stockout}} egunetan agortuko da.", + "low_stock_detection": "Stock baxua detektatu da {product_name}-(e)rako. Stocka {days_until_stockout} egunetan agortuko da.", "stockout_prevention": "Osagai kritikoen desabastetzea saihestea", - "forecast_demand": "Eskari aurreikuspenean oinarrituta: {{predicted_demand}} unitate aurreikusita ({{confidence_score}}% konfiantza)", + "forecast_demand": "Eskari aurreikuspenean oinarrituta: {predicted_demand} unitate aurreikusita ({confidence_score}% konfiantza)", "customer_orders": "Bezeroen eskaera bermatuen betetze", "seasonal_demand": "Aurreikusitako sasoiko eskariaren igoera", "inventory_replenishment": "Inbentario berritze erregularra", diff --git a/frontend/src/locales/index.ts b/frontend/src/locales/index.ts index e4a60a9c..51801cb9 100644 --- a/frontend/src/locales/index.ts +++ b/frontend/src/locales/index.ts @@ -21,6 +21,7 @@ import helpEs from './es/help.json'; import featuresEs from './es/features.json'; import aboutEs from './es/about.json'; import demoEs from './es/demo.json'; +import blogEs from './es/blog.json'; // English translations import commonEn from './en/common.json'; @@ -45,6 +46,7 @@ import helpEn from './en/help.json'; import featuresEn from './en/features.json'; import aboutEn from './en/about.json'; import demoEn from './en/demo.json'; +import blogEn from './en/blog.json'; // Basque translations import commonEu from './eu/common.json'; @@ -69,6 +71,7 @@ import helpEu from './eu/help.json'; import featuresEu from './eu/features.json'; import aboutEu from './eu/about.json'; import demoEu from './eu/demo.json'; +import blogEu from './eu/blog.json'; // Translation resources by language export const resources = { @@ -95,6 +98,7 @@ export const resources = { features: featuresEs, about: aboutEs, demo: demoEs, + blog: blogEs, }, en: { common: commonEn, @@ -119,6 +123,7 @@ export const resources = { features: featuresEn, about: aboutEn, demo: demoEn, + blog: blogEn, }, eu: { common: commonEu, @@ -143,6 +148,7 @@ export const resources = { features: featuresEu, about: aboutEu, demo: demoEu, + blog: blogEu, }, }; @@ -179,7 +185,7 @@ export const languageConfig = { }; // Namespaces available in translations -export const namespaces = ['common', 'auth', 'inventory', 'foodSafety', 'suppliers', 'orders', 'recipes', 'errors', 'dashboard', 'production', 'equipment', 'landing', 'settings', 'ajustes', 'reasoning', 'wizards', 'subscription', 'purchase_orders', 'help', 'features', 'about', 'demo'] as const; +export const namespaces = ['common', 'auth', 'inventory', 'foodSafety', 'suppliers', 'orders', 'recipes', 'errors', 'dashboard', 'production', 'equipment', 'landing', 'settings', 'ajustes', 'reasoning', 'wizards', 'subscription', 'purchase_orders', 'help', 'features', 'about', 'demo', 'blog'] as const; export type Namespace = typeof namespaces[number]; // Helper function to get language display name @@ -193,7 +199,7 @@ export const isSupportedLanguage = (language: string): language is SupportedLang }; // Export individual language modules for direct imports -export { commonEs, authEs, inventoryEs, foodSafetyEs, suppliersEs, ordersEs, recipesEs, errorsEs, equipmentEs, landingEs, settingsEs, ajustesEs, reasoningEs, wizardsEs, wizardsEn, wizardsEu, helpEs, helpEn, helpEu, featuresEs, featuresEn, featuresEu, aboutEs, aboutEn, aboutEu, demoEs, demoEn, demoEu }; +export { commonEs, authEs, inventoryEs, foodSafetyEs, suppliersEs, ordersEs, recipesEs, errorsEs, equipmentEs, landingEs, settingsEs, ajustesEs, reasoningEs, wizardsEs, wizardsEn, wizardsEu, helpEs, helpEn, helpEu, featuresEs, featuresEn, featuresEu, aboutEs, aboutEn, aboutEu, demoEs, demoEn, demoEu, blogEs, blogEn, blogEu }; // Default export with all translations export default resources; diff --git a/frontend/src/pages/public/BlogPage.tsx b/frontend/src/pages/public/BlogPage.tsx index b85e9d09..b20df629 100644 --- a/frontend/src/pages/public/BlogPage.tsx +++ b/frontend/src/pages/public/BlogPage.tsx @@ -2,624 +2,105 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { PublicLayout } from '../../components/layout'; -import { Calendar, Clock, ArrowRight, TrendingUp, Shield, Brain, Package, Users, Award } from 'lucide-react'; +import { Calendar, Clock, ArrowRight, Brain } from 'lucide-react'; interface BlogPost { id: string; slug: string; - title: string; - excerpt: string; - content: string; - author: string; + titleKey: string; + excerptKey: string; + authorKey: string; date: string; readTime: string; - category: string; - image?: string; - tags: string[]; + categoryKey: string; + tagsKeys: string[]; } const BlogPage: React.FC = () => { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(['blog', 'common']); - // SEO-optimized blog posts about bakery management, AI, and food waste + // Blog posts metadata - translations come from i18n const blogPosts: BlogPost[] = [ { id: '1', slug: 'reducir-desperdicio-alimentario-panaderia', - title: 'Cómo Reducir el Desperdicio Alimentario en tu Panadería: Guía Completa 2025', - excerpt: 'El desperdicio alimentario cuesta a las panaderías entre 15-40% de su producción. Descubre técnicas probadas y cómo la IA puede ayudarte a reducirlo hasta un 35%.', - content: ` -# Cómo Reducir el Desperdicio Alimentario en tu Panadería - -El desperdicio alimentario es uno de los mayores desafíos para las panaderías. Cada día, miles de euros en producto terminan en la basura porque no se vendieron. Pero no tiene que ser así. - -## El Problema Real - -Las panaderías pierden entre **15% y 40% de su producción** por: -- Sobreproducción por miedo a quedarse sin stock -- Predicciones manuales inexactas -- Falta de datos sobre patrones de demanda -- Eventos imprevistos (clima, festividades) - -## Soluciones Prácticas - -### 1. Análisis de Datos Históricos -Analiza tus ventas de los últimos 6-12 meses para identificar: -- Días de mayor y menor demanda -- Productos más vendidos por día de la semana -- Impacto de festividades y eventos locales -- Efecto del clima en las ventas - -### 2. Predicción con IA -La inteligencia artificial puede: -- Analizar más de 50 variables simultáneamente -- Predecir demanda con 92% de precisión -- Ajustarse automáticamente a nuevos patrones -- Alertarte de eventos que afectarán ventas - -### 3. Gestión Dinámica de Inventario -- Stock mínimo calculado por producto -- Alertas automáticas de reposición -- Seguimiento de caducidades -- Optimización de órdenes de compra - -## Resultados Reales - -Panaderías que implementan estos sistemas reportan: -- **35% menos desperdicio** en 3 meses -- **€800/mes de ahorro** promedio -- **22% más ventas** por mejor disponibilidad -- **8 horas semanales** ahorradas en planificación - -## Primeros Pasos - -1. Empieza registrando ventas diarias por producto -2. Anota factores externos (clima, eventos) -3. Analiza patrones semanales y mensuales -4. Considera una herramienta de predicción con IA -5. Ajusta producción gradualmente - -El desperdicio alimentario no solo afecta tu rentabilidad, también el medioambiente. Cada kilo que no desperdicias es un paso hacia una panadería más sostenible y rentable. - `, - author: 'Equipo Panadería IA', + titleKey: 'posts.waste_reduction.title', + excerptKey: 'posts.waste_reduction.excerpt', + authorKey: 'posts.waste_reduction.author', date: '2025-01-15', - readTime: '8 min', - category: 'Gestión', - tags: ['desperdicio alimentario', 'sostenibilidad', 'IA', 'gestión'], + readTime: '8', + categoryKey: 'categories.management', + tagsKeys: [ + 'posts.waste_reduction.tags.food_waste', + 'posts.waste_reduction.tags.sustainability', + 'posts.waste_reduction.tags.ai', + 'posts.waste_reduction.tags.management', + ], }, { id: '2', slug: 'ia-predecir-demanda-panaderia', - title: 'Cómo la IA Predice la Demanda en Panaderías con 92% de Precisión', - excerpt: 'La inteligencia artificial ha revolucionado la predicción de demanda. Descubre cómo funcionan los algoritmos de ML aplicados a panaderías', - content: ` -# Cómo la IA Predice la Demanda en Panaderías - -La predicción de demanda siempre ha sido más arte que ciencia en panaderías. Pero la inteligencia artificial está cambiando eso radicalmente. - -## El Problema de la Intuición - -Tradicionalmente, los panaderos predicen basándose en: -- Experiencia personal ("los lunes se vende menos") -- Observación del día anterior -- Sensaciones sobre el clima -- Excel con promedios simples - -**El problema:** La intuición falla cuando hay múltiples variables interactuando. - -## Cómo Funciona la IA - -### Variables que Analiza - -La IA moderna considera más de 50 factores: - -**Históricos:** -- Ventas por producto, día, hora -- Tendencias semanales y mensuales -- Estacionalidad anual -- Crecimiento o declive de productos - -**Externos:** -- Clima (temperatura, lluvia, sol) -- Día de la semana -- Festividades y eventos locales -- Vacaciones escolares -- Eventos deportivos - -**Contextuales:** -- Stock disponible -- Promociones activas -- Nuevos productos -- Cambios de precio - -### Algoritmos de Machine Learning - -Los más efectivos para panaderías: - -1. **Random Forest**: Excelente para patrones no lineales -2. **LSTM (Redes Neuronales)**: Captura tendencias temporales -3. **XGBoost**: Alto rendimiento con datos históricos - -## Precisión Real - -Casos de estudio muestran: -- **92% de precisión** en predicción diaria -- **95% de precisión** en predicción semanal -- **Mejora continua** con más datos - -## Implementación Práctica - -### Fase 1: Recopilación (Semana 1) -- Configura el sistema -- Importa datos históricos (mínimo 3 meses) -- Verifica calidad de datos - -### Fase 2: Entrenamiento (Semana 2-4) -- La IA aprende de tus patrones -- Se ajusta a tu negocio específico -- Comienza predicciones básicas - -### Fase 3: Optimización (Mes 2-3) -- Precisión aumenta gradualmente -- Se adapta a cambios -- Alertas predictivas activas - -## Beneficios Medibles - -- **35% menos desperdicio** en 90 días -- **Nunca quedarse sin stock** de bestsellers -- **Planificación automática** de producción -- **Ahorro de 8 horas/semana** en planificación - -## ¿Vale la Pena? - -Para panaderías que: -- Producen más de 20 productos diferentes -- Venden más de 100 unidades diarias -- Tienen desperdicio >15% -- Quieren escalar el negocio - -**La respuesta es SÍ.** - -La tecnología ya está aquí. La pregunta no es si la IA funciona, sino cuánto estás perdiendo al no usarla. - `, - author: 'Dr. Ana Martínez', + titleKey: 'posts.ai_prediction.title', + excerptKey: 'posts.ai_prediction.excerpt', + authorKey: 'posts.ai_prediction.author', date: '2025-01-10', - readTime: '10 min', - category: 'Tecnología', - tags: ['IA', 'machine learning', 'predicción', 'tecnología'], + readTime: '10', + categoryKey: 'categories.technology', + tagsKeys: [ + 'posts.ai_prediction.tags.ai', + 'posts.ai_prediction.tags.machine_learning', + 'posts.ai_prediction.tags.prediction', + 'posts.ai_prediction.tags.technology', + ], }, { id: '3', slug: 'optimizar-produccion-panaderia-artesanal', - title: 'Guía de Optimización de Producción para Panaderías', - excerpt: 'Aprende a optimizar tu producción sin perder la calidad. Técnicas probadas que aumentan rentabilidad hasta 30% ya sea que produzcas localmente o gestiones un obrador central.', - content: ` -# Optimización de Producción para Panaderías - -Optimizar no significa perder calidad. Se trata de trabajar más inteligente, no más rápido. - -## El Desafío de la Panadería Moderna - -Las panaderías, ya sean locales o con obradores centrales, enfrentan: -- **Productos variados** con tiempos de preparación diferentes -- **Producción manual** que requiere planificación detallada -- **Margen estrecho** donde cada error cuesta -- **Competencia** con panaderías industriales de bajo precio - -## Principios de Optimización - -### 1. Planificación Basada en Datos - -**Antes:** "Hago 50 barras porque ayer vendí 45" -**Después:** "El sistema predice 52 barras considerando que es viernes y hay buen clima" - -**Impacto:** -30% desperdicio, +15% ventas - -### 2. Batch Inteligente de Producción - -Agrupa productos por: -- Temperatura de horneado similar -- Tiempo de fermentación compatible -- Masa base común - -**Resultado:** -25% tiempo de producción, misma calidad - -### 3. Gestión de Timing - -Usa cronogramas visuales: -- Inicio de masas madres (18-24h antes) -- Amasados y formados (secuenciados) -- Horneados (optimizando uso de hornos) -- Enfriado y empaquetado - -**Software especializado reduce planificación de 2 horas a 15 minutos.** - -### 4. Personal Eficiente - -- Tareas claras por rol -- Checklist de producción -- Capacitación continua -- Rotación inteligente de turnos - -## Tecnología que Ayuda (Sin Perder Calidad) - -### IA para Predicción -- Cuánto producir de cada producto -- Qué días son picos de venta -- Alertas de eventos que afectan demanda - -### Automatización de Admin -- Órdenes de compra automáticas -- Control de inventario en tiempo real -- Registro de producción digital - -### Apps para Equipo -- Lista de tareas del día -- Notificaciones de timing crítico -- Registro de problemas/mejoras - -## Lo Que NO Debes Automatizar - -Mantén manual lo que da valor: -- ✅ Amasado y formado (calidad del producto) -- ✅ Control de fermentación (ojo experto) -- ✅ Decoración y acabados -- ✅ Control de calidad final - -## Implementación Paso a Paso - -### Mes 1: Análisis -- Registra tiempos reales de producción -- Identifica cuellos de botella -- Mide desperdicio actual - -### Mes 2: Optimización Básica -- Implementa batch inteligente -- Mejora flujo de trabajo -- Capacita equipo - -### Mes 3: Tecnología -- Integra sistema de predicción -- Automatiza inventario -- Digitaliza planificación - -## Resultados Esperados (3-6 meses) - -- **30% más rentabilidad** -- **25% menos tiempo en admin** -- **20% más producción** (mismo equipo) -- **Calidad mantenida o mejorada** - -## Conclusión - -Optimizar tu panadería no significa perder calidad. Significa liberar tiempo para enfocarte en lo que haces mejor: crear productos excepcionales y servir mejor a tus clientes. - -La tecnología es tu aliada, no tu enemiga. - `, - author: 'Carlos Ruiz', + titleKey: 'posts.production_optimization.title', + excerptKey: 'posts.production_optimization.excerpt', + authorKey: 'posts.production_optimization.author', date: '2025-01-05', - readTime: '12 min', - category: 'Producción', - tags: ['optimización', 'producción', 'artesanal', 'gestión'], + readTime: '12', + categoryKey: 'categories.production', + tagsKeys: [ + 'posts.production_optimization.tags.optimization', + 'posts.production_optimization.tags.production', + 'posts.production_optimization.tags.artisan', + 'posts.production_optimization.tags.management', + ], }, { id: '4', slug: 'obrador-central-vs-produccion-local', - title: 'Obrador Central vs Producción Local: Cómo la IA Optimiza Ambos Modelos', - excerpt: 'Dos modelos de negocio, misma tecnología. Descubre cómo nuestra plataforma de IA se adapta tanto a panaderías locales como a obradores centrales con múltiples puntos de venta.', - content: ` -# Obrador Central vs Producción Local: Cómo la IA Optimiza Ambos Modelos - -En el mundo de la panadería, no existe un modelo único. Dos formas principales dominan el mercado, cada una con sus propios desafíos y ventajas. - -## Los Dos Modelos de Negocio - -### Modelo 1: Producción Local (Todo en un Lugar) - -**Características:** -- Producción y venta en la misma ubicación -- Frescura máxima: del horno al mostrador -- Control total del proceso -- Relación directa con clientes -- Flexibilidad para ajustar producción en tiempo real - -**Ventajas:** -- ✅ Producto ultrafres co -- ✅ Respuesta rápida a demanda -- ✅ Operación simple -- ✅ Identidad local fuerte - -**Desafíos:** -- ⚠️ Capacidad limitada por espacio -- ⚠️ Dificultad para escalar -- ⚠️ Costos fijos altos por ubicación -- ⚠️ Dependencia de tráfico local - -### Modelo 2: Obrador Central + Puntos de Venta - -**Características:** -- Producción centralizada en un obrador -- Distribución a múltiples puntos de venta -- Economías de escala en producción -- Coordinación logística crítica -- Gestión multi-ubicación - -**Ventajas:** -- ✅ Economías de escala -- ✅ Consistencia entre ubicaciones -- ✅ Especialización de personal -- ✅ Mayor alcance de mercado - -**Desafíos:** -- ⚠️ Complejidad logística -- ⚠️ Coordinación entre ubicaciones -- ⚠️ Predicción de demanda agregada -- ⚠️ Gestión de frescura en distribución - -## Cómo la IA Resuelve los Desafíos de Cada Modelo - -### Para Producción Local - -**1. Predicción Hiper-Local** -La IA analiza patrones específicos de tu ubicación: -- Clima local (lluvia reduce tráfico peatonal) -- Eventos cercanos (mercado semanal, partidos) -- Días festivos locales -- Tráfico peatonal histórico - -**Resultado:** Predice demanda con 92% precisión para tu ubicación específica. - -**2. Optimización de Espacio** -Con espacio limitado, cada hornada cuenta: -- Secuenciación óptima de productos -- Maximización de uso de horno -- Gestión de fermentación en espacios reducidos - -**Resultado:** +20% capacidad sin ampliar local. - -**3. Gestión de Inventario Simple** -Un solo punto de stock: -- Alertas automáticas de reposición -- Órdenes de compra optimizadas -- Seguimiento de caducidad - -**Resultado:** -30% en stock inmovilizado. - -### Para Obrador Central + Puntos de Venta - -**1. Predicción Agregada y Granular** -La IA predice a dos niveles: -- **Nivel agregado:** Producción total del obrador -- **Nivel granular:** Demanda por cada punto de venta - -Ejemplo real: -- Obrador debe producir 500 baguettes -- POS 1 (zona oficinas): 200 (pico mañana) -- POS 2 (residencial): 150 (pico tarde) -- POS 3 (turística): 150 (pico mediodía) - -**Resultado:** Distribución optimizada, -25% desperdicio total. - -**2. Coordinación Logística** -La IA gestiona complejidad multi-ubicación: -- Rutas de distribución optimizadas -- Timing de entregas por pico de demanda -- Reabastecimientos intraday si necesario - -**Resultado:** Cada punto recibe lo que necesita, cuando lo necesita. - -**3. Visibilidad Centralizada** -Un dashboard unificado: -- Performance por punto de venta -- Comparación entre ubicaciones -- Identificación de mejores prácticas -- Detección de anomalías - -**Resultado:** Decisiones informadas, mejora continua. - -**4. Gestión de Frescura** -Tracking de tiempos: -- Desde horneado hasta punto de venta -- Tiempo en mostrador por producto -- Alertas de frescura por ubicación - -**Resultado:** Garantía de calidad en todas las ubicaciones. - -## Comparación de Resultados - -### Métricas: Producción Local - -| Métrica | Antes | Después | Mejora | -|---------|-------|---------|--------| -| Desperdicio | 25% | 12% | -13% | -| Stockouts | 18% | 5% | -13% | -| Tiempo planificación | 2h/día | 15min/día | -85% | -| Margen neto | 22% | 32% | +10% | - -### Métricas: Obrador Central (3 POS) - -| Métrica | Antes | Después | Mejora | -|---------|-------|---------|--------| -| Desperdicio total | 30% | 15% | -15% | -| Distribución óptima | 60% | 95% | +35% | -| Reabastecimientos | 12/sem | 3/sem | -75% | -| ROI logística | - | +40% | - | - -## ¿Cuál Modelo Es Mejor? - -**No hay respuesta universal.** Depende de: - -### Elige Producción Local Si: -- Valoras máximo control y flexibilidad -- Tu mercado es hiperlocal -- Quieres empezar con menor inversión -- La frescura instantánea es tu ventaja competitiva - -### Elige Obrador Central Si: -- Quieres escalar a múltiples ubicaciones -- Buscas economías de escala -- Tienes capital para invertir en logística -- Quieres presencia en múltiples barrios/ciudades - -## Lo Importante: La Tecnología Se Adapta - -Lo revolucionario de las plataformas de IA modernas es su **adaptabilidad**: - -- ✅ Mismo sistema, dos configuraciones -- ✅ Creces de local a central sin cambiar plataforma -- ✅ Pruebas A/B entre modelos -- ✅ Híbridos posibles (algunos productos locales, otros centrales) - -## Caso Real: Panadería en Transición - -**Bakery X** empezó como producción local: -- Año 1-2: Un local, IA predice demanda local -- Año 3: Abre 2do local, mismo sistema ahora gestiona ambos -- Año 4: Migra a obrador central + 4 POS, IA escala sin problemas - -**Resultado:** Crecimiento 300% sin perder control operativo. - -## Conclusión - -No necesitas elegir tu tecnología según tu modelo de negocio. Necesitas tecnología que **evolucione contigo**. - -Ya sea que hornees 50 o 5000 panes diarios, en un lugar o en diez, la IA puede optimizar tu operación. - -**La pregunta no es "¿Qué modelo soy?"** -**La pregunta es "¿Cómo optimizo el modelo que tengo?"** - -Y la respuesta es: con datos, con IA, con la herramienta correcta. - `, - author: 'Equipo Panadería IA', + titleKey: 'posts.central_vs_local.title', + excerptKey: 'posts.central_vs_local.excerpt', + authorKey: 'posts.central_vs_local.author', date: '2025-01-20', - readTime: '15 min', - category: 'Estrategia', - tags: ['modelos de negocio', 'obrador central', 'producción local', 'escalabilidad'], + readTime: '15', + categoryKey: 'categories.strategy', + tagsKeys: [ + 'posts.central_vs_local.tags.business_models', + 'posts.central_vs_local.tags.central_bakery', + 'posts.central_vs_local.tags.local_production', + 'posts.central_vs_local.tags.scalability', + ], }, { id: '5', slug: 'gdpr-proteccion-datos-panaderia', - title: 'GDPR y Protección de Datos en Panaderías: Lo Que Debes Saber', - excerpt: 'El RGPD afecta a todas las empresas en España, incluidas panaderías. Guía práctica para cumplir con la ley sin complicaciones.', - content: ` -# GDPR y Protección de Datos en Panaderías - -Si usas software para gestionar tu panadería, necesitas conocer el RGPD (GDPR en inglés). - -## ¿Qué Datos Maneja tu Panadería? - -**Datos de clientes:** -- Nombre y contacto (programas de fidelidad) -- Historial de compras -- Preferencias alimentarias (alergias, veganos) -- Datos de pago (tarjetas) - -**Datos de empleados:** -- Información personal -- Horarios y turnos -- Nóminas -- Evaluaciones de desempeño - -**Datos operativos:** -- Proveedores y contactos -- Recetas y fórmulas -- Ventas e inventario -- Analíticas de negocio - -## Obligaciones Legales (RGPD) - -### 1. Consentimiento Explícito -Los clientes deben **aceptar activamente** que uses sus datos: -- ❌ Casilla pre-marcada -- ✅ Casilla que deben marcar ellos -- ✅ Explicación clara del uso - -### 2. Derecho al Olvido -Clientes pueden solicitar: -- Ver sus datos (portabilidad) -- Corregir datos incorrectos -- Eliminar completamente sus datos - -**Debes responder en 30 días.** - -### 3. Seguridad de Datos -Obligaciones: -- Cifrado de datos sensibles -- Acceso restringido (contraseñas) -- Backups regulares -- Procedimientos ante brechas - -### 4. Transferencia de Datos -Si usas software en la nube: -- Servidores deben estar en UE -- O con acuerdos GDPR válidos -- Nunca en países sin protección adecuada - -## Multas por Incumplimiento - -Las multas RGPD pueden ser: -- Hasta **€20 millones** -- O **4% de facturación anual** -- **Lo que sea mayor** - -Aunque para pequeñas empresas raramente llegan a estas cantidades, las multas reales rondan **€5,000 - €50,000**. - -## Cómo Elegir Software Seguro - -### ✅ Checklist GDPR -- [ ] Servidores en España/UE -- [ ] Cifrado AES-256 o superior -- [ ] Certificación ISO 27001 -- [ ] Auditorías de seguridad regulares -- [ ] Política de privacidad clara -- [ ] Soporte en español -- [ ] Contrato de procesador de datos - -### ❌ Señales de Alerta -- ⚠️ Servidores en EEUU/Asia sin acuerdos -- ⚠️ No menciona GDPR/RGPD -- ⚠️ "Compartimos datos con partners" -- ⚠️ Sin certificaciones de seguridad - -## Caso: Panadería IA - -Nuestro compromiso GDPR: -- ✅ **100% servidores en España** -- ✅ **Cifrado AES-256** -- ✅ **Auditorías trimestrales** -- ✅ **Cumplimiento RGPD garantizado** -- ✅ **Tus datos NUNCA se comparten** -- ✅ **Tú controlas TODO** - -## Pasos Prácticos - -### Hoy -1. Revisa qué datos personales guardas -2. Verifica dónde están almacenados -3. Lee términos de tu software actual - -### Esta Semana -1. Actualiza política de privacidad -2. Obtén consentimientos explícitos -3. Implementa backups regulares - -### Este Mes -1. Capacita equipo en protección de datos -2. Documenta procedimientos de seguridad -3. Considera cambiar a software GDPR-compliant - -## Conclusión - -El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas correctas. - -**Tu prioridad:** software que tome el GDPR en serio, para que tú puedas enfocarte en hacer pan. - `, - author: 'María López (Abogada Digital)', + titleKey: 'posts.gdpr.title', + excerptKey: 'posts.gdpr.excerpt', + authorKey: 'posts.gdpr.author', date: '2025-01-01', - readTime: '9 min', - category: 'Legal', - tags: ['GDPR', 'RGPD', 'privacidad', 'legal', 'seguridad'], + readTime: '9', + categoryKey: 'categories.legal', + tagsKeys: [ + 'posts.gdpr.tags.gdpr', + 'posts.gdpr.tags.rgpd', + 'posts.gdpr.tags.privacy', + 'posts.gdpr.tags.legal', + 'posts.gdpr.tags.security', + ], }, ]; @@ -640,13 +121,13 @@ El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas corr
- Blog de Gestión para Panaderías + {t('blog:hero.badge')}

- Aprende a Optimizar tu Panadería + {t('blog:hero.title')}

- Artículos sobre gestión, IA, reducción de desperdicios y crecimiento sostenible para panaderías. + {t('blog:hero.description')}

@@ -665,36 +146,42 @@ El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas corr
- {post.category} + {t(`blog:${post.categoryKey}`)}
- {new Date(post.date).toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' })} + + {new Date(post.date).toLocaleDateString(i18n.language, { + year: 'numeric', + month: 'long', + day: 'numeric', + })} +
- {post.readTime} + {t('blog:post.read_time', { time: post.readTime })}

- {post.title} + {t(`blog:${post.titleKey}`)}

- {post.excerpt} + {t(`blog:${post.excerptKey}`)}

{/* Tags */}
- {post.tags.slice(0, 3).map((tag) => ( + {post.tagsKeys.slice(0, 3).map((tagKey) => ( - #{tag} + #{t(`blog:${tagKey}`)} ))}
@@ -704,7 +191,7 @@ El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas corr to={`/blog/${post.slug}`} className="inline-flex items-center gap-2 text-[var(--color-primary)] font-medium hover:gap-3 transition-all" > - Leer artículo completo + {t('blog:post.read_more')}
@@ -713,10 +200,12 @@ El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas corr
- {post.author.charAt(0)} + {t(`blog:${post.authorKey}`).charAt(0)}
-
{post.author}
+
+ {t(`blog:${post.authorKey}`)} +
@@ -730,16 +219,16 @@ El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas corr

- ¿Listo para Optimizar tu Panadería? + {t('blog:cta.title')}

- Únete al programa piloto y obtén 3 meses gratis + 20% descuento de por vida + {t('blog:cta.description')}

- Solicitar Plaza en el Piloto + {t('blog:cta.button')}
diff --git a/services/demo_session/app/core/config.py b/services/demo_session/app/core/config.py index 97cc4505..e99c1b6a 100644 --- a/services/demo_session/app/core/config.py +++ b/services/demo_session/app/core/config.py @@ -56,6 +56,7 @@ class Settings(BaseSettings): ORDERS_SERVICE_URL: str = os.getenv("ORDERS_SERVICE_URL", "http://orders-service:8000") PRODUCTION_SERVICE_URL: str = os.getenv("PRODUCTION_SERVICE_URL", "http://production-service:8000") SUPPLIERS_SERVICE_URL: str = os.getenv("SUPPLIERS_SERVICE_URL", "http://suppliers-service:8000") + ORCHESTRATOR_SERVICE_URL: str = os.getenv("ORCHESTRATOR_SERVICE_URL", "http://orchestrator-service:8000") # Logging LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") diff --git a/services/demo_session/app/services/clone_orchestrator.py b/services/demo_session/app/services/clone_orchestrator.py index dd05ad3e..7b365b6d 100644 --- a/services/demo_session/app/services/clone_orchestrator.py +++ b/services/demo_session/app/services/clone_orchestrator.py @@ -95,6 +95,12 @@ class CloneOrchestrator: required=False, # Optional - provides procurement and purchase orders timeout=25.0 # Longer - clones many procurement entities ), + ServiceDefinition( + name="orchestrator", + url=os.getenv("ORCHESTRATOR_SERVICE_URL", "http://orchestrator-service:8000"), + required=False, # Optional - provides orchestration run history + timeout=15.0 # Standard timeout for orchestration data + ), ] async def clone_all_services( diff --git a/services/inventory/scripts/demo/seed_demo_stock.py b/services/inventory/scripts/demo/seed_demo_stock.py index 3bd82127..bd5d2082 100644 --- a/services/inventory/scripts/demo/seed_demo_stock.py +++ b/services/inventory/scripts/demo/seed_demo_stock.py @@ -54,6 +54,74 @@ DEMO_TENANT_LA_ESPIGA = uuid.UUID("b2c3d4e5-f6a7-48b9-c0d1-e2f3a4b5c6d7") # Base reference date for demo data (all relative dates calculated from this) BASE_REFERENCE_DATE = datetime(2025, 1, 15, 12, 0, 0, tzinfo=timezone.utc) +# Daily consumption rates (kg/day) - aligned with procurement seed script +# Used to create realistic stock levels that trigger appropriate PO scenarios +DAILY_CONSUMPTION_RATES = { + "HAR-T55-001": 50.0, # Harina de Trigo T55 + "HAR-INT-001": 15.0, # Harina Integral Ecológica + "MAN-SAL-001": 8.0, # Mantequilla sin Sal 82% MG + "HUE-FRE-001": 100.0, # Huevos Frescos (units, modeled as kg) + "LEV-SEC-001": 2.5, # Levadura Seca + "SAL-FIN-001": 3.0, # Sal Fina + "ACE-OLI-001": 5.0, # Aceite de Oliva Virgen + "AZU-MOR-001": 6.0, # Azúcar Moreno + "SEM-GIR-001": 2.0, # Semillas de Girasol + "MIE-AZA-001": 1.5, # Miel de Azahar + "CHO-NEG-001": 4.0, # Chocolate Negro 70% + "NUE-PEL-001": 3.5, # Nueces Peladas + "PAS-SUL-001": 2.5 # Pasas Sultanas +} + +# Reorder points (kg) - when to trigger PO +REORDER_POINTS_BY_SKU = { + "HAR-T55-001": 150.0, # Critical ingredient + "HAR-INT-001": 50.0, + "MAN-SAL-001": 25.0, + "HUE-FRE-001": 300.0, + "LEV-SEC-001": 10.0, + "SAL-FIN-001": 20.0, + "ACE-OLI-001": 15.0, + "AZU-MOR-001": 20.0, + "SEM-GIR-001": 10.0, + "MIE-AZA-001": 5.0, + "CHO-NEG-001": 15.0, + "NUE-PEL-001": 12.0, + "PAS-SUL-001": 10.0 +} + +def calculate_realistic_stock_level( + ingredient_sku: str, + make_critical: bool = False, + variability_factor: float = 0.2 +) -> float: + """ + Calculate realistic stock level based on consumption rates + + Args: + ingredient_sku: SKU of the ingredient + make_critical: If True, create critically low stock (< 1 day supply) + variability_factor: Random variation (default 20%) + + Returns: + Realistic stock level in kg + """ + daily_consumption = DAILY_CONSUMPTION_RATES.get(ingredient_sku, 5.0) + + if make_critical: + # Critical: 0.5-6 hours worth of stock + days_of_supply = random.uniform(0.02, 0.25) + else: + # Normal: 5-15 days worth of stock (healthy inventory levels) + # This prevents all ingredients from triggering alerts + days_of_supply = random.uniform(5.0, 15.0) + + stock_level = daily_consumption * days_of_supply + + # Add realistic variability + stock_level *= random.uniform(1 - variability_factor, 1 + variability_factor) + + return max(0.1, stock_level) # Minimum 0.1 kg + # Load configuration from JSON def load_stock_config(): """Load stock configuration from JSON file""" @@ -126,13 +194,25 @@ async def create_stock_batches_for_ingredient( stocks = [] num_batches = random.randint(1, 2) # Reduced from 3-5 for faster demo loading - # Calculate target total stock for this ingredient - # Use 40-80% of max_stock_level to allow for realistic variation - # If max_stock_level is not set, use reorder_point * 3 as a reasonable target - if ingredient.max_stock_level: - target_total_stock = float(ingredient.max_stock_level) * random.uniform(0.4, 0.8) + # CRITICAL DEMO SCENARIO: Create consumption-aware stock levels + # This creates realistic scenarios that trigger intelligent PO reasoning + critical_low_stock_skus = ["HAR-T55-001", "LEV-SEC-001", "MAN-SAL-001"] + is_critical_low = ingredient.sku in critical_low_stock_skus + + # Calculate target total stock using consumption-aware logic + if is_critical_low: + # Critical low: < 1 day supply (triggers urgent/critical PO reasoning) + target_total_stock = calculate_realistic_stock_level( + ingredient.sku, + make_critical=True + ) + num_batches = 1 # Single nearly-empty batch for critical items else: - target_total_stock = float(ingredient.reorder_point or 50.0) * 3.0 + # Normal low stock: 1-4 days supply (creates urgency but not critical) + target_total_stock = calculate_realistic_stock_level( + ingredient.sku, + make_critical=False + ) # Distribute total stock across batches batch_quantities = [] diff --git a/services/orchestrator/app/api/dashboard.py b/services/orchestrator/app/api/dashboard.py index 30723179..ef4feed5 100644 --- a/services/orchestrator/app/api/dashboard.py +++ b/services/orchestrator/app/api/dashboard.py @@ -325,6 +325,9 @@ async def get_orchestration_summary( try: po_data = await procurement_client.get_pending_purchase_orders(tenant_id, limit=10) if po_data and isinstance(po_data, list): + # Override stale orchestration count with actual real-time PO count + summary["purchaseOrdersCreated"] = len(po_data) + summary["userActionsRequired"] = len(po_data) # Update actions required to match actual pending POs summary["purchaseOrdersSummary"] = [ PurchaseOrderSummary( supplierName=po.get("supplier_name", "Unknown"), @@ -341,6 +344,8 @@ async def get_orchestration_summary( batch_data = await production_client.get_todays_batches(tenant_id) if batch_data: batches = batch_data.get("batches", []) + # Override stale orchestration count with actual real-time batch count + summary["productionBatchesCreated"] = len(batches) summary["productionBatchesSummary"] = [ ProductionBatchSummary( productName=batch.get("product_name", "Unknown"), diff --git a/services/orchestrator/app/api/internal_demo.py b/services/orchestrator/app/api/internal_demo.py new file mode 100644 index 00000000..9e3684e5 --- /dev/null +++ b/services/orchestrator/app/api/internal_demo.py @@ -0,0 +1,264 @@ +""" +Internal Demo API Endpoints for Orchestrator Service +Used by demo_session service to clone data for virtual demo tenants +""" + +from fastapi import APIRouter, Depends, HTTPException, Header +from typing import Dict, Any +from uuid import UUID +import structlog +import os + +from app.core.database import get_db +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy import select, delete, func +from app.models.orchestration_run import OrchestrationRun +import uuid +from datetime import datetime, timezone, timedelta +from typing import Optional + +router = APIRouter() +logger = structlog.get_logger() + +# Internal API key for service-to-service communication +INTERNAL_API_KEY = os.getenv("INTERNAL_API_KEY", "dev-internal-key-change-in-production") + + +def verify_internal_api_key(x_internal_api_key: str = Header(...)): + """Verify internal API key for service-to-service communication""" + if x_internal_api_key != INTERNAL_API_KEY: + raise HTTPException(status_code=403, detail="Invalid internal API key") + return True + + +@router.post("/internal/demo/clone") +async def clone_demo_data( + base_tenant_id: str, + virtual_tenant_id: str, + demo_account_type: str, + session_id: Optional[str] = None, + session_created_at: Optional[str] = None, + db: AsyncSession = Depends(get_db), + _: bool = Depends(verify_internal_api_key) +): + """ + Clone orchestration run demo data from base tenant to virtual tenant + + This endpoint is called by the demo_session service during session initialization. + It clones orchestration runs with date adjustments to make them appear recent. + """ + + start_time = datetime.now(timezone.utc) + + # Parse session_created_at or use current time + if session_created_at: + try: + reference_time = datetime.fromisoformat(session_created_at.replace('Z', '+00:00')) + except: + reference_time = datetime.now(timezone.utc) + else: + reference_time = datetime.now(timezone.utc) + + logger.info( + "Starting orchestration runs cloning with date adjustment", + base_tenant_id=base_tenant_id, + virtual_tenant_id=virtual_tenant_id, + demo_account_type=demo_account_type, + session_id=session_id, + reference_time=reference_time.isoformat() + ) + + try: + base_uuid = uuid.UUID(base_tenant_id) + virtual_uuid = uuid.UUID(virtual_tenant_id) + + # Fetch base tenant orchestration runs + # Get all completed and partial_success runs from the base tenant + result = await db.execute( + select(OrchestrationRun) + .where(OrchestrationRun.tenant_id == base_uuid) + .order_by(OrchestrationRun.started_at.desc()) + .limit(10) # Clone last 10 runs for demo + ) + base_runs = list(result.scalars().all()) + + runs_cloned = 0 + + # Clone each orchestration run with date adjustment + for base_run in base_runs: + # Calculate time offset: how old was this run relative to when it was created + # We'll adjust all timestamps to be relative to the session creation time + if base_run.started_at: + # Calculate how many days ago this run was from a reference point + # Use a fixed reference date for consistency + reference_date = datetime(2025, 1, 15, 12, 0, 0, tzinfo=timezone.utc) + time_offset = base_run.started_at - reference_date + + # Apply this offset to the current reference time + new_started_at = reference_time + time_offset + else: + new_started_at = reference_time - timedelta(hours=2) + + # Adjust completed_at if it exists + if base_run.completed_at and base_run.started_at: + duration = base_run.completed_at - base_run.started_at + new_completed_at = new_started_at + duration + else: + new_completed_at = None + + # Adjust all step timestamps proportionally + def adjust_timestamp(original_timestamp): + if not original_timestamp or not base_run.started_at: + return None + step_offset = original_timestamp - base_run.started_at + return new_started_at + step_offset + + # Create new orchestration run for virtual tenant + new_run = OrchestrationRun( + id=uuid.uuid4(), + tenant_id=virtual_uuid, + run_number=f"{base_run.run_number}-DEMO", + status=base_run.status, + run_type=base_run.run_type, + priority=base_run.priority, + started_at=new_started_at, + completed_at=new_completed_at, + duration_seconds=base_run.duration_seconds, + + # Forecasting step + forecasting_started_at=adjust_timestamp(base_run.forecasting_started_at), + forecasting_completed_at=adjust_timestamp(base_run.forecasting_completed_at), + forecasting_status=base_run.forecasting_status, + forecasting_error=base_run.forecasting_error, + + # Production step + production_started_at=adjust_timestamp(base_run.production_started_at), + production_completed_at=adjust_timestamp(base_run.production_completed_at), + production_status=base_run.production_status, + production_error=base_run.production_error, + + # Procurement step + procurement_started_at=adjust_timestamp(base_run.procurement_started_at), + procurement_completed_at=adjust_timestamp(base_run.procurement_completed_at), + procurement_status=base_run.procurement_status, + procurement_error=base_run.procurement_error, + + # Notification step + notification_started_at=adjust_timestamp(base_run.notification_started_at), + notification_completed_at=adjust_timestamp(base_run.notification_completed_at), + notification_status=base_run.notification_status, + notification_error=base_run.notification_error, + + # AI Insights (if exists) + ai_insights_started_at=adjust_timestamp(base_run.ai_insights_started_at) if hasattr(base_run, 'ai_insights_started_at') else None, + ai_insights_completed_at=adjust_timestamp(base_run.ai_insights_completed_at) if hasattr(base_run, 'ai_insights_completed_at') else None, + ai_insights_status=base_run.ai_insights_status if hasattr(base_run, 'ai_insights_status') else None, + ai_insights_generated=base_run.ai_insights_generated if hasattr(base_run, 'ai_insights_generated') else None, + ai_insights_posted=base_run.ai_insights_posted if hasattr(base_run, 'ai_insights_posted') else None, + + # Results summary + forecasts_generated=base_run.forecasts_generated, + production_batches_created=base_run.production_batches_created, + procurement_plans_created=base_run.procurement_plans_created, + purchase_orders_created=base_run.purchase_orders_created, + notifications_sent=base_run.notifications_sent, + + # Performance metrics + fulfillment_rate=base_run.fulfillment_rate, + on_time_delivery_rate=base_run.on_time_delivery_rate, + cost_accuracy=base_run.cost_accuracy, + quality_score=base_run.quality_score, + + # Data + forecast_data=base_run.forecast_data, + run_metadata=base_run.run_metadata, + + # Metadata + triggered_by=base_run.triggered_by, + created_at=reference_time, + updated_at=reference_time + ) + + db.add(new_run) + await db.flush() + runs_cloned += 1 + + await db.commit() + + duration_ms = int((datetime.now(timezone.utc) - start_time).total_seconds() * 1000) + + logger.info( + "Orchestration runs cloned successfully", + virtual_tenant_id=str(virtual_tenant_id), + runs_cloned=runs_cloned, + duration_ms=duration_ms + ) + + return { + "service": "orchestrator", + "status": "completed", + "success": True, + "records_cloned": runs_cloned, + "runs_cloned": runs_cloned, + "duration_ms": duration_ms + } + + except Exception as e: + logger.error("Failed to clone orchestration runs", error=str(e), exc_info=True) + await db.rollback() + raise HTTPException(status_code=500, detail=f"Failed to clone orchestration runs: {str(e)}") + + +@router.delete("/internal/demo/tenant/{virtual_tenant_id}") +async def delete_demo_data( + virtual_tenant_id: str, + db: AsyncSession = Depends(get_db), + _: bool = Depends(verify_internal_api_key) +): + """Delete all orchestration runs for a virtual demo tenant""" + logger.info("Deleting orchestration runs for virtual tenant", virtual_tenant_id=virtual_tenant_id) + start_time = datetime.now(timezone.utc) + + try: + virtual_uuid = uuid.UUID(virtual_tenant_id) + + # Count records + run_count = await db.scalar( + select(func.count(OrchestrationRun.id)) + .where(OrchestrationRun.tenant_id == virtual_uuid) + ) + + # Delete orchestration runs + await db.execute( + delete(OrchestrationRun) + .where(OrchestrationRun.tenant_id == virtual_uuid) + ) + await db.commit() + + duration_ms = int((datetime.now(timezone.utc) - start_time).total_seconds() * 1000) + logger.info( + "Orchestration runs deleted successfully", + virtual_tenant_id=virtual_tenant_id, + duration_ms=duration_ms + ) + + return { + "service": "orchestrator", + "status": "deleted", + "virtual_tenant_id": virtual_tenant_id, + "records_deleted": { + "orchestration_runs": run_count, + "total": run_count + }, + "duration_ms": duration_ms + } + except Exception as e: + logger.error("Failed to delete orchestration runs", error=str(e), exc_info=True) + await db.rollback() + raise HTTPException(status_code=500, detail=str(e)) + + +@router.get("/internal/demo/clone/health") +async def health_check(_: bool = Depends(verify_internal_api_key)): + """Health check for demo cloning endpoint""" + return {"status": "healthy", "service": "orchestrator"} diff --git a/services/orchestrator/app/main.py b/services/orchestrator/app/main.py index 23982547..b28975a0 100644 --- a/services/orchestrator/app/main.py +++ b/services/orchestrator/app/main.py @@ -99,8 +99,8 @@ service.add_router(orchestration_router) service.add_router(dashboard_router) # INTERNAL: Service-to-service endpoints -# from app.api import internal_demo -# service.add_router(internal_demo.router) +from app.api import internal_demo +service.add_router(internal_demo.router) @app.middleware("http") diff --git a/services/orchestrator/app/services/dashboard_service.py b/services/orchestrator/app/services/dashboard_service.py index f65a7e81..73d2ef9c 100644 --- a/services/orchestrator/app/services/dashboard_service.py +++ b/services/orchestrator/app/services/dashboard_service.py @@ -417,14 +417,38 @@ class DashboardService: # Get reasoning type and convert to i18n key reasoning_type = reasoning_data.get('type', 'inventory_replenishment') - reasoning_type_i18n_key = self._get_reasoning_type_i18n_key(reasoning_type, context="purchaseOrder") + + # Check if enhanced mode (has product_details with supply chain intelligence) + is_enhanced_mode = reasoning_data.get('metadata', {}).get('enhanced_mode', False) + + # Use enhanced i18n key if available + if is_enhanced_mode and reasoning_type == 'low_stock_detection': + reasoning_type_i18n_key = "reasoning.purchaseOrder.low_stock_detection_detailed" + else: + reasoning_type_i18n_key = self._get_reasoning_type_i18n_key(reasoning_type, context="purchaseOrder") # Preprocess parameters for i18n - MUST create a copy to avoid modifying immutable database objects params = dict(reasoning_data.get('parameters', {})) + # Convert product_names array to product_names_joined string if 'product_names' in params and isinstance(params['product_names'], list): params['product_names_joined'] = ', '.join(params['product_names']) + # Convert critical_products array to indexed params and joined string for i18n + if 'critical_products' in params and isinstance(params['critical_products'], list): + critical_prods = params['critical_products'] + # Add indexed params for select/plural statements + for i, prod in enumerate(critical_prods[:3]): # Limit to first 3 + params[f'critical_products_{i}'] = prod + params['critical_products_joined'] = ', '.join(critical_prods) + + # Convert affected_batches array to indexed params for i18n + if 'affected_batches' in params and isinstance(params['affected_batches'], list): + batches = params['affected_batches'] + for i, batch in enumerate(batches[:3]): # Limit to first 3 + params[f'affected_batches_{i}'] = batch + params['affected_batches_joined'] = ', '.join(batches) + actions.append({ "id": po["id"], "type": ActionType.APPROVE_PO, @@ -594,7 +618,8 @@ class DashboardService: if actual_start and planned_end: total_duration = (planned_end - actual_start).total_seconds() elapsed = (now - actual_start).total_seconds() - progress = min(int((elapsed / total_duration) * 100), 99) + # Ensure progress is never negative (defensive programming) + progress = max(0, min(int((elapsed / total_duration) * 100), 99)) else: progress = 50 status_icon = "🔄" @@ -604,10 +629,12 @@ class DashboardService: "params": {} } else: + # PENDING, SCHEDULED, or any other status + progress = 0 status_icon = "⏰" - status_text = "PENDING" + status_text = status # Use actual status status_i18n = { - "key": "production.status.pending", + "key": f"production.status.{status.lower()}", "params": {} } diff --git a/services/procurement/app/api/internal_demo.py b/services/procurement/app/api/internal_demo.py index 5296b183..76482501 100644 --- a/services/procurement/app/api/internal_demo.py +++ b/services/procurement/app/api/internal_demo.py @@ -301,6 +301,7 @@ async def clone_demo_data( notes=order.notes if hasattr(order, 'notes') else None, internal_notes=order.internal_notes if hasattr(order, 'internal_notes') else None, terms_and_conditions=order.terms_and_conditions if hasattr(order, 'terms_and_conditions') else None, + reasoning_data=order.reasoning_data if hasattr(order, 'reasoning_data') else None, # Clone reasoning for JTBD dashboard created_at=session_time, updated_at=session_time, created_by=system_user_id, diff --git a/services/procurement/scripts/demo/seed_demo_purchase_orders.py b/services/procurement/scripts/demo/seed_demo_purchase_orders.py index bfa4ec42..1394f708 100644 --- a/services/procurement/scripts/demo/seed_demo_purchase_orders.py +++ b/services/procurement/scripts/demo/seed_demo_purchase_orders.py @@ -21,6 +21,7 @@ import random from datetime import datetime, timezone, timedelta, date from pathlib import Path from decimal import Decimal +from typing import List, Dict, Any # Add app to path sys.path.insert(0, str(Path(__file__).parent.parent.parent)) @@ -60,6 +61,48 @@ BASE_SUPPLIER_IDS = [ uuid.UUID("40000000-0000-0000-0000-000000000005"), # Lesaffre Ibérica (low trust) ] +# Supplier lead times (days) for realistic supply chain modeling +SUPPLIER_LEAD_TIMES = { + "Molinos San José S.L.": 2, # 2-day delivery (trusted, local) + "Lácteos del Valle S.A.": 3, # 3-day delivery (regional) + "Lesaffre Ibérica": 4 # 4-day delivery (national) +} + +# Daily consumption rates (kg/day) for realistic stock depletion modeling +# These match real bakery production needs +DAILY_CONSUMPTION_RATES = { + "Harina de Trigo T55": 50.0, + "Harina Integral Ecológica": 15.0, + "Mantequilla sin Sal 82% MG": 8.0, + "Huevos Frescos Categoría A": 100.0, # units, not kg, but modeled as kg for consistency + "Levadura Seca": 2.5, + "Sal Fina": 3.0, + "Aceite de Oliva Virgen": 5.0, + "Azúcar Moreno": 6.0, + "Semillas de Girasol": 2.0, + "Miel de Azahar": 1.5, + "Chocolate Negro 70%": 4.0, + "Nueces Peladas": 3.5, + "Pasas Sultanas": 2.5 +} + +# Reorder points (kg) - when to trigger PO +REORDER_POINTS = { + "Harina de Trigo T55": 150.0, # Critical ingredient + "Harina Integral Ecológica": 50.0, + "Mantequilla sin Sal 82% MG": 25.0, + "Huevos Frescos Categoría A": 300.0, + "Levadura Seca": 10.0, + "Sal Fina": 20.0, + "Aceite de Oliva Virgen": 15.0, + "Azúcar Moreno": 20.0, + "Semillas de Girasol": 10.0, + "Miel de Azahar": 5.0, + "Chocolate Negro 70%": 15.0, + "Nueces Peladas": 12.0, + "Pasas Sultanas": 10.0 +} + def get_demo_supplier_ids(tenant_id: uuid.UUID): """ Generate tenant-specific supplier IDs using XOR strategy with hardcoded base IDs. @@ -96,6 +139,106 @@ def get_demo_supplier_ids(tenant_id: uuid.UUID): return suppliers +def get_simulated_stock_level(product_name: str, make_critical: bool = False) -> float: + """ + Simulate current stock level for demo purposes + + Args: + product_name: Name of the product + make_critical: If True, create critically low stock (< 1 day) + + Returns: + Simulated current stock in kg + """ + daily_consumption = DAILY_CONSUMPTION_RATES.get(product_name, 5.0) + + if make_critical: + # Critical: 0.5-6 hours worth of stock + return round(daily_consumption * random.uniform(0.02, 0.25), 2) + else: + # Normal low stock: 1-3 days worth + return round(daily_consumption * random.uniform(1.0, 3.0), 2) + + +def calculate_product_urgency( + product_name: str, + current_stock: float, + supplier_lead_time_days: int, + reorder_point: float = None +) -> Dict[str, Any]: + """ + Calculate urgency metrics for a product based on supply chain dynamics + + Args: + product_name: Name of the product + current_stock: Current stock level in kg + supplier_lead_time_days: Supplier delivery lead time in days + reorder_point: Reorder point threshold (optional) + + Returns: + Dictionary with urgency metrics + """ + daily_consumption = DAILY_CONSUMPTION_RATES.get(product_name, 5.0) + reorder_pt = reorder_point or REORDER_POINTS.get(product_name, 50.0) + + # Calculate days until depletion + if daily_consumption > 0: + days_until_depletion = current_stock / daily_consumption + else: + days_until_depletion = 999.0 + + # Calculate safety margin (days until depletion - supplier lead time) + safety_margin_days = days_until_depletion - supplier_lead_time_days + + # Determine criticality based on safety margin + if safety_margin_days <= 0: + criticality = "critical" # Already late or will run out before delivery! + order_urgency_reason = f"Stock depletes in {round(days_until_depletion, 1)} days, but delivery takes {supplier_lead_time_days} days" + elif safety_margin_days <= 0.5: + criticality = "urgent" # Must order TODAY + order_urgency_reason = f"Only {round(safety_margin_days * 24, 1)} hours margin before stockout" + elif safety_margin_days <= 1: + criticality = "important" # Should order today + order_urgency_reason = f"Only {round(safety_margin_days, 1)} day margin" + else: + criticality = "normal" + order_urgency_reason = "Standard replenishment" + + return { + "product_name": product_name, + "current_stock_kg": round(current_stock, 2), + "daily_consumption_kg": round(daily_consumption, 2), + "days_until_depletion": round(days_until_depletion, 2), + "reorder_point_kg": round(reorder_pt, 2), + "safety_stock_days": 3, # Standard 3-day safety stock + "safety_margin_days": round(safety_margin_days, 2), + "criticality": criticality, + "urgency_reason": order_urgency_reason + } + + +def determine_overall_po_urgency(product_details: List[Dict[str, Any]]) -> str: + """ + Determine overall PO urgency based on most critical product + + Args: + product_details: List of product urgency dictionaries + + Returns: + Overall urgency: "critical", "urgent", "important", or "normal" + """ + criticalities = [p.get("criticality", "normal") for p in product_details] + + if "critical" in criticalities: + return "critical" + elif "urgent" in criticalities: + return "urgent" + elif "important" in criticalities: + return "important" + else: + return "normal" + + async def create_purchase_order( db: AsyncSession, tenant_id: uuid.UUID, @@ -131,7 +274,7 @@ async def create_purchase_order( # Generate reasoning for JTBD dashboard (if columns exist after migration) days_until_delivery = (required_delivery - created_at).days - # Generate structured reasoning_data for i18n support + # Generate structured reasoning_data with supply chain intelligence reasoning_data = None try: @@ -142,18 +285,57 @@ async def create_purchase_order( if not product_names: product_names = ["Demo Product"] + # Get supplier lead time + supplier_lead_time = SUPPLIER_LEAD_TIMES.get(supplier.name, 3) + if status == PurchaseOrderStatus.pending_approval: - # Low stock detection reasoning - days_until_stockout = days_until_delivery + 2 + # Enhanced low stock detection with per-product urgency analysis + product_details = [] + estimated_loss = 0.0 + + for i, item in enumerate(items_list): + product_name = item.get('name', item.get('product_name', f"Product {i+1}")) + + # Simulate current stock - make first item critical for demo impact + make_critical = (i == 0) and (priority == "urgent") + current_stock = get_simulated_stock_level(product_name, make_critical=make_critical) + + # Calculate product-specific urgency + urgency_info = calculate_product_urgency( + product_name=product_name, + current_stock=current_stock, + supplier_lead_time_days=supplier_lead_time, + reorder_point=item.get('reorder_point') + ) + + product_details.append(urgency_info) + + # Estimate production loss for critical items + if urgency_info["criticality"] in ["critical", "urgent"]: + # Rough estimate: lost production value + estimated_loss += item.get("unit_price", 1.0) * item.get("quantity", 10) * 1.5 + + # Determine overall urgency + overall_urgency = determine_overall_po_urgency(product_details) + + # Find affected production batches (demo: simulate batch names) + affected_batches = [] + critical_products = [p for p in product_details if p["criticality"] in ["critical", "urgent"]] + if critical_products: + # Simulate batch numbers that would be affected + affected_batches = ["BATCH-TODAY-001", "BATCH-TODAY-002"] if overall_urgency == "critical" else \ + ["BATCH-TOMORROW-001"] if overall_urgency == "urgent" else [] + + # Create enhanced reasoning with detailed supply chain intelligence reasoning_data = create_po_reasoning_low_stock( supplier_name=supplier.name, - product_names=product_names, - current_stock=random.uniform(20, 50), # Demo: low stock - required_stock=random.uniform(100, 200), # Demo: needed stock - days_until_stockout=days_until_stockout, - threshold_percentage=20, - affected_products=product_names[:2] if len(product_names) > 1 else product_names, - estimated_lost_orders=random.randint(5, 15) if days_until_stockout <= 3 else None + product_names=product_names, # Legacy compatibility + # Enhanced parameters + product_details=product_details, + supplier_lead_time_days=supplier_lead_time, + order_urgency=overall_urgency, + affected_production_batches=affected_batches, + estimated_production_loss_eur=estimated_loss if estimated_loss > 0 else None ) elif auto_approved: # Supplier contract/auto-approval reasoning @@ -165,6 +347,7 @@ async def create_purchase_order( ) except Exception as e: logger.warning(f"Failed to generate reasoning_data: {e}") + logger.exception(e) pass # Create PO @@ -298,17 +481,17 @@ async def seed_purchase_orders_for_tenant(db: AsyncSession, tenant_id: uuid.UUID ) pos_created.append(po2) - # 3. PENDING_APPROVAL - Large amount (created yesterday) + # 3. PENDING_APPROVAL - URGENT: Critical stock for tomorrow's Croissant production po3 = await create_purchase_order( - db, tenant_id, supplier_medium_trust, + db, tenant_id, supplier_high_trust, PurchaseOrderStatus.pending_approval, - Decimal("250.00"), - created_offset_days=-1, - priority="normal", + Decimal("450.00"), + created_offset_days=0, + priority="urgent", items_data=[ - {"name": "Harina de Fuerza T65", "quantity": 500, "unit_price": 0.95, "uom": "kg"}, - {"name": "Mantequilla Premium", "quantity": 80, "unit_price": 5.20, "uom": "kg"}, - {"name": "Huevos Categoría A", "quantity": 600, "unit_price": 0.22, "uom": "unidad"} + {"name": "Harina de Trigo T55", "quantity": 100, "unit_price": 0.85, "uom": "kg"}, + {"name": "Mantequilla sin Sal 82% MG", "quantity": 30, "unit_price": 6.50, "uom": "kg"}, + {"name": "Huevos Frescos Categoría A", "quantity": 200, "unit_price": 0.25, "uom": "unidad"} ] ) pos_created.append(po3) diff --git a/services/production/scripts/demo/lotes_produccion_es.json b/services/production/scripts/demo/lotes_produccion_es.json index 8dd3ea33..1d2edb4b 100644 --- a/services/production/scripts/demo/lotes_produccion_es.json +++ b/services/production/scripts/demo/lotes_produccion_es.json @@ -593,6 +593,105 @@ "production_notes": "Planificado para mañana", "quality_notes": null, "equipment_used": ["50000000-0000-0000-0000-000000000001"] + }, + { + "id": "40000000-0000-0000-0000-999999999001", + "batch_number": "BATCH-TODAY-001", + "product_id": "20000000-0000-0000-0000-000000000002", + "product_name": "Croissant de Mantequilla Artesanal", + "recipe_id": "30000000-0000-0000-0000-000000000002", + "planned_start_offset_days": 0, + "planned_start_hour": 6, + "planned_start_minute": 0, + "planned_duration_minutes": 240, + "planned_quantity": 120.0, + "actual_quantity": null, + "status": "PENDING", + "priority": "HIGH", + "current_process_stage": null, + "yield_percentage": null, + "quality_score": null, + "waste_quantity": null, + "defect_quantity": null, + "waste_defect_type": null, + "estimated_cost": 280.00, + "actual_cost": null, + "labor_cost": null, + "material_cost": null, + "overhead_cost": null, + "station_id": "STATION-02", + "is_rush_order": false, + "is_special_recipe": false, + "is_ai_assisted": true, + "production_notes": "Lote programado para hoy - Demanda prevista alta", + "quality_notes": null, + "equipment_used": ["50000000-0000-0000-0000-000000000002", "50000000-0000-0000-0000-000000000001"] + }, + { + "id": "40000000-0000-0000-0000-999999999002", + "batch_number": "BATCH-TODAY-002", + "product_id": "20000000-0000-0000-0000-000000000001", + "product_name": "Baguette Francesa Tradicional", + "recipe_id": "30000000-0000-0000-0000-000000000001", + "planned_start_offset_days": 0, + "planned_start_hour": 8, + "planned_start_minute": 30, + "planned_duration_minutes": 165, + "planned_quantity": 100.0, + "actual_quantity": null, + "status": "PENDING", + "priority": "MEDIUM", + "current_process_stage": null, + "yield_percentage": null, + "quality_score": null, + "waste_quantity": null, + "defect_quantity": null, + "waste_defect_type": null, + "estimated_cost": 150.00, + "actual_cost": null, + "labor_cost": null, + "material_cost": null, + "overhead_cost": null, + "station_id": "STATION-01", + "is_rush_order": false, + "is_special_recipe": false, + "is_ai_assisted": true, + "production_notes": "Producción diaria programada", + "quality_notes": null, + "equipment_used": ["50000000-0000-0000-0000-000000000001"] + }, + { + "id": "40000000-0000-0000-0000-999999999003", + "batch_number": "BATCH-TODAY-003", + "product_id": "20000000-0000-0000-0000-000000000003", + "product_name": "Pan de Pueblo con Masa Madre", + "recipe_id": "30000000-0000-0000-0000-000000000003", + "planned_start_offset_days": 0, + "planned_start_hour": 10, + "planned_start_minute": 0, + "planned_duration_minutes": 300, + "planned_quantity": 60.0, + "actual_quantity": null, + "status": "PENDING", + "priority": "MEDIUM", + "current_process_stage": null, + "yield_percentage": null, + "quality_score": null, + "waste_quantity": null, + "defect_quantity": null, + "waste_defect_type": null, + "estimated_cost": 180.00, + "actual_cost": null, + "labor_cost": null, + "material_cost": null, + "overhead_cost": null, + "station_id": "STATION-01", + "is_rush_order": false, + "is_special_recipe": true, + "is_ai_assisted": true, + "production_notes": "Masa madre preparada ayer - Listo para horneado", + "quality_notes": null, + "equipment_used": ["50000000-0000-0000-0000-000000000001"] } ] } diff --git a/services/production/scripts/demo/seed_demo_batches.py b/services/production/scripts/demo/seed_demo_batches.py index 4b427808..372b2fae 100755 --- a/services/production/scripts/demo/seed_demo_batches.py +++ b/services/production/scripts/demo/seed_demo_batches.py @@ -37,6 +37,8 @@ DEMO_TENANT_SAN_PABLO = uuid.UUID("a1b2c3d4-e5f6-47a8-b9c0-d1e2f3a4b5c6") # Ind DEMO_TENANT_LA_ESPIGA = uuid.UUID("b2c3d4e5-f6a7-48b9-c0d1-e2f3a4b5c6d7") # Central bakery # Base reference date for date calculations +# MUST match shared/utils/demo_dates.py for proper demo session cloning +# This fixed date allows demo sessions to adjust all dates relative to session creation time BASE_REFERENCE_DATE = datetime(2025, 1, 15, 12, 0, 0, tzinfo=timezone.utc) @@ -140,7 +142,19 @@ async def seed_batches_for_tenant( actual_end = actual_start + timedelta(minutes=actual_duration) completed_at = actual_end elif batch_data["status"] == "IN_PROGRESS": - actual_start = planned_start + # For IN_PROGRESS batches, set actual_start to a recent time to ensure valid progress calculation + # If planned_start is in the past, use it; otherwise, set to 30 minutes ago + now = datetime.now(timezone.utc) + if planned_start < now: + # If planned start was in the past, use a time that ensures batch is ~30% complete + elapsed_time_minutes = min( + int(batch_data["planned_duration_minutes"] * 0.3), + int((now - planned_start).total_seconds() / 60) + ) + actual_start = now - timedelta(minutes=elapsed_time_minutes) + else: + # If planned_start is in the future, start batch 30 minutes ago + actual_start = now - timedelta(minutes=30) actual_duration = None actual_end = None diff --git a/shared/clients/production_client.py b/shared/clients/production_client.py index 05748579..b39d3d2e 100644 --- a/shared/clients/production_client.py +++ b/shared/clients/production_client.py @@ -456,6 +456,9 @@ class ProductionServiceClient(BaseServiceClient): """ Get today's production batches for dashboard timeline + For demo compatibility: Queries all recent batches and filters for actionable ones + scheduled for today, since demo session dates are adjusted relative to session creation time. + Args: tenant_id: Tenant ID @@ -463,13 +466,67 @@ class ProductionServiceClient(BaseServiceClient): Dict with ProductionBatchListResponse: {"batches": [...], "total_count": n, "page": 1, "page_size": n} """ try: - from datetime import date - today = date.today() - return await self.get( + from datetime import datetime, timezone, timedelta + + # Get today's date range (start of day to end of day in UTC) + now = datetime.now(timezone.utc) + today_start = now.replace(hour=0, minute=0, second=0, microsecond=0) + today_end = today_start + timedelta(days=1) + + # Query all batches without date/status filter for demo compatibility + # The dashboard will filter for PENDING, IN_PROGRESS, or SCHEDULED + result = await self.get( "/production/batches", tenant_id=tenant_id, - params={"start_date": today.isoformat(), "end_date": today.isoformat(), "page_size": 100} + params={"page_size": 100} ) + + if result and "batches" in result: + # Filter for actionable batches scheduled for TODAY + actionable_statuses = {"PENDING", "IN_PROGRESS", "SCHEDULED"} + filtered_batches = [] + + for batch in result["batches"]: + # Check if batch is actionable + if batch.get("status") not in actionable_statuses: + continue + + # Check if batch is scheduled for today + # Include batches that START today OR END today (for overnight batches) + planned_start = batch.get("planned_start_time") + planned_end = batch.get("planned_end_time") + + include_batch = False + + if planned_start: + # Parse the start date string + if isinstance(planned_start, str): + planned_start = datetime.fromisoformat(planned_start.replace('Z', '+00:00')) + + # Include if batch starts today + if today_start <= planned_start < today_end: + include_batch = True + + # Also check if batch ends today (for overnight batches) + if not include_batch and planned_end: + if isinstance(planned_end, str): + planned_end = datetime.fromisoformat(planned_end.replace('Z', '+00:00')) + + # Include if batch ends today (even if it started yesterday) + if today_start <= planned_end < today_end: + include_batch = True + + if include_batch: + filtered_batches.append(batch) + + # Return filtered result + return { + **result, + "batches": filtered_batches, + "total_count": len(filtered_batches) + } + + return result except Exception as e: logger.error("Error fetching today's batches", error=str(e), tenant_id=tenant_id) return None diff --git a/shared/schemas/reasoning_types.py b/shared/schemas/reasoning_types.py index 9b63884b..fa9b42bf 100644 --- a/shared/schemas/reasoning_types.py +++ b/shared/schemas/reasoning_types.py @@ -125,33 +125,118 @@ class ProductionBatchReasoningData(BaseModel): def create_po_reasoning_low_stock( supplier_name: str, - product_names: list, - current_stock: float, - required_stock: float, - days_until_stockout: int, + product_names: list, # Kept for backward compatibility + current_stock: float = None, # Kept for backward compatibility + required_stock: float = None, # Kept for backward compatibility + days_until_stockout: int = None, # Kept for backward compatibility threshold_percentage: int = 20, affected_products: Optional[list] = None, - estimated_lost_orders: Optional[int] = None + estimated_lost_orders: Optional[int] = None, + # New enhanced parameters + product_details: Optional[list] = None, + supplier_lead_time_days: Optional[int] = None, + order_urgency: Optional[str] = None, + affected_production_batches: Optional[list] = None, + estimated_production_loss_eur: Optional[float] = None ) -> Dict[str, Any]: """ - Create reasoning data for low stock detection + Create reasoning data for low stock detection with supply chain intelligence + + Supports two modes: + 1. Legacy mode: Uses product_names, current_stock, days_until_stockout (simple) + 2. Enhanced mode: Uses product_details with per-product depletion analysis Args: supplier_name: Name of the supplier - product_names: List of product names in the order - current_stock: Current stock level - required_stock: Required stock level - days_until_stockout: Days until stock runs out + product_names: List of product names (legacy, for backward compatibility) + current_stock: Current stock level (legacy) + required_stock: Required stock level (legacy) + days_until_stockout: Days until stock runs out (legacy) threshold_percentage: Stock threshold percentage - affected_products: Products that will be affected - estimated_lost_orders: Estimated number of lost orders + affected_products: Products that will be affected (legacy) + estimated_lost_orders: Estimated number of lost orders (legacy) + product_details: List of dicts with per-product analysis (NEW): + [ + { + "product_name": str, + "current_stock_kg": float, + "daily_consumption_kg": float, + "days_until_depletion": float, + "reorder_point_kg": float, + "safety_stock_days": int, + "criticality": str # "critical", "urgent", "important", "normal" + }, + ... + ] + supplier_lead_time_days: Supplier delivery lead time in days (NEW) + order_urgency: Overall order urgency: "critical", "urgent", "important", "normal" (NEW) + affected_production_batches: List of batch numbers that will be impacted (NEW) + estimated_production_loss_eur: Estimated financial loss if not ordered (NEW) Returns: - Reasoning data dictionary + Reasoning data dictionary with enhanced supply chain intelligence """ - return { - "type": PurchaseOrderReasoningType.LOW_STOCK_DETECTION.value, - "parameters": { + # Determine mode based on parameters + enhanced_mode = product_details is not None + + if enhanced_mode: + # Enhanced mode: Use detailed per-product analysis + # Extract critical products for summary + critical_products = [ + p for p in product_details + if p.get("criticality") in ["critical", "urgent"] + ] + + # Find most critical depletion time + min_depletion_days = min( + [p.get("days_until_depletion", 999) for p in product_details], + default=7 + ) + min_depletion_hours = round(min_depletion_days * 24, 1) + + # Calculate safety margin with supplier lead time + safety_margin_days = None + if supplier_lead_time_days is not None: + safety_margin_days = min_depletion_days - supplier_lead_time_days + + # All product names for backward compatibility + all_product_names = [p.get("product_name", "Product") for p in product_details] + + parameters = { + "supplier_name": supplier_name, + "supplier_lead_time_days": supplier_lead_time_days or 2, + "product_details": product_details, + "product_names": all_product_names, # For i18n join operations + "product_count": len(product_details), + "critical_products": [p.get("product_name") for p in critical_products], + "critical_product_count": len(critical_products), + "min_depletion_days": round(min_depletion_days, 2), + "min_depletion_hours": min_depletion_hours, + "safety_margin_days": round(safety_margin_days, 2) if safety_margin_days is not None else None, + "order_urgency": order_urgency or "normal", + "affected_batches": affected_production_batches or [], + "affected_batches_count": len(affected_production_batches) if affected_production_batches else 0, + "potential_loss_eur": round(estimated_production_loss_eur, 2) if estimated_production_loss_eur else 0, + "threshold_percentage": threshold_percentage + } + + # Enhanced consequence calculation + severity = ConsequenceSeverity.CRITICAL.value if order_urgency == "critical" else \ + ConsequenceSeverity.HIGH.value if order_urgency in ["urgent", "important"] else \ + ConsequenceSeverity.MEDIUM.value + + consequence = { + "type": "stockout_risk_detailed", + "severity": severity, + "impact_days": round(min_depletion_days, 2), + "affected_production_batches": affected_production_batches or [], + "estimated_production_loss_eur": round(estimated_production_loss_eur, 2) if estimated_production_loss_eur else 0, + "critical_items": [p.get("product_name") for p in critical_products] + } + + else: + # Legacy mode: Use simple parameters (backward compatibility) + parameters = { "supplier_name": supplier_name, "product_names": product_names, "product_count": len(product_names), @@ -159,18 +244,25 @@ def create_po_reasoning_low_stock( "required_stock": required_stock, "days_until_stockout": days_until_stockout, "threshold_percentage": threshold_percentage, - "stock_percentage": round((current_stock / required_stock * 100), 1) if required_stock > 0 else 0 - }, - "consequence": { + "stock_percentage": round((current_stock / required_stock * 100), 1) if (required_stock and required_stock > 0) else 0 + } + + consequence = { "type": "stockout_risk", - "severity": ConsequenceSeverity.HIGH.value if days_until_stockout <= 2 else ConsequenceSeverity.MEDIUM.value, - "impact_days": days_until_stockout, + "severity": ConsequenceSeverity.HIGH.value if days_until_stockout and days_until_stockout <= 2 else ConsequenceSeverity.MEDIUM.value, + "impact_days": days_until_stockout or 7, "affected_products": affected_products or [], "estimated_lost_orders": estimated_lost_orders or 0 - }, + } + + return { + "type": PurchaseOrderReasoningType.LOW_STOCK_DETECTION.value, + "parameters": parameters, + "consequence": consequence, "metadata": { "trigger_source": "orchestrator_auto", - "ai_assisted": True + "ai_assisted": True, + "enhanced_mode": enhanced_mode } }