-
Notifications
You must be signed in to change notification settings - Fork 3
/
write-off-service.ts
200 lines (177 loc) · 6.33 KB
/
write-off-service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/**
* SudoSOS back-end API service.
* Copyright (C) 2024 Study association GEWIS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* @license
*/
/**
* This is the module page of the write-off-service.
*
* @module write-offs
*/
import WriteOff from '../entity/transactions/write-off';
import { parseUserToBaseResponse } from '../helpers/revision-to-response';
import TransferService from './transfer-service';
import {
BaseWriteOffResponse,
PaginatedWriteOffResponse,
WriteOffResponse,
} from '../controller/response/write-off-response';
import QueryFilter, { FilterMapping } from '../helpers/query-filter';
import {
FindManyOptions,
FindOptionsRelations,
FindOptionsWhere,
} from 'typeorm';
import ContainerRevision from '../entity/container/container-revision';
import { PaginationParameters } from '../helpers/pagination';
import User from '../entity/user/user';
import BalanceService from './balance-service';
import DineroTransformer from '../entity/transformer/dinero-transformer';
import UserService from './user-service';
import { RequestWithToken } from '../middleware/token-middleware';
import { asNumber } from '../helpers/validators';
import VatGroup from '../entity/vat-group';
import ServerSettingsStore from '../server-settings/server-settings-store';
import Transfer from '../entity/transactions/transfer';
import { ISettings } from '../entity/server-setting';
import WithManager from '../database/with-manager';
export interface WriteOffFilterParameters {
/**
* Filter based on to user.
*/
toId?: number;
/**
* Filter based on write-off id.
*/
writeOffId?: number;
}
export function parseWriteOffFilterParameters(req: RequestWithToken): WriteOffFilterParameters {
return {
writeOffId: asNumber(req.query.writeOffId),
toId: asNumber(req.query.toId),
};
}
export default class WriteOffService extends WithManager {
/**
* Parses a write-off object to a BaseWriteOffResponse
* @param writeOff
*/
public static asBaseWriteOffResponse(writeOff: WriteOff): BaseWriteOffResponse {
return {
id: writeOff.id,
createdAt: writeOff.createdAt.toISOString(),
updatedAt: writeOff.updatedAt.toISOString(),
to: parseUserToBaseResponse(writeOff.to, false),
amount: writeOff.amount.toObject(),
};
}
/**
* Parses a write-off object to a WriteOffResponse
* @param writeOff
*/
public static asWriteOffResponse(writeOff: WriteOff): WriteOffResponse {
return {
...this.asBaseWriteOffResponse(writeOff),
transfer: writeOff.transfer ? TransferService.asTransferResponse(writeOff.transfer) : undefined,
};
}
/**
* Returns all write-offs with options.
* @param filters - The filtering parameters.
* @param pagination - The pagination options.
* @returns {Array.<WriteOffResponse>} - all write-offs
*/
public static async getWriteOffs(filters: WriteOffFilterParameters = {}, pagination: PaginationParameters = {}): Promise<PaginatedWriteOffResponse> {
const { take, skip } = pagination;
const options = this.getOptions(filters);
const [data, count] = await WriteOff.findAndCount({ ...options, take, skip });
const records = data.map((writeOff) => this.asWriteOffResponse(writeOff));
return {
_pagination: {
take, skip, count,
},
records,
};
}
private static async getHighVATGroup(): Promise<VatGroup> {
const id = ServerSettingsStore.getInstance().getSetting('highVatGroupId') as ISettings['highVatGroupId'];
const vatGroup = await VatGroup.findOne({ where: { id } });
if (vatGroup) return vatGroup;
else throw new Error('High vat group not found');
}
/**
* Creates a write-off for the given user
* @param manager - The entity manager to use
* @param user - The user to create the write-off for
*/
public async createWriteOff(user: User): Promise<WriteOffResponse> {
const balance = await new BalanceService().getBalance(user.id);
if (balance.amount.amount > 0) {
throw new Error('User has balance, cannot create write off');
}
const amount = DineroTransformer.Instance.from(balance.amount.amount * -1);
const writeOff = Object.assign(new WriteOff(), {
to: user,
amount,
});
await this.manager.save(writeOff);
const transfer = await (new TransferService()).createTransfer({
amount: amount.toObject(),
toId: user.id,
description: 'Write off',
fromId: null,
});
const highVatGroup = await WriteOffService.getHighVATGroup();
writeOff.transfer = transfer;
transfer.writeOff = writeOff;
transfer.vat = highVatGroup;
await this.manager.getRepository(Transfer).save(transfer);
await this.manager.getRepository(WriteOff).save(writeOff);
return WriteOffService.asWriteOffResponse(writeOff);
}
// TODO: This should be a transaction
// wait for BalanceService to be refactored
public async createWriteOffAndCloseUser(user: User): Promise<WriteOffResponse> {
const writeOff = await this.createWriteOff(user);
await UserService.closeUser(user.id, true);
return writeOff;
}
/**
* Function that returns FindManyOptions based on the given parameters
* @param params
*/
public static getOptions(params: WriteOffFilterParameters): FindManyOptions<WriteOff> {
const filterMapping: FilterMapping = {
toId: 'to.id',
writeOffId: 'id',
};
const relations: FindOptionsRelations<WriteOff> = {
transfer: {
vat: true,
},
};
let where: FindOptionsWhere<ContainerRevision> = {
...QueryFilter.createFilterWhereClause(filterMapping, params),
};
const options: FindManyOptions<WriteOff> = {
where,
order: { createdAt: 'DESC' },
relations,
};
return { ...options, relations };
}
}