All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m6s
402 lines
10 KiB
TypeScript
402 lines
10 KiB
TypeScript
/**
|
|
* Composable para gestión de lotes y operaciones de trazabilidad
|
|
*/
|
|
|
|
export interface Lote {
|
|
id: string
|
|
codigo: string | null
|
|
tipo: string
|
|
fecha_creado: string
|
|
lugar_id: number | null
|
|
cantidad_kg: number | null
|
|
meta: Record<string, any> | null
|
|
}
|
|
|
|
export interface Operacion {
|
|
id: string
|
|
tipo: string
|
|
fecha: string
|
|
lugar_id: number | null
|
|
meta: Record<string, any> | null
|
|
}
|
|
|
|
export interface TrazabilidadRow {
|
|
lote_id: string
|
|
codigo: string | null
|
|
tipo: string
|
|
cantidad_kg: number | null
|
|
operacion_id: string | null
|
|
operacion_tipo: string | null
|
|
profundidad: number
|
|
parent_lote_id: string | null
|
|
}
|
|
|
|
export const useLotes = () => {
|
|
console.log('🔵 useLotes: Composable llamado, process.client:', process.client)
|
|
// useToast solo funciona en el cliente, no en SSR
|
|
const toast = process.client ? useToast() : null
|
|
console.log('🔵 useLotes: Toast inicializado:', !!toast)
|
|
|
|
// =====================================================
|
|
// FUNCIONES PARA LOTES
|
|
// =====================================================
|
|
|
|
/**
|
|
* Obtiene todos los lotes con filtros opcionales
|
|
*/
|
|
const fetchLotes = async (filtros?: {
|
|
tipo?: string
|
|
limit?: number
|
|
offset?: number
|
|
}) => {
|
|
console.log('🔵 fetchLotes: Iniciando, filtros:', filtros)
|
|
try {
|
|
const query = new URLSearchParams()
|
|
if (filtros?.tipo) query.append('tipo', filtros.tipo)
|
|
if (filtros?.limit) query.append('limit', filtros.limit.toString())
|
|
if (filtros?.offset) query.append('offset', filtros.offset.toString())
|
|
|
|
const queryString = query.toString()
|
|
const url = `/api/lotes${queryString ? `?${queryString}` : ''}`
|
|
console.log('🔵 fetchLotes: URL construida:', url)
|
|
|
|
console.log('🔵 fetchLotes: Llamando a useFetch...')
|
|
const { data, error } = await useFetch<{
|
|
success: boolean
|
|
data: Lote[]
|
|
count: number
|
|
}>(url)
|
|
console.log('🔵 fetchLotes: useFetch completado, data:', !!data.value, 'error:', !!error.value)
|
|
|
|
if (error.value) {
|
|
throw new Error(error.value.message || 'Error obteniendo lotes')
|
|
}
|
|
|
|
return data.value?.data || []
|
|
} catch (err: any) {
|
|
console.error('Error fetching lotes:', err)
|
|
toast?.add({
|
|
title: 'Error',
|
|
description: err.message || 'Error obteniendo lotes',
|
|
color: 'red',
|
|
})
|
|
return []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Obtiene un lote por su ID
|
|
*/
|
|
const fetchLoteById = async (id: string) => {
|
|
try {
|
|
const { data, error } = await useFetch<{
|
|
success: boolean
|
|
data: Lote
|
|
}>(`/api/lotes/${id}`)
|
|
|
|
if (error.value) {
|
|
throw new Error(error.value.message || 'Error obteniendo lote')
|
|
}
|
|
|
|
return data.value?.data || null
|
|
} catch (err: any) {
|
|
console.error('Error fetching lote:', err)
|
|
toast?.add({
|
|
title: 'Error',
|
|
description: err.message || 'Error obteniendo lote',
|
|
color: 'red',
|
|
})
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crea un nuevo lote
|
|
*/
|
|
const createLote = async (loteData: {
|
|
codigo?: string
|
|
tipo: string
|
|
cantidad_kg?: number
|
|
lugar_id?: number
|
|
meta?: Record<string, any>
|
|
}) => {
|
|
try {
|
|
const { data, error } = await useFetch<{
|
|
success: boolean
|
|
data: Lote
|
|
}>('/api/lotes', {
|
|
method: 'POST',
|
|
body: loteData,
|
|
})
|
|
|
|
if (error.value) {
|
|
throw new Error(error.value.message || 'Error creando lote')
|
|
}
|
|
|
|
toast?.add({
|
|
title: 'Éxito',
|
|
description: 'Lote creado correctamente',
|
|
color: 'green',
|
|
})
|
|
|
|
return data.value?.data || null
|
|
} catch (err: any) {
|
|
console.error('Error creating lote:', err)
|
|
toast?.add({
|
|
title: 'Error',
|
|
description: err.message || 'Error creando lote',
|
|
color: 'red',
|
|
})
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Actualiza un lote existente
|
|
*/
|
|
const updateLote = async (
|
|
id: string,
|
|
updates: Partial<{
|
|
codigo: string | null
|
|
tipo: string
|
|
cantidad_kg: number | null
|
|
lugar_id: number | null
|
|
meta: Record<string, any> | null
|
|
}>
|
|
) => {
|
|
try {
|
|
const { data, error } = await useFetch<{
|
|
success: boolean
|
|
data: Lote
|
|
}>(`/api/lotes/${id}`, {
|
|
method: 'PATCH',
|
|
body: updates,
|
|
})
|
|
|
|
if (error.value) {
|
|
throw new Error(error.value.message || 'Error actualizando lote')
|
|
}
|
|
|
|
toast?.add({
|
|
title: 'Éxito',
|
|
description: 'Lote actualizado correctamente',
|
|
color: 'green',
|
|
})
|
|
|
|
return data.value?.data || null
|
|
} catch (err: any) {
|
|
console.error('Error updating lote:', err)
|
|
toast?.add({
|
|
title: 'Error',
|
|
description: err.message || 'Error actualizando lote',
|
|
color: 'red',
|
|
})
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Elimina un lote
|
|
*/
|
|
const deleteLote = async (id: string) => {
|
|
try {
|
|
const { error } = await useFetch(`/api/lotes/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
|
|
if (error.value) {
|
|
throw new Error(error.value.message || 'Error eliminando lote')
|
|
}
|
|
|
|
toast?.add({
|
|
title: 'Éxito',
|
|
description: 'Lote eliminado correctamente',
|
|
color: 'green',
|
|
})
|
|
|
|
return true
|
|
} catch (err: any) {
|
|
console.error('Error deleting lote:', err)
|
|
toast?.add({
|
|
title: 'Error',
|
|
description: err.message || 'Error eliminando lote',
|
|
color: 'red',
|
|
})
|
|
return false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Obtiene el historial completo de trazabilidad de un lote
|
|
*/
|
|
const fetchTrazabilidad = async (id: string) => {
|
|
try {
|
|
const { data, error } = await useFetch<{
|
|
success: boolean
|
|
data: {
|
|
historial: TrazabilidadRow[]
|
|
estadisticas: {
|
|
total_ancestros: number
|
|
profundidad_maxima: number
|
|
kg_iniciales: number
|
|
}
|
|
}
|
|
}>(`/api/lotes/${id}/trazabilidad`)
|
|
|
|
if (error.value) {
|
|
throw new Error(error.value.message || 'Error obteniendo trazabilidad')
|
|
}
|
|
|
|
return data.value?.data || null
|
|
} catch (err: any) {
|
|
console.error('Error fetching trazabilidad:', err)
|
|
toast?.add({
|
|
title: 'Error',
|
|
description: err.message || 'Error obteniendo trazabilidad',
|
|
color: 'red',
|
|
})
|
|
return null
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// FUNCIONES PARA OPERACIONES
|
|
// =====================================================
|
|
|
|
/**
|
|
* Obtiene todas las operaciones con filtros opcionales
|
|
*/
|
|
const fetchOperaciones = async (filtros?: {
|
|
tipo?: string
|
|
limit?: number
|
|
offset?: number
|
|
}) => {
|
|
try {
|
|
const query = new URLSearchParams()
|
|
if (filtros?.tipo) query.append('tipo', filtros.tipo)
|
|
if (filtros?.limit) query.append('limit', filtros.limit.toString())
|
|
if (filtros?.offset) query.append('offset', filtros.offset.toString())
|
|
|
|
const queryString = query.toString()
|
|
const url = `/api/operaciones${queryString ? `?${queryString}` : ''}`
|
|
|
|
const { data, error } = await useFetch<{
|
|
success: boolean
|
|
data: Operacion[]
|
|
count: number
|
|
}>(url)
|
|
|
|
if (error.value) {
|
|
throw new Error(error.value.message || 'Error obteniendo operaciones')
|
|
}
|
|
|
|
return data.value?.data || []
|
|
} catch (err: any) {
|
|
console.error('Error fetching operaciones:', err)
|
|
toast?.add({
|
|
title: 'Error',
|
|
description: err.message || 'Error obteniendo operaciones',
|
|
color: 'red',
|
|
})
|
|
return []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crea una nueva operación con sus lotes inputs/outputs
|
|
*/
|
|
const createOperacion = async (operacionData: {
|
|
tipo: string
|
|
fecha?: string
|
|
lugar_id?: number
|
|
meta?: Record<string, any>
|
|
inputs: Array<{ lote_id: string; cantidad_kg?: number }>
|
|
outputs: Array<{
|
|
codigo?: string
|
|
tipo: string
|
|
cantidad_kg?: number
|
|
meta?: Record<string, any>
|
|
}>
|
|
}) => {
|
|
try {
|
|
const { data, error } = await useFetch<{
|
|
success: boolean
|
|
data: {
|
|
operacion: Operacion
|
|
lotes_creados: Lote[]
|
|
}
|
|
}>('/api/operaciones', {
|
|
method: 'POST',
|
|
body: operacionData,
|
|
})
|
|
|
|
if (error.value) {
|
|
throw new Error(error.value.message || 'Error creando operación')
|
|
}
|
|
|
|
toast?.add({
|
|
title: 'Éxito',
|
|
description: 'Operación creada correctamente',
|
|
color: 'green',
|
|
})
|
|
|
|
return data.value?.data || null
|
|
} catch (err: any) {
|
|
console.error('Error creating operacion:', err)
|
|
toast?.add({
|
|
title: 'Error',
|
|
description: err.message || 'Error creando operación',
|
|
color: 'red',
|
|
})
|
|
return null
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// CONSTANTES ÚTILES
|
|
// =====================================================
|
|
|
|
const TIPOS_LOTE = [
|
|
{ value: 'uva', label: 'Uva' },
|
|
{ value: 'despulpado_primera', label: 'Despulpado Primera' },
|
|
{ value: 'despulpado_segunda', label: 'Despulpado Segunda' },
|
|
{ value: 'despulpado_rechazos', label: 'Despulpado Rechazos' },
|
|
{ value: 'oreado', label: 'Oreado' },
|
|
{ value: 'presecado', label: 'Presecado' },
|
|
{ value: 'reposo', label: 'Reposo' },
|
|
{ value: 'secado', label: 'Secado' },
|
|
]
|
|
|
|
const TIPOS_OPERACION = [
|
|
{ value: 'ingreso', label: 'Ingreso', icon: 'i-heroicons-arrow-down-tray' },
|
|
{ value: 'despulpado', label: 'Despulpado', icon: 'i-heroicons-beaker' },
|
|
{ value: 'oreado', label: 'Oreado', icon: 'i-heroicons-sun' },
|
|
{ value: 'presecado', label: 'Presecado', icon: 'i-heroicons-fire' },
|
|
{ value: 'reposo', label: 'Reposo', icon: 'i-heroicons-pause' },
|
|
{ value: 'secado', label: 'Secado', icon: 'i-heroicons-check-circle' },
|
|
{ value: 'traslado', label: 'Traslado', icon: 'i-heroicons-arrow-right' },
|
|
{ value: 'mezcla', label: 'Mezcla', icon: 'i-heroicons-beaker' },
|
|
{ value: 'ajuste_merma', label: 'Ajuste Merma', icon: 'i-heroicons-adjustments-horizontal' },
|
|
{ value: 'ajuste_cantidad', label: 'Ajuste Cantidad', icon: 'i-heroicons-calculator' },
|
|
{ value: 'ajuste_tipo', label: 'Ajuste Tipo', icon: 'i-heroicons-pencil' },
|
|
]
|
|
|
|
return {
|
|
// Lotes
|
|
fetchLotes,
|
|
fetchLoteById,
|
|
createLote,
|
|
updateLote,
|
|
deleteLote,
|
|
fetchTrazabilidad,
|
|
|
|
// Operaciones
|
|
fetchOperaciones,
|
|
createOperacion,
|
|
|
|
// Constantes
|
|
TIPOS_LOTE,
|
|
TIPOS_OPERACION,
|
|
}
|
|
}
|