From d1b4d1025717f2337abeb15fd4e8fae8b7b54b55 Mon Sep 17 00:00:00 2001 From: ronalds Date: Thu, 27 Nov 2025 02:07:17 -0300 Subject: [PATCH] =?UTF-8?q?v1.0.66=20Backend=20/=20v1.0.60=20Frontend=20-?= =?UTF-8?q?=20Fix=20error=20422=20en=20an=C3=A1lisis=20IA=20sin=20respuest?= =?UTF-8?q?a?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend (1.0.66): - 🐛 Fix: answer_value ahora es Optional en AnswerBase schema - Permite guardar respuestas con solo análisis IA y fotos - Permite guardar observaciones sin answer_value - Ya no rechaza con 422 cuando answer_value es null/vacío Frontend (1.0.60): - 🐛 Fix: saveAnswer ahora permite guardar si hay: * Valor de respuesta, O * Observaciones de IA, O * Fotos cargadas - Mejorada lógica de determinación de status - Solo calcula status si hay answer.value - Permite guardar análisis IA antes de seleccionar respuesta Flujo mejorado: 1. Usuario sube fotos 2. Click "Analizar con IA" → genera observaciones 3. Puede avanzar sin seleccionar respuesta (guardará solo observaciones) 4. O puede seleccionar respuesta después → actualiza el record Causa del error 422: - answer_value era required en schema - Al analizar fotos sin seleccionar respuesta se enviaba answer_value="" - Backend rechazaba con 422 Unprocessable Entity - Ahora answer_value es opcional y acepta null/vacío --- backend/app/main.py | 2 +- backend/app/schemas.py | 2 +- frontend/package.json | 2 +- frontend/src/App.jsx | 37 +++++++++++++++++++++---------------- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/backend/app/main.py b/backend/app/main.py index 18c667a..3bd5030 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -204,7 +204,7 @@ def send_completed_inspection_to_n8n(inspection, db): # No lanzamos excepción para no interrumpir el flujo normal -BACKEND_VERSION = "1.0.65" +BACKEND_VERSION = "1.0.66" app = FastAPI(title="Checklist Inteligente API", version=BACKEND_VERSION) # S3/MinIO configuration diff --git a/backend/app/schemas.py b/backend/app/schemas.py index 32946f4..7221741 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -200,7 +200,7 @@ class Inspection(InspectionBase): # Answer Schemas class AnswerBase(BaseModel): - answer_value: str + answer_value: Optional[str] = None # Opcional para permitir guardar solo análisis IA status: str = "ok" comment: Optional[str] = None is_flagged: bool = False diff --git a/frontend/package.json b/frontend/package.json index fe10d24..a030146 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "checklist-frontend", "private": true, - "version": "1.0.59", + "version": "1.0.60", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 1a1327a..cee28bf 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -3441,7 +3441,10 @@ function InspectionModal({ checklist, user, onClose, onComplete }) { const question = questions.find(q => q.id === questionId) const answer = answers[questionId] - if (!answer?.value && answer?.value !== '') return // Don't save if no value + // Don't save if no value AND no observations AND no photos + if (!answer?.value && !answer?.observations && (!answer?.photos || answer.photos.length === 0)) { + return + } try { const token = localStorage.getItem('token') @@ -3452,20 +3455,22 @@ function InspectionModal({ checklist, user, onClose, onComplete }) { const config = question.options || {} const questionType = config.type || question.type - if (questionType === 'boolean' && config.choices) { - const selectedChoice = config.choices.find(c => c.value === answer.value) - status = selectedChoice?.status || 'ok' - } else if (questionType === 'single_choice' && config.choices) { - const selectedChoice = config.choices.find(c => c.value === answer.value) - status = selectedChoice?.status || 'ok' - } else if (questionType === 'pass_fail') { - // Compatibilidad hacia atrás - status = answer.value === 'pass' ? 'ok' : 'critical' - } else if (questionType === 'good_bad') { - // Compatibilidad hacia atrás - if (answer.value === 'good') status = 'ok' - else if (answer.value === 'regular') status = 'warning' - else if (answer.value === 'bad') status = 'critical' + if (answer?.value) { + if (questionType === 'boolean' && config.choices) { + const selectedChoice = config.choices.find(c => c.value === answer.value) + status = selectedChoice?.status || 'ok' + } else if (questionType === 'single_choice' && config.choices) { + const selectedChoice = config.choices.find(c => c.value === answer.value) + status = selectedChoice?.status || 'ok' + } else if (questionType === 'pass_fail') { + // Compatibilidad hacia atrás + status = answer.value === 'pass' ? 'ok' : 'critical' + } else if (questionType === 'good_bad') { + // Compatibilidad hacia atrás + if (answer.value === 'good') status = 'ok' + else if (answer.value === 'regular') status = 'warning' + else if (answer.value === 'bad') status = 'critical' + } } // Submit answer @@ -4278,7 +4283,7 @@ function InspectionModal({ checklist, user, onClose, onComplete }) { ) : ( <> 🤖 - Analizar con IA + Analizar Pregunta )}