diff --git a/frontend/src/components/domain/onboarding/steps/SmartInventorySetupStep.tsx b/frontend/src/components/domain/onboarding/steps/SmartInventorySetupStep.tsx index 7ff31c6e..502e138f 100644 --- a/frontend/src/components/domain/onboarding/steps/SmartInventorySetupStep.tsx +++ b/frontend/src/components/domain/onboarding/steps/SmartInventorySetupStep.tsx @@ -122,16 +122,6 @@ export const SmartInventorySetupStep: React.FC = ({ const result = Boolean(hasAuth && (hasTenantId || tenantCreatedSuccessfully || tenantCreatedInOnboarding)); - console.log('🔄 SmartInventorySetup - isTenantAvailable check:', { - hasAuth, - authLoading, - hasUser: !!user, - hasTenantId, - tenantId: getTenantId(), - tenantCreatedSuccessfully, - tenantCreatedInOnboarding, - finalResult: result - }); return result; }; @@ -160,7 +150,8 @@ export const SmartInventorySetupStep: React.FC = ({ console.log('🔄 SmartInventorySetup - suggestions effect:', { suggestionsLength: suggestions?.length || 0, productsLength: products.length, - suggestions: suggestions, + suggestionsIsArray: Array.isArray(suggestions), + suggestionsType: typeof suggestions, }); if (suggestions && suggestions.length > 0 && products.length === 0) { @@ -286,10 +277,20 @@ export const SmartInventorySetupStep: React.FC = ({ if (success) { console.log('✅ File processed successfully, setting stage to review'); setLocalStage('review'); - toast.addToast('El archivo se procesó correctamente. Revisa los productos detectados.', { - title: 'Procesamiento completado', - type: 'success' - }); + + // Check if there was a suggestion error (AI service timeout) + const stepData = data.allStepData?.['smart-inventory-setup']; + if (stepData?.suggestionError) { + toast.addToast(`Archivo procesado. ${stepData.suggestionError} Se crearon sugerencias básicas que puedes editar.`, { + title: 'Procesamiento completado con advertencias', + type: 'warning' + }); + } else { + toast.addToast('El archivo se procesó correctamente. Revisa los productos detectados.', { + title: 'Procesamiento completado', + type: 'success' + }); + } } else { console.error('❌ File processing failed - processSalesFile returned false'); throw new Error('Error procesando el archivo'); diff --git a/frontend/src/hooks/business/onboarding/core/actions.ts b/frontend/src/hooks/business/onboarding/core/actions.ts index c457d87b..86b09588 100644 --- a/frontend/src/hooks/business/onboarding/core/actions.ts +++ b/frontend/src/hooks/business/onboarding/core/actions.ts @@ -166,12 +166,19 @@ export const useOnboardingActions = () => { }, [store, tenantCreation]); const processSalesFile = useCallback(async (file: File): Promise => { + console.log('🎬 Actions - processSalesFile started'); store.setLoading(true); + const result = await salesProcessing.processFile(file); + console.log('🎬 Actions - processFile result:', result); + store.setLoading(false); if (!result.success) { + console.error('❌ Actions - Processing failed:', salesProcessing.error); store.setError(salesProcessing.error || 'Error processing sales file'); + } else { + console.log('✅ Actions - Processing succeeded'); } return result.success; diff --git a/frontend/src/hooks/business/onboarding/services/useSalesProcessing.ts b/frontend/src/hooks/business/onboarding/services/useSalesProcessing.ts index 1224f715..0300688c 100644 --- a/frontend/src/hooks/business/onboarding/services/useSalesProcessing.ts +++ b/frontend/src/hooks/business/onboarding/services/useSalesProcessing.ts @@ -74,13 +74,37 @@ export const useSalesProcessing = () => { } }; - const response = await classifyProductsMutation.mutateAsync(requestPayload); + console.log('📡 Making API request to:', `/tenants/${currentTenant.id}/inventory/classify-products-batch`); + + // Add timeout to the API call with shorter timeout + const timeoutPromise = new Promise((_, reject) => { + setTimeout(() => reject(new Error('API timeout: The inventory service may be overloaded. Please try again in a few moments.')), 15000); // 15 second timeout + }); + + const response = await Promise.race([ + classifyProductsMutation.mutateAsync(requestPayload), + timeoutPromise + ]); console.log('✅ Generated', response?.length || 0, 'suggestions'); return response || []; } catch (error) { - console.error('❌ Error generating suggestions:', error); + const isTimeout = error instanceof Error && error.message.includes('timeout'); + const isNetworkError = error instanceof Error && (error.message.includes('fetch') || error.message.includes('network')); + + console.error('❌ Error generating suggestions:', { + error: error, + message: error instanceof Error ? error.message : 'Unknown error', + isTimeout, + isNetworkError + }); + + // Re-throw timeout/network errors so they can be handled properly by the UI + if (isTimeout || isNetworkError) { + throw error; + } + return []; } }, [classifyProductsMutation, currentTenant]); @@ -138,12 +162,47 @@ export const useSalesProcessing = () => { updateProgress(60, 'analyzing', 'Identificando productos únicos...', onProgress); updateProgress(70, 'analyzing', 'Generando sugerencias de IA...', onProgress); - const suggestions = await generateSuggestions(validationResult.product_list); + let suggestions: ProductSuggestionResponse[] = []; + let suggestionError: string | null = null; + + try { + updateProgress(70, 'analyzing', 'Generando sugerencias de IA...', onProgress); + suggestions = await generateSuggestions(validationResult.product_list); + + console.log('🔍 After generateSuggestions call:', { + suggestionsReceived: suggestions?.length || 0, + }); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Error generando sugerencias'; + suggestionError = errorMessage; + console.error('❌ Suggestions generation failed:', errorMessage); + + // Still continue with empty suggestions - user can manually add products later + updateProgress(80, 'analyzing', 'Preparando productos básicos...', onProgress); + + // Create basic suggestions from product names as fallback + suggestions = validationResult.product_list.map((productName, index) => ({ + suggestion_id: `manual-${index}`, + original_name: productName, + suggested_name: productName, + product_type: 'ingredient', + category: 'Sin categoría', + unit_of_measure: 'units', + confidence_score: 0.5, + estimated_shelf_life_days: 30, + requires_refrigeration: false, + requires_freezing: false, + is_seasonal: false, + notes: 'Clasificación manual - El servicio de IA no está disponible temporalmente' + })); + + console.log('🔧 Created fallback suggestions:', suggestions.length); + } updateProgress(90, 'analyzing', 'Analizando patrones de venta...', onProgress); updateProgress(100, 'completed', 'Procesamiento completado exitosamente', onProgress); - // Update state with suggestions + // Update state with suggestions (even if empty or fallback) setSuggestions(suggestions || []); setValidationResults(validationResult); @@ -155,8 +214,11 @@ export const useSalesProcessing = () => { processingStage: 'completed', processingResults: validationResult, suggestions: suggestions || [], + suggestionError: suggestionError, }); + console.log('📊 Updated onboarding store with suggestions'); + return { success: true, validationResults: validationResult,