const { pool } = require('../db'); const STATUS_LABELS = { open: 'Em aberto', in_progress: 'Em andamento', finished: 'Finalizada', canceled: 'Cancelada' }; const normalizeStatus = (status) => { const normalizedStatus = String(status || 'open').trim().toLowerCase(); if (['open', 'em_aberto', 'em aberto', 'aberta'].includes(normalizedStatus)) return 'open'; if (['in_progress', 'andamento', 'em andamento'].includes(normalizedStatus)) return 'in_progress'; if (['finished', 'finalizada', 'finalizado'].includes(normalizedStatus)) return 'finished'; if (['canceled', 'cancelada', 'cancelado', 'cancelled'].includes(normalizedStatus)) return 'canceled'; return normalizedStatus || 'open'; }; const normalizeDateParam = (value) => { if (!value) return null; const date = new Date(`${value}T00:00:00`); if (Number.isNaN(date.getTime())) return null; return value; }; const formatDate = (value) => { if (!value) return null; if (value instanceof Date && !Number.isNaN(value.getTime())) { return value.toISOString().slice(0, 10); } return String(value).slice(0, 10); }; const mapProductionOrderRow = (row) => { const status = normalizeStatus(row.status); return { id: row.id, tinyId: row.tiny_id || '', number: row.number || '', status, statusLabel: STATUS_LABELS[status] || row.status || 'Em aberto', orderReference: row.order_reference || '', issueDate: formatDate(row.issue_date), expectedDate: formatDate(row.expected_date), productSku: row.product_sku || '', productDescription: row.product_description || '', quantity: Number(row.quantity || 0), unit: row.unit || 'UN', integrationStatus: row.integration_status || '', markers: Array.isArray(row.markers) ? row.markers.filter(Boolean) : [], createdAt: row.created_at || null, updatedAt: row.updated_at || null }; }; const listProductionOrders = async (filters = {}) => { const params = []; const where = []; const normalizedStart = normalizeDateParam(filters.start); const normalizedEnd = normalizeDateParam(filters.end); const normalizedSearch = String(filters.search || '').trim(); if (normalizedStart) { params.push(normalizedStart); where.push(`COALESCE(po.issue_date, po.expected_date, po.created_at::date) >= $${params.length}::date`); } if (normalizedEnd) { params.push(normalizedEnd); where.push(`COALESCE(po.issue_date, po.expected_date, po.created_at::date) <= $${params.length}::date`); } if (normalizedSearch) { params.push(`%${normalizedSearch}%`); where.push(`( po.number ILIKE $${params.length} OR po.order_reference ILIKE $${params.length} OR po.product_sku ILIKE $${params.length} OR po.product_description ILIKE $${params.length} )`); } const result = await pool.query(` SELECT po.id, po.tiny_id, po.number, po.status, po.order_reference, po.issue_date, po.expected_date, po.product_sku, po.product_description, po.quantity, po.unit, po.integration_status, po.created_at, po.updated_at, COALESCE( JSON_AGG( JSON_BUILD_OBJECT( 'label', pom.label, 'color', pom.color ) ORDER BY pom.label ) FILTER (WHERE pom.id IS NOT NULL), '[]'::json ) as markers FROM production_orders po LEFT JOIN production_order_markers pom ON pom.production_order_id = po.id ${where.length ? `WHERE ${where.join(' AND ')}` : ''} GROUP BY po.id ORDER BY COALESCE(po.issue_date, po.created_at::date) DESC, CASE WHEN po.number ~ '^\\d+$' THEN po.number::bigint ELSE NULL END DESC NULLS LAST, po.id DESC; `, params); const orders = result.rows.map(mapProductionOrderRow); const counts = orders.reduce((nextCounts, order) => { nextCounts.all += 1; nextCounts[order.status] = (nextCounts[order.status] || 0) + 1; return nextCounts; }, { all: 0, open: 0, in_progress: 0, finished: 0, canceled: 0 }); return { orders, counts }; }; module.exports = { listProductionOrders, normalizeStatus };