Improve the frontend and fix TODOs
This commit is contained in:
@@ -100,6 +100,9 @@ class DashboardService:
|
||||
stock_value_trend = await self._get_stock_value_trend(db, tenant_id, days=30)
|
||||
alert_trend = await dashboard_repo.get_alert_trend(tenant_id, days=30)
|
||||
|
||||
# Get stock summary for total stock items
|
||||
stock_summary = await repos['stock_repo'].get_stock_summary_by_tenant(tenant_id)
|
||||
|
||||
# Recent activity
|
||||
recent_activity = await self.get_recent_activity(db, tenant_id, limit=10)
|
||||
|
||||
@@ -108,7 +111,7 @@ class DashboardService:
|
||||
total_ingredients=inventory_summary.total_ingredients,
|
||||
active_ingredients=inventory_summary.total_ingredients, # Assuming all are active
|
||||
total_stock_value=inventory_summary.total_stock_value,
|
||||
total_stock_items=await self._get_total_stock_items(db, tenant_id),
|
||||
total_stock_items=stock_summary.get('total_stock_items', 0),
|
||||
|
||||
# Stock status breakdown
|
||||
in_stock_items=await self._get_in_stock_count(db, tenant_id),
|
||||
@@ -872,6 +875,201 @@ class DashboardService:
|
||||
"temperature_compliance_rate": Decimal("100")
|
||||
}
|
||||
|
||||
async def _get_in_stock_count(self, db, tenant_id: UUID) -> int:
|
||||
"""Get count of items currently in stock"""
|
||||
try:
|
||||
repos = self._get_repositories(db)
|
||||
stock_repo = repos['stock_repo']
|
||||
|
||||
# Get stock summary and extract in-stock count
|
||||
stock_summary = await stock_repo.get_stock_summary_by_tenant(tenant_id)
|
||||
return stock_summary.get('in_stock_items', 0)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to get in-stock count", error=str(e))
|
||||
return 0
|
||||
|
||||
async def _get_ingredient_metrics(self, db, tenant_id: UUID) -> Dict[str, Any]:
|
||||
"""Get ingredient metrics for business model analysis"""
|
||||
try:
|
||||
repos = self._get_repositories(db)
|
||||
ingredient_repo = repos['ingredient_repo']
|
||||
|
||||
# Get all ingredients for the tenant
|
||||
ingredients = await ingredient_repo.get_ingredients_by_tenant(tenant_id, limit=1000)
|
||||
|
||||
if not ingredients:
|
||||
return {
|
||||
"total_types": 0,
|
||||
"avg_stock": 0.0,
|
||||
"finished_product_ratio": 0.0,
|
||||
"supplier_count": 0
|
||||
}
|
||||
|
||||
# Calculate metrics
|
||||
total_types = len(ingredients)
|
||||
|
||||
# Calculate average stock per ingredient
|
||||
total_stock = sum(float(i.current_stock_level or 0) for i in ingredients)
|
||||
avg_stock = total_stock / total_types if total_types > 0 else 0
|
||||
|
||||
# Calculate finished product ratio
|
||||
finished_products = len([i for i in ingredients if hasattr(i, 'product_type') and i.product_type and i.product_type.value == 'finished_product'])
|
||||
finished_ratio = finished_products / total_types if total_types > 0 else 0
|
||||
|
||||
# Estimate supplier diversity (simplified)
|
||||
supplier_count = len(set(str(i.supplier_id) for i in ingredients if hasattr(i, 'supplier_id') and i.supplier_id)) or 1
|
||||
|
||||
return {
|
||||
"total_types": total_types,
|
||||
"avg_stock": avg_stock,
|
||||
"finished_product_ratio": finished_ratio,
|
||||
"supplier_count": supplier_count
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to get ingredient metrics", error=str(e))
|
||||
return {
|
||||
"total_types": 0,
|
||||
"avg_stock": 0.0,
|
||||
"finished_product_ratio": 0.0,
|
||||
"supplier_count": 0
|
||||
}
|
||||
|
||||
async def _analyze_operational_patterns(self, db, tenant_id: UUID) -> Dict[str, Any]:
|
||||
"""Analyze operational patterns for business model insights"""
|
||||
try:
|
||||
repos = self._get_repositories(db)
|
||||
|
||||
# Get ingredients to analyze patterns
|
||||
ingredients = await repos['ingredient_repo'].get_ingredients_by_tenant(tenant_id, limit=1000)
|
||||
|
||||
if not ingredients:
|
||||
return {
|
||||
"order_frequency": "unknown",
|
||||
"seasonal_variation": "low",
|
||||
"bulk_indicator": "unknown",
|
||||
"scale_indicator": "small"
|
||||
}
|
||||
|
||||
# Analyze order frequency based on reorder patterns
|
||||
frequent_reorders = len([i for i in ingredients if hasattr(i, 'reorder_frequency') and i.reorder_frequency and i.reorder_frequency > 5])
|
||||
infrequent_reorders = len([i for i in ingredients if hasattr(i, 'reorder_frequency') and i.reorder_frequency and i.reorder_frequency <= 2])
|
||||
|
||||
if frequent_reorders > len(ingredients) * 0.3:
|
||||
order_frequency = "high"
|
||||
elif infrequent_reorders > len(ingredients) * 0.4:
|
||||
order_frequency = "low"
|
||||
else:
|
||||
order_frequency = "moderate"
|
||||
|
||||
# Analyze seasonal variation (simplified estimation)
|
||||
seasonal_variation = "moderate" # Default assumption for bakery business
|
||||
|
||||
# Analyze bulk purchasing indicator
|
||||
bulk_items = len([i for i in ingredients if hasattr(i, 'bulk_order_quantity') and i.bulk_order_quantity and i.bulk_order_quantity > 100])
|
||||
if bulk_items > len(ingredients) * 0.2:
|
||||
bulk_indicator = "high"
|
||||
elif bulk_items < len(ingredients) * 0.05:
|
||||
bulk_indicator = "low"
|
||||
else:
|
||||
bulk_indicator = "moderate"
|
||||
|
||||
# Analyze production scale
|
||||
total_ingredients = len(ingredients)
|
||||
if total_ingredients > 500:
|
||||
scale_indicator = "large"
|
||||
elif total_ingredients > 100:
|
||||
scale_indicator = "medium"
|
||||
else:
|
||||
scale_indicator = "small"
|
||||
|
||||
return {
|
||||
"order_frequency": order_frequency,
|
||||
"seasonal_variation": seasonal_variation,
|
||||
"bulk_indicator": bulk_indicator,
|
||||
"scale_indicator": scale_indicator
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to analyze operational patterns", error=str(e))
|
||||
return {
|
||||
"order_frequency": "unknown",
|
||||
"seasonal_variation": "low",
|
||||
"bulk_indicator": "unknown",
|
||||
"scale_indicator": "small"
|
||||
}
|
||||
|
||||
async def _generate_model_recommendations(
|
||||
self,
|
||||
model: str,
|
||||
ingredient_metrics: Dict[str, Any],
|
||||
operational_patterns: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
"""Generate business model specific recommendations"""
|
||||
try:
|
||||
recommendations = {
|
||||
"specific": [],
|
||||
"optimization": []
|
||||
}
|
||||
|
||||
# Model-specific recommendations
|
||||
if model == "central_bakery":
|
||||
recommendations["specific"].extend([
|
||||
"Optimize distribution network for multi-location delivery",
|
||||
"Implement centralized procurement for bulk discounts",
|
||||
"Standardize recipes across all production facilities"
|
||||
])
|
||||
|
||||
if operational_patterns.get("scale_indicator") == "large":
|
||||
recommendations["optimization"].extend([
|
||||
"Automate inter-facility transfers",
|
||||
"Implement predictive demand forecasting",
|
||||
"Optimize fleet routing for distribution"
|
||||
])
|
||||
|
||||
elif model == "individual_bakery":
|
||||
recommendations["specific"].extend([
|
||||
"Focus on local sourcing to reduce costs",
|
||||
"Implement just-in-time production scheduling",
|
||||
"Optimize single-location workflow efficiency"
|
||||
])
|
||||
|
||||
recommendations["optimization"].extend([
|
||||
"Reduce waste through better portion control",
|
||||
"Implement daily production planning",
|
||||
"Optimize oven scheduling for energy efficiency"
|
||||
])
|
||||
|
||||
elif model == "mixed":
|
||||
recommendations["specific"].extend([
|
||||
"Balance centralized and decentralized operations",
|
||||
"Implement hybrid sourcing strategy",
|
||||
"Maintain flexibility in production planning"
|
||||
])
|
||||
|
||||
recommendations["optimization"].extend([
|
||||
"Optimize batch sizes for efficiency",
|
||||
"Implement cross-training for staff flexibility",
|
||||
"Balance inventory across multiple locations"
|
||||
])
|
||||
|
||||
# Generic recommendations based on metrics
|
||||
if ingredient_metrics.get("finished_product_ratio", 0) > 0.5:
|
||||
recommendations["optimization"].append("Focus on finished product quality control")
|
||||
|
||||
if operational_patterns.get("order_frequency") == "high":
|
||||
recommendations["optimization"].append("Streamline ordering process with automated reordering")
|
||||
|
||||
return recommendations
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to generate model recommendations", error=str(e))
|
||||
return {
|
||||
"specific": ["Review business model configuration"],
|
||||
"optimization": ["Analyze operational data for insights"]
|
||||
}
|
||||
|
||||
async def _analyze_inventory_performance(self, db, tenant_id: UUID, days_back: int) -> Dict[str, Any]:
|
||||
"""Analyze overall inventory performance metrics using real data"""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user