Pub 946 Compliance

This commit is contained in:
2026-06-10 02:09:25 -05:00
parent 7a54d1a386
commit 221ccb7826
18 changed files with 863 additions and 19 deletions

View File

@@ -0,0 +1,68 @@
const { all } = require('../db');
// IRS Pub 946 mid-quarter convention determination. The mid-quarter convention is MANDATORY for all of a
// tax year's MACRS personal property when more than 40% of the aggregate depreciable basis of such
// property is placed in service during the last three months (Q4) of the year. This is a portfolio- and
// year-level fact, computed here once per (company, book, year) and consulted by the depreciation engine
// (depreciation.conventionFor). Real property (mid-month) is excluded. Cached; invalidated on asset writes.
const cache = new Map(); // `${entityId}|${bookCode}|${year}` -> boolean
function clearCache() {
cache.clear();
}
function bookObject(row, bookCode) {
return {
book_type: bookCode,
cost: row.book_cost,
depreciation_method: row.depreciation_method,
convention: row.convention,
useful_life_months: row.book_life,
section_179_amount: row.section_179_amount,
bonus_percent: row.bonus_percent,
business_use_percent: row.book_bup,
investment_use_percent: row.book_ivp,
manual_depreciation: row.manual_depreciation
};
}
// True when the mid-quarter convention applies to (company, book) MACRS personal property placed in
// service in `year`. No-op-friendly: returns false when the portfolio doesn't trip the 40% threshold.
function applies(entityId, bookCode, year) {
if (!entityId || !bookCode || !year) return false;
const key = `${entityId}|${bookCode}|${Number(year)}`;
if (cache.has(key)) return cache.get(key);
const dep = require('../depreciation');
const { ruleSetForBook } = require('./ruleSets');
const { assetFromRow } = require('./assets');
const ruleSet = ruleSetForBook(bookCode);
const rows = all(
`SELECT a.*, b.cost AS book_cost, b.depreciation_method, b.convention, b.useful_life_months AS book_life,
b.section_179_amount, b.bonus_percent, b.business_use_percent AS book_bup, b.investment_use_percent AS book_ivp, b.manual_depreciation
FROM assets a JOIN asset_books b ON b.asset_id = a.id
WHERE b.book_type = ? AND b.active = 1 AND a.entity_id = ? AND a.status != 'disposed'`,
[bookCode, entityId]
);
let total = 0;
let lastQuarter = 0;
for (const row of rows) {
const pis = row.in_service_date || row.acquired_date;
if (!pis || dep.yearFromDate(pis) !== Number(year)) continue;
const book = bookObject(row, bookCode);
const methodRule = dep.getMethodRule(ruleSet, book.depreciation_method);
if (!dep.isMidQuarterEligible(book, methodRule)) continue;
const basis = dep.midQuarterBasis(assetFromRow(row), book);
if (basis <= 0) continue;
total += basis;
if (Math.ceil(dep.monthFromDate(pis) / 3) === 4) lastQuarter += basis;
}
const result = total > 0 && lastQuarter / total > 0.4;
cache.set(key, result);
return result;
}
module.exports = { applies, clearCache };