Pub 946 Compliance
This commit is contained in:
68
server/services/midQuarter.js
Normal file
68
server/services/midQuarter.js
Normal 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 };
|
||||
Reference in New Issue
Block a user