Added Multi-Company Support

This commit is contained in:
2026-06-08 00:54:21 -05:00
parent c164395915
commit db614a6707
32 changed files with 1133 additions and 323 deletions

View File

@@ -87,19 +87,21 @@ function upsertEmployee(employee) {
return one('SELECT * FROM employees WHERE id = ?', [result.lastInsertRowid]);
}
function assignmentRows(query = {}) {
function assignmentRows(query = {}, companyId) {
return all(`
SELECT aa.*, a.asset_id AS asset_code, a.description AS asset_description,
e.name AS employee_name, e.email AS employee_email, e.employee_number
FROM asset_assignments aa
JOIN assets a ON a.id = aa.asset_id
LEFT JOIN employees e ON e.id = aa.employee_id
WHERE (? IS NULL OR aa.asset_id = ?)
WHERE (? IS NULL OR a.entity_id = ?)
AND (? IS NULL OR aa.asset_id = ?)
AND (? IS NULL OR aa.employee_id = ?)
AND (? IS NULL OR aa.released_at IS NULL)
ORDER BY aa.assigned_at DESC, aa.id DESC
LIMIT 500
`, [
companyId || null, companyId || null,
query.asset_id || null,
query.asset_id || null,
query.employee_id || null,
@@ -108,9 +110,10 @@ function assignmentRows(query = {}) {
]).map(assignmentFromRow);
}
function assignAsset(body, userId) {
function assignAsset(body, userId, companyId) {
const timestamp = now();
const asset = one('SELECT * FROM assets WHERE id = ?', [body.asset_id]);
// The asset must belong to the active company so assignments can't cross companies.
const asset = one('SELECT * FROM assets WHERE id = ? AND (? IS NULL OR entity_id = ?)', [body.asset_id, companyId || null, companyId || null]);
if (!asset) throw Object.assign(new Error('Asset not found'), { status: 404 });
const employee = body.employee_id ? one('SELECT * FROM employees WHERE id = ?', [body.employee_id]) : null;
@@ -154,15 +157,18 @@ function assignAsset(body, userId) {
[employee?.name || asset.custodian || null, department, location, timestamp, body.asset_id]
);
const assignment = assignmentRows({ asset_id: body.asset_id, active: true })[0];
const assignment = assignmentRows({ asset_id: body.asset_id, active: true }, companyId)[0];
audit(userId, 'assign', 'asset', body.asset_id, null, assignment);
return assignment || one('SELECT * FROM asset_assignments WHERE id = ?', [result.lastInsertRowid]);
});
}
function releaseAssignment(id, body, userId) {
const before = one('SELECT * FROM asset_assignments WHERE id = ?', [id]);
if (!before) return null;
function releaseAssignment(id, body, userId, companyId) {
const before = one(
'SELECT aa.*, a.entity_id AS asset_entity_id FROM asset_assignments aa JOIN assets a ON a.id = aa.asset_id WHERE aa.id = ?',
[id]
);
if (!before || (companyId && before.asset_entity_id !== companyId)) return null;
const timestamp = now();
run(
`UPDATE asset_assignments
@@ -171,26 +177,28 @@ function releaseAssignment(id, body, userId) {
[timestamp, body.release_reason || 'Released', body.notes || null, timestamp, id]
);
audit(userId, 'release_assignment', 'asset_assignment', id, before, { released_at: timestamp, ...body });
return assignmentRows({ asset_id: before.asset_id }).find((assignment) => assignment.id === Number(id));
return assignmentRows({ asset_id: before.asset_id }, companyId).find((assignment) => assignment.id === Number(id));
}
function assignmentSummary() {
function assignmentSummary(companyId) {
const stats = one(`
SELECT
COUNT(*) AS active_assignments,
COUNT(DISTINCT employee_id) AS assigned_employees,
COUNT(DISTINCT location) AS assigned_locations
FROM asset_assignments
WHERE released_at IS NULL
`);
COUNT(DISTINCT aa.employee_id) AS assigned_employees,
COUNT(DISTINCT aa.location) AS assigned_locations
FROM asset_assignments aa
JOIN assets a ON a.id = aa.asset_id
WHERE aa.released_at IS NULL AND (? IS NULL OR a.entity_id = ?)
`, [companyId || null, companyId || null]);
const unassigned = one(`
SELECT COUNT(*) AS count
FROM assets a
WHERE NOT EXISTS (
SELECT 1 FROM asset_assignments aa
WHERE aa.asset_id = a.id AND aa.released_at IS NULL
)
`);
WHERE (? IS NULL OR a.entity_id = ?)
AND NOT EXISTS (
SELECT 1 FROM asset_assignments aa
WHERE aa.asset_id = a.id AND aa.released_at IS NULL
)
`, [companyId || null, companyId || null]);
return { ...stats, unassigned_assets: unassigned.count };
}