const { all, audit, now, one, run } = require('../db'); let cache = null; function clearCache() { cache = null; } function lookup() { if (!cache) { cache = {}; for (const row of all('SELECT * FROM depreciation_zones')) cache[row.code] = row; } return cache; } // Raw row (incl. dates) for the engine; null when unknown or disabled. function getZone(code) { if (!code) return null; const zone = lookup()[code]; return zone && zone.enabled ? zone : null; } function slugify(value) { return String(value || '').trim().toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '').slice(0, 40); } function fromRow(row) { if (!row) return null; return { id: row.id, code: row.code, name: row.name, allowance_percent: row.allowance_percent, pis_start: row.pis_start, pis_end: row.pis_end, real_property_end: row.real_property_end, max_recovery_years: row.max_recovery_years, leasehold_life_years: row.leasehold_life_years, notes: row.notes, enabled: Boolean(row.enabled), asset_count: one('SELECT COUNT(*) AS c FROM assets WHERE special_zone = ?', [row.code]).c }; } function list() { return all('SELECT * FROM depreciation_zones ORDER BY name').map(fromRow); } function normalize(body) { const num = (v) => (v === '' || v === null || v === undefined ? null : Number(v)); return { name: String(body.name || '').trim(), allowance_percent: Number(body.allowance_percent) || 0, pis_start: body.pis_start || null, pis_end: body.pis_end || null, real_property_end: body.real_property_end || null, max_recovery_years: num(body.max_recovery_years), leasehold_life_years: num(body.leasehold_life_years), notes: body.notes || null, enabled: body.enabled === false ? 0 : 1 }; } function createZone(body, userId) { const input = normalize(body); if (!input.name) throw Object.assign(new Error('A zone name is required'), { status: 400 }); const code = slugify(body.code || input.name); if (!code) throw Object.assign(new Error('A valid zone code is required'), { status: 400 }); if (one('SELECT id FROM depreciation_zones WHERE code = ?', [code])) { throw Object.assign(new Error('A zone with that code already exists'), { status: 400 }); } const ts = now(); run( `INSERT INTO depreciation_zones (code, name, allowance_percent, pis_start, pis_end, real_property_end, max_recovery_years, leasehold_life_years, notes, enabled, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [code, input.name, input.allowance_percent, input.pis_start, input.pis_end, input.real_property_end, input.max_recovery_years, input.leasehold_life_years, input.notes, input.enabled, ts, ts] ); clearCache(); audit(userId, 'create', 'depreciation_zone', code, null, input); return fromRow(one('SELECT * FROM depreciation_zones WHERE code = ?', [code])); } function updateZone(code, body, userId) { const before = one('SELECT * FROM depreciation_zones WHERE code = ?', [code]); if (!before) return null; const input = normalize({ ...before, ...body, enabled: body.enabled === undefined ? Boolean(before.enabled) : body.enabled }); run( `UPDATE depreciation_zones SET name = ?, allowance_percent = ?, pis_start = ?, pis_end = ?, real_property_end = ?, max_recovery_years = ?, leasehold_life_years = ?, notes = ?, enabled = ?, updated_at = ? WHERE code = ?`, [input.name, input.allowance_percent, input.pis_start, input.pis_end, input.real_property_end, input.max_recovery_years, input.leasehold_life_years, input.notes, input.enabled, now(), code] ); clearCache(); audit(userId, 'update', 'depreciation_zone', code, before, input); return fromRow(one('SELECT * FROM depreciation_zones WHERE code = ?', [code])); } function deleteZone(code, userId) { const before = one('SELECT * FROM depreciation_zones WHERE code = ?', [code]); if (!before) return false; run('DELETE FROM depreciation_zones WHERE code = ?', [code]); clearCache(); audit(userId, 'delete', 'depreciation_zone', code, before, null); return true; } module.exports = { clearCache, createZone, deleteZone, getZone, list, updateZone };