Implementar sistema completo de trazabilidad de lotes
Some checks failed
build-and-deploy / build-and-deploy (push) Failing after 1m47s
Some checks failed
build-and-deploy / build-and-deploy (push) Failing after 1m47s
- Agregar PostgreSQL 16 con esquema completo - Crear API endpoints para lotes y operaciones - Implementar UI con Nuxt UI (tablas, formularios, trazabilidad) - Agregar datos de ejemplo del flujo completo - Documentar sistema en PLAN_TRAZABILIDAD.md
This commit is contained in:
44
nuxt4/server/api/operaciones/[id].get.ts
Normal file
44
nuxt4/server/api/operaciones/[id].get.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { getOperacionConLotes } from '~/server/utils/queries'
|
||||
|
||||
/**
|
||||
* GET /api/operaciones/:id
|
||||
* Obtiene una operación específica con sus lotes relacionados (inputs y outputs)
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const id = getRouterParam(event, 'id')
|
||||
|
||||
if (!id) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'ID de operación requerido',
|
||||
})
|
||||
}
|
||||
|
||||
const operacion = await getOperacionConLotes(id)
|
||||
|
||||
if (!operacion) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Operación no encontrada',
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: operacion,
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Error obteniendo operación:', error)
|
||||
|
||||
if (error.statusCode) {
|
||||
throw error
|
||||
}
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Error obteniendo operación',
|
||||
data: { message: error.message },
|
||||
})
|
||||
}
|
||||
})
|
||||
37
nuxt4/server/api/operaciones/index.get.ts
Normal file
37
nuxt4/server/api/operaciones/index.get.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { getOperaciones } from '~/server/utils/queries'
|
||||
|
||||
/**
|
||||
* GET /api/operaciones
|
||||
* Lista todas las operaciones con filtros opcionales
|
||||
*
|
||||
* Query params:
|
||||
* - tipo: filtrar por tipo de operación (ingreso, despulpado, oreado, etc.)
|
||||
* - limit: límite de resultados
|
||||
* - offset: offset para paginación
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const query = getQuery(event)
|
||||
|
||||
const filtros = {
|
||||
tipo: query.tipo as string | undefined,
|
||||
limit: query.limit ? parseInt(query.limit as string) : undefined,
|
||||
offset: query.offset ? parseInt(query.offset as string) : undefined,
|
||||
}
|
||||
|
||||
const operaciones = await getOperaciones(filtros)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: operaciones,
|
||||
count: operaciones.length,
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Error obteniendo operaciones:', error)
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Error obteniendo operaciones',
|
||||
data: { message: error.message },
|
||||
})
|
||||
}
|
||||
})
|
||||
96
nuxt4/server/api/operaciones/index.post.ts
Normal file
96
nuxt4/server/api/operaciones/index.post.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { createOperacion } from '~/server/utils/queries'
|
||||
|
||||
/**
|
||||
* POST /api/operaciones
|
||||
* Crea una nueva operación con sus lotes de entrada y salida
|
||||
*
|
||||
* Body:
|
||||
* {
|
||||
* tipo: string, // ingreso, despulpado, oreado, etc.
|
||||
* fecha?: string, // ISO date (opcional, default: ahora)
|
||||
* lugar_id?: number,
|
||||
* meta?: object,
|
||||
* inputs: [ // Lotes de entrada
|
||||
* { lote_id: string, cantidad_kg?: number }
|
||||
* ],
|
||||
* outputs: [ // Lotes de salida (se crearán)
|
||||
* { codigo?: string, tipo: string, cantidad_kg?: number, meta?: object }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const body = await readBody(event)
|
||||
|
||||
// Validaciones básicas
|
||||
if (!body.tipo) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'El campo "tipo" es requerido',
|
||||
})
|
||||
}
|
||||
|
||||
if (!body.inputs || !Array.isArray(body.inputs)) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'El campo "inputs" es requerido y debe ser un array',
|
||||
})
|
||||
}
|
||||
|
||||
if (!body.outputs || !Array.isArray(body.outputs)) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'El campo "outputs" es requerido y debe ser un array',
|
||||
})
|
||||
}
|
||||
|
||||
// Validar que cada input tenga lote_id
|
||||
for (const input of body.inputs) {
|
||||
if (!input.lote_id) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'Cada input debe tener un "lote_id"',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Validar que cada output tenga tipo
|
||||
for (const output of body.outputs) {
|
||||
if (!output.tipo) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'Cada output debe tener un "tipo"',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const result = await createOperacion({
|
||||
tipo: body.tipo,
|
||||
fecha: body.fecha ? new Date(body.fecha) : undefined,
|
||||
lugar_id: body.lugar_id,
|
||||
meta: body.meta,
|
||||
inputs: body.inputs,
|
||||
outputs: body.outputs,
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
operacion: result.operacion,
|
||||
lotes_creados: result.lotes_creados,
|
||||
},
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Error creando operación:', error)
|
||||
|
||||
if (error.statusCode) {
|
||||
throw error
|
||||
}
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Error creando operación',
|
||||
data: { message: error.message },
|
||||
})
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user