Pub 225 Compliance
This commit is contained in:
@@ -2030,6 +2030,52 @@ async function main() {
|
||||
const lim2032 = (await request('/api/section-179/limitation?book=FEDERAL&year=2032', { headers: aHeaders })).summary;
|
||||
if (lim2032.prior_carryover !== 2000000) throw new Error(`§179 carryover did not chain to next year: ${lim2032.prior_carryover}`);
|
||||
|
||||
// ---- Depreciation recapture: §1245 on disposal + §280F conversion (Form 4797) ---
|
||||
// Fully-depreciated equipment (cost 10k, placed 2018) sold for 12k in 2026 → gain 12k: §1245 ordinary
|
||||
// recapture = depreciation taken (10k), the remaining 2k is §1231 capital gain.
|
||||
const eq = (await request('/api/assets', { method: 'POST', headers: aHeaders, body: JSON.stringify({ asset_id: `EQ-${suffix}`, description: 'Equipment', category: 'Computer Equipment', acquisition_cost: 10000, acquired_date: '2018-01-01', in_service_date: '2018-01-01', useful_life_months: 60, books: [{ book_type: 'FEDERAL', active: true, depreciation_method: 'macrs_gds_200db_5', convention: 'half_year', useful_life_months: 60, bonus_percent: 0, section_179_amount: 0, cost: 10000 }] }) })).asset;
|
||||
const recapDisp = (await request(`/api/assets/${eq.id}/disposal/preview`, { method: 'POST', headers: aHeaders, body: JSON.stringify({ book_type: 'FEDERAL', disposal_date: '2026-08-01', disposal_price: 12000 }) })).preview;
|
||||
if (recapDisp.recapture_section !== '1245') throw new Error(`Recapture section wrong: ${disp.recapture_section}`);
|
||||
if (recapDisp.ordinary_recapture !== 10000) throw new Error(`§1245 ordinary recapture wrong: expected 10,000, got ${recapDisp.ordinary_recapture}`);
|
||||
if (recapDisp.section_1231_gain !== 2000) throw new Error(`§1231 gain wrong: expected 2,000, got ${recapDisp.section_1231_gain}`);
|
||||
|
||||
// §280F conversion recapture: listed PC at 100% use (2024) converting to ≤50% in 2026 → excess of
|
||||
// accelerated-over-ADS through 2025 = 5,200 − 3,000 = 2,200 ordinary income.
|
||||
const pc = (await request('/api/assets', { method: 'POST', headers: aHeaders, body: JSON.stringify({ asset_id: `PC-${suffix}`, description: 'Listed PC', category: 'Computer Equipment', acquisition_cost: 10000, acquired_date: '2024-01-01', in_service_date: '2024-01-01', useful_life_months: 60, business_use_percent: 100, listed_property: true, books: [{ book_type: 'FEDERAL', active: true, depreciation_method: 'macrs_gds_200db_5', convention: 'half_year', useful_life_months: 60, bonus_percent: 0, section_179_amount: 0, cost: 10000 }] }) })).asset;
|
||||
const rec280 = (await request(`/api/assets/${pc.id}/section-280f-recapture?book=FEDERAL&year=2026`, { headers: aHeaders })).recapture;
|
||||
if (!rec280.applies || rec280.recapture !== 2200) throw new Error(`§280F recapture wrong: ${JSON.stringify(rec280)}`);
|
||||
|
||||
// Farm-property recapture (IRS Pub 225): §1252 soil/water (§175) + §1255 cost-sharing (§126). Farmland
|
||||
// held 7 years with $20k §175 and $10k §126, sold at a $50k gain → §1252 = 60% × 20k = 12k; §1255 = 10k.
|
||||
const farm = (await request('/api/assets', { method: 'POST', headers: aHeaders, body: JSON.stringify({ asset_id: `FARM-${suffix}`, description: 'Farmland', category: 'Computer Equipment', acquisition_cost: 100000, land_value: 100000, in_service_date: '2019-06-01', acquired_date: '2019-06-01', useful_life_months: 0, soil_water_deductions: 20000, cost_sharing_excluded: 10000, books: [{ book_type: 'FEDERAL', active: true, depreciation_method: 'straight_line', useful_life_months: 0, cost: 100000 }] }) })).asset;
|
||||
const farmDisp = (await request(`/api/assets/${farm.id}/disposal/preview`, { method: 'POST', headers: aHeaders, body: JSON.stringify({ book_type: 'FEDERAL', disposal_date: '2026-07-01', disposal_price: 150000 }) })).preview;
|
||||
if (farmDisp.section_1252_recapture !== 12000) throw new Error(`§1252 recapture wrong: expected 12,000, got ${farmDisp.section_1252_recapture}`);
|
||||
if (farmDisp.section_1255_recapture !== 10000) throw new Error(`§1255 recapture wrong: expected 10,000, got ${farmDisp.section_1255_recapture}`);
|
||||
if (farmDisp.section_1231_gain !== 28000) throw new Error(`Farm §1231 gain wrong: expected 28,000, got ${farmDisp.section_1231_gain}`);
|
||||
|
||||
// ---- Literal MACRS tables (MT200), true ADS recovery period, short tax year ---
|
||||
const deprRow = async (assetId, year) => (await request('/api/reports/run', { method: 'POST', headers: aHeaders, body: JSON.stringify({ type: 'depreciation_expense', options: { book: 'FEDERAL', year } }) })).report.rows.find((r) => r.asset_id === assetId);
|
||||
// #1 MT200 uses the literal Pub 946 Appendix-A percentages (5-year property year-1 = 20% = 2,000).
|
||||
await request('/api/assets', { method: 'POST', headers: aHeaders, body: JSON.stringify({ asset_id: `MT-${suffix}`, description: 'MT200', category: 'Computer Equipment', acquisition_cost: 10000, acquired_date: '2024-05-01', in_service_date: '2024-05-01', useful_life_months: 60, books: [{ book_type: 'FEDERAL', active: true, depreciation_method: 'MT200', convention: 'half_year', useful_life_months: 60, bonus_percent: 0, section_179_amount: 0, cost: 10000 }] }) });
|
||||
const mtRow = await deprRow(`MT-${suffix}`, 2024);
|
||||
if (!mtRow || Math.abs(mtRow.depreciation - 2000) > 1) throw new Error(`MT200 literal table year-1 wrong: expected 2,000, got ${mtRow && mtRow.depreciation}`);
|
||||
|
||||
// #3 Listed property ≤50% business use uses the ADS recovery period from its asset class (GDS 7 / ADS 10):
|
||||
// basis 10k×40% = 4k, ADS 10-year straight-line, half-year → 200 (not the 7-year GDS life).
|
||||
await request('/api/asset-classes', { method: 'POST', headers: auth, body: JSON.stringify({ class_number: `88.${suffix}`, description: 'ADS test', gds: 7, ads: 10 }) });
|
||||
await request('/api/asset-categories', { method: 'POST', headers: aHeaders, body: JSON.stringify({ name: `ADSCat-${suffix}`, asset_class_number: `88.${suffix}` }) });
|
||||
await request('/api/assets', { method: 'POST', headers: aHeaders, body: JSON.stringify({ asset_id: `ADS-${suffix}`, description: 'ADS', category: `ADSCat-${suffix}`, acquisition_cost: 10000, acquired_date: '2024-05-01', in_service_date: '2024-05-01', useful_life_months: 84, business_use_percent: 40, listed_property: true, books: [{ book_type: 'FEDERAL', active: true, depreciation_method: 'macrs_gds_200db_7', convention: 'half_year', useful_life_months: 84, bonus_percent: 0, section_179_amount: 0, cost: 10000 }] }) });
|
||||
const adsRow = await deprRow(`ADS-${suffix}`, 2024);
|
||||
if (!adsRow || Math.abs(adsRow.depreciation - 200) > 1) throw new Error(`ADS recovery period not applied: expected 200 (10-yr ADS), got ${adsRow && adsRow.depreciation}`);
|
||||
|
||||
// #2 Short tax year prorates that year's MACRS depreciation by months ÷ 12 (2,000 → 1,000 for 6 months).
|
||||
await request('/api/assets', { method: 'POST', headers: aHeaders, body: JSON.stringify({ asset_id: `STY-${suffix}`, description: 'STY', category: 'Computer Equipment', acquisition_cost: 10000, acquired_date: '2033-01-01', in_service_date: '2033-01-01', useful_life_months: 60, books: [{ book_type: 'FEDERAL', active: true, depreciation_method: 'macrs_gds_200db_5', convention: 'half_year', useful_life_months: 60, bonus_percent: 0, section_179_amount: 0, cost: 10000 }] }) });
|
||||
const styBaseline = await deprRow(`STY-${suffix}`, 2033);
|
||||
if (!styBaseline || Math.abs(styBaseline.depreciation - 2000) > 1) throw new Error(`Short-year baseline wrong: ${styBaseline && styBaseline.depreciation}`);
|
||||
await request('/api/short-tax-years', { method: 'POST', headers: aHeaders, body: JSON.stringify({ tax_year: 2033, months: 6 }) });
|
||||
const styShort = await deprRow(`STY-${suffix}`, 2033);
|
||||
if (!styShort || Math.abs(styShort.depreciation - 1000) > 1) throw new Error(`Short tax year not prorated: expected 1,000, got ${styShort && styShort.depreciation}`);
|
||||
|
||||
console.log('Smoke test passed');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user