Add Schedule 3.
authorRobert Sesek <rsesek@bluestatic.org>
Sun, 8 Mar 2020 16:07:50 +0000 (12:07 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Sun, 8 Mar 2020 16:07:50 +0000 (12:07 -0400)
src/fed2019/Form1040.ts
src/fed2019/Schedule3.test.ts [new file with mode: 0644]
src/fed2019/Schedule3.ts [new file with mode: 0644]

index c9c65265d34fb0c43bc4c3864fc8baae860a96cb..13de9cd9ee35d3ba689505cf523dcdaa94191c69 100644 (file)
@@ -12,6 +12,7 @@ import Form1099R, { Box7Code } from './Form1099R';
 import FormW2 from './FormW2';
 import Schedule1 from './Schedule1';
 import Schedule2 from './Schedule2';
+import Schedule3 from './Schedule3';
 import ScheduleD, { ScheduleDTaxWorksheet } from './ScheduleD';
 
 export enum FilingStatus {
@@ -127,10 +128,7 @@ export default class Form1040 extends Form<Form1040['_lines'], Form1040Input> {
 
     // Not supported: 13a - child tax credit
 
-    '13b': new ComputedLine((tr): number => {
-      // TODO: add Sched 3.L7
-      return 0;
-    }, 'Additional credits'),
+    '13b': new ReferenceLine(Schedule3, '7', 'Additional credits', 0),
 
     '14': new ComputedLine((tr): number => {
       const l12b = this.getValue(tr, '12b');
@@ -163,9 +161,18 @@ export default class Form1040 extends Form<Form1040['_lines'], Form1040Input> {
       return reduceBySum(withholding) + additionalMedicare;
     }, 'Federal income tax withheld'),
 
-    // 18 not supported
+    // 18a not supported - Earned income credit (EIC)
+    // 18b not supported - Additional child tax credit. Attach Schedule 8812
+    // 18c not supported - American opportunity credit from Form 8863, line 8
+    '18d': new ReferenceLine(Schedule3, '14', undefined, 0),
+    '18e': new ComputedLine((tr): number => {
+      // Should include 18a-18c.
+      return this.getValue(tr, '18d');
+    }),
 
-    '19': new ReferenceLine(Form1040 as any, '17', 'Total payments'),
+    '19': new ComputedLine((tr): number => {
+      return this.getValue(tr, '17') + this.getValue(tr, '18e');
+    }, 'Total payments'),
 
     '20': new ComputedLine((tr): number => {
       const l16: number = this.getValue(tr, '16');
diff --git a/src/fed2019/Schedule3.test.ts b/src/fed2019/Schedule3.test.ts
new file mode 100644 (file)
index 0000000..a22507c
--- /dev/null
@@ -0,0 +1,66 @@
+import TaxReturn from '../TaxReturn';
+import Person from '../Person';
+import { NotFoundError } from '../Errors';
+
+import Form1040, { FilingStatus } from './Form1040';
+import Form1099DIV from './Form1099DIV';
+import Form1116 from './Form1116';
+import Form8949 from './Form8949';
+import Schedule3 from './Schedule3';
+import ScheduleD from './ScheduleD';
+
+test('foreign tax credit, form 1116 not required', () => {
+  const filingStatusToForeignTax = {
+    [FilingStatus.Single]: 200,
+    [FilingStatus.MarriedFilingJoint]: 500,
+    [FilingStatus.MarriedFilingSeparate]: 200
+  };
+
+  for (const filingStatus of Object.values(FilingStatus)) {
+    const p = Person.self('A');
+    const tr = new TaxReturn(2019);
+    tr.addForm(new Form1040({ filingStatus }));
+    tr.addForm(new Form8949);
+    tr.addForm(new ScheduleD);
+    tr.addForm(new Form1099DIV({
+      payer: 'Brokerage',
+      payee: p,
+      ordinaryDividends: 200000,
+      qualifiedDividends: 70000,
+      totalCapitalGain: 300,
+      foreignTaxPaid: filingStatusToForeignTax[filingStatus],
+    }));
+    const f = new Schedule3();
+    tr.addForm(f);
+
+    expect(f.getValue(tr, '1')).toBe(filingStatusToForeignTax[filingStatus]);
+  }
+});
+
+test('foreign tax credit, form 1116 required', () => {
+  const filingStatusToForeignTax = {
+    [FilingStatus.Single]: 400,
+    [FilingStatus.MarriedFilingJoint]: 600,
+    [FilingStatus.MarriedFilingSeparate]: 400
+  };
+
+  for (const filingStatus of Object.values(FilingStatus)) {
+    const p = Person.self('A');
+    const tr = new TaxReturn(2019);
+    tr.addForm(new Form1040({ filingStatus }));
+    tr.addForm(new Form8949);
+    tr.addForm(new ScheduleD);
+    tr.addForm(new Form1099DIV({
+      payer: 'Brokerage',
+      payee: p,
+      ordinaryDividends: 200000,
+      qualifiedDividends: 70000,
+      totalCapitalGain: 300,
+      foreignTaxPaid: filingStatusToForeignTax[filingStatus],
+    }));
+    const f = new Schedule3();
+    tr.addForm(f);
+
+    expect(() => f.getValue(tr, '1')).toThrow(NotFoundError);
+  }
+});
diff --git a/src/fed2019/Schedule3.ts b/src/fed2019/Schedule3.ts
new file mode 100644 (file)
index 0000000..c9fed01
--- /dev/null
@@ -0,0 +1,61 @@
+import Form from '../Form';
+import TaxReturn from '../TaxReturn';
+import { AccumulatorLine, ComputedLine, InputLine, ReferenceLine } from '../Line';
+import { NotFoundError, UnsupportedFeatureError } from '../Errors';
+
+import Form1040, { FilingStatus } from './Form1040';
+import Form1099DIV from './Form1099DIV';
+import Form1099INT from './Form1099INT';
+import Form1116 from './Form1116';
+import Schedule2 from './Schedule2';
+
+export interface Schedule3Input {
+  estimatedTaxPayments?: number;
+};
+
+export default class Schedule3 extends Form<Schedule3['_lines'], Schedule3Input> {
+  readonly name = 'Schedule 3';
+
+  readonly _lines = {
+    // Part 1
+    '1': new ComputedLine((tr): number => {
+      const f1040 = tr.getForm(Form1040);
+
+      const totalForeignTax = (new AccumulatorLine(Form1099DIV, '7')).value(tr) +
+                              (new AccumulatorLine(Form1099INT, '6')).value(tr);
+      const limit = f1040.getInput('filingStatus') == FilingStatus.MarriedFilingJoint ? 600 : 300;
+
+      if (totalForeignTax < limit) {
+        const sched2l2 = new ReferenceLine(Schedule2, '2', undefined, 0);
+        return Math.min(totalForeignTax, f1040.getValue(tr, '12a') + sched2l2.value(tr));
+      }
+      return tr.getForm(Form1116).getValue(tr, '33');
+    }, 'Foreign tax credit'),
+    // 2 not supported - Credit for child and dependent care expenses. Attach Form 2441
+    // 3 not supported - Education credits from Form 8863, line 19
+    // 4 not supported - Retirement savings contributions credit. Attach Form 8880
+    // 5 not supported - Residential energy credits. Attach Form 5695
+    // 6a not supported - Form 3800
+    // 6b not supported - Form 8801
+    // 6c not supported - Other nonrefundable credits
+    '7': new ComputedLine((tr): number => {
+      // Should include 2-6.
+      return this.getValue(tr, '1');
+    }),
+
+    // Part 2
+    '8': new InputLine<Schedule3Input>('estimatedTaxPayments'),
+    // 9 not supported - Net premium tax credit. Attach Form 8962
+    // 10 not supported - Amount paid with request for extension to file (see instructions)
+    // 11 not supported - Excess social security and tier 1 RRTA tax withheld
+    // 12 not supported - Credit for federal tax on fuels. Attach Form 4136
+    // 13a not supported - Form 2439
+    // 13b is reserved
+    // 13c not supported - Form 8885
+    // 13d not supported - Other refundable credits
+    '14': new ComputedLine((tr): number => {
+      // Should include 9-13.
+      return this.getValue(tr, '8');
+    }),
+  };
+};