Fix AI insights feature issues

This commit is contained in:
Urtzi Alfaro
2025-12-16 13:32:33 +01:00
parent b43648e0f8
commit 0bbfa010bf
5 changed files with 576 additions and 55 deletions

View File

@@ -501,15 +501,157 @@ class SalesService:
error=str(e), product_id=product_id, tenant_id=tenant_id)
return None
async def get_inventory_products_by_category(self, category: str, tenant_id: UUID,
async def get_inventory_products_by_category(self, category: str, tenant_id: UUID,
product_type: Optional[str] = None) -> List[Dict[str, Any]]:
"""Get products by category from inventory service"""
try:
products = await self.inventory_client.get_products_by_category(category, tenant_id, product_type)
logger.info("Retrieved inventory products by category", category=category,
logger.info("Retrieved inventory products by category", category=category,
count=len(products), tenant_id=tenant_id)
return products
except Exception as e:
logger.error("Failed to get inventory products by category",
logger.error("Failed to get inventory products by category",
error=str(e), category=category, tenant_id=tenant_id)
return []
return []
async def analyze_product_demand_patterns(
self,
tenant_id: UUID,
inventory_product_id: UUID,
start_date: Optional[datetime] = None,
end_date: Optional[datetime] = None,
min_history_days: int = 90
) -> Dict[str, Any]:
"""
Analyze demand patterns for a specific product from historical sales data.
This method provides insights on:
- Demand trends (increasing/decreasing)
- Volatility (coefficient of variation)
- Weekly seasonal patterns
- Peak/low demand days
Args:
tenant_id: Tenant identifier
inventory_product_id: Product identifier
start_date: Start date for analysis (optional)
end_date: End date for analysis (optional)
min_history_days: Minimum days of history required
Returns:
Analysis results with patterns, trends, and statistics
"""
try:
import pandas as pd
logger.info(
"Analyzing product demand patterns",
tenant_id=tenant_id,
inventory_product_id=inventory_product_id
)
# Fetch sales data for the product
sales_records = await self.get_product_sales(
tenant_id=tenant_id,
inventory_product_id=inventory_product_id,
start_date=start_date,
end_date=end_date
)
if not sales_records or len(sales_records) < min_history_days:
return {
'analyzed_at': datetime.utcnow().isoformat(),
'history_days': len(sales_records) if sales_records else 0,
'patterns': {},
'trend_analysis': {},
'seasonal_factors': {},
'statistics': {},
'error': f'Insufficient historical data (need {min_history_days} days, got {len(sales_records) if sales_records else 0})'
}
# Convert to DataFrame for analysis
sales_data = pd.DataFrame([{
'date': record.date,
'quantity': record.quantity_sold,
'revenue': float(record.revenue) if record.revenue else 0
} for record in sales_records])
sales_data['date'] = pd.to_datetime(sales_data['date'])
sales_data = sales_data.sort_values('date')
# Calculate basic statistics
mean_demand = sales_data['quantity'].mean()
std_demand = sales_data['quantity'].std()
cv = (std_demand / mean_demand) if mean_demand > 0 else 0
# Trend analysis
sales_data['days_since_start'] = (sales_data['date'] - sales_data['date'].min()).dt.days
trend_correlation = sales_data['days_since_start'].corr(sales_data['quantity'])
is_increasing = trend_correlation > 0.2
is_decreasing = trend_correlation < -0.2
# Seasonal pattern detection (day of week)
sales_data['day_of_week'] = sales_data['date'].dt.dayofweek
weekly_pattern = sales_data.groupby('day_of_week')['quantity'].mean().to_dict()
peak_day = max(weekly_pattern, key=weekly_pattern.get)
low_day = min(weekly_pattern, key=weekly_pattern.get)
peak_ratio = weekly_pattern[peak_day] / weekly_pattern[low_day] if weekly_pattern[low_day] > 0 else 1.0
logger.info(
"Demand pattern analysis complete",
tenant_id=tenant_id,
inventory_product_id=inventory_product_id,
data_points=len(sales_data),
trend_direction='increasing' if is_increasing else 'decreasing' if is_decreasing else 'stable'
)
return {
'analyzed_at': datetime.utcnow().isoformat(),
'history_days': len(sales_data),
'date_range': {
'start': sales_data['date'].min().isoformat(),
'end': sales_data['date'].max().isoformat()
},
'statistics': {
'mean_demand': round(mean_demand, 2),
'std_demand': round(std_demand, 2),
'coefficient_of_variation': round(cv, 3),
'total_quantity': round(sales_data['quantity'].sum(), 2),
'total_revenue': round(sales_data['revenue'].sum(), 2),
'min_demand': round(sales_data['quantity'].min(), 2),
'max_demand': round(sales_data['quantity'].max(), 2)
},
'trend_analysis': {
'correlation': round(trend_correlation, 3),
'is_increasing': is_increasing,
'is_decreasing': is_decreasing,
'direction': 'increasing' if is_increasing else 'decreasing' if is_decreasing else 'stable'
},
'patterns': {
'weekly_pattern': {str(k): round(v, 2) for k, v in weekly_pattern.items()},
'peak_day': int(peak_day),
'low_day': int(low_day)
},
'seasonal_factors': {
'peak_ratio': round(peak_ratio, 2),
'has_strong_pattern': peak_ratio > 1.5
}
}
except Exception as e:
logger.error(
"Error analyzing product demand patterns",
tenant_id=tenant_id,
inventory_product_id=inventory_product_id,
error=str(e),
exc_info=True
)
return {
'analyzed_at': datetime.utcnow().isoformat(),
'history_days': 0,
'patterns': {},
'trend_analysis': {},
'seasonal_factors': {},
'statistics': {},
'error': str(e)
}