Add material transformation planning
This commit is contained in:
@@ -92,6 +92,24 @@ const mapFabricPlan = (row) => ({
|
||||
updatedAt: row.updated_at
|
||||
});
|
||||
|
||||
const mapMaterialTransformation = (row) => ({
|
||||
id: row.id,
|
||||
batchCode: row.batch_code || '',
|
||||
stage: row.stage,
|
||||
inputMaterial: row.input_material,
|
||||
inputQuantityKg: Number(row.input_quantity_kg),
|
||||
outputMaterial: row.output_material,
|
||||
outputColor: row.output_color || '',
|
||||
expectedLossPercent: Number(row.expected_loss_percent || 0),
|
||||
expectedOutputKg: Number(row.expected_output_kg || 0),
|
||||
supplier: row.supplier || '',
|
||||
priority: row.priority || 'Normal',
|
||||
status: row.status || 'planned',
|
||||
notes: row.notes || '',
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at
|
||||
});
|
||||
|
||||
const mapMaterialDetails = (row) => ({
|
||||
materialKey: row.material_key,
|
||||
displayName: row.display_name || '',
|
||||
@@ -182,6 +200,19 @@ const listFabricPlans = async () => {
|
||||
return result.rows.map(mapFabricPlan);
|
||||
};
|
||||
|
||||
const listMaterialTransformations = async () => {
|
||||
const result = await pool.query(`
|
||||
SELECT id, batch_code, stage, input_material, input_quantity_kg, output_material, output_color,
|
||||
expected_loss_percent, expected_output_kg, supplier, priority, status, notes, created_at, updated_at
|
||||
FROM supply_material_transformations
|
||||
ORDER BY
|
||||
CASE status WHEN 'in_progress' THEN 1 WHEN 'planned' THEN 2 WHEN 'completed' THEN 3 ELSE 4 END,
|
||||
CASE priority WHEN 'Crítico' THEN 1 WHEN 'Atenção' THEN 2 ELSE 3 END,
|
||||
created_at DESC, id DESC
|
||||
`);
|
||||
return result.rows.map(mapMaterialTransformation);
|
||||
};
|
||||
|
||||
const listMaterialDetails = async () => {
|
||||
const result = await pool.query(`
|
||||
SELECT material_key, display_name, preferred_supplier, notes, created_at, updated_at
|
||||
@@ -1032,6 +1063,49 @@ const createFabricPlan = async (payload) => {
|
||||
return mapFabricPlan(result.rows[0]);
|
||||
};
|
||||
|
||||
const TRANSFORMATION_STAGES = new Set(['knitting', 'dyeing', 'finishing']);
|
||||
const TRANSFORMATION_STATUSES = new Set(['planned', 'in_progress', 'completed', 'canceled']);
|
||||
|
||||
const createMaterialTransformation = async (payload = {}) => {
|
||||
const stage = normalizeText(payload.stage).toLowerCase();
|
||||
const inputMaterial = normalizeText(payload.inputMaterial);
|
||||
const outputMaterial = normalizeText(payload.outputMaterial);
|
||||
const inputQuantityKg = normalizeNumber(payload.inputQuantityKg);
|
||||
const expectedLossPercent = normalizeNonNegativeNumber(payload.expectedLossPercent) ?? 0;
|
||||
if (!TRANSFORMATION_STAGES.has(stage)) throw createValidationError('Etapa de transformação inválida.');
|
||||
if (!inputMaterial || !outputMaterial) throw createValidationError('Material de entrada e saída são obrigatórios.');
|
||||
if (!inputQuantityKg) throw createValidationError('Quantidade de entrada deve ser maior que zero.');
|
||||
if (expectedLossPercent >= 100) throw createValidationError('A perda esperada deve ser menor que 100%.');
|
||||
const expectedOutputKg = Number((inputQuantityKg * (1 - (expectedLossPercent / 100))).toFixed(4));
|
||||
const result = await pool.query(`
|
||||
INSERT INTO supply_material_transformations (
|
||||
batch_code, stage, input_material, input_quantity_kg, output_material, output_color,
|
||||
expected_loss_percent, expected_output_kg, supplier, priority, status, notes, updated_at
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'planned', $11, CURRENT_TIMESTAMP)
|
||||
RETURNING id, batch_code, stage, input_material, input_quantity_kg, output_material, output_color,
|
||||
expected_loss_percent, expected_output_kg, supplier, priority, status, notes, created_at, updated_at
|
||||
`, [
|
||||
normalizeText(payload.batchCode) || null, stage, inputMaterial, inputQuantityKg, outputMaterial,
|
||||
normalizeText(payload.outputColor) || null, expectedLossPercent, expectedOutputKg,
|
||||
normalizeText(payload.supplier) || null, normalizeText(payload.priority) || 'Normal', normalizeText(payload.notes) || null
|
||||
]);
|
||||
return mapMaterialTransformation(result.rows[0]);
|
||||
};
|
||||
|
||||
const updateMaterialTransformationStatus = async (id, status) => {
|
||||
const normalizedStatus = normalizeText(status).toLowerCase();
|
||||
if (!TRANSFORMATION_STATUSES.has(normalizedStatus)) throw createValidationError('Status da transformação inválido.');
|
||||
const result = await pool.query(`
|
||||
UPDATE supply_material_transformations
|
||||
SET status = $2, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1
|
||||
RETURNING id, batch_code, stage, input_material, input_quantity_kg, output_material, output_color,
|
||||
expected_loss_percent, expected_output_kg, supplier, priority, status, notes, created_at, updated_at
|
||||
`, [id, normalizedStatus]);
|
||||
if (!result.rows[0]) throw createValidationError('Transformação não encontrada.');
|
||||
return mapMaterialTransformation(result.rows[0]);
|
||||
};
|
||||
|
||||
const deleteFabricPlan = async (id) => {
|
||||
await pool.query(`
|
||||
UPDATE supply_fabric_plans
|
||||
@@ -1243,6 +1317,7 @@ module.exports = {
|
||||
approveReceipt,
|
||||
consumeLotForProduction,
|
||||
createFabricPlan,
|
||||
createMaterialTransformation,
|
||||
createPurchaseOrder,
|
||||
createReceipt,
|
||||
deleteFabricPlan,
|
||||
@@ -1251,6 +1326,7 @@ module.exports = {
|
||||
buildProjectPurchaseNeeds,
|
||||
buildPurchaseNeeds,
|
||||
listFabricPlans,
|
||||
listMaterialTransformations,
|
||||
listMaterialDetails,
|
||||
listKnownSuppliers,
|
||||
listPurchaseOrders,
|
||||
@@ -1259,5 +1335,6 @@ module.exports = {
|
||||
listPurchaseNeeds,
|
||||
listReceipts,
|
||||
saveMaterialDetails,
|
||||
updateMaterialTransformationStatus,
|
||||
updatePurchaseOrderStatus
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user