Add local production order workflow
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m40s

This commit is contained in:
Cauê Faleiros
2026-07-20 12:57:28 -03:00
parent 9af5f296a7
commit 88089343a8
6 changed files with 384 additions and 13 deletions

View File

@@ -31,6 +31,14 @@ const formatDate = (value) => {
return String(value).slice(0, 10);
};
const normalizeText = (value) => String(value || '').trim();
const normalizeQuantity = (value) => {
const quantity = Number(value);
if (!Number.isFinite(quantity) || quantity <= 0) return 0;
return quantity;
};
const mapProductionOrderRow = (row) => {
const status = normalizeStatus(row.status);
@@ -54,6 +62,42 @@ const mapProductionOrderRow = (row) => {
};
};
const getOrderById = async (id, client = pool) => {
const result = await client.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 po.id = $1
GROUP BY po.id;
`, [id]);
return result.rows[0] ? mapProductionOrderRow(result.rows[0]) : null;
};
const listProductionOrders = async (filters = {}) => {
const params = [];
const where = [];
@@ -133,7 +177,142 @@ const listProductionOrders = async (filters = {}) => {
return { orders, counts };
};
module.exports = {
listProductionOrders,
normalizeStatus
const createProductionOrders = async (orders = []) => {
const client = await pool.connect();
try {
await client.query('BEGIN');
const created = [];
const skipped = [];
for (const order of orders) {
const productDescription = normalizeText(order.productDescription);
const productSku = normalizeText(order.productSku);
const orderReference = normalizeText(order.orderReference);
const quantity = normalizeQuantity(order.quantity);
if (!productDescription || !quantity) {
skipped.push({ productSku, productDescription, reason: 'invalid_payload' });
continue;
}
const duplicateResult = await client.query(`
SELECT id
FROM production_orders
WHERE COALESCE(order_reference, '') = $1
AND COALESCE(product_sku, '') = $2
AND status IN ('open', 'in_progress')
LIMIT 1;
`, [orderReference, productSku]);
if (duplicateResult.rows.length) {
skipped.push({ productSku, productDescription, reason: 'duplicate_open_order' });
continue;
}
const insertResult = await client.query(`
INSERT INTO production_orders (
tiny_id,
number,
status,
order_reference,
issue_date,
expected_date,
product_sku,
product_description,
quantity,
unit,
integration_status,
tiny_payload
)
VALUES (
NULL,
NULL,
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10::jsonb
)
RETURNING id;
`, [
normalizeStatus(order.status || 'open'),
orderReference,
normalizeDateParam(order.issueDate) || formatDate(new Date()),
normalizeDateParam(order.expectedDate),
productSku,
productDescription,
quantity,
normalizeText(order.unit) || 'UN',
normalizeText(order.integrationStatus) || 'Local',
JSON.stringify(order.metadata || {})
]);
const orderId = insertResult.rows[0].id;
await client.query(`
UPDATE production_orders
SET number = $1, updated_at = CURRENT_TIMESTAMP
WHERE id = $2;
`, [normalizeText(order.number) || `OP-${String(orderId).padStart(5, '0')}`, orderId]);
const markers = Array.isArray(order.markers) ? order.markers : [];
for (const marker of markers) {
const label = normalizeText(marker.label);
if (!label) continue;
await client.query(`
INSERT INTO production_order_markers (production_order_id, label, color)
VALUES ($1, $2, $3)
ON CONFLICT (production_order_id, label) DO UPDATE SET color = EXCLUDED.color;
`, [orderId, label, normalizeText(marker.color) || null]);
}
const createdOrder = await getOrderById(orderId, client);
if (createdOrder) created.push(createdOrder);
}
await client.query('COMMIT');
return { created, skipped };
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}
};
const updateProductionOrderStatus = async (id, status) => {
const normalizedStatus = normalizeStatus(status);
if (!STATUS_LABELS[normalizedStatus]) {
const error = new Error('Invalid production order status');
error.statusCode = 400;
throw error;
}
const result = await pool.query(`
UPDATE production_orders
SET status = $1, updated_at = CURRENT_TIMESTAMP
WHERE id = $2
RETURNING id;
`, [normalizedStatus, id]);
if (!result.rows.length) {
const error = new Error('Production order not found');
error.statusCode = 404;
throw error;
}
return getOrderById(id);
};
module.exports = {
createProductionOrders,
listProductionOrders,
normalizeStatus,
updateProductionOrderStatus
};