@stamhoofd/backend 2.72.0 → 2.73.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/index.ts +1 -0
  2. package/package.json +10 -10
  3. package/src/email-recipient-loaders/orders.ts +1 -1
  4. package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +1 -1
  5. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +7 -7
  6. package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +23 -3
  7. package/src/endpoints/global/audit-logs/GetAuditLogsEndpoint.ts +3 -3
  8. package/src/endpoints/global/events/GetEventsEndpoint.ts +6 -6
  9. package/src/endpoints/global/events/PatchEventsEndpoint.ts +36 -4
  10. package/src/endpoints/global/members/GetMembersEndpoint.ts +4 -4
  11. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +24 -14
  12. package/src/endpoints/global/members/shouldCheckIfMemberIsDuplicate.ts +34 -0
  13. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +11 -1
  14. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +20 -12
  15. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +11 -3
  16. package/src/endpoints/organization/dashboard/documents/GetDocumentsCountEndpoint.ts +1 -1
  17. package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +6 -6
  18. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +2 -1
  19. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +5 -5
  20. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts +51 -9
  21. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersCountEndpoint.ts +1 -1
  22. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +6 -6
  23. package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +6 -6
  24. package/src/excel-loaders/members.ts +8 -0
  25. package/src/excel-loaders/receivable-balances.ts +294 -0
  26. package/src/helpers/AuthenticatedStructures.ts +32 -6
  27. package/src/helpers/SetupStepUpdater.ts +10 -4
  28. package/src/helpers/xlsxAddressTransformerColumnFactory.ts +8 -0
  29. package/src/services/PaymentReallocationService.ts +3 -2
  30. package/src/services/PaymentService.ts +17 -1
  31. package/src/sql-filters/members.ts +20 -1
  32. package/src/sql-filters/organizations.ts +1 -0
  33. package/src/sql-filters/receivable-balances.ts +53 -1
  34. package/src/sql-sorters/organizations.ts +11 -0
@@ -38,7 +38,7 @@ export class GetDocumentsEndpoint extends Endpoint<Params, Query, Body, Response
38
38
  return [false];
39
39
  }
40
40
 
