Added Section 179 Limits
This commit is contained in:
95
server/services/section179Limits.js
Normal file
95
server/services/section179Limits.js
Normal file
@@ -0,0 +1,95 @@
|
||||
const { all, audit, now, one, run } = require('../db');
|
||||
|
||||
let cache = null;
|
||||
|
||||
function clearCache() {
|
||||
cache = null;
|
||||
}
|
||||
|
||||
// Sorted ascending by tax_year, cached for the engine.
|
||||
function rows() {
|
||||
if (!cache) cache = all('SELECT * FROM section_179_limits ORDER BY tax_year');
|
||||
return cache;
|
||||
}
|
||||
|
||||
// Applicable limit for a placed-in-service year: the most recent year at or before it.
|
||||
// Returns null when nothing is configured for/under the year, so the engine leaves §179 uncapped.
|
||||
function getLimit(year) {
|
||||
const y = Number(year);
|
||||
if (!y) return null;
|
||||
let match = null;
|
||||
for (const row of rows()) {
|
||||
if (row.tax_year <= y) match = row;
|
||||
else break;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
function fromRow(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
tax_year: row.tax_year,
|
||||
base_limit: row.base_limit,
|
||||
phaseout_threshold: row.phaseout_threshold
|
||||
};
|
||||
}
|
||||
|
||||
function list() {
|
||||
return all('SELECT * FROM section_179_limits ORDER BY tax_year DESC').map(fromRow);
|
||||
}
|
||||
|
||||
function normalize(body) {
|
||||
return {
|
||||
tax_year: Math.trunc(Number(body.tax_year)) || 0,
|
||||
base_limit: Number(body.base_limit) || 0,
|
||||
phaseout_threshold: Number(body.phaseout_threshold) || 0
|
||||
};
|
||||
}
|
||||
|
||||
function createLimit(body, userId) {
|
||||
const input = normalize(body);
|
||||
if (!input.tax_year) throw Object.assign(new Error('A valid tax year is required'), { status: 400 });
|
||||
if (one('SELECT id FROM section_179_limits WHERE tax_year = ?', [input.tax_year])) {
|
||||
throw Object.assign(new Error('A limit for that tax year already exists'), { status: 400 });
|
||||
}
|
||||
const ts = now();
|
||||
run(
|
||||
`INSERT INTO section_179_limits (tax_year, base_limit, phaseout_threshold, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
[input.tax_year, input.base_limit, input.phaseout_threshold, ts, ts]
|
||||
);
|
||||
clearCache();
|
||||
audit(userId, 'create', 'section_179_limit', String(input.tax_year), null, input);
|
||||
return fromRow(one('SELECT * FROM section_179_limits WHERE tax_year = ?', [input.tax_year]));
|
||||
}
|
||||
|
||||
function updateLimit(taxYear, body, userId) {
|
||||
const before = one('SELECT * FROM section_179_limits WHERE tax_year = ?', [Number(taxYear)]);
|
||||
if (!before) return null;
|
||||
const input = normalize({ ...before, ...body, tax_year: before.tax_year });
|
||||
run(
|
||||
'UPDATE section_179_limits SET base_limit = ?, phaseout_threshold = ?, updated_at = ? WHERE tax_year = ?',
|
||||
[input.base_limit, input.phaseout_threshold, now(), before.tax_year]
|
||||
);
|
||||
clearCache();
|
||||
audit(userId, 'update', 'section_179_limit', String(before.tax_year), before, input);
|
||||
return fromRow(one('SELECT * FROM section_179_limits WHERE tax_year = ?', [before.tax_year]));
|
||||
}
|
||||
|
||||
function deleteLimit(taxYear, userId) {
|
||||
const before = one('SELECT * FROM section_179_limits WHERE tax_year = ?', [Number(taxYear)]);
|
||||
if (!before) return false;
|
||||
run('DELETE FROM section_179_limits WHERE tax_year = ?', [before.tax_year]);
|
||||
clearCache();
|
||||
audit(userId, 'delete', 'section_179_limit', String(before.tax_year), before, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
clearCache,
|
||||
createLimit,
|
||||
deleteLimit,
|
||||
getLimit,
|
||||
list,
|
||||
updateLimit
|
||||
};
|
||||
@@ -37,6 +37,8 @@ function fromRow(row) {
|
||||
real_property_end: row.real_property_end,
|
||||
max_recovery_years: row.max_recovery_years,
|
||||
leasehold_life_years: row.leasehold_life_years,
|
||||
section_179_increase: row.section_179_increase,
|
||||
section_179_cost_factor: row.section_179_cost_factor,
|
||||
notes: row.notes,
|
||||
enabled: Boolean(row.enabled),
|
||||
asset_count: one('SELECT COUNT(*) AS c FROM assets WHERE special_zone = ?', [row.code]).c
|
||||
@@ -57,6 +59,8 @@ function normalize(body) {
|
||||
real_property_end: body.real_property_end || null,
|
||||
max_recovery_years: num(body.max_recovery_years),
|
||||
leasehold_life_years: num(body.leasehold_life_years),
|
||||
section_179_increase: Number(body.section_179_increase) || 0,
|
||||
section_179_cost_factor: body.section_179_cost_factor === '' || body.section_179_cost_factor === null || body.section_179_cost_factor === undefined ? 1 : Number(body.section_179_cost_factor),
|
||||
notes: body.notes || null,
|
||||
enabled: body.enabled === false ? 0 : 1
|
||||
};
|
||||
@@ -72,9 +76,9 @@ function createZone(body, userId) {
|
||||
}
|
||||
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]
|
||||
`INSERT INTO depreciation_zones (code, name, allowance_percent, pis_start, pis_end, real_property_end, max_recovery_years, leasehold_life_years, section_179_increase, section_179_cost_factor, 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.section_179_increase, input.section_179_cost_factor, input.notes, input.enabled, ts, ts]
|
||||
);
|
||||
clearCache();
|
||||
audit(userId, 'create', 'depreciation_zone', code, null, input);
|
||||
@@ -87,8 +91,8 @@ function updateZone(code, body, userId) {
|
||||
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]
|
||||
max_recovery_years = ?, leasehold_life_years = ?, section_179_increase = ?, section_179_cost_factor = ?, 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.section_179_increase, input.section_179_cost_factor, input.notes, input.enabled, now(), code]
|
||||
);
|
||||
clearCache();
|
||||
audit(userId, 'update', 'depreciation_zone', code, before, input);
|
||||
|
||||
Reference in New Issue
Block a user