Simplify core imports.
[ustaxlib.git] / src / fed2019 / ScheduleD.ts
1 import { Form, Person, TaxReturn } from '../core';
2 import { Line, AccumulatorLine, ComputedLine, ReferenceLine, sumLineOfForms } from '../core/Line';
3 import { clampToZero } from '../core/Math';
4 import { UnsupportedFeatureError } from '../core/Errors';
5
6 import Form8949, { Form8949Box } from './Form8949';
7 import Form1099DIV from './Form1099DIV';
8 import Form1040, { FilingStatus, computeTax } from './Form1040';
9
10 export default class ScheduleD extends Form<ScheduleD['_lines']> {
11 readonly name = 'Schedule D';
12
13 protected readonly _lines = {
14 // 1a not supported (Totals for all short-term transactions reported on Form 1099-B for which basis was reported to the IRS and for which you have no adjustments)
15 // 4 is not supported (Short-term gain from Form 6252 and short-term gain or (loss) from Forms 4684, 6781, and 8824)
16 // 5 is not supported (Net short-term gain or (loss) from partnerships, S corporations, estates, and trusts from Schedule(s) K-1)
17 // 6 is not supported (Short-term capital loss carryover. Enter the amount, if any, from line 8 of your Capital Loss Carryover Worksheet in the instructions)
18
19 '7': new ComputedLine((tr): number => {
20 // 1-3 are computed by Form8949.
21 // 4-6 should be included.
22 const f8949 = tr.getForm(Form8949);
23 return f8949.getValue(tr, 'boxA').gainOrLoss +
24 f8949.getValue(tr, 'boxB').gainOrLoss +
25 f8949.getValue(tr, 'boxC').gainOrLoss;
26 }, 'Net short-term capital gain or (loss)'),
27
28 // 8a is not supported.
29
30 // 11 is not supported (Gain from Form 4797, Part I; long-term gain from Forms 2439 and 6252; and long-term gain or (loss) from Forms 4684, 6781, and 8824)
31 // 12 is not supported (Net long-term gain or (loss) from partnerships, S corporations, estates, and trusts from Schedule(s) K-1)
32
33 '13': new AccumulatorLine(Form1099DIV, '2a', 'Capital gain distributions'),
34
35 // 14 is not supported (Long-term capital loss carryover. Enter the amount, if any, from line 13 of your Capital Loss Carryover Worksheet in the instructions)
36
37 '15': new ComputedLine((tr): number => {
38 // 11-14 should be included.
39 const f8949 = tr.getForm(Form8949);
40 return f8949.getValue(tr, 'boxD').gainOrLoss +
41 f8949.getValue(tr, 'boxE').gainOrLoss +
42 f8949.getValue(tr, 'boxF').gainOrLoss +
43 this.getValue(tr, '13');
44 }, 'Net long-term capital gain or (loss)'),
45
46 '16': new ComputedLine((tr): number => {
47 return this.getValue(tr, '7') + this.getValue(tr, '15');
48 }),
49
50 '17': new ComputedLine((tr): boolean => {
51 return this.getValue(tr, '15') > 0 && this.getValue(tr, '16') > 0;
52 }, 'Both ST and LT are gains'),
53
54 '18': new ComputedLine((tr): number | undefined => {
55 if (!this.getValue(tr, '17') || this.getValue(tr, '16') <= 0)
56 return undefined;
57 // Not supported - only for gains on Qualified Small Business Stock or collectibles.
58 return 0;
59 }, '28% Rate Gain Worksheet Value'),
60
61 // 19 is not supported (Unrecaptured Section 1250 Gain Worksheet)
62
63 '20': new ComputedLine((tr): boolean | undefined => {
64 if (!this.getValue(tr, '17') || this.getValue(tr, '16') <= 0)
65 return undefined;
66 const l18 = this.getValue(tr, '18');
67 const l19 = undefined; //this.getValue(tr, '19');
68 return (l18 === 0 || l18 === undefined) || (l19 === 0 || l19 === undefined);
69 }, 'Line 18 and 19 both 0 or blank?'),
70
71 '21': new ComputedLine((tr): number | undefined => {
72 if (!this.getValue(tr, '17') || !this.getValue(tr, '20'))
73 return undefined;
74 const filingStatus = tr.getForm(Form1040).getInput('filingStatus');
75 const limit = filingStatus == FilingStatus.MarriedFilingSeparate ? -1500 : -3000;
76 return Math.min(this.getValue(tr, '16'), limit);
77 }, 'Net capital loss'),
78 };
79 };
80
81 export class ScheduleDTaxWorksheet extends Form<ScheduleDTaxWorksheet['_lines']> {
82 readonly name = 'Schedule D Tax Worksheet';
83
84 protected readonly _lines = {
85 '1': new ReferenceLine(Form1040, '11b'),
86 '2': new ReferenceLine(Form1040, '3a'),
87 // TODO 3 - form 4952
88 // TODO 4 - 4952
89 '5': new ComputedLine((tr): number => 0),
90 '6': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '2') - this.getValue(tr, '5'))),
91 '7': new ComputedLine((tr): number => {
92 const schedD = tr.getForm(ScheduleD);
93 return Math.min(schedD.getValue(tr, '15'), schedD.getValue(tr, '16'));
94 }),
95 '8': new ComputedLine((tr): number => {
96 return 0;
97 // return Math.min(this.getValue(tr, '3'), this.getValue(tr, '4'));
98 }),
99 '9': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '7') - this.getValue(tr, '8'))),
100 '10': new ComputedLine((tr): number => this.getValue(tr, '6') + this.getValue(tr, '9')),
101 '11': new ComputedLine((tr): number => {
102 const schedD = tr.getForm(ScheduleD);
103 // TODO - line 19 is not supported.
104 return Math.min(schedD.getValue(tr, '18'), Infinity); //schedD.getValue(tr, '19'));
105 }),
106 '12': new ComputedLine((tr): number => Math.min(this.getValue(tr, '9'), this.getValue(tr, '11'))),
107 '13': new ComputedLine((tr): number => this.getValue(tr, '10') - this.getValue(tr, '12')),
108 '14': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '1') - this.getValue(tr, '13'))),
109 '15': new ComputedLine((tr): number => {
110 switch (tr.getForm(Form1040).getInput('filingStatus')) {
111 case FilingStatus.Single:
112 case FilingStatus.MarriedFilingSeparate:
113 return 39375;
114 case FilingStatus.MarriedFilingJoint:
115 return 78750;
116 }
117 }),
118 '16': new ComputedLine((tr): number => Math.min(this.getValue(tr, '1'), this.getValue(tr, '15'))),
119 '17': new ComputedLine((tr): number => Math.min(this.getValue(tr, '14'), this.getValue(tr, '16'))),
120 '18': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '1') - this.getValue(tr, '10'))),
121 '19': new ComputedLine((tr): number => {
122 let threshold: number;
123 switch (tr.getForm(Form1040).getInput('filingStatus')) {
124 case FilingStatus.Single:
125 case FilingStatus.MarriedFilingSeparate:
126 threshold = 160725;
127 break;
128 case FilingStatus.MarriedFilingJoint:
129 threshold = 321450;
130 break;
131 }
132 return Math.min(this.getValue(tr, '1'), threshold);
133 }),
134 '20': new ComputedLine((tr): number => Math.min(this.getValue(tr, '14'), this.getValue(tr, '19'))),
135 '21': new ComputedLine((tr): number => Math.max(this.getValue(tr, '18'), this.getValue(tr, '20'))),
136 '22': new ComputedLine((tr): number => this.getValue(tr, '16') - this.getValue(tr, '17')),
137 '23': new ComputedLine((tr): number => Math.min(this.getValue(tr, '1'), this.getValue(tr, '13'))),
138 '24': new ReferenceLine(ScheduleDTaxWorksheet as any, '22'),
139 '25': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '23') - this.getValue(tr, '24'))),
140 '26': new ComputedLine((tr): number => {
141 switch (tr.getForm(Form1040).getInput('filingStatus')) {
142 case FilingStatus.Single:
143 return 434550;
144 case FilingStatus.MarriedFilingSeparate:
145 return 244425;
146 case FilingStatus.MarriedFilingJoint:
147 return 488850;
148 }
149 }),
150 '27': new ComputedLine((tr): number => Math.min(this.getValue(tr, '1'), this.getValue(tr, '26'))),
151 '28': new ComputedLine((tr): number => this.getValue(tr, '21') + this.getValue(tr, '22')),
152 '29': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '27') - this.getValue(tr, '28'))),
153 '30': new ComputedLine((tr): number => Math.min(this.getValue(tr, '25'), this.getValue(tr, '29'))),
154 '31': new ComputedLine((tr): number => this.getValue(tr, '30') * 0.15),
155 '32': new ComputedLine((tr): number => this.getValue(tr, '24') + this.getValue(tr, '30')),
156 '33': new ComputedLine((tr): number => this.getValue(tr, '23') - this.getValue(tr, '32')),
157 '34': new ComputedLine((tr): number => this.getValue(tr, '33') * 0.20),
158 '35': new ComputedLine((tr): number => {
159 const schedD = tr.getForm(ScheduleD);
160 // TODO - line 19 is not supported.
161 return Math.min(this.getValue(tr, '9'), Infinity); //schedD.getValue(tr, '19'));
162 }),
163 '36': new ComputedLine((tr): number => this.getValue(tr, '10') + this.getValue(tr, '21')),
164 '37': new ReferenceLine(ScheduleDTaxWorksheet as any, '1'),
165 '38': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '36') - this.getValue(tr, '37'))),
166 '39': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '35') - this.getValue(tr, '38'))),
167 '40': new ComputedLine((tr): number => this.getValue(tr, '39') * 0.25),
168 '41': new ComputedLine((tr): number => {
169 const schedD = tr.getForm(ScheduleD);
170 if (schedD.getValue(tr, '18'))
171 throw new UnsupportedFeatureError('28% Gain unsupported');
172 return 0;
173 }),
174 '42': new ComputedLine((tr): number => {
175 if (!tr.getForm(ScheduleD).getValue(tr, '18'))
176 return 0;
177 return this.getValue(tr, '1') - this.getValue(tr, '41');
178 }),
179 '43': new ComputedLine((tr): number => {
180 if (!tr.getForm(ScheduleD).getValue(tr, '18'))
181 return 0;
182 return this.getValue(tr, '42') * 0.28;
183 }),
184 '44': new ComputedLine((tr): number => {
185 const income = this.getValue(tr, '21');
186 return computeTax(income, tr.getForm(Form1040).getInput('filingStatus'));
187 }),
188 '45': new ComputedLine((tr): number => {
189 return this.getValue(tr, '31') +
190 this.getValue(tr, '34') +
191 this.getValue(tr, '40') +
192 this.getValue(tr, '43') +
193 this.getValue(tr, '44');
194 }),
195 '46': new ComputedLine((tr): number => {
196 const income = this.getValue(tr, '1');
197 return computeTax(income, tr.getForm(Form1040).getInput('filingStatus'));
198 }),
199 '47': new ComputedLine((tr): number => Math.min(this.getValue(tr, '45'), this.getValue(tr, '46'))),
200 };
201 };