Add local production order workflow
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m40s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m40s
This commit is contained in:
@@ -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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user