All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m18s
158 lines
5.2 KiB
JavaScript
158 lines
5.2 KiB
JavaScript
const { pool } = require('../db');
|
|
|
|
const FAMILY_KEYS = ['BLCS', 'BLOS', 'BLMC', 'BLPM'];
|
|
const FAMILY_KEY_SET = new Set(FAMILY_KEYS);
|
|
const PRODUCT_TYPE_KEYS = [
|
|
'finished_apparel',
|
|
'finished_accessory',
|
|
'raw_material',
|
|
'packaging',
|
|
'dtf_input',
|
|
'dtf_service',
|
|
'kit_bundle',
|
|
'service',
|
|
'machine_part',
|
|
'equipment',
|
|
'ignore_from_planning',
|
|
'unknown'
|
|
];
|
|
const PRODUCT_TYPE_KEY_SET = new Set(PRODUCT_TYPE_KEYS);
|
|
|
|
const normalizeFamilyKey = (value) => {
|
|
const familyKey = String(value || '').trim().toUpperCase();
|
|
return FAMILY_KEY_SET.has(familyKey) ? familyKey : '';
|
|
};
|
|
|
|
const normalizeNumber = (value) => {
|
|
const number = Number(value);
|
|
return Number.isFinite(number) && number > 0 ? number : null;
|
|
};
|
|
|
|
const normalizeText = (value) => String(value || '').replace(/\s+/g, ' ').trim();
|
|
|
|
const normalizeProductType = (value) => {
|
|
const productType = normalizeText(value);
|
|
return PRODUCT_TYPE_KEY_SET.has(productType) ? productType : '';
|
|
};
|
|
|
|
const normalizeFamilyYields = (familyYields = {}) => {
|
|
return FAMILY_KEYS.reduce((normalized, familyKey) => {
|
|
const unitsPerRoll = normalizeNumber(familyYields[familyKey]);
|
|
if (unitsPerRoll) normalized[familyKey] = unitsPerRoll;
|
|
return normalized;
|
|
}, {});
|
|
};
|
|
|
|
const normalizeProductOverrides = (productOverrides = {}) => {
|
|
return Object.entries(productOverrides).reduce((normalized, [productId, override]) => {
|
|
const normalizedProductId = normalizeText(productId);
|
|
if (!normalizedProductId || !override || typeof override !== 'object') return normalized;
|
|
|
|
const familyKey = normalizeFamilyKey(override.familyKey);
|
|
const color = normalizeText(override.color);
|
|
const size = normalizeText(override.size).toUpperCase();
|
|
const productType = normalizeProductType(override.productType);
|
|
const planningNotes = normalizeText(override.planningNotes);
|
|
|
|
if (!familyKey && !color && !size && !productType && !planningNotes) return normalized;
|
|
|
|
normalized[normalizedProductId] = {
|
|
familyKey,
|
|
color,
|
|
size,
|
|
productType,
|
|
planningNotes
|
|
};
|
|
|
|
return normalized;
|
|
}, {});
|
|
};
|
|
|
|
const listCuttingSettings = async () => {
|
|
const [familyResult, overrideResult] = await Promise.all([
|
|
pool.query(`
|
|
SELECT family_key, units_per_roll
|
|
FROM cutting_family_rules
|
|
WHERE units_per_roll IS NOT NULL AND units_per_roll > 0
|
|
ORDER BY family_key
|
|
`),
|
|
pool.query(`
|
|
SELECT product_id, family_key, color, size, product_type, planning_notes
|
|
FROM cutting_product_overrides
|
|
ORDER BY product_id
|
|
`)
|
|
]);
|
|
|
|
return {
|
|
familyYields: familyResult.rows.reduce((settings, row) => {
|
|
settings[row.family_key] = Number(row.units_per_roll);
|
|
return settings;
|
|
}, {}),
|
|
productOverrides: overrideResult.rows.reduce((settings, row) => {
|
|
settings[row.product_id] = {
|
|
familyKey: row.family_key || '',
|
|
color: row.color || '',
|
|
size: row.size || '',
|
|
productType: row.product_type || '',
|
|
planningNotes: row.planning_notes || ''
|
|
};
|
|
return settings;
|
|
}, {})
|
|
};
|
|
};
|
|
|
|
const saveCuttingSettings = async ({ familyYields = {}, productOverrides = {} }) => {
|
|
const normalizedFamilyYields = normalizeFamilyYields(familyYields);
|
|
const normalizedProductOverrides = normalizeProductOverrides(productOverrides);
|
|
const client = await pool.connect();
|
|
|
|
try {
|
|
await client.query('BEGIN');
|
|
|
|
await client.query('DELETE FROM cutting_family_rules');
|
|
for (const [familyKey, unitsPerRoll] of Object.entries(normalizedFamilyYields)) {
|
|
await client.query(`
|
|
INSERT INTO cutting_family_rules (family_key, units_per_roll, updated_at)
|
|
VALUES ($1, $2, CURRENT_TIMESTAMP)
|
|
`, [familyKey, unitsPerRoll]);
|
|
}
|
|
|
|
await client.query('DELETE FROM cutting_product_overrides');
|
|
for (const [productId, override] of Object.entries(normalizedProductOverrides)) {
|
|
await client.query(`
|
|
INSERT INTO cutting_product_overrides (product_id, family_key, color, size, product_type, planning_notes, updated_at)
|
|
VALUES ($1, $2, $3, $4, $5, $6, CURRENT_TIMESTAMP)
|
|
`, [
|
|
productId,
|
|
override.familyKey || null,
|
|
override.color || null,
|
|
override.size || null,
|
|
override.productType || null,
|
|
override.planningNotes || null
|
|
]);
|
|
}
|
|
|
|
await client.query('COMMIT');
|
|
|
|
return {
|
|
familyYields: normalizedFamilyYields,
|
|
productOverrides: normalizedProductOverrides
|
|
};
|
|
} catch (error) {
|
|
await client.query('ROLLBACK');
|
|
throw error;
|
|
} finally {
|
|
client.release();
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
FAMILY_KEYS,
|
|
listCuttingSettings,
|
|
normalizeFamilyKey,
|
|
normalizeFamilyYields,
|
|
normalizeProductType,
|
|
normalizeProductOverrides,
|
|
saveCuttingSettings
|
|
};
|