Updated A LOT
This commit is contained in:
93
server/services/assetClasses.js
Normal file
93
server/services/assetClasses.js
Normal file
@@ -0,0 +1,93 @@
|
||||
const { all, audit, now, one, parseJson, run } = require('../db');
|
||||
|
||||
const SOURCES = ['common', 'industry', 'business', 'custom'];
|
||||
|
||||
// How many asset categories reference a given class number (categories store it in metadata).
|
||||
function categoryUsage() {
|
||||
const counts = {};
|
||||
for (const row of all("SELECT metadata FROM reference_values WHERE type = 'category'")) {
|
||||
const num = parseJson(row.metadata, {}).asset_class_number;
|
||||
if (num) counts[num] = (counts[num] || 0) + 1;
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
|
||||
function fromRow(row, usage) {
|
||||
if (!row) return null;
|
||||
return {
|
||||
id: row.id,
|
||||
class_number: row.class_number,
|
||||
description: row.description,
|
||||
gds: row.gds,
|
||||
ads: row.ads,
|
||||
source: row.source,
|
||||
table: row.source, // back-compat alias used by the category picker
|
||||
category_count: row.class_number ? (usage[row.class_number] || 0) : 0
|
||||
};
|
||||
}
|
||||
|
||||
function list() {
|
||||
const usage = categoryUsage();
|
||||
return all('SELECT * FROM asset_classes ORDER BY description').map((row) => fromRow(row, usage));
|
||||
}
|
||||
|
||||
function getClass(id) {
|
||||
return fromRow(one('SELECT * FROM asset_classes WHERE id = ?', [id]), categoryUsage());
|
||||
}
|
||||
|
||||
function normalize(body) {
|
||||
const num = (value) => {
|
||||
if (value === '' || value === null || value === undefined) return null;
|
||||
const n = Number(value);
|
||||
return Number.isFinite(n) ? n : null;
|
||||
};
|
||||
return {
|
||||
class_number: body.class_number ? String(body.class_number).trim() : null,
|
||||
description: String(body.description || '').trim(),
|
||||
gds: num(body.gds),
|
||||
ads: num(body.ads),
|
||||
source: SOURCES.includes(body.source) ? body.source : 'custom'
|
||||
};
|
||||
}
|
||||
|
||||
function createClass(body, userId) {
|
||||
const input = normalize(body);
|
||||
if (!input.description) throw Object.assign(new Error('A description is required'), { status: 400 });
|
||||
const ts = now();
|
||||
const result = run(
|
||||
'INSERT INTO asset_classes (class_number, description, gds, ads, source, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)',
|
||||
[input.class_number, input.description, input.gds, input.ads, input.source, ts, ts]
|
||||
);
|
||||
audit(userId, 'create', 'asset_class', result.lastInsertRowid, null, input);
|
||||
return getClass(result.lastInsertRowid);
|
||||
}
|
||||
|
||||
function updateClass(id, body, userId) {
|
||||
const before = one('SELECT * FROM asset_classes WHERE id = ?', [id]);
|
||||
if (!before) return null;
|
||||
const input = normalize({ ...before, ...body });
|
||||
if (!input.description) throw Object.assign(new Error('A description is required'), { status: 400 });
|
||||
run(
|
||||
'UPDATE asset_classes SET class_number = ?, description = ?, gds = ?, ads = ?, source = ?, updated_at = ? WHERE id = ?',
|
||||
[input.class_number, input.description, input.gds, input.ads, input.source, now(), id]
|
||||
);
|
||||
audit(userId, 'update', 'asset_class', id, before, input);
|
||||
return getClass(id);
|
||||
}
|
||||
|
||||
function deleteClass(id, userId) {
|
||||
const before = one('SELECT * FROM asset_classes WHERE id = ?', [id]);
|
||||
if (!before) return false;
|
||||
run('DELETE FROM asset_classes WHERE id = ?', [id]);
|
||||
audit(userId, 'delete', 'asset_class', id, before, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
SOURCES,
|
||||
createClass,
|
||||
deleteClass,
|
||||
getClass,
|
||||
list,
|
||||
updateClass
|
||||
};
|
||||
Reference in New Issue
Block a user