Add new frontend - fix 24

This commit is contained in:
Urtzi Alfaro
2025-07-23 17:51:39 +02:00
parent 20c31a07f7
commit e3a5256281
3 changed files with 161 additions and 313 deletions

View File

@@ -19,28 +19,13 @@ export interface UploadResponse {
upload_id?: string;
}
// ✅ FIXED: Updated to match backend SalesValidationResult schema
export interface DataValidation {
is_valid: boolean; // Changed from 'valid' to 'is_valid'
total_records: number; // Changed from 'recordCount' to 'total_records'
valid_records: number; // Added missing field
invalid_records: number; // Added missing field
errors: Array<{ // Changed from string[] to object array
row?: number;
field?: string;
message: string;
value?: any;
}>;
warnings: Array<{ // Changed from string[] to object array
row?: number;
field?: string;
message: string;
value?: any;
}>;
summary: { // Added missing summary field
[key: string]: any;
};
duplicates?: number; // Made optional, may not always be present
valid: boolean; // ✅ Backend uses "valid", not "is_valid"
errors: string[]; // ✅ Backend returns string array, not objects
warnings: string[]; // ✅ Backend returns string array, not objects
suggestions: string[]; // ✅ Backend uses "suggestions", not "summary"
recordCount?: number; // ✅ Optional field for record count (if backend provides it)
duplicates?: number; // ✅ Optional field for duplicates
}
// Data types
@@ -104,11 +89,10 @@ export class DataService {
* ✅ COMPLETELY FIXED: Validate sales data before upload
* Backend expects JSON data with SalesDataImport structure, not a file upload
*/
async validateSalesData(file: File): Promise<DataValidation> {
async validateSalesData(file: File, tenantId?: string): Promise<DataValidation> {
try {
console.log('Reading file content...', file.name);
// ✅ FIXED: Proper file reading implementation
const fileContent = await this.readFileAsText(file);
if (!fileContent) {
@@ -128,219 +112,92 @@ export class DataService {
} else if (fileName.endsWith('.xlsx') || fileName.endsWith('.xls')) {
dataFormat = 'excel';
} else {
// Default to CSV if unable to determine
dataFormat = 'csv';
}
console.log('Detected file format:', dataFormat);
// ✅ CRITICAL FIX: Use correct endpoint based on API Gateway routing
// ✅ FIXED: Use proper tenant ID when available
const importData: SalesDataImportRequest = {
tenant_id: '', // Will be set by backend from auth context
tenant_id: tenantId || '00000000-0000-0000-0000-000000000000',
data: fileContent,
data_format: dataFormat,
validate_only: true
};
console.log('Sending validation request to:', '/api/v1/data/sales/import/validate');
console.log('Sending validation request with tenant_id:', importData.tenant_id);
// ✅ FIXED: Correct endpoint path - Gateway routes /api/v1/data/sales/* to data service /api/v1/sales/*
const response = await apiClient.post<ApiResponse<DataValidation>>(
'/api/v1/data/sales/import/validate', // Gateway will proxy this to data service
'/api/v1/data/sales/import/validate',
importData
);
console.log('Raw response from API:', response);
// ✅ CRITICAL FIX: Handle various response formats properly
// Check if response contains error information first
// ✅ FIXED: Handle response according to backend's actual format
if (response && typeof response === 'object') {
// Handle direct error responses (like 404)
// Handle validation errors from FastAPI
if ('detail' in response) {
console.error('API returned error:', response.detail);
if (response.detail === 'Not Found') {
// Return a proper validation failure for missing endpoint
return {
is_valid: false,
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{
message: 'El servicio de validación no está disponible temporalmente. Por favor contacta al soporte técnico.'
}],
warnings: [],
summary: {
validation_error: true,
error_type: 'service_unavailable',
message: 'Validation service endpoint not found'
if (Array.isArray(response.detail)) {
// Handle Pydantic validation errors
const errorMessages = response.detail.map(err => {
if (typeof err === 'object' && err.msg) {
return `${err.loc ? err.loc.join('.') + ': ' : ''}${err.msg}`;
}
};
} else {
// Handle other API errors
return err.toString();
});
return {
is_valid: false,
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{
message: `Error del servidor: ${response.detail}`
}],
valid: false,
errors: errorMessages,
warnings: [],
summary: {
validation_error: true,
error_type: 'api_error',
message: response.detail
}
suggestions: ['Revisa el formato de los datos enviados']
};
}
return {
valid: false,
errors: [typeof response.detail === 'string' ? response.detail : 'Error de validación'],
warnings: [],
suggestions: []
};
}
// Handle successful response (either wrapped or direct)
const validationResult = response.data || response;
// Verify that we have a proper validation response
if (validationResult && typeof validationResult === 'object' && 'is_valid' in validationResult) {
console.log('Valid validation response received:', validationResult);
return validationResult;
// Handle successful response - check for nested data
if ('data' in response) {
return response.data;
}
// If response seems to be the validation result directly
if ('valid' in response) {
return response as DataValidation;
}
}
// If we get here, the response format is unexpected
console.warn('Unexpected response format:', response);
return {
is_valid: false,
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{
message: 'Respuesta inválida del servidor. Formato de respuesta no reconocido.'
}],
warnings: [],
summary: {
validation_error: true,
error_type: 'invalid_response',
message: 'Unexpected response format from validation service'
}
};
throw new Error('Invalid response format from validation service');
} catch (error: any) {
console.error('Error in validateSalesData:', error);
console.error('Error validating file:', error);
// ✅ COMPREHENSIVE ERROR HANDLING
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;
}
// Handle network/connection errors
if (error.code === 'NETWORK_ERROR' || error.message?.includes('fetch')) {
return {
is_valid: false,
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{
message: 'Error de conexión. Verifica tu conexión a internet y vuelve a intentar.'
}],
warnings: [],
summary: {
validation_error: true,
error_type: 'network_error',
message: 'Failed to connect to validation service'
}
};
}
// Handle HTTP status errors
if (error.response) {
const status = error.response.status;
console.log('HTTP error status:', status);
if (status === 404) {
return {
is_valid: false,
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{
message: 'El servicio de validación no está disponible. Contacta al administrador del sistema.'
}],
warnings: [],
summary: {
validation_error: true,
error_type: 'service_not_found',
message: 'Validation endpoint not found (404)'
}
};
}
if (status === 422) {
return {
is_valid: false,
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{
message: error.response?.data?.detail || 'Formato de datos inválido'
}],
warnings: [],
summary: {
validation_error: true,
error_type: 'validation_failed',
message: 'Data validation failed'
}
};
}
if (status === 400) {
return {
is_valid: false,
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{
message: error.response?.data?.detail || 'Solicitud inválida'
}],
warnings: [],
summary: {
validation_error: true,
error_type: 'bad_request',
message: 'Bad request to validation service'
}
};
}
if (status >= 500) {
return {
is_valid: false,
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{
message: 'Error interno del servidor. Inténtalo más tarde.'
}],
warnings: [],
summary: {
validation_error: true,
error_type: 'server_error',
message: 'Internal server error during validation'
}
};
}
}
// Handle any other unknown errors
// ✅ FIXED: Return format matching backend schema
return {
is_valid: false,
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{
message: error.message || 'Error desconocido durante la validación'
}],
valid: false,
errors: [errorMessage],
warnings: [],
summary: {
validation_error: true,
error_type: 'unknown_error',
message: error.message || 'Unknown validation error'
}
suggestions: ['Intenta con un archivo diferente o contacta soporte']
};
}
}