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