import Form1040, { FilingStatus, Schedule2 } from './Form1040';
import Form1099DIV from './Form1099DIV';
import Form1099INT from './Form1099INT';
+import Form8959 from './Form8959';
import FormW2 from './FormW2';
test('w2 wages', () => {
const f1040 = new Form1040({ filingStatus: FilingStatus.MarriedFilingJoint });
tr.addForm(f1040);
tr.addForm(new Schedule2);
+ tr.addForm(new Form8959);
expect(f1040.getValue(tr, '1')).toBe(1000036.32);
f1040.getValue(tr, '23');
});
import { Line, AccumulatorLine, ComputedLine, ReferenceLine } from '../Line';
import { UnsupportedFeatureError } from '../Errors';
+import Form8959 from './Form8959';
+
export enum FilingStatus {
Single,
MarriedFilingSeparate,
const wages = f1040.getLine('1').value(tr);
const agi = f1040.getLine('8b').value(tr);
- let additionalMedicare: boolean, niit: boolean;
+ let niit: boolean;
+ const filingStatus = f1040.getInput('filingStatus');
+
+ const additionalMedicare = wages > Form8959.filingStatusLimit(filingStatus);
+
switch (f1040.getInput('filingStatus')) {
case FilingStatus.Single:
if (wages > 200000) {
- additionalMedicare = true;
niit = true;
}
break;
case FilingStatus.MarriedFilingJoint:
if (wages > 250000) {
- additionalMedicare = true;
niit = true;
}
break;
case FilingStatus.MarriedFilingSeparate:
if (wages > 125000) {
- additionalMedicare = true;
niit = true;
}
break;
--- /dev/null
+import Form from '../Form';
+import TaxReturn from '../TaxReturn';
+import { Line, AccumulatorLine, ComputedLine, ReferenceLine } from '../Line';
+
+import Form1040, { FilingStatus } from './Form1040';
+
+export default class Form8959 extends Form<Form8959['_lines']> {
+ readonly name = '8959';
+
+ protected readonly _lines = {
+ '1': new AccumulatorLine('W-2', '5', 'Medicare wages'),
+ // 2 is not supported (Unreported tips from Form 4137)
+ // 3 is not supported (Wages from Form 8919)
+ '4': new ComputedLine((tr: TaxReturn): number => {
+ // Should include 2-3.
+ return this.getValue(tr, '1');
+ }),
+ '5': new ComputedLine((tr: TaxReturn): number => {
+ return Form8959.filingStatusLimit(tr.getForm<Form1040>('1040').getInput('filingStatus'));
+ }),
+ '6': new ComputedLine((tr: TaxReturn): number => {
+ const value = this.getValue(tr, '5') - this.getValue(tr, '4');
+ return value < 0 ? 0 : value;
+ }),
+ '7': new ComputedLine((tr: TaxReturn): number => {
+ return this.getValue(tr, '6') * 0.009;
+ }, 'Additional Medicare tax on Medicare wages'),
+
+ // All of Section 2 and 3 skipped.
+
+ '18': new ComputedLine((tr: TaxReturn): number => {
+ // Should include 13 and 17.
+ return this.getValue(tr, '7');
+ }),
+
+ '19': new AccumulatorLine('W-2', '6', 'Medicare tax withheld'),
+ '20': new ReferenceLine<number>('8595', '1'),
+ '21': new ComputedLine((tr: TaxReturn): number => {
+ return this.getValue(tr, '20') * 0.0145;
+ }, 'Regular Medicare withholding on Medicare wages'),
+ '22': new ComputedLine((tr: TaxReturn): number => {
+ const value = this.getValue(tr, '19') - this.getValue(tr, '21');
+ return value < 0 ? 0 : value;
+ }, 'Additional Medicare withholding on Medicare wages'),
+ // 23 is not supported (Additional Medicare Tax withholding on railroad retirement (RRTA) compensation)
+ '24': new ComputedLine((tr: TaxReturn): number => {
+ // Should include 23.
+ return this.getValue(tr, '22');
+ }),
+ };
+
+ static filingStatusLimit(filingStatus: FilingStatus): number {
+ switch (filingStatus) {
+ case FilingStatus.Single: return 200000;
+ case FilingStatus.MarriedFilingJoint: return 250000;
+ case FilingStatus.MarriedFilingSeparate: return 125000;
+ }
+ }
+};