Redo 1099-B to be simplerf for recording adjustments.
[ustaxlib.git] / src / fed2019 / Form8949.test.ts
1 // Copyright 2020 Blue Static <https://www.bluestatic.org>
2 // This program is free software licensed under the GNU General Public License,
3 // version 3.0. The full text of the license can be found in LICENSE.txt.
4 // SPDX-License-Identifier: GPL-3.0-only
5
6 import { Person } from '../core';
7
8 import Form1040, { FilingStatus } from './Form1040';
9 import Form1099B, { Form1099BInput } from './Form1099B';
10 import Form8949, { Form8949Box, Form8949Total } from './Form8949';
11 import TaxReturn from './TaxReturn';
12
13 describe('single form', () => {
14 for (const box of [Form8949Box.A, Form8949Box.B, Form8949Box.D, Form8949Box.E]) {
15 test(`box ${Form8949Box[box]}`, () => {
16 const p = Person.self('A');
17 const tr = new TaxReturn();
18 tr.addPerson(p);
19 tr.addForm(new Form1040({ filingStatus: FilingStatus.Single }));
20
21 const fieldMap: { [key: string]: keyof Form1099BInput } = {
22 [Form8949Box.A]: 'shortTermBasisReported',
23 [Form8949Box.B]: 'shortTermBasisUnreported',
24 [Form8949Box.C]: 'shortTermUnreported',
25 [Form8949Box.D]: 'longTermBasisReported',
26 [Form8949Box.E]: 'longTermBasisUnreported',
27 [Form8949Box.F]: 'longTermUnreported',
28 };
29 const field = fieldMap[box];
30
31 tr.addForm(new Form1099B({
32 payer: 'Brokerage',
33 payee: p,
34 [field]: [
35 {
36 description: '10 shares',
37 proceeds: 100,
38 costBasis: 110,
39 }
40 ],
41 }));
42
43 const form = new Form8949();
44 tr.addForm(form);
45
46 const allBoxes: (keyof Form8949['lines'])[] = ['boxA', 'boxB', 'boxC', 'boxD', 'boxE', 'boxF'];
47 const otherBoxes = allBoxes.filter(b => b != `box${box}`);
48 const thisBox = `box${box}` as keyof Form8949['lines'];
49
50 let total = form.getValue(tr, thisBox);
51
52 expect(total.proceeds).toBe(100);
53 expect(total.costBasis).toBe(110);
54 expect(total.adjustments).toBe(0);
55 expect(total.gainOrLoss).toBe(-10);
56
57 for (let otherBox of otherBoxes) {
58 total = form.getValue(tr, otherBox);
59 expect(total.proceeds).toBe(0);
60 expect(total.costBasis).toBe(0);
61 expect(total.adjustments).toBe(0);
62 expect(total.gainOrLoss).toBe(0);
63 }
64 });
65 }
66 });
67
68 test('multiple forms', () => {
69 const p = Person.self('A');
70 const tr = new TaxReturn();
71 tr.addPerson(p);
72 tr.addForm(new Form1040({ filingStatus: FilingStatus.Single }));
73 tr.addForm(new Form1099B({
74 payer: 'Brokerage',
75 payee: p,
76 shortTermBasisReported: [
77 {
78 description: '10 SCHB',
79 proceeds: 55,
80 costBasis: 50,
81 }
82 ],
83 longTermBasisUnreported: [
84 {
85 description: '10 SCHB',
86 proceeds: 55,
87 costBasis: 50,
88 },
89 {
90 description: '10 SCHF',
91 proceeds: 22.40,
92 costBasis: 10.10,
93 }
94 ],
95 }));
96
97 const form = new Form8949();
98 tr.addForm(form);
99
100 const boxA = form.getValue(tr, 'boxA');
101 expect(boxA.proceeds).toBe(55);
102 expect(boxA.costBasis).toBe(50);
103 expect(boxA.adjustments).toBe(0);
104 expect(boxA.gainOrLoss).toBe(5);
105
106 const boxE = form.getValue(tr, 'boxE');
107 expect(boxE.proceeds).toBe(77.40);
108 expect(boxE.costBasis).toBe(60.10);
109 expect(boxE.adjustments).toBe(0);
110 expect(boxE.gainOrLoss).toBeCloseTo(17.3);
111
112 const otherBoxes: (keyof Form8949['lines'])[] = ['boxB', 'boxC', 'boxD', 'boxF'];
113 for (const otherBox of otherBoxes) {
114 const other = form.getValue(tr, otherBox);
115 expect(other.proceeds).toBe(0);
116 expect(other.costBasis).toBe(0);
117 expect(other.adjustments).toBe(0);
118 expect(other.gainOrLoss).toBe(0);
119 }
120 });
121
122 test('adjustments', () => {
123 const p = Person.self('A');
124 const tr = new TaxReturn();
125 tr.addPerson(p);
126 tr.addForm(new Form1040({ filingStatus: FilingStatus.Single }));
127 const b1 = new Form1099B({
128 payer: 'Brokerage',
129 payee: p,
130 shortTermBasisUnreported: [
131 {
132 description: '10 SCHB',
133 proceeds: 55,
134 costBasis: 50,
135 adjustments: -10,
136 }
137 ],
138 longTermBasisUnreported: [
139 {
140 description: '10 SCHB',
141 proceeds: 18,
142 costBasis: 25,
143 adjustments: 90,
144 }
145 ],
146 longTermBasisReported: [
147 {
148 description: '10 SCHF',
149 proceeds: 22.40,
150 costBasis: 10.10,
151 }
152 ]
153 });
154 tr.addForm(b1);
155
156 const form = new Form8949();
157 tr.addForm(form);
158
159 const boxB = form.getValue(tr, 'boxB');
160 expect(boxB.proceeds).toBe(55);
161 expect(boxB.costBasis).toBe(50);
162 expect(boxB.adjustments).toBe(-10);
163 expect(boxB.gainOrLoss).toBe(-5);
164
165 const boxE = form.getValue(tr, 'boxE');
166 expect(boxE.proceeds).toBe(18);
167 expect(boxE.costBasis).toBe(25);
168 expect(boxE.adjustments).toBe(90);
169 expect(boxE.gainOrLoss).toBe(83);
170
171 const boxD = form.getValue(tr, 'boxD');
172 expect(boxD.proceeds).toBe(22.40);
173 expect(boxD.costBasis).toBe(10.10);
174 expect(boxD.adjustments).toBe(0);
175 expect(boxD.gainOrLoss).toBeCloseTo(12.30);
176
177 const otherBoxes: (keyof Form8949['lines'])[] = ['boxA', 'boxC', 'boxF'];
178 for (const otherBox of otherBoxes) {
179 const other = form.getValue(tr, otherBox);
180 expect(other.proceeds).toBe(0);
181 expect(other.costBasis).toBe(0);
182 expect(other.adjustments).toBe(0);
183 expect(other.gainOrLoss).toBe(0);
184 }
185 });