Validaciones de errores

This commit is contained in:
2026-04-16 11:44:18 -05:00
parent 5e6ee5d4d1
commit 7ddd85e73b
2 changed files with 73 additions and 12 deletions

View File

@@ -27,7 +27,7 @@
import ItemSheetInv from './inv/item-sheet-inv.svelte';
import { itemPresetsApi, type ItemPreset } from '$lib/api/dashboard/a76/item-presets';
import { Checkbox } from '$lib/components/ui/checkbox';
import { cleanLineData, normalizeItemData } from '$lib/utils/items-logic';
import { cleanLineData, normalizeItemData, formatItemError } from '$lib/utils/items-logic';
import { getVisibility } from '$lib/config/invoice-item-visibility';
let {
@@ -370,19 +370,10 @@
await loadItems();
showItemSheet = false;
} catch (error: any) {
const rawDetail = error?.response?.data?.detail ?? error?.response?.data ?? error?.message ?? String(error);
let errorMsg = 'No se pudo guardar la partida.';
if (Array.isArray(rawDetail)) {
errorMsg = rawDetail.map((e: any) => `[${e.loc?.join('.') ?? '?'}]: ${e.msg}`).join('\n');
} else if (typeof rawDetail === 'string') {
errorMsg = rawDetail;
} else if (rawDetail && typeof rawDetail === 'object') {
errorMsg = JSON.stringify(rawDetail, null, 2);
}
const errorMsg = formatItemError(error);
toast.error('Error al guardar', {
description: errorMsg.slice(0, 500),
description: errorMsg,
duration: 10000
});
} finally {

View File

@@ -244,3 +244,73 @@ export function hasValues(obj: any): boolean {
!(typeof val === 'object' && !hasValues(val))
);
}
// Human-readable mapping for field errors
const FIELD_MAP: Record<string, string> = {
'class_id': 'Clase',
'invoice_id': 'ID de Factura',
'line_number': 'Número de Línea',
'unit_of_measure': 'Unidad de Medida',
'description.description_spanish': 'Descripción en Español',
'description.description_english': 'Descripción en Inglés',
'quantity.quantity': 'Cantidad',
'quantity.net_weight': 'Peso Neto',
'quantity.gross_weight': 'Peso Bruto',
'financial.unit_cost_capture': 'Costo Unitario',
'customs.fraction': 'Fracción Arancelaria',
'customs.origin_country': 'País de Origen',
'fa_data.search_invoice': 'Factura de Referencia',
'fa_data.search_line': 'Línea de Referencia',
'fa_data.search_type': 'Tipo de Búsqueda',
'fa_data.movement_type_import': 'Tipo de Importación'
};
/**
* Formats a backend error into a human-readable Spanish message.
* Handles 422 (Validation), 403 (Forbidden), 404 (Not Found), and 500 (Server Error).
*/
export function formatItemError(error: any): string {
if (!error) return 'Error desconocido';
const status = error?.response?.status;
const data = error?.response?.data;
const detail = data?.detail;
// 1. Handle Validation Errors (422)
if (status === 422 && Array.isArray(detail)) {
const errors = detail.map((err: any) => {
// Join location path, skipping 'body' prefix
const locPath = (err.loc || [])
.filter((l: string) => l !== 'body')
.join('.');
const fieldName = FIELD_MAP[locPath] || locPath || 'campo';
// Translate common Pydantic error messages
let msg = err.msg || 'error de validación';
if (msg.includes('field required')) msg = 'es obligatorio';
if (msg.includes('value is not a valid decimal')) msg = 'debe ser un número válido';
if (msg.includes('value is not a valid integer')) msg = 'debe ser un número entero';
return `${fieldName}: ${msg}`;
});
return `Por favor revisa los siguientes campos:\n${errors.join('\n')}`;
}
// 2. Handle known detail strings (from raise HTTPException)
if (typeof detail === 'string') {
// Translate some common backend messages
if (detail.includes('Access denied')) return 'No tienes permisos para realizar esta acción o acceder a este recurso.';
if (detail.includes('not found')) return 'El registro solicitado no existe o fue eliminado.';
if (detail.includes('Class mismatch')) return 'Error de validación: ' + detail; // Keep descriptive logic errors
return detail;
}
// 3. Handle Status Codes fallbacks
if (status === 403) return 'No tienes permisos para realizar esta operación.';
if (status === 404) return 'No se encontró el recurso solicitado.';
if (status >= 500) return 'Hubo un problema en el servidor. Por favor intenta de nuevo más tarde o contacta a soporte.';
// 4. Default Axios error message
return data?.message || error.message || 'Error al procesar la solicitud.';
}