import Form1099INT from './Form1099INT';
import Form1099DIV from './Form1099DIV';
import FormW2 from './FormW2';
-import ScheduleD from './ScheduleD';
+import ScheduleD, { ScheduleDTaxWorksheet } from './ScheduleD';
export enum FilingStatus {
Single,
// Form 8814 (election to report child's interest or dividends)
// Form 4972 (relating to lump-sum distributions)
const taxableIncome = this.getValue(tr, '11b');
- if (taxableIncome < 100000)
- throw new UnsupportedFeatureError('Tax-table tax liability not supported');
- const l11b = this.getValue(tr, '11b');
+ if (this.getValue(tr, '3a') > 0 && !tr.findForm(ScheduleD))
+ throw new UnsupportedFeatureError('Qualified Dividends and Captial Gains Tax Worksheet not supported, Schedule D requried');
- switch (this.getInput('filingStatus')) {
- case FilingStatus.Single:
- if (taxableIncome < 160725)
- return (l11b * 0.24) - 5825.50;
- else if (taxableIncome < 204100)
- return (l11b * 0.32) - 18683.50;
- else if (taxableIncome < 510300)
- return (l11b * 0.35) - 24806.50;
- else
- return (l11b * 0.38) - 35012.50;
- case FilingStatus.MarriedFilingJoint:
- if (taxableIncome < 168400)
- return (l11b * 0.22) - 8283.00;
- else if (taxableIncome < 321450)
- return (l11b * 0.24) - 11651.00;
- else if (taxableIncome < 408200)
- return (l11b * 0.32) - 37367.00;
- else if (taxableIncome < 612350)
- return (l11b * 0.35) - 49613.00;
- else
- return (l11b * 0.37) - 61860.00;
- case FilingStatus.MarriedFilingSeparate:
- if (taxableIncome < 160725)
- return (l11b * 0.24) - 5825.50;
- else if (taxableIncome < 204100)
- return (l11b * 0.32) - 18683.50;
- else if (taxableIncome < 306175)
- return (l11b * 0.35) - 24806.50;
- else
- return (l11b * 0.37) - 30930.00;
- }
- throw new UnsupportedFeatureError('Unexpected return type');
+ const schedD = tr.findForm(ScheduleDTaxWorksheet);
+ if (schedD)
+ return schedD.getValue(tr, '47');
+
+ return computeTax(taxableIncome, this.getInput('filingStatus'));
}, 'Tax'),
'12b': new ComputedLine((tr: TaxReturn): number => {
})
};
};
+
+export function computeTax(income: number, filingStatus: FilingStatus): number {
+ if (income < 100000)
+ throw new UnsupportedFeatureError('Tax-table tax liability not supported');
+
+ switch (filingStatus) {
+ case FilingStatus.Single:
+ if (income < 160725)
+ return (income * 0.24) - 5825.50;
+ else if (income < 204100)
+ return (income * 0.32) - 18683.50;
+ else if (income < 510300)
+ return (income * 0.35) - 24806.50;
+ else
+ return (income * 0.38) - 35012.50;
+ case FilingStatus.MarriedFilingJoint:
+ if (income < 168400)
+ return (income * 0.22) - 8283.00;
+ else if (income < 321450)
+ return (income * 0.24) - 11651.00;
+ else if (income < 408200)
+ return (income * 0.32) - 37367.00;
+ else if (income < 612350)
+ return (income * 0.35) - 49613.00;
+ else
+ return (income * 0.37) - 61860.00;
+ case FilingStatus.MarriedFilingSeparate:
+ if (income < 160725)
+ return (income * 0.24) - 5825.50;
+ else if (income < 204100)
+ return (income * 0.32) - 18683.50;
+ else if (income < 306175)
+ return (income * 0.35) - 24806.50;
+ else
+ return (income * 0.37) - 30930.00;
+ }
+ throw new UnsupportedFeatureError('Unexpected return type');
+};
import Form from '../Form';
import Person from '../Person';
import TaxReturn from '../TaxReturn';
-import { Line, AccumulatorLine, ComputedLine, sumLineOfForms } from '../Line';
+import { Line, AccumulatorLine, ComputedLine, ReferenceLine, sumLineOfForms } from '../Line';
+import { clampToZero } from '../Math';
+import { UnsupportedFeatureError } from '../Errors';
import Form8949, { Form8949Box } from './Form8949';
import Form1099DIV from './Form1099DIV';
-import Form1040, { FilingStatus } from './Form1040';
+import Form1040, { FilingStatus, computeTax } from './Form1040';
export default class ScheduleD extends Form<ScheduleD['_lines']> {
readonly name = 'Schedule D';
}, 'Both ST and LT are gains'),
'18': new ComputedLine((tr: TaxReturn): number | undefined => {
- if (!this.getValue(tr, '17'))
+ if (!this.getValue(tr, '17') || this.getValue(tr, '16') <= 0)
return undefined;
- // TODO
+ // Not supported - only for gains on Qualified Small Business Stock or collectibles.
return 0;
}, '28% Rate Gain Worksheet Value'),
// 19 is not supported (Unrecaptured Section 1250 Gain Worksheet)
'20': new ComputedLine((tr: TaxReturn): boolean | undefined => {
- if (!this.getValue(tr, '17'))
+ if (!this.getValue(tr, '17') || this.getValue(tr, '16') <= 0)
return undefined;
const l18 = this.getValue(tr, '18');
const l19 = undefined; //this.getValue(tr, '19');
}, 'Line 18 and 19 both 0 or blank?'),
'21': new ComputedLine((tr: TaxReturn): number | undefined => {
- if (!this.getValue(tr, '17'))
+ if (!this.getValue(tr, '17') || !this.getValue(tr, '20'))
return undefined;
const filingStatus = tr.getForm(Form1040).getInput('filingStatus');
const limit = filingStatus == FilingStatus.MarriedFilingSeparate ? -1500 : -3000;
}, 'Net capital loss'),
};
};
+
+export class ScheduleDTaxWorksheet extends Form<ScheduleDTaxWorksheet['_lines']> {
+ readonly name = 'Schedule D Tax Worksheet';
+
+ protected readonly _lines = {
+ '1': new ReferenceLine(Form1040, '11b'),
+ '2': new ReferenceLine(Form1040, '3a'),
+ // TODO 3 - form 4952
+ // TODO 4 - 4952
+ '5': new ComputedLine((tr: TaxReturn): number => 0),
+ '6': new ComputedLine((tr: TaxReturn): number => clampToZero(this.getValue(tr, '2') - this.getValue(tr, '5'))),
+ '7': new ComputedLine((tr: TaxReturn): number => {
+ const schedD = tr.getForm(ScheduleD);
+ return Math.min(schedD.getValue(tr, '15'), schedD.getValue(tr, '16'));
+ }),
+ '8': new ComputedLine((tr: TaxReturn): number => {
+ return 0;
+ // return Math.min(this.getValue(tr, '3'), this.getValue(tr, '4'));
+ }),
+ '9': new ComputedLine((tr: TaxReturn): number => clampToZero(this.getValue(tr, '7') - this.getValue(tr, '8'))),
+ '10': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '6') + this.getValue(tr, '9')),
+ '11': new ComputedLine((tr: TaxReturn): number => {
+ const schedD = tr.getForm(ScheduleD);
+ // TODO - line 19 is not supported.
+ return Math.min(schedD.getValue(tr, '18'), Infinity); //schedD.getValue(tr, '19'));
+ }),
+ '12': new ComputedLine((tr: TaxReturn): number => Math.min(this.getValue(tr, '9'), this.getValue(tr, '11'))),
+ '13': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '10') - this.getValue(tr, '12')),
+ '14': new ComputedLine((tr: TaxReturn): number => clampToZero(this.getValue(tr, '1') - this.getValue(tr, '13'))),
+ '15': new ComputedLine((tr: TaxReturn): number => {
+ switch (tr.getForm(Form1040).getInput('filingStatus')) {
+ case FilingStatus.Single:
+ case FilingStatus.MarriedFilingSeparate:
+ return 39375;
+ case FilingStatus.MarriedFilingJoint:
+ return 78750;
+ }
+ }),
+ '16': new ComputedLine((tr: TaxReturn): number => Math.min(this.getValue(tr, '1'), this.getValue(tr, '15'))),
+ '17': new ComputedLine((tr: TaxReturn): number => Math.min(this.getValue(tr, '14'), this.getValue(tr, '16'))),
+ '18': new ComputedLine((tr: TaxReturn): number => clampToZero(this.getValue(tr, '1') - this.getValue(tr, '10'))),
+ '19': new ComputedLine((tr: TaxReturn): number => {
+ let threshold: number;
+ switch (tr.getForm(Form1040).getInput('filingStatus')) {
+ case FilingStatus.Single:
+ case FilingStatus.MarriedFilingSeparate:
+ threshold = 160725;
+ break;
+ case FilingStatus.MarriedFilingJoint:
+ threshold = 321450;
+ break;
+ }
+ return Math.min(this.getValue(tr, '1'), threshold);
+ }),
+ '20': new ComputedLine((tr: TaxReturn): number => Math.min(this.getValue(tr, '14'), this.getValue(tr, '19'))),
+ '21': new ComputedLine((tr: TaxReturn): number => Math.max(this.getValue(tr, '18'), this.getValue(tr, '20'))),
+ '22': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '16') - this.getValue(tr, '17')),
+ '23': new ComputedLine((tr: TaxReturn): number => Math.min(this.getValue(tr, '1'), this.getValue(tr, '13'))),
+ '24': new ReferenceLine(ScheduleDTaxWorksheet as any, '22'),
+ '25': new ComputedLine((tr: TaxReturn): number => clampToZero(this.getValue(tr, '23') - this.getValue(tr, '24'))),
+ '26': new ComputedLine((tr: TaxReturn): number => {
+ switch (tr.getForm(Form1040).getInput('filingStatus')) {
+ case FilingStatus.Single:
+ return 434550;
+ case FilingStatus.MarriedFilingSeparate:
+ return 244425;
+ case FilingStatus.MarriedFilingJoint:
+ return 488850;
+ }
+ }),
+ '27': new ComputedLine((tr: TaxReturn): number => Math.min(this.getValue(tr, '1'), this.getValue(tr, '26'))),
+ '28': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '21') + this.getValue(tr, '22')),
+ '29': new ComputedLine((tr: TaxReturn): number => clampToZero(this.getValue(tr, '27') - this.getValue(tr, '28'))),
+ '30': new ComputedLine((tr: TaxReturn): number => Math.min(this.getValue(tr, '25'), this.getValue(tr, '29'))),
+ '31': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '30') * 0.15),
+ '32': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '24') + this.getValue(tr, '30')),
+ '33': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '23') - this.getValue(tr, '32')),
+ '34': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '33') * 0.20),
+ '35': new ComputedLine((tr: TaxReturn): number => {
+ const schedD = tr.getForm(ScheduleD);
+ // TODO - line 19 is not supported.
+ return Math.min(this.getValue(tr, '9'), Infinity); //schedD.getValue(tr, '19'));
+ }),
+ '36': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '10') + this.getValue(tr, '21')),
+ '37': new ReferenceLine(ScheduleDTaxWorksheet as any, '1'),
+ '38': new ComputedLine((tr: TaxReturn): number => clampToZero(this.getValue(tr, '36') - this.getValue(tr, '37'))),
+ '39': new ComputedLine((tr: TaxReturn): number => clampToZero(this.getValue(tr, '35') - this.getValue(tr, '38'))),
+ '40': new ComputedLine((tr: TaxReturn): number => this.getValue(tr, '39') * 0.25),
+ '41': new ComputedLine((tr: TaxReturn): number => {
+ const schedD = tr.getForm(ScheduleD);
+ if (schedD.getValue(tr, '18'))
+ throw new UnsupportedFeatureError('28% Gain unsupported');
+ return 0;
+ }),
+ '42': new ComputedLine((tr: TaxReturn): number => {
+ if (!tr.getForm(ScheduleD).getValue(tr, '18'))
+ return 0;
+ return this.getValue(tr, '1') - this.getValue(tr, '41');
+ }),
+ '43': new ComputedLine((tr: TaxReturn): number => {
+ if (!tr.getForm(ScheduleD).getValue(tr, '18'))
+ return 0;
+ return this.getValue(tr, '42') * 0.28;
+ }),
+ '44': new ComputedLine((tr: TaxReturn): number => {
+ const income = this.getValue(tr, '21');
+ return computeTax(income, tr.getForm(Form1040).getInput('filingStatus'));
+ }),
+ '45': new ComputedLine((tr: TaxReturn): number => {
+ return this.getValue(tr, '31') +
+ this.getValue(tr, '34') +
+ this.getValue(tr, '40') +
+ this.getValue(tr, '43') +
+ this.getValue(tr, '44');
+ }),
+ '46': new ComputedLine((tr: TaxReturn): number => {
+ const income = this.getValue(tr, '1');
+ return computeTax(income, tr.getForm(Form1040).getInput('filingStatus'));
+ }),
+ '47': new ComputedLine((tr: TaxReturn): number => Math.min(this.getValue(tr, '45'), this.getValue(tr, '46'))),
+ };
+};