Add license information.
[ustaxlib.git] / src / core / TaxReturn.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 Form, { FormClass, isFormT } from './Form';
7 import Person, { Relation } from './Person';
8 import { NotFoundError, InconsistencyError, UnsupportedFeatureError } from './Errors';
9
10 export default abstract class TaxReturn {
11 private _people: Person[] = [];
12 private _forms: Form<any, unknown>[] = [];
13
14 abstract get year(): number;
15
16 abstract get includeJointPersonForms(): boolean;
17
18 get forms(): Form<any, unknown>[] {
19 return [...this._forms];
20 }
21
22 addPerson(person: Person) {
23 if (person.relation == Relation.Dependent) {
24 throw new UnsupportedFeatureError('Dependents are not supported');
25 }
26 if (person.relation == Relation.Self || person.relation == Relation.Spouse) {
27 const others = this._people.filter(p => p.relation == person.relation);
28 if (others.length > 0) {
29 throw new InconsistencyError('Cannot have more than one Self or Spouse');
30 }
31 }
32 this._people.push(person);
33 }
34
35 getPerson(name: RegExp | string): Person {
36 const people = this._people.filter(p => p.name.search(name) !== -1);
37 if (people.length != 1) {
38 throw new Error(`Person ${name} not found or too imprecise`);
39 }
40 return people[0];
41 }
42
43 addForm(form: Form<any>) {
44 if (!form.supportsMultipleCopies) {
45 const other = this.findForms(form.constructor as FormClass<Form<any>>);
46 if (other.length > 0) {
47 throw new InconsistencyError(`Cannot have more than one type of form ${form.name}`);
48 }
49 }
50 form.init();
51 this._forms.push(form);
52 }
53
54 findForm<T extends Form<any>>(cls: FormClass<T>): T | null {
55 const forms = this.findForms(cls);
56 if (forms.length == 0)
57 return null;
58 if (forms.length > 1)
59 throw new InconsistencyError(`Form ${forms[0].name} has multiple copies`);
60 return forms[0];
61 }
62
63 findForms<T extends Form<any>>(cls: FormClass<T>): T[] {
64 const forms: T[] = this._forms
65 .filter((form: Form<any>): form is T => isFormT(form, cls))
66 .filter((form: T) => {
67 const person = form.person();
68 if (person === undefined)
69 return true;
70
71 if (person == Person.joint && this.includeJointPersonForms)
72 return true;
73
74 return this._people.includes(form.person());
75 });
76 return forms;
77 }
78
79 getForm<T extends Form<any>>(cls: FormClass<T>): T {
80 const form = this.findForm(cls);
81 if (!form)
82 throw new NotFoundError(`No form ${cls.name}`);
83 return form;
84 }
85 };