Align cutting families with Olist production data
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 1m17s
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 1m17s
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
const { pool } = require('../db');
|
||||
|
||||
const FAMILY_KEYS = new Set(['BLCS', 'BLOS', 'BLMC', 'BLPM']);
|
||||
const FAMILY_KEYS = new Set(['BLCS', 'BLOS', 'BLMC', 'BLPM', 'BLRM']);
|
||||
const REQUIRED_HEADERS = ['id_op', 'numero_op', 'sku_produto', 'descricao_produto', 'quantidade_produzida', 'data_emissao', 'data_conclusao', 'situacao', 'observacoes'];
|
||||
|
||||
const normalizeText = (value) => String(value || '').replace(/\s+/g, ' ').trim();
|
||||
@@ -76,12 +76,18 @@ const extractObservationFields = (notes) => {
|
||||
const raw = String(notes || '');
|
||||
const lineValue = (pattern) => raw.match(pattern)?.[1]?.trim() || '';
|
||||
const supplier = lineValue(/(?:^|\n)\s*FORNECEDOR\s*:\s*([^\r\n]+)/i);
|
||||
const lotCode = lineValue(/(?:^|\n)\s*LOTE\s*:\s*([^\r\n]+)/i);
|
||||
const yieldPiecesPerKg = normalizeNumber(raw.match(/RENDIMENTO\s*:\s*([\d.,]+)/i)?.[1]);
|
||||
const explicitRolls = normalizeNumber(raw.match(/(?:QUANTIDADE\s+DE\s+ROLOS|ROLOS|BOBINAS)\s*:\s*([\d.,]+)/i)?.[1]);
|
||||
const lotCode = lineValue(/(?:^|\n)\s*(?:-\s*)?LOTE\s*:?[\t ]*([^\r\n]+)/i);
|
||||
const yieldMatch = raw.match(/RENDIMENTO\s*:\s*([\d.,]+)(?:\s*[-–]\s*([\d.,]+)\s*KG)?/i);
|
||||
const yieldPiecesPerKg = normalizeNumber(yieldMatch?.[1]);
|
||||
const bobbinMatch = raw.match(/(?:QUANTIDADE\s+DE\s+ROLOS|ROLOS|BOBINAS)\s*:\s*(\d+(?:[.,]\d+)?)(?:\s*\(\s*X\s*(\d+(?:[.,]\d+)?)\s*\))?(?:\s*[-–]\s*([\d.,]+)\s*KG)?/i);
|
||||
const rollBase = normalizeNumber(bobbinMatch?.[1]);
|
||||
const rollMultiplier = normalizeNumber(bobbinMatch?.[2]) || 1;
|
||||
const explicitRolls = rollBase ? rollBase * rollMultiplier : null;
|
||||
const fabricKg = normalizeNumber(raw.match(/(?:QUILOS?\s+DE\s+MALHA|QUILOS?\s+MALHA)\s*:\s*([\d.,]+)(?:\s*KG)?/i)?.[1])
|
||||
|| normalizeNumber(raw.match(/(?:ROLOS|BOBINAS)\s*:\s*[\d.,]+\s*[-–]\s*([\d.,]+)\s*KG/i)?.[1]);
|
||||
const ribKg = normalizeNumber(raw.match(/(?:QUILOS?\s+DE\s+(?:GOLA|RIBANA|VIEZ(?:\s*\([^)]*\))?))\s*:\s*([\d.,]+)(?:\s*KG)?/i)?.[1]);
|
||||
|| normalizeNumber(bobbinMatch?.[3])
|
||||
|| normalizeNumber(yieldMatch?.[2])
|
||||
|| normalizeNumber(raw.match(/(?:^|\n)\s*KG\s*:\s*([\d.,]+)(?:\s*KG)?/i)?.[1]);
|
||||
const ribKg = normalizeNumber(raw.match(/(?:QUILOS?\s+DE\s+(?:GOLA|RIBANA|VIEZ(?:\s*\([^)]*\))?)|RIBANA)\s*:\s*([\d.,]+)(?:\s*KG)?/i)?.[1]);
|
||||
|
||||
return { supplier, lotCode, yieldPiecesPerKg, rollQuantity: explicitRolls, fabricKg, ribKg };
|
||||
};
|
||||
@@ -165,6 +171,7 @@ const parseFinalizedProductionOrderCsv = (csv) => {
|
||||
|
||||
const refreshYieldRecommendations = async (client) => {
|
||||
await client.query('DELETE FROM production_yield_recommendations;');
|
||||
await client.query('DELETE FROM production_yield_supplier_recommendations;');
|
||||
await client.query(`
|
||||
INSERT INTO production_yield_recommendations (
|
||||
family_key, sample_count, yield_sample_count, roll_sample_count,
|
||||
@@ -178,21 +185,44 @@ const refreshYieldRecommendations = async (client) => {
|
||||
COUNT(*) FILTER (WHERE fabric_kg > 0 AND roll_quantity > 0)::int,
|
||||
AVG(yield_pieces_per_kg),
|
||||
AVG(fabric_kg / roll_quantity) FILTER (WHERE fabric_kg > 0 AND roll_quantity > 0),
|
||||
AVG(yield_pieces_per_kg) FILTER (WHERE fabric_kg > 0 AND roll_quantity > 0 AND yield_pieces_per_kg > 0)
|
||||
* AVG(fabric_kg / roll_quantity) FILTER (WHERE fabric_kg > 0 AND roll_quantity > 0 AND yield_pieces_per_kg > 0),
|
||||
AVG(yield_pieces_per_kg * (fabric_kg / roll_quantity)) FILTER (WHERE fabric_kg > 0 AND roll_quantity > 0 AND yield_pieces_per_kg > 0),
|
||||
MAX(completed_date),
|
||||
CURRENT_TIMESTAMP
|
||||
FROM production_orders
|
||||
WHERE status = 'finished'
|
||||
AND split_part(product_sku, '.', 1) IN ('BLCS', 'BLOS', 'BLMC', 'BLPM')
|
||||
AND split_part(product_sku, '.', 1) IN ('BLCS', 'BLOS', 'BLMC', 'BLPM', 'BLRM')
|
||||
GROUP BY split_part(product_sku, '.', 1);
|
||||
`);
|
||||
await client.query(`
|
||||
INSERT INTO production_yield_supplier_recommendations (
|
||||
family_key, supplier, sample_count, yield_sample_count, roll_sample_count,
|
||||
avg_yield_pieces_per_kg, avg_kg_per_roll, recommended_units_per_roll,
|
||||
last_completed_date, updated_at
|
||||
)
|
||||
SELECT
|
||||
split_part(product_sku, '.', 1) AS family_key,
|
||||
supplier,
|
||||
COUNT(*)::int,
|
||||
COUNT(yield_pieces_per_kg)::int,
|
||||
COUNT(*) FILTER (WHERE fabric_kg > 0 AND roll_quantity > 0)::int,
|
||||
AVG(yield_pieces_per_kg),
|
||||
AVG(fabric_kg / roll_quantity) FILTER (WHERE fabric_kg > 0 AND roll_quantity > 0),
|
||||
AVG(yield_pieces_per_kg * (fabric_kg / roll_quantity)) FILTER (WHERE fabric_kg > 0 AND roll_quantity > 0 AND yield_pieces_per_kg > 0),
|
||||
MAX(completed_date),
|
||||
CURRENT_TIMESTAMP
|
||||
FROM production_orders
|
||||
WHERE status = 'finished'
|
||||
AND supplier IS NOT NULL
|
||||
AND split_part(product_sku, '.', 1) IN ('BLCS', 'BLOS', 'BLMC', 'BLPM', 'BLRM')
|
||||
GROUP BY split_part(product_sku, '.', 1), supplier;
|
||||
`);
|
||||
};
|
||||
|
||||
const listProductionOrderImportData = async () => {
|
||||
const [runs, recommendations] = await Promise.all([
|
||||
const [runs, recommendations, supplierRecommendations] = await Promise.all([
|
||||
pool.query(`SELECT id, filename, status, total_rows, imported_count, updated_count, skipped_count, failed_count, error_message, started_at, completed_at FROM production_order_import_runs ORDER BY started_at DESC LIMIT 10;`),
|
||||
pool.query(`SELECT family_key, sample_count, yield_sample_count, roll_sample_count, avg_yield_pieces_per_kg, avg_kg_per_roll, recommended_units_per_roll, last_completed_date, updated_at FROM production_yield_recommendations ORDER BY family_key;`)
|
||||
pool.query(`SELECT family_key, sample_count, yield_sample_count, roll_sample_count, avg_yield_pieces_per_kg, avg_kg_per_roll, recommended_units_per_roll, last_completed_date, updated_at FROM production_yield_recommendations ORDER BY family_key;`),
|
||||
pool.query(`SELECT family_key, supplier, sample_count, yield_sample_count, roll_sample_count, avg_yield_pieces_per_kg, avg_kg_per_roll, recommended_units_per_roll, last_completed_date, updated_at FROM production_yield_supplier_recommendations ORDER BY family_key, supplier;`)
|
||||
]);
|
||||
return {
|
||||
runs: runs.rows.map(row => ({
|
||||
@@ -207,6 +237,14 @@ const listProductionOrderImportData = async () => {
|
||||
avgKgPerRoll: row.avg_kg_per_roll === null ? null : Number(row.avg_kg_per_roll),
|
||||
recommendedUnitsPerRoll: row.recommended_units_per_roll === null ? null : Number(row.recommended_units_per_roll),
|
||||
lastCompletedDate: row.last_completed_date || null, updatedAt: row.updated_at
|
||||
})),
|
||||
supplierRecommendations: supplierRecommendations.rows.map(row => ({
|
||||
familyKey: row.family_key, supplier: row.supplier, sampleCount: Number(row.sample_count),
|
||||
yieldSampleCount: Number(row.yield_sample_count), rollSampleCount: Number(row.roll_sample_count),
|
||||
avgYieldPiecesPerKg: row.avg_yield_pieces_per_kg === null ? null : Number(row.avg_yield_pieces_per_kg),
|
||||
avgKgPerRoll: row.avg_kg_per_roll === null ? null : Number(row.avg_kg_per_roll),
|
||||
recommendedUnitsPerRoll: row.recommended_units_per_roll === null ? null : Number(row.recommended_units_per_roll),
|
||||
lastCompletedDate: row.last_completed_date || null, updatedAt: row.updated_at
|
||||
}))
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user