v1.0.66 Backend / v1.0.60 Frontend - Fix error 422 en análisis IA sin respuesta

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
This commit is contained in:
2025-11-27 02:07:17 -03:00
parent 7fb2e40a1e
commit d1b4d10257
4 changed files with 24 additions and 19 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -1,7 +1,7 @@
{
"name": "checklist-frontend",
"private": true,
"version": "1.0.59",
"version": "1.0.60",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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 }) {
) : (
<>
<span>🤖</span>
<span>Analizar con IA</span>
<span>Analizar Pregunta</span>
</>
)}
</button>