value(tr: TaxReturn): number {
const forms: F[] = tr.findForms(this._form);
- const reducer = (acc: number, curr: F) => acc + curr.getValue(tr, this._line);
- return forms.reduce(reducer, 0);
+ return sumLineOfForms(tr, forms, this._line);
}
};
+
+export function sumLineOfForms<F extends Form<any>, L extends keyof F['lines']>(
+ tr: TaxReturn, forms: F[], line: L): number {
+ const reducer = (acc: number, curr: F) => acc + curr.getValue(tr, line);
+ return forms.reduce(reducer, 0);
+}
import Form1040, { FilingStatus, Schedule2 } from './Form1040';
import Form1099DIV from './Form1099DIV';
import Form1099INT from './Form1099INT';
+import Form1099B, { GainType } from './Form1099B';
+import ScheduleD from './ScheduleD';
import Form8959 from './Form8959';
+import Form8949 from './Form8949';
import FormW2 from './FormW2';
test('w2 wages', () => {
expect(f1040.getValue(tr, '3a')).toBe(75 * 2);
expect(f1040.getValue(tr, '3b')).toBe(200);
});
+
+test('capital gain/loss', () => {
+ const p = Person.self('A');
+ const tr = new TaxReturn(2019);
+ tr.addForm(new Form1040({ filingStatus: FilingStatus.Single }));
+ tr.addForm(new Form1099B({
+ payer: 'Brokerage',
+ payee: p,
+ description: '10 FNDC',
+ proceeds: 1000,
+ costBasis: 800,
+ gainType: GainType.LongTerm,
+ basisReportedToIRS: true
+ }));
+ Form8949.addForms(tr, []);
+ tr.addForm(new ScheduleD());
+ tr.getForm(ScheduleD).getValue(tr, '21');
+});
import Form1099INT from './Form1099INT';
import Form1099DIV from './Form1099DIV';
import FormW2 from './FormW2';
+import ScheduleD from './ScheduleD';
export enum FilingStatus {
Single,
'4d': new ComputedLine(() => 0),
// 4c and 4d are not supported
// 5a and 5b are not supported
- '6': new ReferenceLine(/*'Schedule D'*/ undefined, '21', 'Capital gain/loss', 0),
+ '6': new ComputedLine((tr: TaxReturn): number => {
+ const schedD = tr.findForm(ScheduleD);
+ if (!schedD)
+ return 0;
+
+ const l6 = schedD.getValue(tr, '16');
+ if (l6 > 0)
+ return l6;
+ return schedD.getValue(tr, '21');
+ }, 'Capital gain/loss'),
'7a': new ReferenceLine(/*'Schedule 1'*/ undefined, '9', 'Other income from Schedule 1', 0),
'7b': new ComputedLine((tr: TaxReturn): number => {
--- /dev/null
+import Form from '../Form';
+import Person from '../Person';
+import TaxReturn from '../TaxReturn';
+import { InputLine } from '../Line';
+
+export enum GainType {
+ ShortTerm = 'ST',
+ LongTerm = 'LT',
+ Ordinary = 'O',
+};
+
+export interface SpecialProceeds {
+ collectibles?: boolean;
+ qof?: boolean;
+};
+
+export interface IRSReporting {
+ grossProceeds?: boolean;
+ netProceeds?: boolean;
+};
+
+export interface Form1099BInput {
+ payer: string;
+ payee: Person;
+ description: string;
+ dateAcquired?: string;
+ dateSold?: string;
+ proceeds: number;
+ costBasis: number;
+ accruedMarketDiscount?: number;
+ washSaleLossDisallowed?: number;
+ gainType: GainType;
+ specialProceeds?: SpecialProceeds;
+ fedIncomeTax?: number;
+ nonCoveredSecurity?: boolean;
+ irsReporting?: IRSReporting;
+ disallowedLoss?: boolean;
+ profitOnClosedContracts?: number;
+ unrealizedProfitOnOpenContractsCurrentTY?: number;
+ unrealizedProfitOnOpenContractsNextTY?: number;
+ aggregateProfitOnContracts?: number;
+ basisReportedToIRS?: boolean;
+ bartering?: number;
+};
+
+class Input<T extends keyof Form1099BInput> extends InputLine<Form1099BInput, T> {};
+
+export default class Form1099B extends Form<Form1099B['_lines'], Form1099BInput> {
+ readonly name = '1099-B';
+
+ readonly supportsMultipleCopies = true;
+
+ protected readonly _lines = {
+ 'payer': new Input('payer'),
+ 'recipient': new Input('payee'),
+ '1a': new Input('description'),
+ '1b': new Input('dateAcquired'),
+ '1c': new Input('dateSold'),
+ '1d': new Input('proceeds'),
+ '1e': new Input('costBasis'),
+ '1f': new Input('accruedMarketDiscount'),
+ '1g': new Input('washSaleLossDisallowed'),
+ '2': new Input('gainType'),
+ '3': new Input('specialProceeds'),
+ '4': new Input('fedIncomeTax'),
+ '5': new Input('nonCoveredSecurity'),
+ '6': new Input('irsReporting'),
+ '7': new Input('disallowedLoss'),
+ '8': new Input('profitOnClosedContracts'),
+ '9': new Input('unrealizedProfitOnOpenContractsCurrentTY'),
+ '10': new Input('unrealizedProfitOnOpenContractsNextTY'),
+ '11': new Input('aggregateProfitOnContracts'),
+ '12': new Input('basisReportedToIRS'),
+ '13': new Input('bartering')
+ };
+};
--- /dev/null
+import TaxReturn from '../TaxReturn';
+import Person from '../Person';
+
+import Form1040, { FilingStatus } from './Form1040';
+import Form1099B, { GainType } from './Form1099B';
+import Form8949, { Form8949Box } from './Form8949';
+
+describe('single form', () => {
+ for (const box of [Form8949Box.A, Form8949Box.B, Form8949Box.D, Form8949Box.E]) {
+ test(`box ${Form8949Box[box]}`, () => {
+ const p = Person.self('A');
+ const tr = new TaxReturn(2019);
+ tr.addForm(new Form1040({ filingStatus: FilingStatus.Single }));
+ tr.addForm(new Form1099B({
+ payer: 'Brokerage',
+ payee: p,
+ description: '10 shares',
+ proceeds: 100,
+ costBasis: 110,
+ gainType: (box == Form8949Box.A || box == Form8949Box.B) ? GainType.ShortTerm : GainType.LongTerm,
+ basisReportedToIRS: (box == Form8949Box.A || box == Form8949Box.D),
+ }));
+ Form8949.addForms(tr, []);
+
+ const f8949s = tr.findForms(Form8949);
+ expect(f8949s.length).toBe(6);
+
+ for (let form of f8949s) {
+ if (form.getValue(tr, 'Box') == box) {
+ expect(form.getValue(tr, '2(d)')).toBe(100);
+ expect(form.getValue(tr, '2(e)')).toBe(110);
+ expect(form.getValue(tr, '2(g)')).toBe(0);
+ } else {
+ expect(form.getValue(tr, '2(d)')).toBe(0);
+ expect(form.getValue(tr, '2(e)')).toBe(0);
+ expect(form.getValue(tr, '2(g)')).toBe(0);
+ }
+ }
+ });
+ }
+});
+
+test('multiple forms', () => {
+ const p = Person.self('A');
+ const tr = new TaxReturn(2019);
+ tr.addForm(new Form1040({ filingStatus: FilingStatus.Single }));
+ tr.addForm(new Form1099B({
+ payer: 'Brokerage',
+ payee: p,
+ description: '10 SCHB',
+ proceeds: 55,
+ costBasis: 50,
+ gainType: GainType.ShortTerm,
+ basisReportedToIRS: true,
+ }));
+ tr.addForm(new Form1099B({
+ payer: 'Brokerage',
+ payee: p,
+ description: '10 SCHB',
+ proceeds: 55,
+ costBasis: 50,
+ gainType: GainType.LongTerm,
+ basisReportedToIRS: false,
+ }));
+ tr.addForm(new Form1099B({
+ payer: 'Brokerage',
+ payee: p,
+ description: '10 SCHF',
+ proceeds: 22.40,
+ costBasis: 10.10,
+ gainType: GainType.LongTerm,
+ basisReportedToIRS: false,
+ }));
+ Form8949.addForms(tr, []);
+
+ const f8949s = tr.findForms(Form8949);
+ expect(f8949s.length).toBe(6);
+
+ const boxA = f8949s.filter(f => f.getValue(tr, 'Box') == Form8949Box.A).pop();
+ expect(boxA.getValue(tr, '2(d)')).toBe(55);
+ expect(boxA.getValue(tr, '2(e)')).toBe(50);
+ expect(boxA.getValue(tr, '2(g)')).toBe(0);
+
+ const boxE = f8949s.filter(f => f.getValue(tr, 'Box') == Form8949Box.E).pop();
+ expect(boxE.getValue(tr, '2(d)')).toBe(77.40);
+ expect(boxE.getValue(tr, '2(e)')).toBe(60.10);
+ expect(boxE.getValue(tr, '2(g)')).toBe(0);
+
+ const otherBoxes = f8949s.filter(f => ![Form8949Box.A, Form8949Box.E].includes(f.getValue(tr, 'Box')));
+ for (const other of otherBoxes) {
+ expect(other.getValue(tr, '2(d)')).toBe(0);
+ expect(other.getValue(tr, '2(e)')).toBe(0);
+ expect(other.getValue(tr, '2(g)')).toBe(0);
+ }
+});
+
+test('adjustments', () => {
+ const p = Person.self('A');
+ const tr = new TaxReturn(2019);
+ tr.addForm(new Form1040({ filingStatus: FilingStatus.Single }));
+ const b1 = new Form1099B({
+ payer: 'Brokerage',
+ payee: p,
+ description: '10 SCHB',
+ proceeds: 55,
+ costBasis: 50,
+ gainType: GainType.ShortTerm,
+ basisReportedToIRS: false,
+ });
+ tr.addForm(b1);
+ const b2 = new Form1099B({
+ payer: 'Brokerage',
+ payee: p,
+ description: '10 SCHB',
+ proceeds: 18,
+ costBasis: 25,
+ gainType: GainType.LongTerm,
+ basisReportedToIRS: false,
+ });
+ tr.addForm(b2);
+ tr.addForm(new Form1099B({
+ payer: 'Brokerage',
+ payee: p,
+ description: '10 SCHF',
+ proceeds: 22.40,
+ costBasis: 10.10,
+ gainType: GainType.LongTerm,
+ basisReportedToIRS: true,
+ }));
+ Form8949.addForms(tr, [
+ { entry: b1, code: 'W', amount: -10 },
+ { entry: b2, code: 'W', amount: 90 },
+ ]);
+
+ const f8949s = tr.findForms(Form8949);
+ expect(f8949s.length).toBe(6);
+
+ const boxA = f8949s.filter(f => f.getValue(tr, 'Box') == Form8949Box.B).pop();
+ expect(boxA.getValue(tr, '2(d)')).toBe(55);
+ expect(boxA.getValue(tr, '2(e)')).toBe(50);
+ expect(boxA.getValue(tr, '2(g)')).toBe(-10);
+
+ const boxD = f8949s.filter(f => f.getValue(tr, 'Box') == Form8949Box.D).pop();
+ expect(boxD.getValue(tr, '2(d)')).toBe(22.40);
+ expect(boxD.getValue(tr, '2(e)')).toBe(10.10);
+ expect(boxD.getValue(tr, '2(g)')).toBe(0);
+
+ const boxE = f8949s.filter(f => f.getValue(tr, 'Box') == Form8949Box.E).pop();
+ expect(boxE.getValue(tr, '2(d)')).toBe(18);
+ expect(boxE.getValue(tr, '2(e)')).toBe(25);
+ expect(boxE.getValue(tr, '2(g)')).toBe(90);
+
+ const otherBoxes = f8949s.filter(f => ![Form8949Box.B, Form8949Box.D, Form8949Box.E].includes(f.getValue(tr, 'Box')));
+ for (const other of otherBoxes) {
+ expect(other.getValue(tr, '2(d)')).toBe(0);
+ expect(other.getValue(tr, '2(e)')).toBe(0);
+ expect(other.getValue(tr, '2(g)')).toBe(0);
+ }
+});
--- /dev/null
+import Form from '../Form';
+import Person from '../Person';
+import TaxReturn from '../TaxReturn';
+import { Line, InputLine, ComputedLine, sumLineOfForms } from '../Line';
+
+import Form1099B, { GainType } from './Form1099B';
+
+export enum Form8949Box {
+ A = 'A', // Short-term transactions reported on Form(s) 1099-B showing basis was reported to the IRS
+ B = 'B', // Short-term transactions reported on Form(s) 1099-B showing basis wasn’t reported to the IRS
+ C = 'C', // Short-term transactions not reported to you on Form 1099-B
+ D = 'D', // Long-term transactions reported on Form(s) 1099-B showing basis was reported to the IRS
+ E = 'E', // Long-term transactions reported on Form(s) 1099-B showing basis wasn’t reported to the IRS
+ F = 'F', // Long-term transactions not reported to you on Form 1099-B
+};
+
+export interface Adjustment {
+ entry: Form1099B;
+ code: string;
+ amount: number;
+};
+
+export interface Form8949Input {
+ box: Form8949Box;
+ adjustments?: Adjustment[];
+};
+
+function matching1099Bs(tr: TaxReturn, box: Form8949Box): Form1099B[] {
+ return tr.findForms(Form1099B).filter(f => {
+ const gainType: GainType = f.getValue(tr, '2');
+ const basisReported: boolean = f.getValue(tr, '12');
+
+ switch (box) {
+ case Form8949Box.A:
+ return gainType == GainType.ShortTerm && basisReported;
+ case Form8949Box.B:
+ return gainType == GainType.ShortTerm && !basisReported;
+ case Form8949Box.D:
+ return gainType == GainType.LongTerm && basisReported;
+ case Form8949Box.E:
+ return gainType == GainType.LongTerm && !basisReported;
+ };
+
+ return false;
+ });
+}
+
+class Form8949Line extends Line<number> {
+ private _box: Form8949Box;
+ private _line: keyof Form1099B['lines'];
+
+ constructor(f8949Functor: () => Form8949, line: keyof Form1099B['lines'], description: string) {
+ const box = f8949Functor().getInput('box');
+ super(`Form 8949 Box ${box} total of 1099-B ${line} (${description})`);
+ this._box = box;
+ this._line = line;
+ }
+
+ value(tr: TaxReturn): number {
+ const f1099bs = matching1099Bs(tr, this._box);
+ return sumLineOfForms(tr, f1099bs, this._line);
+ }
+};
+
+export default class Form8949 extends Form<Form8949['_lines'], Form8949Input> {
+ readonly name = '8949';
+
+ readonly supportsMultipleCopies = true;
+
+ protected readonly _lines = {
+ 'Box': new InputLine<Form8949Input>('box'),
+ '2(d)': new Form8949Line(() => this, '1d', 'proceeds'),
+ '2(e)': new Form8949Line(() => this, '1e', 'cost'),
+ '2(g)': new ComputedLine((tr: TaxReturn): number => {
+ const f1099bs = matching1099Bs(tr, this.getInput('box'));
+ const adjustments = this.getInput('adjustments').filter((a: Adjustment): boolean => {
+ return f1099bs.includes(a.entry);
+ });
+ return adjustments.reduce((acc, curr) => acc + curr.amount, 0);
+ }, 'adjustments')
+ };
+
+ static addForms(tr: TaxReturn, adjustments: Adjustment[]) {
+ tr.addForm(new Form8949({ box: Form8949Box.A, adjustments }));
+ tr.addForm(new Form8949({ box: Form8949Box.B, adjustments }));
+ tr.addForm(new Form8949({ box: Form8949Box.C, adjustments }));
+ tr.addForm(new Form8949({ box: Form8949Box.D, adjustments }));
+ tr.addForm(new Form8949({ box: Form8949Box.E, adjustments }));
+ tr.addForm(new Form8949({ box: Form8949Box.F, adjustments }));
+ }
+};
+
+/*
+export interface Adjustment {
+ entry: Form1099B;
+ code: string;
+ amount: number;
+};
+
+export interface Form8949Input {
+ adjustments?: []Adjustment;
+};
+
+export interface Form8949Total {
+ proceeds: number;
+ costBasis: number;
+ adjustmentAmount: number;
+ gainOrLoss: number;
+};
+
+class Form8949Line extends Line<Form8949Total> {
+ private _box: Form8949Box;
+
+ constructor(description: string, box: Form8949Input) {
+ super(description);
+ this._box = box;
+ }
+
+ value(tr: TaxReturn): Form8949Total {
+ const lineShortTerm = this._box == Form8949Box.A || this._box == Form8949Box.B || this._box == Form8949Box.C;
+ const lineBasisReported = this._box == Form8949Box.A || this._box == Form8949Box.D;
+
+ const f1099bs = tr.findForms(Form1099B);
+ const relevant1099bs: Form1099B[] = [];
+ for (const form of f1099bs) {
+ const gainType = form.getValue(tr, '2');
+ const basisReported = form.getValue(tr, '12');
+
+ if (lineBasisReported != basisReported)
+ continue;
+
+ if (gainType == GainType.ShortTerm && lineShortTerm) {
+ relevant1099bs.push(form);
+ } else if (gainType == GainType.LongTerm && !lineShortTerm) {
+ relevant1099bs.push(form);
+ }
+ }
+
+ const sumValues = (line: keyof Form1099B['lines']) =>
+ relevant1099bs.map((f: Form1099B): number => f.getValue(tr, line))
+ .reduce((acc, curr) => acc + curr, 0);
+
+ const proceeds = sumValues('1d');
+ const costBasis = sumValues('1e');
+
+ return {
+ proceeds,
+ costBasis,
+ adjustmentAmount: 0,
+ gainOrLoss: costBasis - proceeds,
+ };
+ }
+};
+
+export default class Form8949 extends Form<Form8949['_lines'], Form8949Input> {
+ readonly name = '8949';
+
+ protected readonly _lines = {
+ boxATotals: new Form8949Line('Short-term basis reported', Form8949Box.A),
+ boxBTotals: new Form8949Line('Short-term basis NOT reported', Form8949Box.B),
+ boxCTotals: new Form8949Line('Short-term unreported', Form8949Box.C),
+ boxDTotals: new Form8949Line('Long-term basis reported', Form8949Box.D),
+ boxETotals: new Form8949Line('Long-term basis NOT reported', Form8949Box.E),
+ boxFTotals: new Form8949Line('Long-term unreported', Form8949Box.F)
+ };
+};
+*/
--- /dev/null
+import Form from '../Form';
+import Person from '../Person';
+import TaxReturn from '../TaxReturn';
+import { Line, AccumulatorLine, ComputedLine, sumLineOfForms } from '../Line';
+
+import Form8949, { Form8949Box } from './Form8949';
+import Form1099DIV from './Form1099DIV';
+import Form1040, { FilingStatus } from './Form1040';
+
+class ScheduleDTotal extends Line<number> {
+ private _line: keyof Form8949['lines'];
+ private _box: Form8949Box;
+
+ constructor(description: string, line: keyof Form8949['lines'], box: Form8949Box) {
+ super(description);
+ this._line = line;
+ this._box = box;
+ }
+
+ value(tr: TaxReturn): number {
+ const forms: Form8949[] = tr.findForms(Form8949).filter(f => f.getValue(tr, 'Box') == this._box);
+ return sumLineOfForms(tr, forms, this._line);
+ }
+};
+
+export default class ScheduleD extends Form<ScheduleD['_lines']> {
+ readonly name = 'Schedule D';
+
+ protected readonly _lines = {
+ // 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)
+
+ '1b(d)': new ScheduleDTotal('Proceeds of short-term basis reported', '2(d)', Form8949Box.A),
+ '1b(e)': new ScheduleDTotal('Cost basis of short-term basis-reported', '2(e)', Form8949Box.A),
+ '1b(g)': new ScheduleDTotal('Adjustments to short-term basis-reported', '2(g)', Form8949Box.A),
+ '1b(h)': new ComputedLine((tr: TaxReturn): number => {
+ return (this.getValue(tr, '1b(d)') - this.getValue(tr, '1b(e)')) + this.getValue(tr, '1b(g)');
+ }, 'Gain of short-term basis reported'),
+
+ '2(d)': new ScheduleDTotal('Proceeds of short-term basis NOT reported', '2(d)', Form8949Box.B),
+ '2(e)': new ScheduleDTotal('Cost basis of short-term NOT basis-reported', '2(e)', Form8949Box.B),
+ '2(g)': new ScheduleDTotal('Adjustments to short-term NOT basis-reported', '2(g)', Form8949Box.B),
+ '2(h)': new ComputedLine((tr: TaxReturn): number => {
+ return (this.getValue(tr, '2(d)') - this.getValue(tr, '2(e)')) + this.getValue(tr, '2(g)');
+ }, 'Gain of short-term basis NOT reported'),
+
+ '3(d)': new ScheduleDTotal('Proceeds of short-term basis unreported', '2(d)', Form8949Box.C),
+ '3(e)': new ScheduleDTotal('Cost basis of short-term unreported', '2(e)', Form8949Box.C),
+ '3(g)': new ScheduleDTotal('Adjustments to short-term unreported', '2(g)', Form8949Box.C),
+ '3(h)': new ComputedLine((tr: TaxReturn): number => {
+ return (this.getValue(tr, '3(d)') - this.getValue(tr, '3(e)')) + this.getValue(tr, '3(g)');
+ }, 'Gain of short-term unreported'),
+
+ // 4 is not supported (Short-term gain from Form 6252 and short-term gain or (loss) from Forms 4684, 6781, and 8824)
+ // 5 is not supported (Net short-term gain or (loss) from partnerships, S corporations, estates, and trusts from Schedule(s) K-1)
+ // 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)
+
+ '7': new ComputedLine((tr: TaxReturn): number => {
+ // 4-6 should be included.
+ return this.getValue(tr, '1b(h)') + this.getValue(tr, '2(h)'), this.getValue(tr, '3(h)');
+ }, 'Net short-term capital gain or (loss)'),
+
+ // 8a is not supported.
+
+ '8b(d)': new ScheduleDTotal('Proceeds of long-term basis reported', '2(d)', Form8949Box.D),
+ '8b(e)': new ScheduleDTotal('Cost basis of long-term basis-reported', '2(e)', Form8949Box.D),
+ '8b(g)': new ScheduleDTotal('Adjustments to long-term basis-reported', '2(g)', Form8949Box.D),
+ '8b(h)': new ComputedLine((tr: TaxReturn): number => {
+ return (this.getValue(tr, '8b(d)') - this.getValue(tr, '8b(e)')) + this.getValue(tr, '8b(g)');
+ }, 'Gain of long-term basis reported'),
+
+ '9(d)': new ScheduleDTotal('Proceeds of long-term basis NOT reported', '2(d)', Form8949Box.E),
+ '9(e)': new ScheduleDTotal('Cost basis of long-term NOT basis-reported', '2(e)', Form8949Box.E),
+ '9(g)': new ScheduleDTotal('Adjustments to long-term NOT basis-reported', '2(g)', Form8949Box.E),
+ '9(h)': new ComputedLine((tr: TaxReturn): number => {
+ return (this.getValue(tr, '9(d)') - this.getValue(tr, '9(e)')) + this.getValue(tr, '9(g)');
+ }, 'Gain of long-term basis NOT reported'),
+
+ '10(d)': new ScheduleDTotal('Proceeds of long-term basis unreported', '2(d)', Form8949Box.F),
+ '10(e)': new ScheduleDTotal('Cost basis of long-term unreported', '2(e)', Form8949Box.F),
+ '10(g)': new ScheduleDTotal('Adjustments to long-term unreported', '2(g)', Form8949Box.F),
+ '10(h)': new ComputedLine((tr: TaxReturn): number => {
+ return (this.getValue(tr, '10(d)') - this.getValue(tr, '10(e)')) + this.getValue(tr, '10(g)');
+ }, 'Gain of long-term unreported'),
+
+ // 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)
+ // 12 is not supported (Net long-term gain or (loss) from partnerships, S corporations, estates, and trusts from Schedule(s) K-1)
+
+ '13': new AccumulatorLine(Form1099DIV, '2a', 'Capital gain distributions'),
+
+ // 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)
+
+ '15': new ComputedLine((tr: TaxReturn): number => {
+ // 11-14 should be included.
+ return this.getValue(tr, '8b(h)') + this.getValue(tr, '9(h)') + this.getValue(tr, '10(h)') +
+ this.getValue(tr, '13');
+ }, 'Net long-term capital gain or (loss)'),
+
+ '16': new ComputedLine((tr: TaxReturn): number => {
+ return this.getValue(tr, '7') + this.getValue(tr, '15');
+ }),
+
+ '17': new ComputedLine((tr: TaxReturn): boolean => {
+ return this.getValue(tr, '15') > 0 && this.getValue(tr, '16') > 0;
+ }, 'Both ST and LT are gains'),
+
+ '18': new ComputedLine((tr: TaxReturn): number | undefined => {
+ if (!this.getValue(tr, '17'))
+ return undefined;
+ // TODO
+ 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'))
+ return undefined;
+ const l18 = this.getValue(tr, '18');
+ const l19 = undefined; //this.getValue(tr, '19');
+ return (l18 === 0 || l18 === undefined) || (l19 === 0 || l19 === undefined);
+ }, 'Line 18 and 19 both 0 or blank?'),
+
+ '21': new ComputedLine((tr: TaxReturn): number | undefined => {
+ if (!this.getValue(tr, '17'))
+ return undefined;
+ const filingStatus = tr.getForm(Form1040).getInput('filingStatus');
+ const limit = filingStatus == FilingStatus.MarriedFilingSeparate ? -1500 : -3000;
+ return Math.min(this.getValue(tr, '16'), limit);
+ }, 'Net capital loss'),
+ };
+};