Add new frontend - fix 23
This commit is contained in:
@@ -22,7 +22,7 @@ import {
|
||||
} from '@/api/services';
|
||||
|
||||
|
||||
import api from '@/api/services';
|
||||
import { api } from '@/api/services';
|
||||
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
|
||||
@@ -208,7 +208,7 @@ const OnboardingPage = () => {
|
||||
setCurrentTenantId(tenant.id);
|
||||
showNotification('success', 'Panadería registrada', 'Información guardada correctamente.');
|
||||
|
||||
} else if (currentStep === 3) {
|
||||
} else if (currentStep === 3) {
|
||||
// FIXED: Sales upload step with proper validation handling
|
||||
if (formData.salesFile) {
|
||||
try {
|
||||
@@ -219,10 +219,12 @@ const OnboardingPage = () => {
|
||||
setUploadValidation(validation);
|
||||
}
|
||||
|
||||
// FIXED: Check validation using correct field names
|
||||
// ✅ FIXED: Check validation using correct field name is_valid
|
||||
if (!validation.is_valid) {
|
||||
const errorMessages = validation.errors.map(error =>
|
||||
`${error.row ? `Fila ${error.row}: ` : ''}${error.message}`
|
||||
`${error.row ? `Fila ${error.row}: ` : ''}${
|
||||
typeof error === 'string' ? error : error.message
|
||||
}`
|
||||
).join('; ');
|
||||
|
||||
showNotification('error', 'Datos inválidos',
|
||||
@@ -234,15 +236,16 @@ const OnboardingPage = () => {
|
||||
// Show warnings if any
|
||||
if (validation.warnings.length > 0) {
|
||||
const warningMessages = validation.warnings.map(warning =>
|
||||
`${warning.row ? `Fila ${warning.row}: ` : ''}${warning.message}`
|
||||
`${warning.row ? `Fila ${warning.row}: ` : ''}${
|
||||
typeof warning === 'string' ? warning : warning.message
|
||||
}`
|
||||
).join('; ');
|
||||
|
||||
showNotification('warning', 'Advertencias encontradas',
|
||||
`Advertencias: ${warningMessages.slice(0, 200)}${warningMessages.length > 200 ? '...' : ''}`);
|
||||
}
|
||||
|
||||
// Proceed with import - Use the existing uploadSalesHistory method
|
||||
// or create a new importSalesData method
|
||||
// Proceed with actual upload
|
||||
const uploadResult = await api.data.uploadSalesHistory(
|
||||
formData.salesFile,
|
||||
{ tenant_id: currentTenantId }
|
||||
@@ -250,40 +253,10 @@ const OnboardingPage = () => {
|
||||
|
||||
showNotification('success', 'Archivo subido',
|
||||
`${uploadResult.records_processed} registros procesados exitosamente.`);
|
||||
|
||||
console.log('Upload successful:', {
|
||||
records_processed: uploadResult.records_processed,
|
||||
validation_summary: {
|
||||
total_records: validation.total_records,
|
||||
valid_records: validation.valid_records,
|
||||
invalid_records: validation.invalid_records,
|
||||
errors_count: validation.errors.length,
|
||||
warnings_count: validation.warnings.length
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Sales upload error:', error);
|
||||
|
||||
let errorMessage = 'No se pudo procesar el archivo de ventas.';
|
||||
let errorTitle = 'Error al subir';
|
||||
|
||||
if (error.response?.status === 422) {
|
||||
errorTitle = 'Error de validación';
|
||||
errorMessage = error.response.data?.detail || 'Formato de datos incorrecto';
|
||||
} else if (error.response?.status === 400) {
|
||||
errorTitle = 'Archivo inválido';
|
||||
errorMessage = error.response.data?.detail || 'El formato del archivo no es compatible';
|
||||
} else if (error.response?.status >= 500) {
|
||||
errorTitle = 'Error del servidor';
|
||||
errorMessage = 'Problema temporal del servidor. Inténtalo más tarde.';
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
|
||||
showNotification('error', errorTitle, errorMessage);
|
||||
setLoading(false);
|
||||
return;
|
||||
// ... existing error handling
|
||||
}
|
||||
}
|
||||
} else if (currentStep === 4) {
|
||||
@@ -351,63 +324,150 @@ const OnboardingPage = () => {
|
||||
|
||||
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (file) {
|
||||
setFormData(prev => ({ ...prev, salesFile: file }));
|
||||
setUploadValidation(null);
|
||||
if (!file) return;
|
||||
|
||||
setFormData(prev => ({ ...prev, salesFile: file }));
|
||||
setUploadValidation(null);
|
||||
|
||||
// Auto-validate file on selection
|
||||
try {
|
||||
setLoading(true);
|
||||
console.log('Validating file:', file.name);
|
||||
|
||||
// Auto-validate file on selection
|
||||
try {
|
||||
setLoading(true);
|
||||
console.log('Validating file:', file.name);
|
||||
|
||||
// FIXED: Use the corrected validation method
|
||||
const validation = await api.data.validateSalesData(file);
|
||||
setUploadValidation(validation);
|
||||
|
||||
// FIXED: Use correct field names from backend response
|
||||
if (validation.is_valid) {
|
||||
showNotification('success', 'Archivo válido',
|
||||
`${validation.total_records} registros detectados, ${validation.valid_records} válidos.`);
|
||||
} else if (validation.warnings.length > 0 && validation.errors.length === 0) {
|
||||
showNotification('warning', 'Archivo con advertencias',
|
||||
'El archivo es válido pero tiene algunas advertencias.');
|
||||
} else {
|
||||
const errorCount = validation.errors.length;
|
||||
showNotification('error', 'Archivo con errores',
|
||||
`Se encontraron ${errorCount} errores en el archivo.`);
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Error validating file:', error);
|
||||
|
||||
// Handle network or other errors
|
||||
let errorMessage = 'Error al validar el archivo';
|
||||
if (error.response?.status === 422) {
|
||||
errorMessage = 'Formato de archivo inválido';
|
||||
} else if (error.response?.status === 400) {
|
||||
errorMessage = 'El archivo no se puede procesar';
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
|
||||
showNotification('error', 'Error de validación', errorMessage);
|
||||
|
||||
// Set a failed validation state
|
||||
setUploadValidation({
|
||||
is_valid: false,
|
||||
total_records: 0,
|
||||
valid_records: 0,
|
||||
invalid_records: 0,
|
||||
errors: [{ message: errorMessage }],
|
||||
warnings: [],
|
||||
summary: { validation_failed: true }
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
// ✅ CRITICAL FIX: Add null check for validation response
|
||||
const validation = await api.data.validateSalesData(file);
|
||||
|
||||
if (!validation) {
|
||||
throw new Error('No validation response received from server');
|
||||
}
|
||||
|
||||
console.log('Validation result:', validation); // Debug log
|
||||
|
||||
setUploadValidation(validation);
|
||||
|
||||
// ✅ FIXED: Use correct field name is_valid instead of valid
|
||||
if (validation.is_valid) {
|
||||
showNotification('success', 'Archivo válido',
|
||||
`${validation.total_records} registros detectados, ${validation.valid_records} válidos.`);
|
||||
} else if (validation.warnings && validation.warnings.length > 0 &&
|
||||
validation.errors && validation.errors.length === 0) {
|
||||
showNotification('warning', 'Archivo con advertencias',
|
||||
'El archivo es válido pero tiene algunas advertencias.');
|
||||
} else {
|
||||
const errorCount = validation.errors ? validation.errors.length : 0;
|
||||
showNotification('error', 'Archivo con errores',
|
||||
`Se encontraron ${errorCount} errores en el archivo.`);
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Error validating file:', error);
|
||||
|
||||
// Handle network or other errors
|
||||
let errorMessage = 'Error al validar el archivo';
|
||||
if (error.response?.status === 422) {
|
||||
errorMessage = 'Formato de archivo inválido';
|
||||
} else if (error.response?.status === 400) {
|
||||
errorMessage = 'El archivo no se puede procesar';
|
||||
} else if (error.response?.status === 500) {
|
||||
errorMessage = 'Error del servidor. Inténtalo más tarde.';
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
|
||||
showNotification('error', 'Error de validación', errorMessage);
|
||||
|
||||
// ✅ FIXED: Set validation state with correct field names
|
||||
setUploadValidation({
|
||||
is_valid: false, // ✅ Use is_valid not valid
|
||||
total_records: 0,
|
||||
valid_records: 0,
|
||||
invalid_records: 0,
|
||||
errors: [{ message: errorMessage }], // ✅ Array of objects, not strings
|
||||
warnings: [],
|
||||
summary: { validation_failed: true }
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Fixed validation display component
|
||||
const renderValidationResult = () => {
|
||||
{uploadValidation && (
|
||||
<div className={`border rounded-lg p-4 ${
|
||||
uploadValidation.is_valid ? 'bg-green-50 border-green-200' : 'bg-red-50 border-red-200'
|
||||
}`}>
|
||||
<div className="flex items-start">
|
||||
{uploadValidation.is_valid ? (
|
||||
<CheckIcon className="w-5 h-5 text-green-600 mt-0.5 mr-3" />
|
||||
) : (
|
||||
<XMarkIcon className="w-5 h-5 text-red-600 mt-0.5 mr-3" />
|
||||
)}
|
||||
<div className="flex-1">
|
||||
<h4 className={`font-semibold ${
|
||||
uploadValidation.is_valid ? 'text-green-800' : 'text-red-800'
|
||||
}`}>
|
||||
{uploadValidation.is_valid ? 'Archivo válido' : 'Archivo con problemas'}
|
||||
</h4>
|
||||
|
||||
{/* Always safe record count display */}
|
||||
<p className={`text-sm mt-1 ${
|
||||
uploadValidation.is_valid ? 'text-green-700' : 'text-red-700'
|
||||
}`}>
|
||||
{uploadValidation.total_records || uploadValidation.recordCount || 0} registros procesados
|
||||
</p>
|
||||
|
||||
{/* Only show errors if they exist and are in array format */}
|
||||
{!uploadValidation.is_valid && uploadValidation.errors && (
|
||||
<div className="mt-2">
|
||||
<p className="text-sm font-medium text-red-700 mb-1">
|
||||
{Array.isArray(uploadValidation.errors) ? 'Errores encontrados:' : 'Error:'}
|
||||
</p>
|
||||
{Array.isArray(uploadValidation.errors) ? (
|
||||
<ul className="text-sm text-red-700 space-y-1">
|
||||
{uploadValidation.errors.map((error, idx) => (
|
||||
<li key={idx}>
|
||||
• {error?.message || error || 'Error no especificado'}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p className="text-sm text-red-700">
|
||||
{uploadValidation.errors.message || uploadValidation.errors || 'Error desconocido'}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Show warnings if they exist */}
|
||||
{uploadValidation.warnings && Array.isArray(uploadValidation.warnings) && uploadValidation.warnings.length > 0 && (
|
||||
<div className="mt-2">
|
||||
<p className="text-sm font-medium text-yellow-700 mb-1">Advertencias:</p>
|
||||
<ul className="text-sm text-yellow-700 space-y-1">
|
||||
{uploadValidation.warnings.map((warning, idx) => (
|
||||
<li key={idx}>
|
||||
• {warning?.message || warning || 'Advertencia no especificada'}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Show technical info for debugging */}
|
||||
{uploadValidation.summary && uploadValidation.summary.error_type && (
|
||||
<div className="mt-2 p-2 bg-gray-100 rounded">
|
||||
<p className="text-xs text-gray-600">
|
||||
<strong>Info técnica:</strong> {uploadValidation.summary.error_type}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
};
|
||||
|
||||
|
||||
const renderStepIndicator = () => (
|
||||
<div className="mb-12">
|
||||
<div className="flex items-center justify-between">
|
||||
|
||||
Reference in New Issue
Block a user