Improve te panel de control logic
This commit is contained in:
594
frontend/src/locales/en/blog.json
Normal file
594
frontend/src/locales/en/blog.json
Normal file
@@ -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."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"purchaseOrder": {
|
"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": "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}.",
|
"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}.",
|
"safety_stock_replenishment": "Replenishing safety stock for {product_names_joined} from {supplier_name}.",
|
||||||
"supplier_contract": "Scheduled order per contract with {supplier_name}.",
|
"supplier_contract": "Scheduled order per contract with {supplier_name}.",
|
||||||
@@ -108,8 +109,8 @@
|
|||||||
"title": "Last Night I Planned Your Day",
|
"title": "Last Night I Planned Your Day",
|
||||||
"ready_to_plan": "Ready to Plan Your Bakery Day",
|
"ready_to_plan": "Ready to Plan Your Bakery Day",
|
||||||
"run_planning": "Run Daily Planning",
|
"run_planning": "Run Daily Planning",
|
||||||
"run_info": "Orchestration run #{{runNumber}}",
|
"run_info": "Orchestration run #{runNumber}",
|
||||||
"took": "Took {{seconds}}s",
|
"took": "Took {seconds}s",
|
||||||
"created_pos": "Created {count} purchase order{count, plural, one {} other {s}}",
|
"created_pos": "Created {count} purchase order{count, plural, one {} other {s}}",
|
||||||
"scheduled_batches": "Scheduled {count} production batch{count, plural, one {} other {es}}",
|
"scheduled_batches": "Scheduled {count} production batch{count, plural, one {} other {es}}",
|
||||||
"show_more": "Show {count} more",
|
"show_more": "Show {count} more",
|
||||||
|
|||||||
594
frontend/src/locales/es/blog.json
Normal file
594
frontend/src/locales/es/blog.json
Normal file
@@ -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."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"purchaseOrder": {
|
"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": "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}.",
|
"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}.",
|
"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}.",
|
"supplier_contract": "Pedido programado según contrato con {supplier_name}.",
|
||||||
@@ -108,8 +109,8 @@
|
|||||||
"title": "Anoche Planifiqué Tu Día",
|
"title": "Anoche Planifiqué Tu Día",
|
||||||
"ready_to_plan": "Listo Para Planificar Tu Día en la Panadería",
|
"ready_to_plan": "Listo Para Planificar Tu Día en la Panadería",
|
||||||
"run_planning": "Ejecutar Planificación Diaria",
|
"run_planning": "Ejecutar Planificación Diaria",
|
||||||
"run_info": "Ejecución de orquestación #{{runNumber}}",
|
"run_info": "Ejecución de orquestación #{runNumber}",
|
||||||
"took": "Duró {{seconds}}s",
|
"took": "Duró {seconds}s",
|
||||||
"created_pos": "{count} orden{count, plural, one {} other {es}} de compra creada{count, plural, one {} other {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}}",
|
"scheduled_batches": "{count} lote{count, plural, one {} other {s}} de producción programado{count, plural, one {} other {s}}",
|
||||||
"show_more": "Mostrar {count} más",
|
"show_more": "Mostrar {count} más",
|
||||||
|
|||||||
594
frontend/src/locales/eu/blog.json
Normal file
594
frontend/src/locales/eu/blog.json
Normal file
@@ -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."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"purchaseOrder": {
|
"purchaseOrder": {
|
||||||
"low_stock_detection": "{supplier_name}-rentzat stock baxua. {product_names_joined}-ren egungo stocka {days_until_stockout} egunetan amaituko da.",
|
"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.",
|
"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.",
|
"safety_stock_replenishment": "{supplier_name}-ren {product_names_joined}-rentzat segurtasun stockaren birjartzea.",
|
||||||
"supplier_contract": "{supplier_name}-rekin kontratuaren arabera programatutako eskaera.",
|
"supplier_contract": "{supplier_name}-rekin kontratuaren arabera programatutako eskaera.",
|
||||||
@@ -18,12 +19,12 @@
|
|||||||
"regular_schedule": "{product_name}-ren ohiko ekoizpen programatua."
|
"regular_schedule": "{product_name}-ren ohiko ekoizpen programatua."
|
||||||
},
|
},
|
||||||
"consequence": {
|
"consequence": {
|
||||||
"stockout_risk": "Stock amaitzeko arriskua {{impact_days}} egunetan. Produktu kaltetuak: {{affected_products_joined}}.",
|
"stockout_risk": "Stock amaitzeko arriskua {impact_days} egunetan. Produktu kaltetuak: {affected_products_joined}.",
|
||||||
"insufficient_supply": "{{impact_days}} eguneko aldirako hornidura ez nahikoa.",
|
"insufficient_supply": "{impact_days} eguneko aldirako hornidura ez nahikoa.",
|
||||||
"production_delay": "{{delay_hours}} orduko ekoizpen atzerapena posiblea.",
|
"production_delay": "{delay_hours} orduko ekoizpen atzerapena posiblea.",
|
||||||
"customer_commitment": "Bezeroari entregatzeko konpromisoa arriskuan.",
|
"customer_commitment": "Bezeroari entregatzeko konpromisoa arriskuan.",
|
||||||
"quality_issue": "Kalitate estandarrak arriskuan egon daitezke.",
|
"quality_issue": "Kalitate estandarrak arriskuan egon daitezke.",
|
||||||
"cost_increase": "Materialen kostuak %{{percentage}} gehitu daitezke."
|
"cost_increase": "Materialen kostuak %{percentage} gehitu daitezke."
|
||||||
},
|
},
|
||||||
"severity": {
|
"severity": {
|
||||||
"critical": "Kritikoa",
|
"critical": "Kritikoa",
|
||||||
@@ -45,27 +46,27 @@
|
|||||||
"NO_DEMAND_DATA": "Ez dago eskaeraren datu historikorik eskuragarri (gutxienez 2 datu puntu behar dira)"
|
"NO_DEMAND_DATA": "Ez dago eskaeraren datu historikorik eskuragarri (gutxienez 2 datu puntu behar dira)"
|
||||||
},
|
},
|
||||||
"safetyStock": {
|
"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.",
|
"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.",
|
"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.",
|
"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_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)."
|
"error_insufficient_data": "Eskaeraren historiala ez da nahikoa segurtasun-stock kalkulatzeko ({data_points} datu puntu, {min_required} behar dira)."
|
||||||
},
|
},
|
||||||
"priceForecaster": {
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"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)."
|
"insufficient_data": "Prezioen historiala ez da nahikoa aurreikuspen fidagarrirako ({history_days} egun eskuragarri, {min_required_days} egun behar dira)."
|
||||||
},
|
},
|
||||||
"optimization": {
|
"optimization": {
|
||||||
"eoq_base": "Eskaera Kantitate Ekonomikoa kalkulatu da: {{eoq}} unitate (beharrezkoa: {{required_quantity}}, urteko eskaera: {{annual_demand}}). {{optimal_quantity}} unitatetan optimizatuta.",
|
"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.",
|
"moq_applied": "Gutxieneko eskaera-kantitatearen murrizketa aplikatu da: {moq} unitate.",
|
||||||
"max_applied": "Gehienezko eskaera-kantitatearen murrizketa aplikatu da: {{max_qty}} 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.",
|
"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}}).",
|
"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."
|
"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": {
|
"jtbd": {
|
||||||
"health_status": {
|
"health_status": {
|
||||||
@@ -75,8 +76,8 @@
|
|||||||
"last_updated": "Azken eguneratzea",
|
"last_updated": "Azken eguneratzea",
|
||||||
"next_check": "Hurrengo egiaztapena",
|
"next_check": "Hurrengo egiaztapena",
|
||||||
"never": "Inoiz ez",
|
"never": "Inoiz ez",
|
||||||
"critical_issues": "{{count}} arazo kritiko",
|
"critical_issues": "{count} arazo kritiko",
|
||||||
"actions_needed": "{{count}} ekintza behar"
|
"actions_needed": "{count} ekintza behar"
|
||||||
},
|
},
|
||||||
"action_queue": {
|
"action_queue": {
|
||||||
"title": "Zer Behar Du Zure Arreta",
|
"title": "Zer Behar Du Zure Arreta",
|
||||||
@@ -108,19 +109,19 @@
|
|||||||
"title": "Bart Gauean Zure Eguna Planifikatu Nuen",
|
"title": "Bart Gauean Zure Eguna Planifikatu Nuen",
|
||||||
"ready_to_plan": "Zure Okindegiko Eguna Planifikatzeko Prest",
|
"ready_to_plan": "Zure Okindegiko Eguna Planifikatzeko Prest",
|
||||||
"run_planning": "Exekutatu Eguneko Plangintza",
|
"run_planning": "Exekutatu Eguneko Plangintza",
|
||||||
"run_info": "Orkestazio exekuzioa #{{runNumber}}",
|
"run_info": "Orkestazio exekuzioa #{runNumber}",
|
||||||
"took": "{{seconds}}s behar izan zituen",
|
"took": "{seconds}s behar izan zituen",
|
||||||
"created_pos": "{{count}} erosketa agindu sortu",
|
"created_pos": "{count} erosketa agindu sortu",
|
||||||
"scheduled_batches": "{{count}} ekoizpen lote programatu",
|
"scheduled_batches": "{count} ekoizpen lote programatu",
|
||||||
"show_more": "Erakutsi {{count}} gehiago",
|
"show_more": "Erakutsi {count} gehiago",
|
||||||
"show_less": "Erakutsi gutxiago",
|
"show_less": "Erakutsi gutxiago",
|
||||||
"no_actions": "Ez dira ekintza berriak behar - dena bidean dago!",
|
"no_actions": "Ez dira ekintza berriak behar - dena bidean dago!",
|
||||||
"based_on": "Oinarrituta:",
|
"based_on": "Oinarrituta:",
|
||||||
"customer_orders": "{{count}} bezero eskaera",
|
"customer_orders": "{count} bezero eskaera",
|
||||||
"historical_demand": "Eskaera historikoa",
|
"historical_demand": "Eskaera historikoa",
|
||||||
"inventory_levels": "Inbentario mailak",
|
"inventory_levels": "Inbentario mailak",
|
||||||
"ai_optimization": "IA optimizazioa",
|
"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.",
|
"no_tenant_error": "Ez da inquilino ID aurkitu. Mesedez, ziurtatu saioa hasi duzula.",
|
||||||
"planning_started": "Plangintza behar bezala hasi da",
|
"planning_started": "Plangintza behar bezala hasi da",
|
||||||
"planning_failed": "Errorea plangintza hastean",
|
"planning_failed": "Errorea plangintza hastean",
|
||||||
@@ -159,9 +160,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"types": {
|
"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",
|
"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",
|
"customer_orders": "Bezeroen eskaera bermatuen betetze",
|
||||||
"seasonal_demand": "Aurreikusitako sasoiko eskariaren igoera",
|
"seasonal_demand": "Aurreikusitako sasoiko eskariaren igoera",
|
||||||
"inventory_replenishment": "Inbentario berritze erregularra",
|
"inventory_replenishment": "Inbentario berritze erregularra",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import helpEs from './es/help.json';
|
|||||||
import featuresEs from './es/features.json';
|
import featuresEs from './es/features.json';
|
||||||
import aboutEs from './es/about.json';
|
import aboutEs from './es/about.json';
|
||||||
import demoEs from './es/demo.json';
|
import demoEs from './es/demo.json';
|
||||||
|
import blogEs from './es/blog.json';
|
||||||
|
|
||||||
// English translations
|
// English translations
|
||||||
import commonEn from './en/common.json';
|
import commonEn from './en/common.json';
|
||||||
@@ -45,6 +46,7 @@ import helpEn from './en/help.json';
|
|||||||
import featuresEn from './en/features.json';
|
import featuresEn from './en/features.json';
|
||||||
import aboutEn from './en/about.json';
|
import aboutEn from './en/about.json';
|
||||||
import demoEn from './en/demo.json';
|
import demoEn from './en/demo.json';
|
||||||
|
import blogEn from './en/blog.json';
|
||||||
|
|
||||||
// Basque translations
|
// Basque translations
|
||||||
import commonEu from './eu/common.json';
|
import commonEu from './eu/common.json';
|
||||||
@@ -69,6 +71,7 @@ import helpEu from './eu/help.json';
|
|||||||
import featuresEu from './eu/features.json';
|
import featuresEu from './eu/features.json';
|
||||||
import aboutEu from './eu/about.json';
|
import aboutEu from './eu/about.json';
|
||||||
import demoEu from './eu/demo.json';
|
import demoEu from './eu/demo.json';
|
||||||
|
import blogEu from './eu/blog.json';
|
||||||
|
|
||||||
// Translation resources by language
|
// Translation resources by language
|
||||||
export const resources = {
|
export const resources = {
|
||||||
@@ -95,6 +98,7 @@ export const resources = {
|
|||||||
features: featuresEs,
|
features: featuresEs,
|
||||||
about: aboutEs,
|
about: aboutEs,
|
||||||
demo: demoEs,
|
demo: demoEs,
|
||||||
|
blog: blogEs,
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
common: commonEn,
|
common: commonEn,
|
||||||
@@ -119,6 +123,7 @@ export const resources = {
|
|||||||
features: featuresEn,
|
features: featuresEn,
|
||||||
about: aboutEn,
|
about: aboutEn,
|
||||||
demo: demoEn,
|
demo: demoEn,
|
||||||
|
blog: blogEn,
|
||||||
},
|
},
|
||||||
eu: {
|
eu: {
|
||||||
common: commonEu,
|
common: commonEu,
|
||||||
@@ -143,6 +148,7 @@ export const resources = {
|
|||||||
features: featuresEu,
|
features: featuresEu,
|
||||||
about: aboutEu,
|
about: aboutEu,
|
||||||
demo: demoEu,
|
demo: demoEu,
|
||||||
|
blog: blogEu,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -179,7 +185,7 @@ export const languageConfig = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Namespaces available in translations
|
// 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];
|
export type Namespace = typeof namespaces[number];
|
||||||
|
|
||||||
// Helper function to get language display name
|
// 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 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
|
// Default export with all translations
|
||||||
export default resources;
|
export default resources;
|
||||||
|
|||||||
@@ -2,624 +2,105 @@ import React from 'react';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PublicLayout } from '../../components/layout';
|
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 {
|
interface BlogPost {
|
||||||
id: string;
|
id: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
title: string;
|
titleKey: string;
|
||||||
excerpt: string;
|
excerptKey: string;
|
||||||
content: string;
|
authorKey: string;
|
||||||
author: string;
|
|
||||||
date: string;
|
date: string;
|
||||||
readTime: string;
|
readTime: string;
|
||||||
category: string;
|
categoryKey: string;
|
||||||
image?: string;
|
tagsKeys: string[];
|
||||||
tags: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BlogPage: React.FC = () => {
|
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[] = [
|
const blogPosts: BlogPost[] = [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
slug: 'reducir-desperdicio-alimentario-panaderia',
|
slug: 'reducir-desperdicio-alimentario-panaderia',
|
||||||
title: 'Cómo Reducir el Desperdicio Alimentario en tu Panadería: Guía Completa 2025',
|
titleKey: 'posts.waste_reduction.title',
|
||||||
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%.',
|
excerptKey: 'posts.waste_reduction.excerpt',
|
||||||
content: `
|
authorKey: 'posts.waste_reduction.author',
|
||||||
# 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',
|
|
||||||
date: '2025-01-15',
|
date: '2025-01-15',
|
||||||
readTime: '8 min',
|
readTime: '8',
|
||||||
category: 'Gestión',
|
categoryKey: 'categories.management',
|
||||||
tags: ['desperdicio alimentario', 'sostenibilidad', 'IA', 'gestión'],
|
tagsKeys: [
|
||||||
|
'posts.waste_reduction.tags.food_waste',
|
||||||
|
'posts.waste_reduction.tags.sustainability',
|
||||||
|
'posts.waste_reduction.tags.ai',
|
||||||
|
'posts.waste_reduction.tags.management',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
slug: 'ia-predecir-demanda-panaderia',
|
slug: 'ia-predecir-demanda-panaderia',
|
||||||
title: 'Cómo la IA Predice la Demanda en Panaderías con 92% de Precisión',
|
titleKey: 'posts.ai_prediction.title',
|
||||||
excerpt: 'La inteligencia artificial ha revolucionado la predicción de demanda. Descubre cómo funcionan los algoritmos de ML aplicados a panaderías',
|
excerptKey: 'posts.ai_prediction.excerpt',
|
||||||
content: `
|
authorKey: 'posts.ai_prediction.author',
|
||||||
# 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',
|
|
||||||
date: '2025-01-10',
|
date: '2025-01-10',
|
||||||
readTime: '10 min',
|
readTime: '10',
|
||||||
category: 'Tecnología',
|
categoryKey: 'categories.technology',
|
||||||
tags: ['IA', 'machine learning', 'predicción', 'tecnología'],
|
tagsKeys: [
|
||||||
|
'posts.ai_prediction.tags.ai',
|
||||||
|
'posts.ai_prediction.tags.machine_learning',
|
||||||
|
'posts.ai_prediction.tags.prediction',
|
||||||
|
'posts.ai_prediction.tags.technology',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '3',
|
id: '3',
|
||||||
slug: 'optimizar-produccion-panaderia-artesanal',
|
slug: 'optimizar-produccion-panaderia-artesanal',
|
||||||
title: 'Guía de Optimización de Producción para Panaderías',
|
titleKey: 'posts.production_optimization.title',
|
||||||
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.',
|
excerptKey: 'posts.production_optimization.excerpt',
|
||||||
content: `
|
authorKey: 'posts.production_optimization.author',
|
||||||
# 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',
|
|
||||||
date: '2025-01-05',
|
date: '2025-01-05',
|
||||||
readTime: '12 min',
|
readTime: '12',
|
||||||
category: 'Producción',
|
categoryKey: 'categories.production',
|
||||||
tags: ['optimización', 'producción', 'artesanal', 'gestión'],
|
tagsKeys: [
|
||||||
|
'posts.production_optimization.tags.optimization',
|
||||||
|
'posts.production_optimization.tags.production',
|
||||||
|
'posts.production_optimization.tags.artisan',
|
||||||
|
'posts.production_optimization.tags.management',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '4',
|
id: '4',
|
||||||
slug: 'obrador-central-vs-produccion-local',
|
slug: 'obrador-central-vs-produccion-local',
|
||||||
title: 'Obrador Central vs Producción Local: Cómo la IA Optimiza Ambos Modelos',
|
titleKey: 'posts.central_vs_local.title',
|
||||||
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.',
|
excerptKey: 'posts.central_vs_local.excerpt',
|
||||||
content: `
|
authorKey: 'posts.central_vs_local.author',
|
||||||
# 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',
|
|
||||||
date: '2025-01-20',
|
date: '2025-01-20',
|
||||||
readTime: '15 min',
|
readTime: '15',
|
||||||
category: 'Estrategia',
|
categoryKey: 'categories.strategy',
|
||||||
tags: ['modelos de negocio', 'obrador central', 'producción local', 'escalabilidad'],
|
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',
|
id: '5',
|
||||||
slug: 'gdpr-proteccion-datos-panaderia',
|
slug: 'gdpr-proteccion-datos-panaderia',
|
||||||
title: 'GDPR y Protección de Datos en Panaderías: Lo Que Debes Saber',
|
titleKey: 'posts.gdpr.title',
|
||||||
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.',
|
excerptKey: 'posts.gdpr.excerpt',
|
||||||
content: `
|
authorKey: 'posts.gdpr.author',
|
||||||
# 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)',
|
|
||||||
date: '2025-01-01',
|
date: '2025-01-01',
|
||||||
readTime: '9 min',
|
readTime: '9',
|
||||||
category: 'Legal',
|
categoryKey: 'categories.legal',
|
||||||
tags: ['GDPR', 'RGPD', 'privacidad', 'legal', 'seguridad'],
|
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
|
|||||||
<div className="text-center max-w-3xl mx-auto">
|
<div className="text-center max-w-3xl mx-auto">
|
||||||
<div className="inline-flex items-center gap-2 bg-[var(--color-primary)]/10 text-[var(--color-primary)] px-4 py-2 rounded-full text-sm font-medium mb-6">
|
<div className="inline-flex items-center gap-2 bg-[var(--color-primary)]/10 text-[var(--color-primary)] px-4 py-2 rounded-full text-sm font-medium mb-6">
|
||||||
<Brain className="w-4 h-4" />
|
<Brain className="w-4 h-4" />
|
||||||
<span>Blog de Gestión para Panaderías</span>
|
<span>{t('blog:hero.badge')}</span>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-4xl lg:text-5xl font-extrabold text-[var(--text-primary)] mb-6">
|
<h1 className="text-4xl lg:text-5xl font-extrabold text-[var(--text-primary)] mb-6">
|
||||||
Aprende a Optimizar tu Panadería
|
{t('blog:hero.title')}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xl text-[var(--text-secondary)]">
|
<p className="text-xl text-[var(--text-secondary)]">
|
||||||
Artículos sobre gestión, IA, reducción de desperdicios y crecimiento sostenible para panaderías.
|
{t('blog:hero.description')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -665,36 +146,42 @@ El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas corr
|
|||||||
<div className="p-8">
|
<div className="p-8">
|
||||||
<div className="flex items-center gap-4 mb-4">
|
<div className="flex items-center gap-4 mb-4">
|
||||||
<span className="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-[var(--color-primary)]/10 text-[var(--color-primary)]">
|
<span className="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-[var(--color-primary)]/10 text-[var(--color-primary)]">
|
||||||
{post.category}
|
{t(`blog:${post.categoryKey}`)}
|
||||||
</span>
|
</span>
|
||||||
<div className="flex items-center gap-2 text-sm text-[var(--text-tertiary)]">
|
<div className="flex items-center gap-2 text-sm text-[var(--text-tertiary)]">
|
||||||
<Calendar className="w-4 h-4" />
|
<Calendar className="w-4 h-4" />
|
||||||
<span>{new Date(post.date).toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' })}</span>
|
<span>
|
||||||
|
{new Date(post.date).toLocaleDateString(i18n.language, {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 text-sm text-[var(--text-tertiary)]">
|
<div className="flex items-center gap-2 text-sm text-[var(--text-tertiary)]">
|
||||||
<Clock className="w-4 h-4" />
|
<Clock className="w-4 h-4" />
|
||||||
<span>{post.readTime}</span>
|
<span>{t('blog:post.read_time', { time: post.readTime })}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 className="text-2xl font-bold text-[var(--text-primary)] mb-4 hover:text-[var(--color-primary)] transition-colors">
|
<h2 className="text-2xl font-bold text-[var(--text-primary)] mb-4 hover:text-[var(--color-primary)] transition-colors">
|
||||||
<Link to={`/blog/${post.slug}`}>
|
<Link to={`/blog/${post.slug}`}>
|
||||||
{post.title}
|
{t(`blog:${post.titleKey}`)}
|
||||||
</Link>
|
</Link>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p className="text-[var(--text-secondary)] mb-6 line-clamp-3">
|
<p className="text-[var(--text-secondary)] mb-6 line-clamp-3">
|
||||||
{post.excerpt}
|
{t(`blog:${post.excerptKey}`)}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Tags */}
|
{/* Tags */}
|
||||||
<div className="flex flex-wrap gap-2 mb-6">
|
<div className="flex flex-wrap gap-2 mb-6">
|
||||||
{post.tags.slice(0, 3).map((tag) => (
|
{post.tagsKeys.slice(0, 3).map((tagKey) => (
|
||||||
<span
|
<span
|
||||||
key={tag}
|
key={tagKey}
|
||||||
className="text-xs px-2 py-1 rounded bg-[var(--bg-tertiary)] text-[var(--text-tertiary)]"
|
className="text-xs px-2 py-1 rounded bg-[var(--bg-tertiary)] text-[var(--text-tertiary)]"
|
||||||
>
|
>
|
||||||
#{tag}
|
#{t(`blog:${tagKey}`)}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -704,7 +191,7 @@ El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas corr
|
|||||||
to={`/blog/${post.slug}`}
|
to={`/blog/${post.slug}`}
|
||||||
className="inline-flex items-center gap-2 text-[var(--color-primary)] font-medium hover:gap-3 transition-all"
|
className="inline-flex items-center gap-2 text-[var(--color-primary)] font-medium hover:gap-3 transition-all"
|
||||||
>
|
>
|
||||||
<span>Leer artículo completo</span>
|
<span>{t('blog:post.read_more')}</span>
|
||||||
<ArrowRight className="w-4 h-4" />
|
<ArrowRight className="w-4 h-4" />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -713,10 +200,12 @@ El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas corr
|
|||||||
<div className="px-8 py-4 bg-[var(--bg-tertiary)] border-t border-[var(--border-primary)]">
|
<div className="px-8 py-4 bg-[var(--bg-tertiary)] border-t border-[var(--border-primary)]">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-10 h-10 rounded-full bg-[var(--color-primary)] flex items-center justify-center text-white font-bold">
|
<div className="w-10 h-10 rounded-full bg-[var(--color-primary)] flex items-center justify-center text-white font-bold">
|
||||||
{post.author.charAt(0)}
|
{t(`blog:${post.authorKey}`).charAt(0)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-medium text-[var(--text-primary)]">{post.author}</div>
|
<div className="text-sm font-medium text-[var(--text-primary)]">
|
||||||
|
{t(`blog:${post.authorKey}`)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -730,16 +219,16 @@ El RGPD no es opcional. Pero tampoco es complicado si usas las herramientas corr
|
|||||||
<section className="py-16 bg-gradient-to-r from-[var(--color-primary)] to-orange-600">
|
<section className="py-16 bg-gradient-to-r from-[var(--color-primary)] to-orange-600">
|
||||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
||||||
<h2 className="text-3xl font-bold text-white mb-4">
|
<h2 className="text-3xl font-bold text-white mb-4">
|
||||||
¿Listo para Optimizar tu Panadería?
|
{t('blog:cta.title')}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xl text-white/90 mb-8">
|
<p className="text-xl text-white/90 mb-8">
|
||||||
Únete al programa piloto y obtén 3 meses gratis + 20% descuento de por vida
|
{t('blog:cta.description')}
|
||||||
</p>
|
</p>
|
||||||
<Link
|
<Link
|
||||||
to="/register"
|
to="/register"
|
||||||
className="inline-flex items-center gap-2 px-8 py-4 bg-white text-[var(--color-primary)] rounded-xl font-bold hover:shadow-2xl transition-all hover:scale-105"
|
className="inline-flex items-center gap-2 px-8 py-4 bg-white text-[var(--color-primary)] rounded-xl font-bold hover:shadow-2xl transition-all hover:scale-105"
|
||||||
>
|
>
|
||||||
<span>Solicitar Plaza en el Piloto</span>
|
<span>{t('blog:cta.button')}</span>
|
||||||
<ArrowRight className="w-5 h-5" />
|
<ArrowRight className="w-5 h-5" />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class Settings(BaseSettings):
|
|||||||
ORDERS_SERVICE_URL: str = os.getenv("ORDERS_SERVICE_URL", "http://orders-service:8000")
|
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")
|
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")
|
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
|
# Logging
|
||||||
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
|
LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ class CloneOrchestrator:
|
|||||||
required=False, # Optional - provides procurement and purchase orders
|
required=False, # Optional - provides procurement and purchase orders
|
||||||
timeout=25.0 # Longer - clones many procurement entities
|
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(
|
async def clone_all_services(
|
||||||
|
|||||||
@@ -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 for demo data (all relative dates calculated from this)
|
||||||
BASE_REFERENCE_DATE = datetime(2025, 1, 15, 12, 0, 0, tzinfo=timezone.utc)
|
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
|
# Load configuration from JSON
|
||||||
def load_stock_config():
|
def load_stock_config():
|
||||||
"""Load stock configuration from JSON file"""
|
"""Load stock configuration from JSON file"""
|
||||||
@@ -126,13 +194,25 @@ async def create_stock_batches_for_ingredient(
|
|||||||
stocks = []
|
stocks = []
|
||||||
num_batches = random.randint(1, 2) # Reduced from 3-5 for faster demo loading
|
num_batches = random.randint(1, 2) # Reduced from 3-5 for faster demo loading
|
||||||
|
|
||||||
# Calculate target total stock for this ingredient
|
# CRITICAL DEMO SCENARIO: Create consumption-aware stock levels
|
||||||
# Use 40-80% of max_stock_level to allow for realistic variation
|
# This creates realistic scenarios that trigger intelligent PO reasoning
|
||||||
# If max_stock_level is not set, use reorder_point * 3 as a reasonable target
|
critical_low_stock_skus = ["HAR-T55-001", "LEV-SEC-001", "MAN-SAL-001"]
|
||||||
if ingredient.max_stock_level:
|
is_critical_low = ingredient.sku in critical_low_stock_skus
|
||||||
target_total_stock = float(ingredient.max_stock_level) * random.uniform(0.4, 0.8)
|
|
||||||
|
# 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:
|
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
|
# Distribute total stock across batches
|
||||||
batch_quantities = []
|
batch_quantities = []
|
||||||
|
|||||||
@@ -325,6 +325,9 @@ async def get_orchestration_summary(
|
|||||||
try:
|
try:
|
||||||
po_data = await procurement_client.get_pending_purchase_orders(tenant_id, limit=10)
|
po_data = await procurement_client.get_pending_purchase_orders(tenant_id, limit=10)
|
||||||
if po_data and isinstance(po_data, list):
|
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"] = [
|
summary["purchaseOrdersSummary"] = [
|
||||||
PurchaseOrderSummary(
|
PurchaseOrderSummary(
|
||||||
supplierName=po.get("supplier_name", "Unknown"),
|
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)
|
batch_data = await production_client.get_todays_batches(tenant_id)
|
||||||
if batch_data:
|
if batch_data:
|
||||||
batches = batch_data.get("batches", [])
|
batches = batch_data.get("batches", [])
|
||||||
|
# Override stale orchestration count with actual real-time batch count
|
||||||
|
summary["productionBatchesCreated"] = len(batches)
|
||||||
summary["productionBatchesSummary"] = [
|
summary["productionBatchesSummary"] = [
|
||||||
ProductionBatchSummary(
|
ProductionBatchSummary(
|
||||||
productName=batch.get("product_name", "Unknown"),
|
productName=batch.get("product_name", "Unknown"),
|
||||||
|
|||||||
264
services/orchestrator/app/api/internal_demo.py
Normal file
264
services/orchestrator/app/api/internal_demo.py
Normal file
@@ -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"}
|
||||||
@@ -99,8 +99,8 @@ service.add_router(orchestration_router)
|
|||||||
service.add_router(dashboard_router)
|
service.add_router(dashboard_router)
|
||||||
|
|
||||||
# INTERNAL: Service-to-service endpoints
|
# INTERNAL: Service-to-service endpoints
|
||||||
# from app.api import internal_demo
|
from app.api import internal_demo
|
||||||
# service.add_router(internal_demo.router)
|
service.add_router(internal_demo.router)
|
||||||
|
|
||||||
|
|
||||||
@app.middleware("http")
|
@app.middleware("http")
|
||||||
|
|||||||
@@ -417,14 +417,38 @@ class DashboardService:
|
|||||||
|
|
||||||
# Get reasoning type and convert to i18n key
|
# Get reasoning type and convert to i18n key
|
||||||
reasoning_type = reasoning_data.get('type', 'inventory_replenishment')
|
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
|
# Preprocess parameters for i18n - MUST create a copy to avoid modifying immutable database objects
|
||||||
params = dict(reasoning_data.get('parameters', {}))
|
params = dict(reasoning_data.get('parameters', {}))
|
||||||
|
|
||||||
# Convert product_names array to product_names_joined string
|
# Convert product_names array to product_names_joined string
|
||||||
if 'product_names' in params and isinstance(params['product_names'], list):
|
if 'product_names' in params and isinstance(params['product_names'], list):
|
||||||
params['product_names_joined'] = ', '.join(params['product_names'])
|
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({
|
actions.append({
|
||||||
"id": po["id"],
|
"id": po["id"],
|
||||||
"type": ActionType.APPROVE_PO,
|
"type": ActionType.APPROVE_PO,
|
||||||
@@ -594,7 +618,8 @@ class DashboardService:
|
|||||||
if actual_start and planned_end:
|
if actual_start and planned_end:
|
||||||
total_duration = (planned_end - actual_start).total_seconds()
|
total_duration = (planned_end - actual_start).total_seconds()
|
||||||
elapsed = (now - 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:
|
else:
|
||||||
progress = 50
|
progress = 50
|
||||||
status_icon = "🔄"
|
status_icon = "🔄"
|
||||||
@@ -604,10 +629,12 @@ class DashboardService:
|
|||||||
"params": {}
|
"params": {}
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
|
# PENDING, SCHEDULED, or any other status
|
||||||
|
progress = 0
|
||||||
status_icon = "⏰"
|
status_icon = "⏰"
|
||||||
status_text = "PENDING"
|
status_text = status # Use actual status
|
||||||
status_i18n = {
|
status_i18n = {
|
||||||
"key": "production.status.pending",
|
"key": f"production.status.{status.lower()}",
|
||||||
"params": {}
|
"params": {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ async def clone_demo_data(
|
|||||||
notes=order.notes if hasattr(order, 'notes') else None,
|
notes=order.notes if hasattr(order, 'notes') else None,
|
||||||
internal_notes=order.internal_notes if hasattr(order, 'internal_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,
|
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,
|
created_at=session_time,
|
||||||
updated_at=session_time,
|
updated_at=session_time,
|
||||||
created_by=system_user_id,
|
created_by=system_user_id,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import random
|
|||||||
from datetime import datetime, timezone, timedelta, date
|
from datetime import datetime, timezone, timedelta, date
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from typing import List, Dict, Any
|
||||||
|
|
||||||
# Add app to path
|
# Add app to path
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
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)
|
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):
|
def get_demo_supplier_ids(tenant_id: uuid.UUID):
|
||||||
"""
|
"""
|
||||||
Generate tenant-specific supplier IDs using XOR strategy with hardcoded base IDs.
|
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
|
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(
|
async def create_purchase_order(
|
||||||
db: AsyncSession,
|
db: AsyncSession,
|
||||||
tenant_id: uuid.UUID,
|
tenant_id: uuid.UUID,
|
||||||
@@ -131,7 +274,7 @@ async def create_purchase_order(
|
|||||||
# Generate reasoning for JTBD dashboard (if columns exist after migration)
|
# Generate reasoning for JTBD dashboard (if columns exist after migration)
|
||||||
days_until_delivery = (required_delivery - created_at).days
|
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
|
reasoning_data = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -142,18 +285,57 @@ async def create_purchase_order(
|
|||||||
if not product_names:
|
if not product_names:
|
||||||
product_names = ["Demo Product"]
|
product_names = ["Demo Product"]
|
||||||
|
|
||||||
|
# Get supplier lead time
|
||||||
|
supplier_lead_time = SUPPLIER_LEAD_TIMES.get(supplier.name, 3)
|
||||||
|
|
||||||
if status == PurchaseOrderStatus.pending_approval:
|
if status == PurchaseOrderStatus.pending_approval:
|
||||||
# Low stock detection reasoning
|
# Enhanced low stock detection with per-product urgency analysis
|
||||||
days_until_stockout = days_until_delivery + 2
|
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(
|
reasoning_data = create_po_reasoning_low_stock(
|
||||||
supplier_name=supplier.name,
|
supplier_name=supplier.name,
|
||||||
product_names=product_names,
|
product_names=product_names, # Legacy compatibility
|
||||||
current_stock=random.uniform(20, 50), # Demo: low stock
|
# Enhanced parameters
|
||||||
required_stock=random.uniform(100, 200), # Demo: needed stock
|
product_details=product_details,
|
||||||
days_until_stockout=days_until_stockout,
|
supplier_lead_time_days=supplier_lead_time,
|
||||||
threshold_percentage=20,
|
order_urgency=overall_urgency,
|
||||||
affected_products=product_names[:2] if len(product_names) > 1 else product_names,
|
affected_production_batches=affected_batches,
|
||||||
estimated_lost_orders=random.randint(5, 15) if days_until_stockout <= 3 else None
|
estimated_production_loss_eur=estimated_loss if estimated_loss > 0 else None
|
||||||
)
|
)
|
||||||
elif auto_approved:
|
elif auto_approved:
|
||||||
# Supplier contract/auto-approval reasoning
|
# Supplier contract/auto-approval reasoning
|
||||||
@@ -165,6 +347,7 @@ async def create_purchase_order(
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Failed to generate reasoning_data: {e}")
|
logger.warning(f"Failed to generate reasoning_data: {e}")
|
||||||
|
logger.exception(e)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Create PO
|
# Create PO
|
||||||
@@ -298,17 +481,17 @@ async def seed_purchase_orders_for_tenant(db: AsyncSession, tenant_id: uuid.UUID
|
|||||||
)
|
)
|
||||||
pos_created.append(po2)
|
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(
|
po3 = await create_purchase_order(
|
||||||
db, tenant_id, supplier_medium_trust,
|
db, tenant_id, supplier_high_trust,
|
||||||
PurchaseOrderStatus.pending_approval,
|
PurchaseOrderStatus.pending_approval,
|
||||||
Decimal("250.00"),
|
Decimal("450.00"),
|
||||||
created_offset_days=-1,
|
created_offset_days=0,
|
||||||
priority="normal",
|
priority="urgent",
|
||||||
items_data=[
|
items_data=[
|
||||||
{"name": "Harina de Fuerza T65", "quantity": 500, "unit_price": 0.95, "uom": "kg"},
|
{"name": "Harina de Trigo T55", "quantity": 100, "unit_price": 0.85, "uom": "kg"},
|
||||||
{"name": "Mantequilla Premium", "quantity": 80, "unit_price": 5.20, "uom": "kg"},
|
{"name": "Mantequilla sin Sal 82% MG", "quantity": 30, "unit_price": 6.50, "uom": "kg"},
|
||||||
{"name": "Huevos Categoría A", "quantity": 600, "unit_price": 0.22, "uom": "unidad"}
|
{"name": "Huevos Frescos Categoría A", "quantity": 200, "unit_price": 0.25, "uom": "unidad"}
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
pos_created.append(po3)
|
pos_created.append(po3)
|
||||||
|
|||||||
@@ -593,6 +593,105 @@
|
|||||||
"production_notes": "Planificado para mañana",
|
"production_notes": "Planificado para mañana",
|
||||||
"quality_notes": null,
|
"quality_notes": null,
|
||||||
"equipment_used": ["50000000-0000-0000-0000-000000000001"]
|
"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"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
DEMO_TENANT_LA_ESPIGA = uuid.UUID("b2c3d4e5-f6a7-48b9-c0d1-e2f3a4b5c6d7") # Central bakery
|
||||||
|
|
||||||
# Base reference date for date calculations
|
# 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)
|
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)
|
actual_end = actual_start + timedelta(minutes=actual_duration)
|
||||||
completed_at = actual_end
|
completed_at = actual_end
|
||||||
elif batch_data["status"] == "IN_PROGRESS":
|
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_duration = None
|
||||||
actual_end = None
|
actual_end = None
|
||||||
|
|
||||||
|
|||||||
@@ -456,6 +456,9 @@ class ProductionServiceClient(BaseServiceClient):
|
|||||||
"""
|
"""
|
||||||
Get today's production batches for dashboard timeline
|
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:
|
Args:
|
||||||
tenant_id: Tenant ID
|
tenant_id: Tenant ID
|
||||||
|
|
||||||
@@ -463,13 +466,67 @@ class ProductionServiceClient(BaseServiceClient):
|
|||||||
Dict with ProductionBatchListResponse: {"batches": [...], "total_count": n, "page": 1, "page_size": n}
|
Dict with ProductionBatchListResponse: {"batches": [...], "total_count": n, "page": 1, "page_size": n}
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
from datetime import date
|
from datetime import datetime, timezone, timedelta
|
||||||
today = date.today()
|
|
||||||
return await self.get(
|
# 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",
|
"/production/batches",
|
||||||
tenant_id=tenant_id,
|
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:
|
except Exception as e:
|
||||||
logger.error("Error fetching today's batches", error=str(e), tenant_id=tenant_id)
|
logger.error("Error fetching today's batches", error=str(e), tenant_id=tenant_id)
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -125,33 +125,118 @@ class ProductionBatchReasoningData(BaseModel):
|
|||||||
|
|
||||||
def create_po_reasoning_low_stock(
|
def create_po_reasoning_low_stock(
|
||||||
supplier_name: str,
|
supplier_name: str,
|
||||||
product_names: list,
|
product_names: list, # Kept for backward compatibility
|
||||||
current_stock: float,
|
current_stock: float = None, # Kept for backward compatibility
|
||||||
required_stock: float,
|
required_stock: float = None, # Kept for backward compatibility
|
||||||
days_until_stockout: int,
|
days_until_stockout: int = None, # Kept for backward compatibility
|
||||||
threshold_percentage: int = 20,
|
threshold_percentage: int = 20,
|
||||||
affected_products: Optional[list] = None,
|
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]:
|
) -> 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:
|
Args:
|
||||||
supplier_name: Name of the supplier
|
supplier_name: Name of the supplier
|
||||||
product_names: List of product names in the order
|
product_names: List of product names (legacy, for backward compatibility)
|
||||||
current_stock: Current stock level
|
current_stock: Current stock level (legacy)
|
||||||
required_stock: Required stock level
|
required_stock: Required stock level (legacy)
|
||||||
days_until_stockout: Days until stock runs out
|
days_until_stockout: Days until stock runs out (legacy)
|
||||||
threshold_percentage: Stock threshold percentage
|
threshold_percentage: Stock threshold percentage
|
||||||
affected_products: Products that will be affected
|
affected_products: Products that will be affected (legacy)
|
||||||
estimated_lost_orders: Estimated number of lost orders
|
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:
|
Returns:
|
||||||
Reasoning data dictionary
|
Reasoning data dictionary with enhanced supply chain intelligence
|
||||||
"""
|
"""
|
||||||
return {
|
# Determine mode based on parameters
|
||||||
"type": PurchaseOrderReasoningType.LOW_STOCK_DETECTION.value,
|
enhanced_mode = product_details is not None
|
||||||
"parameters": {
|
|
||||||
|
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,
|
"supplier_name": supplier_name,
|
||||||
"product_names": product_names,
|
"product_names": product_names,
|
||||||
"product_count": len(product_names),
|
"product_count": len(product_names),
|
||||||
@@ -159,18 +244,25 @@ def create_po_reasoning_low_stock(
|
|||||||
"required_stock": required_stock,
|
"required_stock": required_stock,
|
||||||
"days_until_stockout": days_until_stockout,
|
"days_until_stockout": days_until_stockout,
|
||||||
"threshold_percentage": threshold_percentage,
|
"threshold_percentage": threshold_percentage,
|
||||||
"stock_percentage": round((current_stock / required_stock * 100), 1) if required_stock > 0 else 0
|
"stock_percentage": round((current_stock / required_stock * 100), 1) if (required_stock and required_stock > 0) else 0
|
||||||
},
|
}
|
||||||
"consequence": {
|
|
||||||
|
consequence = {
|
||||||
"type": "stockout_risk",
|
"type": "stockout_risk",
|
||||||
"severity": ConsequenceSeverity.HIGH.value if days_until_stockout <= 2 else ConsequenceSeverity.MEDIUM.value,
|
"severity": ConsequenceSeverity.HIGH.value if days_until_stockout and days_until_stockout <= 2 else ConsequenceSeverity.MEDIUM.value,
|
||||||
"impact_days": days_until_stockout,
|
"impact_days": days_until_stockout or 7,
|
||||||
"affected_products": affected_products or [],
|
"affected_products": affected_products or [],
|
||||||
"estimated_lost_orders": estimated_lost_orders or 0
|
"estimated_lost_orders": estimated_lost_orders or 0
|
||||||
},
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"type": PurchaseOrderReasoningType.LOW_STOCK_DETECTION.value,
|
||||||
|
"parameters": parameters,
|
||||||
|
"consequence": consequence,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"trigger_source": "orchestrator_auto",
|
"trigger_source": "orchestrator_auto",
|
||||||
"ai_assisted": True
|
"ai_assisted": True,
|
||||||
|
"enhanced_mode": enhanced_mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user