const { all, audit, json, now, one, parseJson, run, tx } = require('../db'); function employeeFromRow(row) { if (!row) return null; return { ...row, source_payload: parseJson(row.source_payload, null) }; } function assignmentFromRow(row) { if (!row) return null; return { ...row, active: !row.released_at }; } function listEmployees(query = {}) { return all(` SELECT * FROM employees WHERE (? IS NULL OR status = ?) AND (? IS NULL OR name LIKE '%' || ? || '%' OR email LIKE '%' || ? || '%' OR employee_number LIKE '%' || ? || '%') ORDER BY name LIMIT 500 `, [ query.status || null, query.status || null, query.search || null, query.search || null, query.search || null, query.search || null ]).map(employeeFromRow); } function upsertEmployee(employee) { const timestamp = now(); const workdayId = employee.workday_worker_id || employee.workdayWorkerId || employee.workerId || null; const existing = workdayId ? one('SELECT id FROM employees WHERE workday_worker_id = ?', [workdayId]) : one('SELECT id FROM employees WHERE employee_number = ? OR lower(email) = lower(?)', [employee.employee_number || '', employee.email || '']); const values = [ workdayId, employee.employee_number || employee.employeeNumber || employee.workerNumber || null, employee.name || employee.fullName || [employee.firstName, employee.lastName].filter(Boolean).join(' ') || 'Unnamed employee', employee.email || employee.workEmail || null, employee.department || employee.organization || null, employee.location || employee.workLocation || null, employee.manager_name || employee.managerName || null, employee.status || 'active', employee.source || 'manual', json(employee.source_payload || employee), employee.last_synced_at || null, timestamp ]; if (existing) { run( `UPDATE employees SET workday_worker_id = COALESCE(?, workday_worker_id), employee_number = ?, name = ?, email = ?, department = ?, location = ?, manager_name = ?, status = ?, source = ?, source_payload = ?, last_synced_at = COALESCE(?, last_synced_at), updated_at = ? WHERE id = ?`, [...values, existing.id] ); return one('SELECT * FROM employees WHERE id = ?', [existing.id]); } const result = run( `INSERT INTO employees ( workday_worker_id, employee_number, name, email, department, location, manager_name, status, source, source_payload, last_synced_at, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [...values, timestamp] ); return one('SELECT * FROM employees WHERE id = ?', [result.lastInsertRowid]); } 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 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, query.employee_id || null, query.active ? 1 : null ]).map(assignmentFromRow); } function assignAsset(body, userId, companyId) { const timestamp = now(); // 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; const department = body.department ?? employee?.department ?? asset.department ?? null; const location = body.location ?? employee?.location ?? asset.location ?? null; return tx(() => { run( `UPDATE asset_assignments SET released_at = ?, status = 'released', release_reason = 'Reassigned', updated_at = ? WHERE asset_id = ? AND released_at IS NULL`, [timestamp, timestamp, body.asset_id] ); const result = run( `INSERT INTO asset_assignments ( asset_id, employee_id, department, location, status, assigned_at, assigned_by, notes, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ body.asset_id, body.employee_id || null, department, location, 'assigned', body.assigned_at || timestamp, userId, body.notes || null, timestamp, timestamp ] ); run( `UPDATE assets SET custodian = ?, department = ?, location = ?, status = 'in_service', updated_at = ? WHERE id = ?`, [employee?.name || asset.custodian || null, department, location, timestamp, body.asset_id] ); 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, 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 SET released_at = ?, status = 'released', release_reason = ?, notes = COALESCE(?, notes), updated_at = ? WHERE id = ?`, [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 }, companyId).find((assignment) => assignment.id === Number(id)); } function assignmentSummary(companyId) { const stats = one(` SELECT COUNT(*) AS active_assignments, 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 (? 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 }; } module.exports = { assignAsset, assignmentRows, assignmentSummary, employeeFromRow, listEmployees, releaseAssignment, upsertEmployee };