From 4e26f231d1a90de1d2b28ee11079af95bb52f5a9 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Wed, 18 Mar 2020 20:22:40 -0400 Subject: [PATCH] Add Form8995 to compute REIT QBI deduction. --- src/fed2019/Form1040.ts | 11 ++--- src/fed2019/Form8995.test.ts | 79 ++++++++++++++++++++++++++++++++++++ src/fed2019/Form8995.ts | 60 +++++++++++++++++++++++++++ src/fed2019/index.ts | 1 + 4 files changed, 144 insertions(+), 7 deletions(-) create mode 100644 src/fed2019/Form8995.test.ts create mode 100644 src/fed2019/Form8995.ts diff --git a/src/fed2019/Form1040.ts b/src/fed2019/Form1040.ts index 7d1a986..f88f3f6 100644 --- a/src/fed2019/Form1040.ts +++ b/src/fed2019/Form1040.ts @@ -13,6 +13,7 @@ import Form8959 from './Form8959'; import Form1099INT from './Form1099INT'; import Form1099DIV from './Form1099DIV'; import Form1099R, { Box7Code } from './Form1099R'; +import Form8995REIT from './Form8995'; import W2 from './W2'; import Schedule1 from './Schedule1'; import Schedule2 from './Schedule2'; @@ -100,13 +101,9 @@ export default class Form1040 extends Form { }, 'Deduction'), '10': new ComputedLine((tr): number => { - const taxableIncome = this.getValue(tr, '8b'); - let use8995a = false; - switch (this.filingStatus) { - case FilingStatus.Single: use8995a = taxableIncome <= 160700; break; - case FilingStatus.MarriedFilingSeparate: use8995a = taxableIncome <= 160725; break; - case FilingStatus.MarriedFilingJoint: use8995a = taxableIncome <= 321400; break; - }; + const f8995 = tr.findForm(Form8995REIT); + if (f8995) + return f8995.getValue(tr, '39'); return 0; }, 'Qualified business income deduction'), diff --git a/src/fed2019/Form8995.test.ts b/src/fed2019/Form8995.test.ts new file mode 100644 index 0000000..48e64bf --- /dev/null +++ b/src/fed2019/Form8995.test.ts @@ -0,0 +1,79 @@ +// Copyright 2020 Blue Static +// This program is free software licensed under the GNU General Public License, +// version 3.0. The full text of the license can be found in LICENSE.txt. +// SPDX-License-Identifier: GPL-3.0-only + +import { Person } from '../core'; + +import Form1040, { FilingStatus } from './Form1040'; +import Form1099B, { GainType } from './Form1099B'; +import Form1099DIV from './Form1099DIV'; +import Form8949 from './Form8949'; +import Form8995REIT from './Form8995'; +import ScheduleD from './ScheduleD'; +import TaxReturn from './TaxReturn'; + +test('REIT QBI no Schedule D', () => { + const p = Person.self('A'); + const tr = new TaxReturn(); + tr.addPerson(p); + tr.addForm(new Form1040({ filingStatus: FilingStatus.Single })); + tr.addForm(new Form1099DIV({ + payer: 'Brokerage', + payee: p, + ordinaryDividends: 50000, + qualifiedDividends: 35000, + totalCapitalGain: 7500, + section199ADividends: 2220, + })); + + const f = new Form8995REIT(); + tr.addForm(f); + + expect(f.getValue(tr, '28')).toBe(2220); + expect(f.getValue(tr, '31')).toBe(444); + expect(f.getValue(tr, '32')).toBe(444); + expect(f.getValue(tr, '33')).toBe(50000 - 12200); + expect(f.getValue(tr, '34')).toBe(35000); + expect(f.getValue(tr, '39')).toBe(444); + expect(f.getValue(tr, '40')).toBe(0); + expect(tr.getForm(Form1040).getValue(tr, '10')).toBe(444); +}); + +test('REIT QBI with Schedule D', () => { + const p = Person.self('A'); + const tr = new TaxReturn(); + tr.addPerson(p); + tr.addForm(new Form1040({ filingStatus: FilingStatus.Single })); + tr.addForm(new Form1099DIV({ + payer: 'Brokerage', + payee: p, + ordinaryDividends: 50000, + qualifiedDividends: 35000, + totalCapitalGain: 7500, + section199ADividends: 2220, + })); + tr.addForm(new Form1099B({ + payer: 'Brokerage2 ', + payee: p, + description: '100 VTI', + proceeds: 230000, + costBasis: 221000, + gainType: GainType.LongTerm, + basisReportedToIRS: true + })); + tr.addForm(new Form8949); + tr.addForm(new ScheduleD); + + const f = new Form8995REIT(); + tr.addForm(f); + + expect(f.getValue(tr, '28')).toBe(2220); + expect(f.getValue(tr, '31')).toBe(444); + expect(f.getValue(tr, '32')).toBe(444); + expect(f.getValue(tr, '33')).toBe(50000 + 7500 + 9000 - 12200); + expect(f.getValue(tr, '34')).toBe(35000 + 7500 + 9000); + expect(f.getValue(tr, '39')).toBe(444); + expect(f.getValue(tr, '40')).toBe(0); + expect(tr.getForm(Form1040).getValue(tr, '10')).toBe(444); +}); diff --git a/src/fed2019/Form8995.ts b/src/fed2019/Form8995.ts new file mode 100644 index 0000000..ad94894 --- /dev/null +++ b/src/fed2019/Form8995.ts @@ -0,0 +1,60 @@ +// Copyright 2020 Blue Static +// This program is free software licensed under the GNU General Public License, +// version 3.0. The full text of the license can be found in LICENSE.txt. +// SPDX-License-Identifier: GPL-3.0-only + +import { Form, Person, TaxReturn } from '../core'; +import { AccumulatorLine, ComputedLine, InputLine } from '../core/Line'; +import { clampToZero } from '../core/Math'; + +import Form1040 from './Form1040'; +import Form1099DIV from './Form1099DIV'; +import ScheduleD from './ScheduleD'; + +export interface Form8995REITInput { + qualifiedReitDividendCarryforward?: number; +}; + +// Dividends from REITs get preferential tax treatment, but the form used to +// calculate that differs based off taxable income amounts. But the QBI +// computation for RETIs is the same. This just models the REIT portion. +export default class Form8995REIT extends Form { + readonly name = '8995 REIT'; + + // This uses line numbers from 8995-A. + protected readonly _lines = { + // 1-26 not supported + '27': new ComputedLine(() => 0, 'Total qualified business income component'), // Not supported. + '28': new AccumulatorLine(Form1099DIV, '5', 'Qualified REIT dividends'), + '29': new InputLine('qualifiedReitDividendCarryforward', undefined, 0), + '30': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '28') + this.getValue(tr, '29'))), + '31': new ComputedLine((tr): number => this.getValue(tr, '30') * 0.20, 'REIT and PTP component'), + '32': new ComputedLine((tr): number => this.getValue(tr, '27') + this.getValue(tr, '31'), 'QBI deduction before limitation'), + '33': new ComputedLine((tr): number => { + const f1040 = tr.getForm(Form1040); + return f1040.getValue(tr, '8b') - f1040.getValue(tr, '9'); + }, 'Taxable income before deduction'), + '34': new ComputedLine((tr): number => { + const f1040 = tr.getForm(Form1040); + + let value = f1040.getValue(tr, '3a'); + + const schedD = tr.findForm(ScheduleD); + if (schedD) { + value += Math.min( + clampToZero(schedD.getValue(tr, '15')), + clampToZero(schedD.getValue(tr, '16'))); + } else { + value += f1040.getValue(tr, '6'); + } + + return value; + }, 'Net capital gain'), + '35': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '33') - this.getValue(tr, '34'))), + '36': new ComputedLine((tr): number => this.getValue(tr, '35') * 0.20, 'Income limitation'), + '37': new ComputedLine((tr): number => Math.min(this.getValue(tr, '32'), this.getValue(tr, '36'))), + '38': new ComputedLine(() => 0, 'DPAD under section 199A(g) allocated from an agricultural or horticultural cooperative'), // Not supported, + '39': new ComputedLine((tr): number => this.getValue(tr, '37') + this.getValue(tr, '38')), + '40': new ComputedLine((tr): number => Math.min(0, this.getValue(tr, '28') + this.getValue(tr, '29')), 'Total qualified REIT dividends and PTP loss carryforward.'), + }; +}; diff --git a/src/fed2019/index.ts b/src/fed2019/index.ts index b0bb5c6..6c92fec 100644 --- a/src/fed2019/index.ts +++ b/src/fed2019/index.ts @@ -13,6 +13,7 @@ export { default as Form8606 } from './Form8606'; export { default as Form8949 } from './Form8949'; export { default as Form8959 } from './Form8959'; export { default as Form8960 } from './Form8960'; +export { default as Form8995REIT } from './Form8995'; export { default as Schedule1 } from './Schedule1'; export { default as Schedule2 } from './Schedule2'; export { default as Schedule3 } from './Schedule3'; -- 2.22.5