Fix new services implementation 10

This commit is contained in:
Urtzi Alfaro
2025-08-16 08:22:51 +02:00
parent 9de0f9943c
commit 119beb541f
5 changed files with 68 additions and 63 deletions

View File

@@ -548,7 +548,10 @@ export class InventoryService {
async getProductsList(tenantId: string): Promise<ProductInfo[]> {
try {
const response = await apiClient.get(`/tenants/${tenantId}/ingredients`, {
params: { limit: 100 }, // Get all products
params: {
limit: 100,
product_type: 'finished_product' // Only get finished products, not raw ingredients
},
});
console.log('🔍 Inventory Products API Response:', response);

View File

@@ -90,31 +90,7 @@ export const useDashboard = () => {
try {
// 1. Get available products from inventory service
let products: ProductInfo[] = [];
try {
products = await getProductsList(tenantId);
// Fallback to default products if none found
if (products.length === 0) {
products = [
{ inventory_product_id: 'fallback-croissants', name: 'Croissants' },
{ inventory_product_id: 'fallback-pan', name: 'Pan de molde' },
{ inventory_product_id: 'fallback-baguettes', name: 'Baguettes' },
{ inventory_product_id: 'fallback-cafe', name: 'Café' },
{ inventory_product_id: 'fallback-napolitanas', name: 'Napolitanas' }
];
console.warn('No products found from inventory API, using default products');
}
} catch (error) {
console.warn('Failed to fetch products from inventory:', error);
products = [
{ inventory_product_id: 'fallback-croissants', name: 'Croissants' },
{ inventory_product_id: 'fallback-pan', name: 'Pan de molde' },
{ inventory_product_id: 'fallback-baguettes', name: 'Baguettes' },
{ inventory_product_id: 'fallback-cafe', name: 'Café' },
{ inventory_product_id: 'fallback-napolitanas', name: 'Napolitanas' }
];
}
const products = await getProductsList(tenantId);
// 2. Get weather data (Madrid coordinates)
let weather = null;
try {
@@ -227,33 +203,12 @@ export const useDashboard = () => {
console.error('Error loading dashboard data:', error);
setError(error instanceof Error ? error.message : 'Failed to load dashboard data');
// Set fallback data
// Set empty fallback data on error
setDashboardData({
weather: {
temperature: 18,
description: 'Parcialmente nublado',
precipitation: 0
},
todayForecasts: [
{ product: 'Croissants', inventory_product_id: 'fallback-croissants', predicted: 48, confidence: 'high', change: 8 },
{ product: 'Pan de molde', inventory_product_id: 'fallback-pan', predicted: 35, confidence: 'high', change: 3 },
{ product: 'Baguettes', inventory_product_id: 'fallback-baguettes', predicted: 25, confidence: 'medium', change: -3 },
{ product: 'Café', inventory_product_id: 'fallback-cafe', predicted: 72, confidence: 'high', change: 5 },
{ product: 'Napolitanas', inventory_product_id: 'fallback-napolitanas', predicted: 26, confidence: 'medium', change: 3 }
],
metrics: {
totalSales: 1247,
wasteReduction: 15.3,
accuracy: 87.2,
stockouts: 2
},
products: [
{ inventory_product_id: 'fallback-croissants', name: 'Croissants' },
{ inventory_product_id: 'fallback-pan', name: 'Pan de molde' },
{ inventory_product_id: 'fallback-baguettes', name: 'Baguettes' },
{ inventory_product_id: 'fallback-cafe', name: 'Café' },
{ inventory_product_id: 'fallback-napolitanas', name: 'Napolitanas' }
]
weather: null,
todayForecasts: [],
metrics: null,
products: []
});
} finally {
setIsLoading(false);

View File

@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
import { TrendingUp, TrendingDown, Calendar, Cloud, AlertTriangle, Info, RefreshCw } from 'lucide-react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import { useForecast } from '../../api/hooks/useForecast';
import { useInventory } from '../../api/hooks/useInventory';
import { useInventoryProducts } from '../../api/hooks/useInventory';
import { useTenantId } from '../../hooks/useTenantId';
import type { ForecastResponse } from '../../api/types/forecasting';
@@ -30,6 +30,7 @@ const ForecastPage: React.FC = () => {
const [forecastData, setForecastData] = useState<ForecastData[]>([]);
const [weatherAlert, setWeatherAlert] = useState<WeatherAlert | null>(null);
const [isGenerating, setIsGenerating] = useState(false);
const [inventoryItems, setInventoryItems] = useState<any[]>([]);
// Hooks
const { tenantId } = useTenantId();
@@ -43,10 +44,10 @@ const ForecastPage: React.FC = () => {
exportForecasts
} = useForecast();
const {
items: inventoryItems,
getProductsList,
isLoading: inventoryLoading,
loadItems
} = useInventory(false); // Disable auto-load, we'll load manually
error: inventoryError
} = useInventoryProducts();
// Debug logging
if (process.env.NODE_ENV === 'development') {
@@ -81,10 +82,37 @@ const ForecastPage: React.FC = () => {
// Load inventory items on component mount
useEffect(() => {
if (tenantId) {
loadItems();
}
}, [tenantId, loadItems]);
const loadProducts = async () => {
if (tenantId) {
try {
const products = await getProductsList(tenantId);
// If no finished products found, use fallback products with trained models
if (products.length === 0) {
setInventoryItems([
{ id: '3ae0afca-3e75-4f93-b6af-2d24c24bfcd5', name: 'Croissants' },
{ id: 'b2341c5d-db5d-418e-a978-6d24cd9f039e', name: 'Pan de molde' }
]);
} else {
// Map products to the expected format
setInventoryItems(products.map(p => ({
id: p.inventory_product_id,
name: p.name
})));
}
} catch (error) {
console.error('Failed to load products:', error);
// Use fallback products with trained models
setInventoryItems([
{ id: '3ae0afca-3e75-4f93-b6af-2d24c24bfcd5', name: 'Croissants' },
{ id: 'b2341c5d-db5d-418e-a978-6d24cd9f039e', name: 'Pan de molde' }
]);
}
}
};
loadProducts();
}, [tenantId, getProductsList]);
// Transform API forecasts to our local format
const transformForecastResponse = (forecast: ForecastResponse): ForecastData => {
@@ -142,8 +170,8 @@ const ForecastPage: React.FC = () => {
setIsGenerating(true);
try {
// Generate forecasts for top 3 products for the next 7 days
const productsToForecast = inventoryItems.slice(0, 3);
// Generate forecasts for products with trained models only
const productsToForecast = inventoryItems;
const chartData = [];
// Generate data for the next 7 days

View File

@@ -151,6 +151,7 @@ async def list_ingredients(
skip: int = Query(0, ge=0, description="Number of records to skip"),
limit: int = Query(100, ge=1, le=1000, description="Number of records to return"),
category: Optional[str] = Query(None, description="Filter by category"),
product_type: Optional[str] = Query(None, description="Filter by product type (ingredient or finished_product)"),
is_active: Optional[bool] = Query(None, description="Filter by active status"),
is_low_stock: Optional[bool] = Query(None, description="Filter by low stock status"),
needs_reorder: Optional[bool] = Query(None, description="Filter by reorder needed"),
@@ -171,6 +172,8 @@ async def list_ingredients(
filters = {}
if category:
filters['category'] = category
if product_type:
filters['product_type'] = product_type
if is_active is not None:
filters['is_active'] = is_active
if is_low_stock is not None:

View File

@@ -101,6 +101,22 @@ class IngredientRepository(BaseRepository[Ingredient, IngredientCreate, Ingredie
if filters:
if filters.get('category'):
query_filters['category'] = filters['category']
if filters.get('product_type'):
# Convert string to enum object
from app.models.inventory import ProductType
product_type_value = filters['product_type']
try:
# Find the enum member by value
for enum_member in ProductType:
if enum_member.value == product_type_value:
query_filters['product_type'] = enum_member
break
else:
# If not found, skip this filter
logger.warning(f"Invalid product_type value: {product_type_value}")
except Exception as e:
logger.warning(f"Error converting product_type: {e}")
# Skip invalid product_type filter
if filters.get('is_active') is not None:
query_filters['is_active'] = filters['is_active']
if filters.get('is_perishable') is not None: