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

@@ -47,10 +47,11 @@ function normalize(body) {
return input;
}
function listContacts(query = {}) {
function listContacts(query = {}, companyId) {
return all(
`SELECT * FROM contacts
WHERE (? IS NULL OR type = ?)
WHERE (? IS NULL OR entity_id = ?)
AND (? IS NULL OR type = ?)
AND (? IS NULL OR status = ?)
AND (? IS NULL OR (
first_name LIKE '%' || ? || '%' OR last_name LIKE '%' || ? || '%' OR
@@ -59,6 +60,7 @@ function listContacts(query = {}) {
))
ORDER BY type, organization, last_name, first_name`,
[
companyId || null, companyId || null,
query.type || null, query.type || null,
query.status || null, query.status || null,
query.search || null, query.search || null, query.search || null,
@@ -67,51 +69,52 @@ function listContacts(query = {}) {
).map((row) => fromRow(row));
}
function getContact(id) {
return fromRow(one('SELECT * FROM contacts WHERE id = ?', [id]), true);
function getContact(id, companyId) {
return fromRow(one('SELECT * FROM contacts WHERE id = ? AND (? IS NULL OR entity_id = ?)', [id, companyId || null, companyId || null]), true);
}
function createContact(body, userId) {
function createContact(body, userId, companyId) {
const input = normalize(body);
const ts = now();
const cols = COLUMNS.filter((c) => input[c] !== undefined);
const result = run(
`INSERT INTO contacts (${cols.join(', ')}, created_by, created_at, updated_at)
VALUES (${cols.map(() => '?').join(', ')}, ?, ?, ?)`,
[...cols.map((c) => input[c]), userId, ts, ts]
`INSERT INTO contacts (entity_id, ${cols.join(', ')}, created_by, created_at, updated_at)
VALUES (?, ${cols.map(() => '?').join(', ')}, ?, ?, ?)`,
[companyId || null, ...cols.map((c) => input[c]), userId, ts, ts]
);
audit(userId, 'create', 'contact', result.lastInsertRowid, null, { type: input.type, name: displayName(input) });
return getContact(result.lastInsertRowid);
return getContact(result.lastInsertRowid, companyId);
}
function updateContact(id, body, userId) {
function updateContact(id, body, userId, companyId) {
const before = one('SELECT * FROM contacts WHERE id = ?', [id]);
if (!before) return null;
if (!before || (companyId && before.entity_id !== companyId)) return null;
const input = normalize({ ...before, ...body });
run(
`UPDATE contacts SET ${COLUMNS.map((c) => `${c} = ?`).join(', ')}, updated_at = ? WHERE id = ?`,
[...COLUMNS.map((c) => input[c] ?? null), now(), id]
);
audit(userId, 'update', 'contact', id, before, body);
return getContact(id);
return getContact(id, companyId);
}
function deleteContact(id, userId) {
function deleteContact(id, userId, companyId) {
const before = one('SELECT * FROM contacts WHERE id = ?', [id]);
if (!before) return false;
if (!before || (companyId && before.entity_id !== companyId)) return false;
run('DELETE FROM contacts WHERE id = ?', [id]);
audit(userId, 'delete', 'contact', id, before, null);
return true;
}
function addNote(contactId, bodyText, userId) {
if (!one('SELECT id FROM contacts WHERE id = ?', [contactId])) return null;
function addNote(contactId, bodyText, userId, companyId) {
if (!one('SELECT id FROM contacts WHERE id = ? AND (? IS NULL OR entity_id = ?)', [contactId, companyId || null, companyId || null])) return null;
const result = run('INSERT INTO contact_notes (contact_id, body, created_by, created_at) VALUES (?, ?, ?, ?)', [contactId, bodyText, userId, now()]);
audit(userId, 'create', 'contact_note', result.lastInsertRowid, null, { contact_id: contactId });
return one('SELECT n.id, n.body, n.created_at, u.name AS author FROM contact_notes n LEFT JOIN users u ON u.id = n.created_by WHERE n.id = ?', [result.lastInsertRowid]);
}
function deleteNote(contactId, noteId, userId) {
function deleteNote(contactId, noteId, userId, companyId) {
if (companyId && !one('SELECT id FROM contacts WHERE id = ? AND entity_id = ?', [contactId, companyId])) return false;
const result = run('DELETE FROM contact_notes WHERE id = ? AND contact_id = ?', [noteId, contactId]);
if (!result.changes) return false;
audit(userId, 'delete', 'contact_note', noteId, null, { contact_id: contactId });
@@ -152,10 +155,12 @@ function upsertWorkdayContact(worker) {
);
return existing.id;
}
// Workday sync is global (no request company context); new workers land in the default company.
const defaultCompany = one("SELECT id FROM entities WHERE status = 'active' ORDER BY id LIMIT 1");
const cols = Object.keys(fields);
const result = run(
`INSERT INTO contacts (${cols.join(', ')}, last_synced_at, created_at, updated_at) VALUES (${cols.map(() => '?').join(', ')}, ?, ?, ?)`,
[...cols.map((c) => fields[c]), ts, ts, ts]
`INSERT INTO contacts (entity_id, ${cols.join(', ')}, last_synced_at, created_at, updated_at) VALUES (?, ${cols.map(() => '?').join(', ')}, ?, ?, ?)`,
[defaultCompany ? defaultCompany.id : null, ...cols.map((c) => fields[c]), ts, ts, ts]
);
return result.lastInsertRowid;
}