41
- static buildQuery(q: CountFilteredRequest | LimitedFilteredRequest) {
41
+ static async buildQuery(q: CountFilteredRequest | LimitedFilteredRequest) {
42
42
  const organization = Context.organization!;
43
43
 
44
44
  const documentTable: string = Document.table;
@@ -46,25 +46,25 @@ export class GetDocumentsEndpoint extends Endpoint<Params, Query, Body, Response
46
46
  const query = SQL
47
47
  .select(SQL.wildcard(documentTable))
48
48
  .from(SQL.table(documentTable))
49
- .where(compileToSQLFilter({
49
+ .where(await compileToSQLFilter({
50
50
  organizationId: organization.id,
51
51
  }, filterCompilers));
52
52
 
53
53
  if (q.filter) {
54
- query.where(compileToSQLFilter(q.filter, filterCompilers));
54
+ query.where(await compileToSQLFilter(q.filter, filterCompilers));
55
55
  }
56
56
 
57
57
  if (q.search) {
58
58
  const searchFilter: StamhoofdFilter | null = getDocumentSearchFilter(q.search);
59
59
 
60
60
  if (searchFilter) {
61
- query.where(compileToSQLFilter(searchFilter, filterCompilers));
61
+ query.where(await compileToSQLFilter(searchFilter, filterCompilers));
62
62
  }
63
63
  }
64
64
 
65
65
  if (q instanceof LimitedFilteredRequest) {
66
66
  if (q.pageFilter) {
67
- query.where(compileToSQLFilter(q.pageFilter, filterCompilers));
67
+ query.where(await compileToSQLFilter(q.pageFilter, filterCompilers));
68
68
  }
69
69
 
70
70
  q.sort = assertSort(q.sort, [{ key: 'id' }]);
@@ -76,7 +76,7 @@ export class GetDocumentsEndpoint extends Endpoint<Params, Query, Body, Response
76
76
  }
77
77
 
78
78
  static async buildData(requestQuery: LimitedFilteredRequest) {
79
- const query = this.buildQuery(requestQuery);
79
+ const query = await this.buildQuery(requestQuery);
80
80
  const data = await query.fetch();
81
81
 
82
82
  const documents: Document[] = Document.fromRows(data, Document.table);
@@ -8,9 +8,9 @@ import { Formatter } from '@stamhoofd/utility';
8
8
  import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
9
9
  import { BuckarooHelper } from '../../../../helpers/BuckarooHelper';
10
10
  import { Context } from '../../../../helpers/Context';
11
+ import { SetupStepUpdater } from '../../../../helpers/SetupStepUpdater';
11
12
  import { TagHelper } from '../../../../helpers/TagHelper';
12
13
  import { ViesHelper } from '../../../../helpers/ViesHelper';
13
- import { SetupStepUpdater } from '../../../../helpers/SetupStepUpdater';
14
14
 
15
15
  type Params = Record<string, never>;
16
16
  type Query = undefined;
@@ -126,6 +126,7 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
126
126
  organization.privateMeta.privateKey = request.body.privateMeta.privateKey ?? organization.privateMeta.privateKey;
127
127
  organization.privateMeta.featureFlags = patchObject(organization.privateMeta.featureFlags, request.body.privateMeta.featureFlags);
128
128
  organization.privateMeta.balanceNotificationSettings = patchObject(organization.privateMeta.balanceNotificationSettings, request.body.privateMeta.balanceNotificationSettings);
129
+ organization.privateMeta.recordAnswers = request.body.privateMeta.recordAnswers.applyTo(organization.privateMeta.recordAnswers);
129
130
 
130
131
  if (request.body.privateMeta.mollieProfile !== undefined) {
131
132
  organization.privateMeta.mollieProfile = patchObject(organization.privateMeta.mollieProfile, request.body.privateMeta.mollieProfile);
@@ -5,11 +5,11 @@ import { Payment } from '@stamhoofd/models';
5
5
  import { SQL, compileToSQLFilter, compileToSQLSorter } from '@stamhoofd/sql';
6
6
  import { CountFilteredRequest, LimitedFilteredRequest, PaginatedResponse, PaymentGeneral, StamhoofdFilter, TransferSettings, assertSort, getSortFilter } from '@stamhoofd/structures';
7
7
 
8
+ import { SQLResultNamespacedRow } from '@simonbackx/simple-database';
8
9
  import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
9
10
  import { Context } from '../../../../helpers/Context';
10
11
  import { paymentFilterCompilers } from '../../../../sql-filters/payments';
11
12
  import { paymentSorters } from '../../../../sql-sorters/payments';
12
- import { SQLResultNamespacedRow } from '@simonbackx/simple-database';
13
13
 
14
14
  type Params = Record<string, never>;
15
15
  type Query = LimitedFilteredRequest;
@@ -59,11 +59,11 @@ export class GetPaymentsEndpoint extends Endpoint<Params, Query, Body, ResponseB
59
59
  );
60
60
 
61
61
  if (scopeFilter) {
62
- query.where(compileToSQLFilter(scopeFilter, filterCompilers));
62
+ query.where(await compileToSQLFilter(scopeFilter, filterCompilers));
63
63
  }
64
64
 
65
65
  if (q.filter) {
66
- query.where(compileToSQLFilter(q.filter, filterCompilers));
66
+ query.where(await compileToSQLFilter(q.filter, filterCompilers));
67
67
  }
68
68
 
69
69
  if (q.search) {
@@ -142,13 +142,13 @@ export class GetPaymentsEndpoint extends Endpoint<Params, Query, Body, ResponseB
142
142
  }
143
143
 
144
144
  if (searchFilter) {
145
- query.where(compileToSQLFilter(searchFilter, filterCompilers));
145
+ query.where(await compileToSQLFilter(searchFilter, filterCompilers));
146
146
  }
147
147
  }
148
148
 
149
149
  if (q instanceof LimitedFilteredRequest) {
150
150
  if (q.pageFilter) {
151
- query.where(compileToSQLFilter(q.pageFilter, filterCompilers));
151
+ query.where(await compileToSQLFilter(q.pageFilter, filterCompilers));
152
152
  }
153
153
 
154
154
  q.sort = assertSort(q.sort, [{ key: 'id' }]);
@@ -3,7 +3,7 @@ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-
3
3
  import { SimpleError } from '@simonbackx/simple-errors';
4
4
  import { CachedBalance } from '@stamhoofd/models';
5
5
  import { compileToSQLFilter, compileToSQLSorter } from '@stamhoofd/sql';
6
- import { ReceivableBalance as ReceivableBalanceStruct, CountFilteredRequest, LimitedFilteredRequest, PaginatedResponse, StamhoofdFilter, assertSort, getSortFilter, ReceivableBalanceType } from '@stamhoofd/structures';
6
+ import { assertSort, CountFilteredRequest, DetailedReceivableBalance, getSortFilter, LimitedFilteredRequest, PaginatedResponse, ReceivableBalance as ReceivableBalanceStruct, StamhoofdFilter } from '@stamhoofd/structures';
7
7
 
8
8
  import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
9
9
  import { Context } from '../../../../helpers/Context';
@@ -54,23 +54,49 @@ export class GetReceivableBalancesEndpoint extends Endpoint<Params, Query, Body,
54
54
  .select();
55
55
 
56
56
  if (scopeFilter) {
57
- query.where(compileToSQLFilter(scopeFilter, filterCompilers));
57
+ query.where(await compileToSQLFilter(scopeFilter, filterCompilers));
58
58
  }
59
59
 
60
60
  if (q.filter) {
61
- query.where(compileToSQLFilter(q.filter, filterCompilers));
61
+ query.where(await compileToSQLFilter(q.filter, filterCompilers));
62
62
  }
63
63
 
64
64
  if (q.search) {
65
- throw new SimpleError({
66
- code: 'not_implemented',
67
- message: 'Zoeken in openstaande bedragen is voorlopig nog niet mogelijk',
68
- });
65
+ let searchFilter: StamhoofdFilter | null = null;
66
+
67
+ searchFilter = {
68
+ $or: [
69
+ {
70
+ organizations: {
71
+ $elemMatch: {
72
+ $or: [
73
+ { name: { $contains: q.search } },
74
+ { uri: q.search },
75
+ ],
76
+ },
77
+ },
78
+ },
79
+ {
80
+ members: {
81
+ $elemMatch: { name: { $contains: q.search } },
82
+ },
83
+ },
84
+ {
85
+ users: {
86
+ $elemMatch: { name: { $contains: q.search } },
87
+ },
88
+ },
89
+ ],
90
+ };
91
+
92
+ if (searchFilter) {
93
+ query.where(await compileToSQLFilter(searchFilter, filterCompilers));
94
+ }
69
95
  }
70
96
 
71
97
  if (q instanceof LimitedFilteredRequest) {
72
98
  if (q.pageFilter) {
73
- query.where(compileToSQLFilter(q.pageFilter, filterCompilers));
99
+ query.where(await compileToSQLFilter(q.pageFilter, filterCompilers));
74
100
  }
75
101
 
76
102
  q.sort = assertSort(q.sort, [{ key: 'id' }]);
@@ -81,7 +107,7 @@ export class GetReceivableBalancesEndpoint extends Endpoint<Params, Query, Body,
81
107
  return query;
82
108
  }
83
109
 
84
- static async buildData(requestQuery: LimitedFilteredRequest) {
110
+ static async buildDataHelper(requestQuery: LimitedFilteredRequest) {
85
111
  const query = await GetReceivableBalancesEndpoint.buildQuery(requestQuery);
86
112
  const data = await query.fetch();
87
113
 
@@ -107,12 +133,28 @@ export class GetReceivableBalancesEndpoint extends Endpoint<Params, Query, Body,
107
133
  }
108
134
  }
109
135
 
136
+ return { data, next };
137
+ }
138
+
139
+ static async buildData(requestQuery: LimitedFilteredRequest) {
140
+ const { data, next } = await GetReceivableBalancesEndpoint.buildDataHelper(requestQuery);
141
+
110
142
  return new PaginatedResponse<ReceivableBalanceStruct[], LimitedFilteredRequest>({
111
143
  results: await AuthenticatedStructures.receivableBalances(data),
112
144
  next,
113
145
  });
114
146
  }
115
147
 
148
+ static async buildDetailedData(requestQuery: LimitedFilteredRequest) {
149
+ const organization = Context.organization ?? await Context.setOrganizationScope();
150
+ const { data, next } = await GetReceivableBalancesEndpoint.buildDataHelper(requestQuery);
151
+
152
+ return new PaginatedResponse<DetailedReceivableBalance[], LimitedFilteredRequest>({
153
+ results: await AuthenticatedStructures.detailedReceivableBalances(organization.id, data),
154
+ next,
155
+ });
156
+ }
157
+
116
158
  async handle(request: DecodedRequest<Params, Query, Body>) {
117
159
  await Context.setOrganizationScope();
118
160
  await Context.authenticate();
@@ -35,7 +35,7 @@ export class GetWebshopOrdersCountEndpoint extends Endpoint<Params, Query, Body,
35
35
  throw Context.auth.error();
36
36
  }
37
37
 
38
- const query = GetWebshopOrdersEndpoint.buildQuery(request.query);
38
+ const query = await GetWebshopOrdersEndpoint.buildQuery(request.query);
39
39
 
40
40
  const count = await query
41
41
  .count();
@@ -35,7 +35,7 @@ export class GetWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Resp
35
35
  return [false];
36
36
  }
37
37
 
38
- static buildQuery(q: CountFilteredRequest | LimitedFilteredRequest) {
38
+ static async buildQuery(q: CountFilteredRequest | LimitedFilteredRequest) {
39
39
  // todo: filter userId???
40
40
  const organization = Context.organization!;
41
41
 
@@ -44,7 +44,7 @@ export class GetWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Resp
44
44
  const query = SQL
45
45
  .select(SQL.wildcard(ordersTable))
46
46
  .from(SQL.table(ordersTable))
47
- .where(compileToSQLFilter({
47
+ .where(await compileToSQLFilter({
48
48
  organizationId: organization.id,
49
49
  number: {
50
50
  $neq: null,
@@ -52,20 +52,20 @@ export class GetWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Resp
52
52
  }, filterCompilers));
53
53
 
54
54
  if (q.filter) {
55
- query.where(compileToSQLFilter(q.filter, filterCompilers));
55
+ query.where(await compileToSQLFilter(q.filter, filterCompilers));
56
56
  }
57
57
 
58
58
  if (q.search) {
59
59
  const searchFilter: StamhoofdFilter | null = getOrderSearchFilter(q.search, parsePhoneNumber);
60
60
 
61
61
  if (searchFilter) {
62
- query.where(compileToSQLFilter(searchFilter, filterCompilers));
62
+ query.where(await compileToSQLFilter(searchFilter, filterCompilers));
63
63
  }
64
64
  }
65
65
 
66
66
  if (q instanceof LimitedFilteredRequest) {
67
67
  if (q.pageFilter) {
68
- query.where(compileToSQLFilter(q.pageFilter, filterCompilers));
68
+ query.where(await compileToSQLFilter(q.pageFilter, filterCompilers));
69
69
  }
70
70
 
71
71
  q.sort = assertSort(q.sort, [{ key: 'id' }]);
@@ -77,7 +77,7 @@ export class GetWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Resp
77
77
  }
78
78
 
79
79
  static async buildData(requestQuery: LimitedFilteredRequest) {
80
- const query = this.buildQuery(requestQuery);
80
+ const query = await this.buildQuery(requestQuery);
81
81
  const data = await query.fetch();
82
82
 
83
83
  const orders: Order[] = Order.fromRows(data, Order.table);
@@ -34,7 +34,7 @@ export class GetWebshopTicketsEndpoint extends Endpoint<Params, Query, Body, Res
34
34
  return [false];
35
35
  }
36
36
 
37
- static buildQuery(q: CountFilteredRequest | LimitedFilteredRequest) {
37
+ static async buildQuery(q: CountFilteredRequest | LimitedFilteredRequest) {
38
38
  const organization = Context.organization!;
39
39
 
40
40
  const ticketsTable: string = Ticket.table;
@@ -42,12 +42,12 @@ export class GetWebshopTicketsEndpoint extends Endpoint<Params, Query, Body, Res
42
42
  const query = SQL
43
43
  .select(SQL.wildcard(ticketsTable))
44
44
  .from(SQL.table(ticketsTable))
45
- .where(compileToSQLFilter({
45
+ .where(await Promise.resolve(compileToSQLFilter({
46
46
  organizationId: organization.id,
47
- }, filterCompilers));
47
+ }, filterCompilers)));
48
48
 
49
49
  if (q.filter) {
50
- query.where(compileToSQLFilter(q.filter, filterCompilers));
50
+ query.where(await Promise.resolve(compileToSQLFilter(q.filter, filterCompilers)));
51
51
  }
52
52
 
53
53
  // currently no search supported, probably not needed?
@@ -56,7 +56,7 @@ export class GetWebshopTicketsEndpoint extends Endpoint<Params, Query, Body, Res
56
56
 
57
57
  if (q instanceof LimitedFilteredRequest) {
58
58
  if (q.pageFilter) {
59
- query.where(compileToSQLFilter(q.pageFilter, filterCompilers));
59
+ query.where(await Promise.resolve(compileToSQLFilter(q.pageFilter, filterCompilers)));
60
60
  }
61
61
 
62
62
  q.sort = assertSort(q.sort, [{ key: 'id' }]);
@@ -68,7 +68,7 @@ export class GetWebshopTicketsEndpoint extends Endpoint<Params, Query, Body, Res
68
68
  }
69
69
 
70
70
  static async buildData(requestQuery: LimitedFilteredRequest) {
71
- const query = this.buildQuery(requestQuery);
71
+ const query = await this.buildQuery(requestQuery);
72
72
  const data = await query.fetch();
73
73
 
74
74
  const tickets: Ticket[] = Ticket.fromRows(data, Ticket.table);
@@ -204,6 +204,14 @@ const sheet: XlsxTransformerSheet<PlatformMember, PlatformMember> = {
204
204
  };
205
205
  },
206
206
  },
207
+ {
208
+ id: 'nationalRegisterNumber',
209
+ name: 'Rijksregisternummer',
210
+ width: 30,
211
+ getValue: ({ patchedMember: object }: PlatformMember) => ({
212
+ value: object.details.nationalRegisterNumber?.toString() ?? '',
213
+ }),
214
+ },
207
215
 
208
216
  ...XlsxTransformerColumnHelper.creatColumnsForParents(),
209
217
 
@@ -0,0 +1,294 @@
1
+ import { XlsxBuiltInNumberFormat, XlsxTransformerColumn, XlsxTransformerConcreteColumn } from '@stamhoofd/excel-writer';
2
+ import { BalanceItemRelationType, BalanceItemWithPayments, DetailedReceivableBalance, ExcelExportType, getBalanceItemRelationTypeName, getBalanceItemStatusName, getBalanceItemTypeName, getReceivableBalanceTypeNameNotTranslated, PaginatedResponse, ReceivableBalance } from '@stamhoofd/structures';
3
+ import { Formatter } from '@stamhoofd/utility';
4
+ import { ExportToExcelEndpoint } from '../endpoints/global/files/ExportToExcelEndpoint';
5
+ import { GetReceivableBalancesEndpoint } from '../endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint';
6
+
7
+ type ReceivableBalanceWithItem = {
8
+ receivableBalance: DetailedReceivableBalance;
9
+ balanceItem: BalanceItemWithPayments;
10
+ };
11
+
12
+ ExportToExcelEndpoint.loaders.set(ExcelExportType.ReceivableBalances, {
13
+ fetch: async (requestQuery) => {
14
+ const data = await GetReceivableBalancesEndpoint.buildDetailedData(requestQuery);
15
+
16
+ return new PaginatedResponse({
17
+ ...data,
18
+ });
19
+ },
20
+ sheets: [
21
+ {
22
+ id: 'receivableBalances',
23
+ name: 'Te ontvangen bedragen',
24
+ columns: getGeneralColumns(),
25
+ },
26
+ {
27
+ id: 'balanceItems',
28
+ name: 'Lijnen',
29
+ transform: (data: DetailedReceivableBalance): ReceivableBalanceWithItem[] => data.balanceItems.map(balanceItem => ({
30
+ receivableBalance: data,
31
+ balanceItem,
32
+ })),
33
+ columns: [
34
+ ...getBalanceItemColumns(),
35
+
36
+ // Repeating columns need to de-transform again
37
+ ...getGeneralColumns()
38
+ .map((c) => {
39
+ return {
40
+ ...c,
41
+ id: `receivableBalance.${c.id}`,
42
+ getValue: (object: ReceivableBalanceWithItem) => {
43
+ return c.getValue(object.receivableBalance);
44
+ },
45
+ };
46
+ }),
47
+ ],
48
+ },
49
+ ],
50
+ });
51
+
52
+ function getBalanceItemColumns(): XlsxTransformerColumn<ReceivableBalanceWithItem>[] {
53
+ return [
54
+ {
55
+ id: 'id',
56
+ name: 'ID',
57
+ width: 40,
58
+ getValue: (object: ReceivableBalanceWithItem) => ({
59
+ value: object.balanceItem.id,
60
+ style: {
61
+ font: {
62
+ bold: true,
63
+ },
64
+ },
65
+ }),
66
+ },
67
+ {
68
+ id: 'type',
69
+ name: 'Type',
70
+ width: 30,
71
+ getValue: (object: ReceivableBalanceWithItem) => ({
72
+ value: getBalanceItemTypeName(object.balanceItem.type),
73
+ }),
74
+ },
75
+ {
76
+ id: 'category',
77
+ name: 'Categorie',
78
+ width: 30,
79
+ getValue: (object: ReceivableBalanceWithItem) => {
80
+ return {
81
+ value: Formatter.capitalizeFirstLetter(object.balanceItem.category),
82
+ };
83
+ },
84
+ },
85
+ {
86
+ id: 'description',
87
+ name: 'Beschrijving',
88
+ width: 40,
89
+ getValue: (object: ReceivableBalanceWithItem) => ({
90
+ value: object.balanceItem.description,
91
+ }),
92
+ },
93
+ {
94
+ id: 'amount',
95
+ name: 'Aantal',
96
+ width: 20,
97
+ getValue: (object: ReceivableBalanceWithItem) => ({
98
+ value: object.balanceItem.amount,
99
+ style: {
100
+ numberFormat: {
101
+ id: XlsxBuiltInNumberFormat.Number,
102
+ },
103
+ },
104
+ }),
105
+ },
106
+ {
107
+ id: 'unitPrice',
108
+ name: 'Eenheidsprijs',
109
+ width: 20,
110
+ getValue: (object: ReceivableBalanceWithItem) => ({
111
+ value: object.balanceItem.unitPrice / 100,
112
+ style: {
113
+ numberFormat: {
114
+ id: XlsxBuiltInNumberFormat.Currency2DecimalWithRed,
115
+ },
116
+ },
117
+ }),
118
+ },
119
+ {
120
+ id: 'price',
121
+ name: 'Prijs',
122
+ width: 20,
123
+ getValue: (object: ReceivableBalanceWithItem) => ({
124
+ value: object.balanceItem.price / 100,
125
+ style: {
126
+ numberFormat: {
127
+ id: XlsxBuiltInNumberFormat.Currency2DecimalWithRed,
128
+ },
129
+ },
130
+ }),
131
+ },
132
+ {
133
+ id: 'pricePaid',
134
+ name: 'Betaald bedrag',
135
+ width: 20,
136
+ getValue: (object: ReceivableBalanceWithItem) => ({
137
+ value: object.balanceItem.pricePaid / 100,
138
+ style: {
139
+ numberFormat: {
140
+ id: XlsxBuiltInNumberFormat.Currency2DecimalWithRed,
141
+ },
142
+ },
143
+ }),
144
+ },
145
+ {
146
+ id: 'pricePending',
147
+ name: 'In verwerking',
148
+ width: 20,
149
+ getValue: (object: ReceivableBalanceWithItem) => ({
150
+ value: object.balanceItem.pricePending / 100,
151
+ style: {
152
+ numberFormat: {
153
+ id: XlsxBuiltInNumberFormat.Currency2DecimalWithRed,
154
+ },
155
+ },
156
+ }),
157
+ },
158
+ {
159
+ id: 'priceOpen',
160
+ name: 'Openstaand bedrag',
161
+ width: 20,
162
+ getValue: (object: ReceivableBalanceWithItem) => ({
163
+ value: object.balanceItem.priceOpen / 100,
164
+ style: {
165
+ numberFormat: {
166
+ id: XlsxBuiltInNumberFormat.Currency2DecimalWithRed,
167
+ },
168
+ },
169
+ }),
170
+ },
171
+ {
172
+ id: 'createdAt',
173
+ name: 'Aangemaakt op',
174
+ width: 20,
175
+ getValue: (object: ReceivableBalanceWithItem) => ({
176
+ value: object.balanceItem.createdAt,
177
+ style: {
178
+ numberFormat: {
179
+ id: XlsxBuiltInNumberFormat.DateSlash,
180
+ },
181
+ },
182
+ }),
183
+ },
184
+ {
185
+ id: 'dueAt',
186
+ name: 'Verschuldigd vanaf',
187
+ width: 20,
188
+ getValue: (object: ReceivableBalanceWithItem) => ({
189
+ value: object.balanceItem.dueAt,
190
+ style: {
191
+ numberFormat: {
192
+ id: XlsxBuiltInNumberFormat.DateSlash,
193
+ },
194
+ },
195
+ }),
196
+ },
197
+ {
198
+ id: 'status',
199
+ name: 'Status',
200
+ width: 20,
201
+ getValue: (object: ReceivableBalanceWithItem) => ({
202
+ value: getBalanceItemStatusName(object.balanceItem.status),
203
+ }),
204
+ },
205
+
206
+ {
207
+ match: (id) => {
208
+ if (id.startsWith('relations.')) {
209
+ const type = id.split('.')[1] as BalanceItemRelationType;
210
+ if (Object.values(BalanceItemRelationType).includes(type)) {
211
+ return [
212
+ {
213
+ id: `relations.${type}`,
214
+ name: getBalanceItemRelationTypeName(type),
215
+ width: 35,
216
+ getValue: (object: ReceivableBalanceWithItem) => ({
217
+ value: object.balanceItem.relations.get(type)?.name || '',
218
+ }),
219
+ },
220
+ ];
221
+ }
222
+ }
223
+ },
224
+ },
225
+ ];
226
+ }
227
+
228
+ function getGeneralColumns(): XlsxTransformerConcreteColumn<ReceivableBalance>[] {
229
+ return [
230
+ {
231
+ id: 'id',
232
+ name: 'ID schuldenaar',
233
+ width: 40,
234
+ getValue: (object: ReceivableBalance) => ({
235
+ value: object.id,
236
+ style: {
237
+ font: {
238
+ bold: true,
239
+ },
240
+ },
241
+ }),
242
+ },
243
+ {
244
+ id: 'name',
245
+ name: 'Schuldenaar',
246
+ width: 40,
247
+ getValue: (object: ReceivableBalance) => ({
248
+ value: object.object.name,
249
+ }),
250
+ },
251
+ {
252
+ id: 'uri',
253
+ name: 'Groepsnummer',
254
+ width: 16,
255
+ getValue: (object: ReceivableBalance) => ({
256
+ value: object.object.uri,
257
+ }),
258
+ },
259
+ {
260
+ id: 'amountOpen',
261
+ name: 'Openstaand bedrag',
262
+ width: 10,
263
+ getValue: (object: ReceivableBalance) => ({
264
+ value: object.amountOpen / 100,
265
+ style: {
266
+ numberFormat: {
267
+ id: XlsxBuiltInNumberFormat.Currency2DecimalWithRed,
268
+ },
269
+ },
270
+ }),
271
+ },
272
+ {
273
+ id: 'amountPending',
274
+ name: 'In verwerking',
275
+ width: 18,
276
+ getValue: (object: ReceivableBalance) => ({
277
+ value: object.amountPending / 100,
278
+ style: {
279
+ numberFormat: {
280
+ id: XlsxBuiltInNumberFormat.Currency2DecimalWithRed,
281
+ },
282
+ },
283
+ }),
284
+ },
285
+ {
286
+ id: 'objectType',
287
+ name: 'type',
288
+ width: 10,
289
+ getValue: (object: ReceivableBalance) => ({
290
+ value: getReceivableBalanceTypeNameNotTranslated(object.objectType),
291
+ }),
292
+ },
293
+ ];
294
+ }