Add production defect and workstation foundation

This commit is contained in:
Cauê Faleiros
2026-08-25 11:58:43 -03:00
parent 282f1e194a
commit 5370dffce2
3 changed files with 145 additions and 3 deletions

View File

@@ -267,6 +267,18 @@ const mapLotReservation = (reservation) => ({
lotSupplier: reservation.lot_supplier || ''
});
const mapDefect = (defect) => ({
id: Number(defect.id),
workstationId: defect.workstation_id === null ? null : Number(defect.workstation_id),
workstationName: defect.workstation_name || '',
defectType: defect.defect_type || '',
origin: defect.origin || '',
quantity: Number(defect.quantity || 0),
lotCode: defect.lot_code || '',
notes: defect.notes || '',
occurredAt: defect.occurred_at || null
});
const mapProductionOrderRow = (row) => {
const status = normalizeStatus(row.status);
@@ -301,6 +313,7 @@ const mapProductionOrderRow = (row) => {
rejectedQuantity: Number(row.rejected_quantity || 0),
finishedQuantity: row.finished_quantity === null ? null : Number(row.finished_quantity),
qualityNotes: row.quality_notes || '',
defects: Array.isArray(row.defects) ? row.defects.map(mapDefect) : [],
lotReservations: Array.isArray(row.lot_reservations) ? row.lot_reservations.map(mapLotReservation) : [],
markers: Array.isArray(row.markers) ? row.markers.filter(Boolean) : [],
components: Array.isArray(row.components) ? row.components.map(mapComponent) : [],
@@ -502,7 +515,26 @@ const getOrderById = async (id, client = pool) => {
WHERE step.production_order_id = po.id
),
'[]'::json
) as steps
) as steps,
COALESCE(
(
SELECT JSON_AGG(JSON_BUILD_OBJECT(
'id', defect.id,
'workstation_id', defect.workstation_id,
'workstation_name', workstation.name,
'defect_type', defect.defect_type,
'origin', defect.origin,
'quantity', defect.quantity,
'lot_code', defect.lot_code,
'notes', defect.notes,
'occurred_at', defect.occurred_at
) ORDER BY defect.occurred_at DESC, defect.id DESC)
FROM production_order_defects defect
LEFT JOIN production_workstations workstation ON workstation.id = defect.workstation_id
WHERE defect.production_order_id = po.id
),
'[]'::json
) as defects
FROM production_orders po
LEFT JOIN production_plans plan ON plan.id = po.production_plan_id
WHERE po.id = $1;
@@ -621,7 +653,26 @@ const baseProductionOrderSelect = `
WHERE step.production_order_id = po.id
),
'[]'::json
) as steps
) as steps,
COALESCE(
(
SELECT JSON_AGG(JSON_BUILD_OBJECT(
'id', defect.id,
'workstation_id', defect.workstation_id,
'workstation_name', workstation.name,
'defect_type', defect.defect_type,
'origin', defect.origin,
'quantity', defect.quantity,
'lot_code', defect.lot_code,
'notes', defect.notes,
'occurred_at', defect.occurred_at
) ORDER BY defect.occurred_at DESC, defect.id DESC)
FROM production_order_defects defect
LEFT JOIN production_workstations workstation ON workstation.id = defect.workstation_id
WHERE defect.production_order_id = po.id
),
'[]'::json
) as defects
FROM production_orders po
LEFT JOIN production_plans plan ON plan.id = po.production_plan_id
`;
@@ -1739,12 +1790,49 @@ const updateProductionOrderExecution = async (id, payload = {}) => {
return getOrderById(id);
};
const listProductionWorkstations = async () => {
const result = await pool.query(`
SELECT id, code, name, color, sort_order, is_active
FROM production_workstations
WHERE is_active = TRUE
ORDER BY sort_order, name;
`);
return result.rows.map(row => ({ id: Number(row.id), code: row.code, name: row.name, color: row.color, sortOrder: Number(row.sort_order), isActive: Boolean(row.is_active) }));
};
const addProductionOrderDefect = async (id, payload = {}) => {
const defectType = normalizeText(payload.defectType);
const quantity = normalizeQuantity(payload.quantity);
const workstationId = normalizeInteger(payload.workstationId);
if (!defectType || !quantity) {
const error = new Error('Informe o tipo e a quantidade do defeito.');
error.statusCode = 400;
throw error;
}
if (workstationId) {
const workstation = await pool.query('SELECT id FROM production_workstations WHERE id = $1 AND is_active = TRUE;', [workstationId]);
if (!workstation.rowCount) {
const error = new Error('Posto de trabalho inválido.');
error.statusCode = 400;
throw error;
}
}
const result = await pool.query(`
INSERT INTO production_order_defects (production_order_id, workstation_id, defect_type, origin, quantity, lot_code, notes)
VALUES ($1, $2, $3, NULLIF($4, ''), $5, NULLIF($6, ''), NULLIF($7, ''))
RETURNING id;
`, [id, workstationId, defectType, normalizeText(payload.origin), quantity, normalizeText(payload.lotCode), normalizeText(payload.notes)]);
if (!result.rowCount) throw new Error('Não foi possível registrar o defeito.');
return getOrderById(id);
};
module.exports = {
createProductionOrders,
deleteManualProductComposition,
getProductComposition,
importTinyProductCompositionExport,
listProductionPlans,
listProductionWorkstations,
listProductCompositions,
listProductionOrders,
normalizeStatus,
@@ -1753,6 +1841,7 @@ module.exports = {
upsertTinyProductionOrderDetail,
updateProductionPlan,
updateProductionPlanStatus,
addProductionOrderDefect,
updateProductionOrderExecution,
updateProductionOrderStatus
};