Fix new services implementation 11

This commit is contained in:
Urtzi Alfaro
2025-08-16 08:43:35 +02:00
parent 119beb541f
commit 995a51e285
8 changed files with 114 additions and 71 deletions

View File

@@ -15,6 +15,7 @@ import ForecastPage from './pages/forecast/ForecastPage';
import OrdersPage from './pages/orders/OrdersPage';
import InventoryPage from './pages/inventory/InventoryPage';
import SalesPage from './pages/sales/SalesPage';
import RecipesPage from './pages/recipes/RecipesPage';
import SettingsPage from './pages/settings/SettingsPage';
import Layout from './components/layout/Layout';
@@ -31,7 +32,7 @@ import './i18n';
// Global styles
import './styles/globals.css';
type CurrentPage = 'landing' | 'login' | 'register' | 'onboarding' | 'dashboard' | 'reports' | 'orders' | 'production' | 'inventory' | 'sales' | 'settings';
type CurrentPage = 'landing' | 'login' | 'register' | 'onboarding' | 'dashboard' | 'reports' | 'orders' | 'production' | 'inventory' | 'recipes' | 'sales' | 'settings';
interface User {
id: string;
@@ -295,6 +296,8 @@ const App: React.FC = () => {
return <ProductionPage />;
case 'inventory':
return <InventoryPage />;
case 'recipes':
return <RecipesPage />;
case 'sales':
return <SalesPage />;
case 'settings':
@@ -305,6 +308,7 @@ const App: React.FC = () => {
onNavigateToReports={() => navigateTo('reports')}
onNavigateToProduction={() => navigateTo('production')}
onNavigateToInventory={() => navigateTo('inventory')}
onNavigateToRecipes={() => navigateTo('recipes')}
onNavigateToSales={() => navigateTo('sales')}
/>;
}

View File

@@ -304,9 +304,11 @@ private buildURL(endpoint: string): string {
}
const responseData = await response.json();
console.log('🔍 Raw responseData from fetch:', responseData);
// Apply response interceptors
const processedResponse = await this.applyResponseInterceptors(responseData);
console.log('🔍 processedResponse after interceptors:', processedResponse);
return processedResponse;
});
@@ -335,9 +337,14 @@ private buildURL(endpoint: string): string {
// Handle both wrapped and unwrapped responses
// If result has a 'data' property, return it; otherwise return the result itself
console.log('🔍 Final result before return:', result);
console.log('🔍 Result has data property?', result && typeof result === 'object' && 'data' in result);
if (result && typeof result === 'object' && 'data' in result) {
console.log('🔍 Returning result.data:', result.data);
return result.data as T;
}
console.log('🔍 Returning raw result:', result);
return result as T;
} catch (error) {
// Record error metrics

View File

@@ -550,27 +550,46 @@ export class InventoryService {
const response = await apiClient.get(`/tenants/${tenantId}/ingredients`, {
params: {
limit: 100,
product_type: 'finished_product' // Only get finished products, not raw ingredients
product_type: 'finished_product'
},
});
console.log('🔍 Inventory Products API Response:', response);
console.log('🔍 Raw response data:', response.data);
console.log('🔍 Response status:', response.status);
console.log('🔍 Response headers:', response.headers);
console.log('🔍 Full response object keys:', Object.keys(response || {}));
console.log('🔍 Response data type:', typeof response);
console.log('🔍 Response data constructor:', response?.constructor?.name);
// Check if response.data exists and what type it is
if (response && 'data' in response) {
console.log('🔍 Response.data exists:', typeof response.data);
console.log('🔍 Response.data keys:', Object.keys(response.data || {}));
console.log('🔍 Response.data constructor:', response.data?.constructor?.name);
}
let productsArray: any[] = [];
if (Array.isArray(response)) {
productsArray = response;
} else if (response && typeof response === 'object') {
// Check response.data first (typical API client behavior)
const dataToProcess = response?.data || response;
if (Array.isArray(dataToProcess)) {
productsArray = dataToProcess;
console.log('✅ Found array data with', productsArray.length, 'items');
} else if (dataToProcess && typeof dataToProcess === 'object') {
// Handle different response formats
const keys = Object.keys(response);
const keys = Object.keys(dataToProcess);
if (keys.length > 0 && keys.every(key => !isNaN(Number(key)))) {
productsArray = Object.values(response);
productsArray = Object.values(dataToProcess);
console.log('✅ Found object with numeric keys, converted to array with', productsArray.length, 'items');
} else {
console.warn('⚠️ Response is object but not with numeric keys:', response);
console.warn('⚠️ Response is object but not with numeric keys:', dataToProcess);
console.warn('⚠️ Object keys:', keys);
return [];
}
} else {
console.warn('⚠️ Response is not array or object:', response);
console.warn('⚠️ Response data is not array or object:', dataToProcess);
return [];
}
@@ -593,8 +612,19 @@ export class InventoryService {
} catch (error) {
console.error('❌ Failed to fetch inventory products:', error);
console.error('❌ Error details:', {
message: error instanceof Error ? error.message : 'Unknown error',
response: (error as any)?.response,
status: (error as any)?.response?.status,
data: (error as any)?.response?.data
});
// Return empty array on error - let dashboard handle fallback
// If it's an authentication error, throw it to trigger auth flow
if ((error as any)?.response?.status === 401) {
throw error;
}
// Return empty array on other errors - let dashboard handle fallback
return [];
}
}

View File

@@ -12,6 +12,10 @@ export interface ProductInfo {
sales_count?: number;
total_quantity?: number;
last_sale_date?: string;
// Additional inventory fields
current_stock?: number;
unit?: string;
cost_per_unit?: number;
}
export interface SalesData {

View File

@@ -12,7 +12,8 @@ import {
ChevronDown,
ChefHat,
Warehouse,
ShoppingCart
ShoppingCart,
BookOpen
} from 'lucide-react';
interface LayoutProps {
@@ -44,6 +45,7 @@ const Layout: React.FC<LayoutProps> = ({
{ id: 'dashboard', label: 'Inicio', icon: Home, href: '/dashboard' },
{ id: 'orders', label: 'Pedidos', icon: Package, href: '/orders' },
{ id: 'production', label: 'Producción', icon: ChefHat, href: '/production' },
{ id: 'recipes', label: 'Recetas', icon: BookOpen, href: '/recipes' },
{ id: 'inventory', label: 'Inventario', icon: Warehouse, href: '/inventory' },
{ id: 'sales', label: 'Ventas', icon: ShoppingCart, href: '/sales' },
{ id: 'reports', label: 'Informes', icon: TrendingUp, href: '/reports' },

View File

@@ -224,6 +224,7 @@ export const useDashboard = () => {
return {
...dashboardData,
tenantId,
isLoading: isLoading || salesLoading || inventoryLoading || externalLoading || forecastLoading,
error: error || salesError || inventoryError || externalError || forecastError,
reload: () => tenantId ? loadDashboardData(tenantId) : Promise.resolve(),

View File

@@ -32,13 +32,16 @@ const SUPPLIERS: Record<string, string> = {
'Bolsas papel': 'Distribuciones Madrid',
};
export const useOrderSuggestions = () => {
export const useOrderSuggestions = (providedTenantId?: string | null) => {
const [dailyOrders, setDailyOrders] = useState<DailyOrderItem[]>([]);
const [weeklyOrders, setWeeklyOrders] = useState<WeeklyOrderItem[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { tenantId, isLoading: tenantLoading, error: tenantError } = useTenantId();
const { tenantId: hookTenantId, isLoading: tenantLoading, error: tenantError } = useTenantId();
// Use provided tenant ID if available, otherwise use hook tenant ID
const tenantId = providedTenantId !== undefined ? providedTenantId : hookTenantId;
console.log('🏢 OrderSuggestions: Tenant info:', { tenantId, tenantLoading, tenantError });
const {
@@ -65,43 +68,32 @@ export const useOrderSuggestions = () => {
console.log('📊 OrderSuggestions: Generating daily suggestions for tenant:', tenantId);
// Get products list from backend
let products: string[] = [];
try {
products = await getProductsList(tenantId);
console.log('📋 OrderSuggestions: Products list:', products);
} catch (error) {
console.error('❌ OrderSuggestions: Failed to get products list:', error);
throw error;
}
const productsList = await getProductsList(tenantId);
const products = productsList.map(p => p.name);
console.log('📋 OrderSuggestions: Products list:', products);
// Filter for daily bakery products (case insensitive)
const dailyProductKeywords = ['pan', 'baguette', 'croissant', 'magdalena'];
const dailyProducts = products.filter(p =>
['Pan de Molde', 'Baguettes', 'Croissants', 'Magdalenas'].includes(p)
dailyProductKeywords.some(keyword =>
p.toLowerCase().includes(keyword.toLowerCase())
)
);
console.log('🥖 OrderSuggestions: Daily products:', dailyProducts);
// Get quick forecasts for these products
let quickForecasts: any[] = [];
try {
quickForecasts = await getQuickForecasts(tenantId);
console.log('🔮 OrderSuggestions: Quick forecasts:', quickForecasts);
} catch (error) {
console.error('❌ OrderSuggestions: Failed to get quick forecasts:', error);
throw error;
}
const quickForecasts = await getQuickForecasts(tenantId);
console.log('🔮 OrderSuggestions: Quick forecasts:', quickForecasts);
// Get weather data to determine urgency
let weather: any = null;
try {
weather = await getCurrentWeather(tenantId, 40.4168, -3.7038);
console.log('🌤️ OrderSuggestions: Weather data:', weather);
} catch (error) {
console.error('❌ OrderSuggestions: Failed to get current weather:', error);
throw error;
}
const weather = await getCurrentWeather(tenantId, 40.4168, -3.7038);
console.log('🌤️ OrderSuggestions: Weather data:', weather);
const suggestions: DailyOrderItem[] = [];
console.log('🔄 OrderSuggestions: Processing daily products:', dailyProducts);
for (const product of dailyProducts) {
console.log('🔄 OrderSuggestions: Processing product:', product);
// Find forecast for this product
const forecast = quickForecasts.find(f =>
f.product_name === product || f.inventory_product_id === product
@@ -145,14 +137,15 @@ export const useOrderSuggestions = () => {
};
suggestions.push(orderItem);
console.log(' OrderSuggestions: Added daily suggestion:', orderItem);
}
}
console.log('🎯 OrderSuggestions: Final daily suggestions:', suggestions);
return suggestions;
} catch (error) {
console.error('❌ OrderSuggestions: Error generating daily suggestions, using fallback:', error);
// Return mock data as fallback
return getMockDailyOrders();
console.error('❌ OrderSuggestions: Error in generateDailyOrderSuggestions:', error);
return [];
}
}, [tenantId, getProductsList, getQuickForecasts, getCurrentWeather]);
@@ -160,21 +153,14 @@ export const useOrderSuggestions = () => {
const generateWeeklyOrderSuggestions = useCallback(async (): Promise<WeeklyOrderItem[]> => {
if (!tenantId) return [];
try {
console.log('📊 OrderSuggestions: Generating weekly suggestions for tenant:', tenantId);
console.log('📊 OrderSuggestions: Generating weekly suggestions for tenant:', tenantId);
// Get sales analytics for the past month
const endDate = new Date().toISOString();
const startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
let analytics: any = null;
try {
analytics = await getSalesAnalytics(tenantId, startDate, endDate);
console.log('📈 OrderSuggestions: Sales analytics:', analytics);
} catch (error) {
console.error('❌ OrderSuggestions: Failed to get sales analytics:', error);
throw error;
}
const analytics = await getSalesAnalytics(tenantId, startDate, endDate);
console.log('📈 OrderSuggestions: Sales analytics:', analytics);
// Weekly products (ingredients and supplies)
const weeklyProducts = [
@@ -221,11 +207,6 @@ export const useOrderSuggestions = () => {
}
return suggestions.sort((a, b) => a.stockDays - b.stockDays); // Sort by urgency
} catch (error) {
console.error('❌ OrderSuggestions: Error generating weekly suggestions, using fallback:', error);
// Return mock data as fallback
return getMockWeeklyOrders();
}
}, [tenantId, getSalesAnalytics]);
// Load order suggestions
@@ -233,10 +214,7 @@ export const useOrderSuggestions = () => {
console.log('🔍 OrderSuggestions: loadOrderSuggestions called, tenantId:', tenantId);
if (!tenantId) {
console.log('❌ OrderSuggestions: No tenantId available, loading mock data');
// Load mock data when tenant ID is not available
setDailyOrders(getMockDailyOrders());
setWeeklyOrders(getMockWeeklyOrders());
console.log('❌ OrderSuggestions: No tenantId available, skipping load');
return;
}
@@ -245,15 +223,21 @@ export const useOrderSuggestions = () => {
try {
console.log('📊 OrderSuggestions: Starting to generate suggestions...');
console.log('📊 OrderSuggestions: About to call generateDailyOrderSuggestions');
const [daily, weekly] = await Promise.all([
generateDailyOrderSuggestions(),
generateWeeklyOrderSuggestions()
]);
const dailyPromise = generateDailyOrderSuggestions();
console.log('📊 OrderSuggestions: About to call generateWeeklyOrderSuggestions');
const weeklyPromise = generateWeeklyOrderSuggestions();
console.log('📊 OrderSuggestions: Waiting for both promises to resolve...');
const [daily, weekly] = await Promise.all([dailyPromise, weeklyPromise]);
console.log('✅ OrderSuggestions: Generated suggestions:', {
dailyCount: daily.length,
weeklyCount: weekly.length
weeklyCount: weekly.length,
dailyData: daily,
weeklyData: weekly
});
setDailyOrders(daily);
@@ -268,9 +252,13 @@ export const useOrderSuggestions = () => {
// Load on mount and when tenant changes
useEffect(() => {
console.log('🔄 OrderSuggestions: useEffect triggered, tenantId:', tenantId);
loadOrderSuggestions();
}, [loadOrderSuggestions]);
console.log('🔄 OrderSuggestions: useEffect triggered, tenantId:', tenantId, 'tenantLoading:', tenantLoading);
// Only load if we have a tenantId or if tenant loading is complete
if (tenantId || !tenantLoading) {
loadOrderSuggestions();
}
}, [tenantId, tenantLoading, loadOrderSuggestions]);
return {
dailyOrders,

View File

@@ -15,15 +15,22 @@ interface DashboardPageProps {
onNavigateToOrders?: () => void;
onNavigateToReports?: () => void;
onNavigateToProduction?: () => void;
onNavigateToInventory?: () => void;
onNavigateToRecipes?: () => void;
onNavigateToSales?: () => void;
}
const DashboardPage: React.FC<DashboardPageProps> = ({
onNavigateToOrders,
onNavigateToReports,
onNavigateToProduction
onNavigateToProduction,
onNavigateToInventory,
onNavigateToRecipes,
onNavigateToSales
}) => {
const {
weather,
tenantId,
isLoading,
error,
reload,
@@ -31,13 +38,13 @@ const DashboardPage: React.FC<DashboardPageProps> = ({
metrics
} = useDashboard();
// Use real API data for order suggestions
// Use real API data for order suggestions - pass tenantId from dashboard
const {
dailyOrders: realDailyOrders,
weeklyOrders: realWeeklyOrders,
isLoading: ordersLoading,
error: ordersError
} = useOrderSuggestions();
} = useOrderSuggestions(tenantId);
// Debug order suggestions
console.log('📈 Dashboard: OrderSuggestions data:', {