Add Form8995 to compute REIT QBI deduction.
authorRobert Sesek <rsesek@bluestatic.org>
Thu, 19 Mar 2020 00:22:40 +0000 (20:22 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Thu, 19 Mar 2020 00:22:40 +0000 (20:22 -0400)
src/fed2019/Form1040.ts
src/fed2019/Form8995.test.ts [new file with mode: 0644]
src/fed2019/Form8995.ts [new file with mode: 0644]
src/fed2019/index.ts

index 7d1a98619292f3fc352b610005a8ecfe77e2dde0..f88f3f6579fcda269f2d4be8bd71436738827a96 100644 (file)
@@ -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<Form1040['_lines'], Form1040Input> {
     }, '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 (file)
index 0000000..48e64bf
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2020 Blue Static <https://www.bluestatic.org>
+// 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 (file)
index 0000000..ad94894
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2020 Blue Static <https://www.bluestatic.org>
+// 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<Form8995REIT['_lines']> {
+  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<Form8995REITInput>('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.'),
+  };
+};
index b0bb5c6a51f9c21e842996b0f9eeee9670f7c6f9..6c92fec947a04bd6ad16a0b2b995db9a42fc9c8d 100644 (file)
@@ -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';