@sneat/extension-splitus-contract 0.2.1 → 0.2.3
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.
package/README.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
Splitus extension contract library.
|
|
4
4
|
|
|
5
|
+
## Bill contract version 1
|
|
6
|
+
|
|
7
|
+
`ICreateSplitusBillV1Request` carries exact major-unit decimal strings,
|
|
8
|
+
client-stable bill identity, and separate paid/owed contact allocations. The
|
|
9
|
+
host must call `assertCreateSplitusBillV1Recorder` with its trusted
|
|
10
|
+
authenticated identity before accepting the recorder audit claim.
|
|
11
|
+
|
|
12
|
+
Parse untrusted API responses with `parseCreateSplitusBillV1Response`,
|
|
13
|
+
`parseGetSplitusBillV1Response`, or `parseListSplitusBillsV1Response`. This
|
|
14
|
+
rejects numeric money JSON, invalid posting proof, unsafe identifiers, and
|
|
15
|
+
unbounded list/detail arrays before a runtime renders them. Contact IDs are
|
|
16
|
+
resolved through the host's real Contactus data; they are not display labels.
|
|
17
|
+
|
|
18
|
+
The earlier split DTOs and `ISplitusService` remain exported as deprecated
|
|
19
|
+
compatibility surfaces until every consumer has moved to
|
|
20
|
+
`ISplitusBillServiceV1`.
|
|
21
|
+
|
|
22
|
+
The matching storage-neutral Go host contract is module
|
|
23
|
+
`github.com/sneat-co/sneat-ext-contracts/splitus`, package
|
|
24
|
+
`contract4splitus`.
|
|
25
|
+
|
|
5
26
|
## Provenance
|
|
6
27
|
|
|
7
28
|
Migrated from sneat-co/debtus (npm continuity from @sneat/extension-splitus-contract@0.2.0).
|
|
@@ -1,10 +1,752 @@
|
|
|
1
1
|
import { InjectionToken } from '@angular/core';
|
|
2
2
|
|
|
3
|
+
/** The first stable Splitus bill browser/host wire contract. */
|
|
4
|
+
const SPLITUS_BILL_CONTRACT_VERSION = 1;
|
|
5
|
+
const MAX_SPLITUS_BILL_PARTICIPANTS = 256;
|
|
6
|
+
const MAX_SPLITUS_BILL_LIST_PAGE_SIZE = 100;
|
|
7
|
+
const MAX_SPLITUS_BILL_OBLIGATIONS = 256;
|
|
8
|
+
const MAX_SPLITUS_OBLIGATION_IDS_PER_LINE = 256;
|
|
9
|
+
const MAX_EXACT_MINOR_UNITS = 9223372036854775807n;
|
|
10
|
+
const exactDecimalPattern = /^(?:0|[1-9][0-9]*)\.[0-9]{2}$/;
|
|
11
|
+
const datePattern = /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/;
|
|
12
|
+
function parseExactDecimalString(value) {
|
|
13
|
+
if (typeof value !== 'string' || !exactDecimalPattern.test(value)) {
|
|
14
|
+
throw new TypeError('amount must be a canonical decimal string with exactly two fraction digits');
|
|
15
|
+
}
|
|
16
|
+
const minorUnits = BigInt(value.replace('.', ''));
|
|
17
|
+
if (minorUnits > MAX_EXACT_MINOR_UNITS) {
|
|
18
|
+
throw new RangeError('amount exceeds the Splitus contract limit');
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function parseCreateSplitusBillV1Request(value) {
|
|
23
|
+
const input = record(value, 'create bill request');
|
|
24
|
+
if (input['contractVersion'] !== SPLITUS_BILL_CONTRACT_VERSION) {
|
|
25
|
+
throw new TypeError('unsupported Splitus bill contract version');
|
|
26
|
+
}
|
|
27
|
+
const billKind = enumValue(input['billKind'], ['general', 'utility'], 'billKind');
|
|
28
|
+
const actualAmount = positiveAmount(input['actualAmount'], 'actualAmount');
|
|
29
|
+
const spaceID = storageID(input['spaceID'], 'spaceID');
|
|
30
|
+
const billID = storageID(input['billID'], 'billID');
|
|
31
|
+
const recorderUserID = storageID(input['recorderUserID'], 'recorderUserID');
|
|
32
|
+
const request = {
|
|
33
|
+
contractVersion: SPLITUS_BILL_CONTRACT_VERSION,
|
|
34
|
+
spaceID,
|
|
35
|
+
billID,
|
|
36
|
+
recorderUserID,
|
|
37
|
+
title: optionalText(input['title'], 'title', 256),
|
|
38
|
+
billKind,
|
|
39
|
+
currency: currency(input['currency']),
|
|
40
|
+
actualAmount,
|
|
41
|
+
paidAllocations: allocations(input['paidAllocations'], 'paidAllocations'),
|
|
42
|
+
owedAllocations: allocations(input['owedAllocations'], 'owedAllocations'),
|
|
43
|
+
utility: input['utility'] === undefined ? undefined : utility(input['utility']),
|
|
44
|
+
recurringOccurrence: input['recurringOccurrence'] === undefined
|
|
45
|
+
? undefined
|
|
46
|
+
: recurring(input['recurringOccurrence'], actualAmount, billID),
|
|
47
|
+
};
|
|
48
|
+
if ((billKind === 'utility') !== (request.utility !== undefined)) {
|
|
49
|
+
throw new TypeError('utility details are required only for utility bills');
|
|
50
|
+
}
|
|
51
|
+
validateAllocationTotals(request);
|
|
52
|
+
return request;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Executable host-boundary check for the request's audit claim. The trusted
|
|
56
|
+
* authenticated identity is supplied by the host, never derived from the
|
|
57
|
+
* request itself.
|
|
58
|
+
*/
|
|
59
|
+
function assertCreateSplitusBillV1Recorder(request, authenticatedUserID) {
|
|
60
|
+
const trustedUserID = storageID(authenticatedUserID, 'authenticatedUserID');
|
|
61
|
+
if (request.recorderUserID !== trustedUserID) {
|
|
62
|
+
throw new TypeError('recorderUserID must match the trusted authenticated identity');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function parseListSplitusBillsV1Request(value) {
|
|
66
|
+
const input = record(value, 'list bills request');
|
|
67
|
+
if (input['contractVersion'] !== SPLITUS_BILL_CONTRACT_VERSION) {
|
|
68
|
+
throw new TypeError('unsupported Splitus bill contract version');
|
|
69
|
+
}
|
|
70
|
+
const pageSize = input['pageSize'];
|
|
71
|
+
if (typeof pageSize !== 'number' ||
|
|
72
|
+
!Number.isSafeInteger(pageSize) ||
|
|
73
|
+
pageSize < 1 ||
|
|
74
|
+
pageSize > MAX_SPLITUS_BILL_LIST_PAGE_SIZE) {
|
|
75
|
+
throw new RangeError(`pageSize must be an integer from 1 to ${MAX_SPLITUS_BILL_LIST_PAGE_SIZE}`);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
contractVersion: SPLITUS_BILL_CONTRACT_VERSION,
|
|
79
|
+
spaceID: storageID(input['spaceID'], 'spaceID'),
|
|
80
|
+
pageSize,
|
|
81
|
+
cursor: optionalText(input['cursor'], 'cursor', 2048),
|
|
82
|
+
utilityKind: input['utilityKind'] === undefined
|
|
83
|
+
? undefined
|
|
84
|
+
: enumValue(input['utilityKind'], ['electricity', 'gas', 'water', 'internet', 'other'], 'utilityKind'),
|
|
85
|
+
period: input['period'] === undefined ? undefined : period(input['period']),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function parseGetSplitusBillV1Request(value) {
|
|
89
|
+
const input = versionedRecord(value, 'get bill request');
|
|
90
|
+
return {
|
|
91
|
+
contractVersion: SPLITUS_BILL_CONTRACT_VERSION,
|
|
92
|
+
spaceID: storageID(input['spaceID'], 'spaceID'),
|
|
93
|
+
billID: storageID(input['billID'], 'billID'),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function parseCreateSplitusBillV1Response(value) {
|
|
97
|
+
const input = versionedRecord(value, 'create bill response');
|
|
98
|
+
return {
|
|
99
|
+
contractVersion: SPLITUS_BILL_CONTRACT_VERSION,
|
|
100
|
+
bill: parseSplitusBillV1(input['bill']),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function parseGetSplitusBillV1Response(value) {
|
|
104
|
+
const input = versionedRecord(value, 'get bill response');
|
|
105
|
+
return {
|
|
106
|
+
contractVersion: SPLITUS_BILL_CONTRACT_VERSION,
|
|
107
|
+
bill: parseSplitusBillV1(input['bill']),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function parseListSplitusBillsV1Response(value, requestedPageSize) {
|
|
111
|
+
const input = versionedRecord(value, 'list bills response');
|
|
112
|
+
const pageSize = boundedPageSize(input['pageSize']);
|
|
113
|
+
if (requestedPageSize !== undefined && pageSize !== requestedPageSize) {
|
|
114
|
+
throw new RangeError('response pageSize does not match the accepted request');
|
|
115
|
+
}
|
|
116
|
+
if (!Array.isArray(input['items']) || input['items'].length > pageSize) {
|
|
117
|
+
throw new RangeError('response items exceed the bounded pageSize');
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
contractVersion: SPLITUS_BILL_CONTRACT_VERSION,
|
|
121
|
+
pageSize,
|
|
122
|
+
items: input['items'].map((item) => splitusBillListItem(item)),
|
|
123
|
+
nextCursor: optionalText(input['nextCursor'], 'nextCursor', 2048),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function parseSplitusBillV1(value) {
|
|
127
|
+
const input = record(value, 'bill');
|
|
128
|
+
const request = parseCreateSplitusBillV1Request(input);
|
|
129
|
+
const resolvedSourceEffects = sourceEffects(input['resolvedSourceEffects']);
|
|
130
|
+
const revisionValue = positiveIntegerString(input['revision'], 'revision');
|
|
131
|
+
const createdAt = timestamp(input['createdAt'], 'createdAt');
|
|
132
|
+
const updatedAt = timestamp(input['updatedAt'], 'updatedAt');
|
|
133
|
+
if (Date.parse(updatedAt) < Date.parse(createdAt)) {
|
|
134
|
+
throw new RangeError('updatedAt must not precede createdAt');
|
|
135
|
+
}
|
|
136
|
+
const postingValue = posting(input['posting'], revisionValue);
|
|
137
|
+
const debtusValue = input['debtus'] === undefined
|
|
138
|
+
? undefined
|
|
139
|
+
: debtusStatus(input['debtus'], request.spaceID, request.billID, request.currency);
|
|
140
|
+
if (debtusValue !== undefined && postingValue.status !== 'applied') {
|
|
141
|
+
throw new TypeError('Debtus status requires applied posting');
|
|
142
|
+
}
|
|
143
|
+
if (debtusValue !== undefined) {
|
|
144
|
+
const receipt = postingValue.receipt;
|
|
145
|
+
if (receipt === undefined) {
|
|
146
|
+
throw new TypeError('Debtus status requires an applied posting receipt');
|
|
147
|
+
}
|
|
148
|
+
validateDebtusMatchesReceipt(receipt, debtusValue);
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
...request,
|
|
152
|
+
resolvedSourceEffects,
|
|
153
|
+
revision: revisionValue,
|
|
154
|
+
posting: postingValue,
|
|
155
|
+
debtus: debtusValue,
|
|
156
|
+
createdAt,
|
|
157
|
+
updatedAt,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function sourceEffects(value) {
|
|
161
|
+
if (value === undefined)
|
|
162
|
+
return [];
|
|
163
|
+
if (!Array.isArray(value) || value.length > 100) {
|
|
164
|
+
throw new RangeError('resolvedSourceEffects exceeds maximum item count 100');
|
|
165
|
+
}
|
|
166
|
+
const effects = value.map((item, index) => sourceEffect(item, index));
|
|
167
|
+
return effects;
|
|
168
|
+
}
|
|
169
|
+
function sourceEffect(value, index) {
|
|
170
|
+
const input = record(value, `resolvedSourceEffects[${index}]`);
|
|
171
|
+
const agreementID = optionalStorageID(input['agreementID'], 'agreementID');
|
|
172
|
+
const priceRevision = input['priceRevision'];
|
|
173
|
+
if (typeof priceRevision !== 'number' ||
|
|
174
|
+
!Number.isSafeInteger(priceRevision) ||
|
|
175
|
+
priceRevision < 0) {
|
|
176
|
+
throw new RangeError('priceRevision must be a non-negative safe integer');
|
|
177
|
+
}
|
|
178
|
+
const expectedAmount = parseExactDecimalString(input['expectedAmount']);
|
|
179
|
+
if (typeof input['sourceAttributionCaptured'] !== 'boolean') {
|
|
180
|
+
throw new TypeError('sourceAttributionCaptured must be boolean');
|
|
181
|
+
}
|
|
182
|
+
const assetIDs = input['assetIDs'] === undefined
|
|
183
|
+
? []
|
|
184
|
+
: identifierArray(input['assetIDs'], 'assetIDs', 100);
|
|
185
|
+
const contactLinks = sourceContactLinks(input['contactLinks']);
|
|
186
|
+
const ownerSpaceID = optionalStorageID(input['ownerSpaceID'], 'ownerSpaceID');
|
|
187
|
+
const enrollmentID = optionalStorageID(input['enrollmentID'], 'enrollmentID');
|
|
188
|
+
const chargeID = optionalStorageID(input['chargeID'], 'chargeID');
|
|
189
|
+
const occurrenceID = optionalStorageID(input['occurrenceID'], 'occurrenceID');
|
|
190
|
+
const direction = optionalEnum(input['direction'], ['expense', 'income', 'transfer'], 'direction');
|
|
191
|
+
const temporalBasis = optionalEnum(input['temporalBasis'], [
|
|
192
|
+
'occurrence_service_cost',
|
|
193
|
+
'contract_period_cost',
|
|
194
|
+
'normalized_service_cost',
|
|
195
|
+
], 'temporalBasis');
|
|
196
|
+
const economicPeriod = input['economicPeriod'] === undefined
|
|
197
|
+
? undefined
|
|
198
|
+
: period(input['economicPeriod']);
|
|
199
|
+
const eligible = optionalBoolean(input['invoiceReconciliationEligible'], 'invoiceReconciliationEligible');
|
|
200
|
+
const contactAttributions = sourceAttributions(input['contactAttributions'], 'contactAttributions');
|
|
201
|
+
const assetAttributions = sourceAttributions(input['assetAttributions'], 'assetAttributions');
|
|
202
|
+
return {
|
|
203
|
+
priceID: storageID(input['priceID'], 'priceID'),
|
|
204
|
+
priceRevision,
|
|
205
|
+
expectedAmount,
|
|
206
|
+
sourceAttributionCaptured: input['sourceAttributionCaptured'],
|
|
207
|
+
assetIDs,
|
|
208
|
+
contactLinks,
|
|
209
|
+
ownerSpaceID,
|
|
210
|
+
agreementID,
|
|
211
|
+
enrollmentID,
|
|
212
|
+
chargeID,
|
|
213
|
+
occurrenceID,
|
|
214
|
+
direction,
|
|
215
|
+
temporalBasis,
|
|
216
|
+
economicPeriod,
|
|
217
|
+
invoiceReconciliationEligible: eligible,
|
|
218
|
+
contactAttributions,
|
|
219
|
+
assetAttributions,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function sourceContactLinks(value) {
|
|
223
|
+
if (value === undefined)
|
|
224
|
+
return [];
|
|
225
|
+
if (!Array.isArray(value) || value.length > 100) {
|
|
226
|
+
throw new RangeError('contactLinks exceeds maximum item count 100');
|
|
227
|
+
}
|
|
228
|
+
const links = value.map((item, index) => {
|
|
229
|
+
const input = record(item, `contactLinks[${index}]`);
|
|
230
|
+
const roles = textArray(input['roles'], `contactLinks[${index}].roles`, 32);
|
|
231
|
+
return {
|
|
232
|
+
contactID: storageID(input['contactID'], `contactLinks[${index}].contactID`),
|
|
233
|
+
roles,
|
|
234
|
+
};
|
|
235
|
+
});
|
|
236
|
+
return links;
|
|
237
|
+
}
|
|
238
|
+
function sourceAttributions(value, name) {
|
|
239
|
+
if (value === undefined)
|
|
240
|
+
return [];
|
|
241
|
+
if (!Array.isArray(value) || value.length > 100) {
|
|
242
|
+
throw new RangeError(`${name} exceeds maximum item count 100`);
|
|
243
|
+
}
|
|
244
|
+
const values = value.map((item, index) => {
|
|
245
|
+
const input = record(item, `${name}[${index}]`);
|
|
246
|
+
return {
|
|
247
|
+
id: storageID(input['id'], `${name}[${index}].id`),
|
|
248
|
+
amount: parseExactDecimalString(input['amount']),
|
|
249
|
+
};
|
|
250
|
+
});
|
|
251
|
+
return values;
|
|
252
|
+
}
|
|
253
|
+
function splitusBillListItem(value) {
|
|
254
|
+
const input = versionedRecord(value, 'bill list item');
|
|
255
|
+
const billKind = enumValue(input['billKind'], ['general', 'utility'], 'billKind');
|
|
256
|
+
const utilityKind = input['utilityKind'] === undefined
|
|
257
|
+
? undefined
|
|
258
|
+
: enumValue(input['utilityKind'], ['electricity', 'gas', 'water', 'internet', 'other'], 'utilityKind');
|
|
259
|
+
const periodValue = input['period'] === undefined ? undefined : period(input['period']);
|
|
260
|
+
if ((billKind === 'utility') !==
|
|
261
|
+
(utilityKind !== undefined && periodValue !== undefined)) {
|
|
262
|
+
throw new TypeError('utility list items require utilityKind and period');
|
|
263
|
+
}
|
|
264
|
+
const postingStatus = enumValue(input['postingStatus'], ['pending', 'posting', 'applied', 'attention'], 'postingStatus');
|
|
265
|
+
const debtusSettlementStatus = input['debtusSettlementStatus'] === undefined
|
|
266
|
+
? undefined
|
|
267
|
+
: settlementStatus(input['debtusSettlementStatus'], 'debtusSettlementStatus');
|
|
268
|
+
if (debtusSettlementStatus !== undefined &&
|
|
269
|
+
postingStatus !== 'applied') {
|
|
270
|
+
throw new TypeError('Debtus settlement status requires applied posting');
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
contractVersion: SPLITUS_BILL_CONTRACT_VERSION,
|
|
274
|
+
spaceID: storageID(input['spaceID'], 'spaceID'),
|
|
275
|
+
billID: storageID(input['billID'], 'billID'),
|
|
276
|
+
title: optionalText(input['title'], 'title', 256),
|
|
277
|
+
billKind,
|
|
278
|
+
utilityKind,
|
|
279
|
+
period: periodValue,
|
|
280
|
+
currency: currency(input['currency']),
|
|
281
|
+
actualAmount: positiveAmount(input['actualAmount'], 'actualAmount'),
|
|
282
|
+
ownPaidAmount: nonNegativeAmount(input['ownPaidAmount'], 'ownPaidAmount'),
|
|
283
|
+
ownOwedAmount: nonNegativeAmount(input['ownOwedAmount'], 'ownOwedAmount'),
|
|
284
|
+
postingStatus,
|
|
285
|
+
debtusSettlementStatus,
|
|
286
|
+
createdAt: timestamp(input['createdAt'], 'createdAt'),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function posting(value, billRevision) {
|
|
290
|
+
const input = record(value, 'posting');
|
|
291
|
+
const status = enumValue(input['status'], ['pending', 'posting', 'applied', 'attention'], 'posting.status');
|
|
292
|
+
const operationKey = storageID(input['operationKey'], 'posting.operationKey');
|
|
293
|
+
const inputDigest = digest(input['inputDigest'], 'posting.inputDigest');
|
|
294
|
+
const receiptValue = input['receipt'] === undefined
|
|
295
|
+
? undefined
|
|
296
|
+
: postingReceipt(input['receipt'], billRevision, operationKey, inputDigest);
|
|
297
|
+
const attentionCode = input['attentionCode'] === undefined
|
|
298
|
+
? undefined
|
|
299
|
+
: enumValue(input['attentionCode'], [
|
|
300
|
+
'authorization_changed',
|
|
301
|
+
'source_conflict',
|
|
302
|
+
'provider_rejected',
|
|
303
|
+
'invalid_provider_receipt',
|
|
304
|
+
'operator_action_required',
|
|
305
|
+
], 'posting.attentionCode');
|
|
306
|
+
if ((status === 'applied') !== (receiptValue !== undefined)) {
|
|
307
|
+
throw new TypeError('applied posting status requires exactly one receipt');
|
|
308
|
+
}
|
|
309
|
+
if ((status === 'attention') !== (attentionCode !== undefined)) {
|
|
310
|
+
throw new TypeError('attention posting status requires exactly one code');
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
status,
|
|
314
|
+
operationKey,
|
|
315
|
+
inputDigest,
|
|
316
|
+
receipt: receiptValue,
|
|
317
|
+
attentionCode,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function postingReceipt(value, billRevision, operationKey, inputDigest) {
|
|
321
|
+
const input = record(value, 'posting.receipt');
|
|
322
|
+
const revisionValue = positiveIntegerString(input['revision'], 'posting.receipt.revision');
|
|
323
|
+
const receiptOperationKey = storageID(input['operationKey'], 'posting.receipt.operationKey');
|
|
324
|
+
const receiptInputDigest = digest(input['inputDigest'], 'posting.receipt.inputDigest');
|
|
325
|
+
if (revisionValue !== billRevision ||
|
|
326
|
+
receiptOperationKey !== operationKey ||
|
|
327
|
+
receiptInputDigest !== inputDigest) {
|
|
328
|
+
throw new TypeError('posting receipt does not match the accepted bill revision');
|
|
329
|
+
}
|
|
330
|
+
if (!Array.isArray(input['obligationLines']) ||
|
|
331
|
+
input['obligationLines'].length > MAX_SPLITUS_BILL_OBLIGATIONS) {
|
|
332
|
+
throw new RangeError('posting receipt obligationLines are unbounded');
|
|
333
|
+
}
|
|
334
|
+
const lineIDs = new Set();
|
|
335
|
+
const obligationIDs = new Set();
|
|
336
|
+
const obligationLines = input['obligationLines'].map((value, index) => {
|
|
337
|
+
const line = record(value, `posting.receipt.obligationLines[${index}]`);
|
|
338
|
+
const lineID = storageID(line['lineID'], `posting.receipt.obligationLines[${index}].lineID`);
|
|
339
|
+
if (lineIDs.has(lineID)) {
|
|
340
|
+
throw new TypeError('posting receipt repeats an obligation line');
|
|
341
|
+
}
|
|
342
|
+
lineIDs.add(lineID);
|
|
343
|
+
const ids = identifierArray(line['obligationIDs'], `posting.receipt.obligationLines[${index}].obligationIDs`, MAX_SPLITUS_OBLIGATION_IDS_PER_LINE);
|
|
344
|
+
for (const id of ids) {
|
|
345
|
+
if (obligationIDs.has(id)) {
|
|
346
|
+
throw new TypeError('posting receipt repeats an obligation ID');
|
|
347
|
+
}
|
|
348
|
+
obligationIDs.add(id);
|
|
349
|
+
}
|
|
350
|
+
return { lineID, obligationIDs: ids };
|
|
351
|
+
});
|
|
352
|
+
return {
|
|
353
|
+
receiptID: storageID(input['receiptID'], 'posting.receipt.receiptID'),
|
|
354
|
+
operationKey: receiptOperationKey,
|
|
355
|
+
inputDigest: receiptInputDigest,
|
|
356
|
+
revision: revisionValue,
|
|
357
|
+
obligationLines,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function debtusStatus(value, spaceID, billID, billCurrency) {
|
|
361
|
+
const input = record(value, 'debtus');
|
|
362
|
+
if (!Array.isArray(input['obligations']) ||
|
|
363
|
+
input['obligations'].length > MAX_SPLITUS_BILL_OBLIGATIONS) {
|
|
364
|
+
throw new RangeError('Debtus obligations are unbounded');
|
|
365
|
+
}
|
|
366
|
+
const lineIDs = new Set();
|
|
367
|
+
const obligations = input['obligations'].map((item, index) => {
|
|
368
|
+
const obligation = record(item, `debtus.obligations[${index}]`);
|
|
369
|
+
const lineID = storageID(obligation['lineID'], `debtus.obligations[${index}].lineID`);
|
|
370
|
+
if (lineIDs.has(lineID)) {
|
|
371
|
+
throw new TypeError('Debtus status repeats an obligation line');
|
|
372
|
+
}
|
|
373
|
+
lineIDs.add(lineID);
|
|
374
|
+
const obligationCurrency = currency(obligation['currency']);
|
|
375
|
+
if (obligationCurrency !== billCurrency) {
|
|
376
|
+
throw new TypeError('Debtus obligation currency differs from the bill');
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
lineID,
|
|
380
|
+
obligationIDs: identifierArray(obligation['obligationIDs'], `debtus.obligations[${index}].obligationIDs`, MAX_SPLITUS_OBLIGATION_IDS_PER_LINE),
|
|
381
|
+
debtorContactID: storageID(obligation['debtorContactID'], `debtus.obligations[${index}].debtorContactID`),
|
|
382
|
+
creditorContactID: storageID(obligation['creditorContactID'], `debtus.obligations[${index}].creditorContactID`),
|
|
383
|
+
currency: obligationCurrency,
|
|
384
|
+
principalAmount: positiveAmount(obligation['principalAmount'], `debtus.obligations[${index}].principalAmount`),
|
|
385
|
+
outstandingAmount: nonNegativeAmount(obligation['outstandingAmount'], `debtus.obligations[${index}].outstandingAmount`),
|
|
386
|
+
repaidAmount: nonNegativeAmount(obligation['repaidAmount'], `debtus.obligations[${index}].repaidAmount`),
|
|
387
|
+
creditAmount: nonNegativeAmount(obligation['creditAmount'], `debtus.obligations[${index}].creditAmount`),
|
|
388
|
+
status: settlementStatus(obligation['status'], `debtus.obligations[${index}].status`),
|
|
389
|
+
settlementTarget: settlementTarget(obligation['settlementTarget'], spaceID, billID, lineID),
|
|
390
|
+
};
|
|
391
|
+
});
|
|
392
|
+
return {
|
|
393
|
+
status: settlementStatus(input['status'], 'debtus.status'),
|
|
394
|
+
obligations,
|
|
395
|
+
settlementTarget: settlementTarget(input['settlementTarget'], spaceID, billID),
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
function validateDebtusMatchesReceipt(receipt, debtus) {
|
|
399
|
+
if (receipt.obligationLines.length !== debtus.obligations.length) {
|
|
400
|
+
throw new TypeError('Debtus obligations do not exactly match the applied posting receipt');
|
|
401
|
+
}
|
|
402
|
+
const receiptLines = new Map(receipt.obligationLines.map((line) => [
|
|
403
|
+
line.lineID,
|
|
404
|
+
new Set(line.obligationIDs),
|
|
405
|
+
]));
|
|
406
|
+
for (const obligation of debtus.obligations) {
|
|
407
|
+
const receiptIDs = receiptLines.get(obligation.lineID);
|
|
408
|
+
if (receiptIDs === undefined ||
|
|
409
|
+
receiptIDs.size !== obligation.obligationIDs.length ||
|
|
410
|
+
obligation.obligationIDs.some((id) => !receiptIDs.has(id))) {
|
|
411
|
+
throw new TypeError('Debtus obligations do not exactly match the applied posting receipt');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function settlementTarget(value, spaceID, billID, expectedLineID) {
|
|
416
|
+
const input = record(value, 'settlementTarget');
|
|
417
|
+
const lineID = input['lineID'] === undefined
|
|
418
|
+
? undefined
|
|
419
|
+
: storageID(input['lineID'], 'settlementTarget.lineID');
|
|
420
|
+
if (input['route'] !== 'debtus.source-obligations' ||
|
|
421
|
+
input['sourceNamespace'] !== 'splitus' ||
|
|
422
|
+
input['spaceID'] !== spaceID ||
|
|
423
|
+
input['sourceRecordID'] !== billID ||
|
|
424
|
+
lineID !== expectedLineID) {
|
|
425
|
+
throw new TypeError('settlement target does not match the Splitus bill source');
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
route: 'debtus.source-obligations',
|
|
429
|
+
spaceID,
|
|
430
|
+
sourceNamespace: 'splitus',
|
|
431
|
+
sourceRecordID: billID,
|
|
432
|
+
lineID,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
function versionedRecord(value, name) {
|
|
436
|
+
const input = record(value, name);
|
|
437
|
+
if (input['contractVersion'] !== SPLITUS_BILL_CONTRACT_VERSION) {
|
|
438
|
+
throw new TypeError('unsupported Splitus bill contract version');
|
|
439
|
+
}
|
|
440
|
+
return input;
|
|
441
|
+
}
|
|
442
|
+
function boundedPageSize(value) {
|
|
443
|
+
if (typeof value !== 'number' ||
|
|
444
|
+
!Number.isSafeInteger(value) ||
|
|
445
|
+
value < 1 ||
|
|
446
|
+
value > MAX_SPLITUS_BILL_LIST_PAGE_SIZE) {
|
|
447
|
+
throw new RangeError(`pageSize must be an integer from 1 to ${MAX_SPLITUS_BILL_LIST_PAGE_SIZE}`);
|
|
448
|
+
}
|
|
449
|
+
return value;
|
|
450
|
+
}
|
|
451
|
+
function settlementStatus(value, name) {
|
|
452
|
+
return enumValue(value, ['unsettled', 'part_settled', 'settled'], name);
|
|
453
|
+
}
|
|
454
|
+
function identifierArray(value, name, maximum) {
|
|
455
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > maximum) {
|
|
456
|
+
throw new RangeError(`${name} must contain 1 to ${maximum} identifiers`);
|
|
457
|
+
}
|
|
458
|
+
const seen = new Set();
|
|
459
|
+
return value.map((item, index) => {
|
|
460
|
+
const id = storageID(item, `${name}[${index}]`);
|
|
461
|
+
if (seen.has(id)) {
|
|
462
|
+
throw new TypeError(`${name} contains a duplicate identifier`);
|
|
463
|
+
}
|
|
464
|
+
seen.add(id);
|
|
465
|
+
return id;
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
function digest(value, name) {
|
|
469
|
+
if (typeof value !== 'string' || !/^[0-9a-f]{64}$/.test(value)) {
|
|
470
|
+
throw new TypeError(`${name} must be a lowercase SHA-256 digest`);
|
|
471
|
+
}
|
|
472
|
+
return value;
|
|
473
|
+
}
|
|
474
|
+
function positiveIntegerString(value, name) {
|
|
475
|
+
if (typeof value !== 'string' || !/^[1-9][0-9]*$/.test(value)) {
|
|
476
|
+
throw new TypeError(`${name} must be a canonical positive integer string`);
|
|
477
|
+
}
|
|
478
|
+
if (BigInt(value) > 18446744073709551615n) {
|
|
479
|
+
throw new RangeError(`${name} exceeds unsigned 64-bit range`);
|
|
480
|
+
}
|
|
481
|
+
return value;
|
|
482
|
+
}
|
|
483
|
+
function timestamp(value, name) {
|
|
484
|
+
if (typeof value !== 'string' ||
|
|
485
|
+
!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(value) ||
|
|
486
|
+
Number.isNaN(Date.parse(value))) {
|
|
487
|
+
throw new TypeError(`${name} must be an RFC 3339 timestamp`);
|
|
488
|
+
}
|
|
489
|
+
date(value.slice(0, 10), name);
|
|
490
|
+
return value;
|
|
491
|
+
}
|
|
492
|
+
function nonNegativeAmount(value, name) {
|
|
493
|
+
try {
|
|
494
|
+
return parseExactDecimalString(value);
|
|
495
|
+
}
|
|
496
|
+
catch (error) {
|
|
497
|
+
if (error instanceof RangeError) {
|
|
498
|
+
throw new RangeError(`${name}: ${error.message}`);
|
|
499
|
+
}
|
|
500
|
+
if (error instanceof Error) {
|
|
501
|
+
throw new TypeError(`${name}: ${error.message}`);
|
|
502
|
+
}
|
|
503
|
+
throw error;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function validateAllocationTotals(request) {
|
|
507
|
+
const contacts = new Set();
|
|
508
|
+
for (const allocation of [
|
|
509
|
+
...request.paidAllocations,
|
|
510
|
+
...request.owedAllocations,
|
|
511
|
+
]) {
|
|
512
|
+
contacts.add(allocation.contactID);
|
|
513
|
+
}
|
|
514
|
+
if (contacts.size < 2 || contacts.size > MAX_SPLITUS_BILL_PARTICIPANTS) {
|
|
515
|
+
throw new RangeError(`bill must have 2 to ${MAX_SPLITUS_BILL_PARTICIPANTS} participants`);
|
|
516
|
+
}
|
|
517
|
+
const actual = amountToMinorUnits(request.actualAmount);
|
|
518
|
+
if (sumAllocations(request.paidAllocations) !== actual) {
|
|
519
|
+
throw new RangeError('paid allocations must reconcile to actualAmount');
|
|
520
|
+
}
|
|
521
|
+
if (sumAllocations(request.owedAllocations) !== actual) {
|
|
522
|
+
throw new RangeError('owed allocations must reconcile to actualAmount');
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function allocations(value, name) {
|
|
526
|
+
if (!Array.isArray(value) || value.length < 1 || value.length > MAX_SPLITUS_BILL_PARTICIPANTS) {
|
|
527
|
+
throw new RangeError(`${name} must contain 1 to ${MAX_SPLITUS_BILL_PARTICIPANTS} allocations`);
|
|
528
|
+
}
|
|
529
|
+
const allocationIDs = new Set();
|
|
530
|
+
const contactIDs = new Set();
|
|
531
|
+
return value.map((item, index) => {
|
|
532
|
+
const input = record(item, `${name}[${index}]`);
|
|
533
|
+
const allocationID = storageID(input['allocationID'], `${name}[${index}].allocationID`);
|
|
534
|
+
const contactID = storageID(input['contactID'], `${name}[${index}].contactID`);
|
|
535
|
+
if (allocationIDs.has(allocationID) || contactIDs.has(contactID)) {
|
|
536
|
+
throw new TypeError(`${name} contains a duplicate allocation or contact`);
|
|
537
|
+
}
|
|
538
|
+
allocationIDs.add(allocationID);
|
|
539
|
+
contactIDs.add(contactID);
|
|
540
|
+
return {
|
|
541
|
+
allocationID,
|
|
542
|
+
contactID,
|
|
543
|
+
amount: positiveAmount(input['amount'], `${name}[${index}].amount`),
|
|
544
|
+
};
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
function sumAllocations(allocationsToSum) {
|
|
548
|
+
let total = 0n;
|
|
549
|
+
for (const allocation of allocationsToSum) {
|
|
550
|
+
total += amountToMinorUnits(allocation.amount);
|
|
551
|
+
if (total > MAX_EXACT_MINOR_UNITS) {
|
|
552
|
+
throw new RangeError('allocation total exceeds the Splitus contract limit');
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return total;
|
|
556
|
+
}
|
|
557
|
+
function amountToMinorUnits(value) {
|
|
558
|
+
return BigInt(value.replace('.', ''));
|
|
559
|
+
}
|
|
560
|
+
function positiveAmount(value, name) {
|
|
561
|
+
const amount = parseExactDecimalString(value);
|
|
562
|
+
if (amountToMinorUnits(amount) === 0n) {
|
|
563
|
+
throw new RangeError(`${name} must be positive`);
|
|
564
|
+
}
|
|
565
|
+
return amount;
|
|
566
|
+
}
|
|
567
|
+
function utility(value) {
|
|
568
|
+
const input = record(value, 'utility');
|
|
569
|
+
return {
|
|
570
|
+
utilityKind: enumValue(input['utilityKind'], ['electricity', 'gas', 'water', 'internet', 'other'], 'utility.utilityKind'),
|
|
571
|
+
providerName: optionalText(input['providerName'], 'utility.providerName', 256),
|
|
572
|
+
period: period(input['period']),
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
function recurring(value, actualAmount, billID) {
|
|
576
|
+
const input = record(value, 'recurringOccurrence');
|
|
577
|
+
const expectedAmount = input['expectedAmount'] === undefined
|
|
578
|
+
? undefined
|
|
579
|
+
: positiveAmount(input['expectedAmount'], 'recurringOccurrence.expectedAmount');
|
|
580
|
+
const standingChargeAmount = input['standingChargeAmount'] === undefined
|
|
581
|
+
? undefined
|
|
582
|
+
: positiveAmount(input['standingChargeAmount'], 'recurringOccurrence.standingChargeAmount');
|
|
583
|
+
const expectedComparison = input['expectedComparison'] === undefined
|
|
584
|
+
? undefined
|
|
585
|
+
: enumValue(input['expectedComparison'], ['not_available', 'matches', 'increased', 'decreased'], 'recurringOccurrence.expectedComparison');
|
|
586
|
+
if (expectedAmount === undefined &&
|
|
587
|
+
expectedComparison !== undefined &&
|
|
588
|
+
expectedComparison !== 'not_available') {
|
|
589
|
+
throw new TypeError('comparison must be not_available exactly when expectedAmount is absent');
|
|
590
|
+
}
|
|
591
|
+
if (expectedAmount !== undefined) {
|
|
592
|
+
const expectedComparisonForAmounts = compareAmounts(actualAmount, expectedAmount);
|
|
593
|
+
if (expectedComparison !== undefined && expectedComparison !== expectedComparisonForAmounts) {
|
|
594
|
+
throw new TypeError('comparison does not match expected and actual amounts');
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (standingChargeAmount !== undefined &&
|
|
598
|
+
amountToMinorUnits(standingChargeAmount) > amountToMinorUnits(actualAmount)) {
|
|
599
|
+
throw new RangeError('standing charge cannot exceed actualAmount');
|
|
600
|
+
}
|
|
601
|
+
return {
|
|
602
|
+
happeningID: storageID(input['happeningID'], 'recurringOccurrence.happeningID'),
|
|
603
|
+
occurrenceID: storageID(input['occurrenceID'], 'recurringOccurrence.occurrenceID'),
|
|
604
|
+
chargeID: input['chargeID'] === undefined
|
|
605
|
+
? undefined
|
|
606
|
+
: storageID(input['chargeID'], 'recurringOccurrence.chargeID'),
|
|
607
|
+
expectedAmount,
|
|
608
|
+
standingChargeAmount,
|
|
609
|
+
expectedComparison,
|
|
610
|
+
previousComparable: input['previousComparable'] === undefined
|
|
611
|
+
? undefined
|
|
612
|
+
: previousComparable(input['previousComparable'], actualAmount, billID),
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
function previousComparable(value, actualAmount, billID) {
|
|
616
|
+
const input = record(value, 'recurringOccurrence.previousComparable');
|
|
617
|
+
const previousBillID = storageID(input['billID'], 'recurringOccurrence.previousComparable.billID');
|
|
618
|
+
if (previousBillID === billID) {
|
|
619
|
+
throw new TypeError('previous comparable bill must have a different billID');
|
|
620
|
+
}
|
|
621
|
+
const previousActualAmount = positiveAmount(input['actualAmount'], 'recurringOccurrence.previousComparable.actualAmount');
|
|
622
|
+
const comparison = enumValue(input['comparison'], ['matches', 'increased', 'decreased'], 'recurringOccurrence.previousComparable.comparison');
|
|
623
|
+
const expectedComparison = compareAmounts(actualAmount, previousActualAmount);
|
|
624
|
+
if (comparison !== expectedComparison) {
|
|
625
|
+
throw new TypeError('previous comparison does not match current and prior actual amounts');
|
|
626
|
+
}
|
|
627
|
+
return {
|
|
628
|
+
billID: previousBillID,
|
|
629
|
+
actualAmount: previousActualAmount,
|
|
630
|
+
comparison,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
function compareAmounts(current, baseline) {
|
|
634
|
+
const currentMinor = amountToMinorUnits(current);
|
|
635
|
+
const baselineMinor = amountToMinorUnits(baseline);
|
|
636
|
+
return currentMinor === baselineMinor
|
|
637
|
+
? 'matches'
|
|
638
|
+
: currentMinor > baselineMinor
|
|
639
|
+
? 'increased'
|
|
640
|
+
: 'decreased';
|
|
641
|
+
}
|
|
642
|
+
function period(value) {
|
|
643
|
+
const input = record(value, 'period');
|
|
644
|
+
const startDate = date(input['startDate'], 'period.startDate');
|
|
645
|
+
const endDate = date(input['endDate'], 'period.endDate');
|
|
646
|
+
if (endDate < startDate) {
|
|
647
|
+
throw new RangeError('period.endDate must not precede period.startDate');
|
|
648
|
+
}
|
|
649
|
+
return { startDate, endDate };
|
|
650
|
+
}
|
|
651
|
+
function date(value, name) {
|
|
652
|
+
if (typeof value !== 'string') {
|
|
653
|
+
throw new TypeError(`${name} must be an ISO calendar date`);
|
|
654
|
+
}
|
|
655
|
+
const match = datePattern.exec(value);
|
|
656
|
+
if (match === null) {
|
|
657
|
+
throw new TypeError(`${name} must be an ISO calendar date`);
|
|
658
|
+
}
|
|
659
|
+
const parsed = new Date(`${value}T00:00:00.000Z`);
|
|
660
|
+
if (Number.isNaN(parsed.valueOf()) || parsed.toISOString().slice(0, 10) !== value) {
|
|
661
|
+
throw new TypeError(`${name} must be a real ISO calendar date`);
|
|
662
|
+
}
|
|
663
|
+
return value;
|
|
664
|
+
}
|
|
665
|
+
function currency(value) {
|
|
666
|
+
return enumValue(value, ['EUR', 'GBP', 'USD'], 'currency');
|
|
667
|
+
}
|
|
668
|
+
function storageID(value, name) {
|
|
669
|
+
if (typeof value !== 'string' ||
|
|
670
|
+
value.length === 0 ||
|
|
671
|
+
value.trim() !== value ||
|
|
672
|
+
new TextEncoder().encode(value).length > 512 ||
|
|
673
|
+
value.includes('/') ||
|
|
674
|
+
hasControlCharacters(value) ||
|
|
675
|
+
value === '.' ||
|
|
676
|
+
value === '..' ||
|
|
677
|
+
(/^__/.test(value) && /__$/.test(value))) {
|
|
678
|
+
throw new TypeError(`${name} is not a safe identifier`);
|
|
679
|
+
}
|
|
680
|
+
return value;
|
|
681
|
+
}
|
|
682
|
+
function optionalText(value, name, maxBytes) {
|
|
683
|
+
if (value === undefined) {
|
|
684
|
+
return undefined;
|
|
685
|
+
}
|
|
686
|
+
if (typeof value !== 'string' ||
|
|
687
|
+
value.length === 0 ||
|
|
688
|
+
value.trim() !== value ||
|
|
689
|
+
new TextEncoder().encode(value).length > maxBytes ||
|
|
690
|
+
hasControlCharacters(value)) {
|
|
691
|
+
throw new TypeError(`${name} is empty, padded, too long, or contains controls`);
|
|
692
|
+
}
|
|
693
|
+
return value;
|
|
694
|
+
}
|
|
695
|
+
function hasControlCharacters(value) {
|
|
696
|
+
for (const character of value) {
|
|
697
|
+
const code = character.charCodeAt(0);
|
|
698
|
+
if (code < 0x20 || code === 0x7f) {
|
|
699
|
+
return true;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
function record(value, name) {
|
|
705
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
706
|
+
throw new TypeError(`${name} must be an object`);
|
|
707
|
+
}
|
|
708
|
+
return value;
|
|
709
|
+
}
|
|
710
|
+
function enumValue(value, allowed, name) {
|
|
711
|
+
if (typeof value !== 'string' || !allowed.includes(value)) {
|
|
712
|
+
throw new TypeError(`${name} has an unsupported value`);
|
|
713
|
+
}
|
|
714
|
+
return value;
|
|
715
|
+
}
|
|
716
|
+
function optionalStorageID(value, name) {
|
|
717
|
+
return value === undefined ? undefined : storageID(value, name);
|
|
718
|
+
}
|
|
719
|
+
function optionalEnum(value, allowed, name) {
|
|
720
|
+
return value === undefined ? undefined : enumValue(value, allowed, name);
|
|
721
|
+
}
|
|
722
|
+
function optionalBoolean(value, name) {
|
|
723
|
+
if (value === undefined)
|
|
724
|
+
return undefined;
|
|
725
|
+
if (typeof value !== 'boolean')
|
|
726
|
+
throw new TypeError(`${name} must be boolean`);
|
|
727
|
+
return value;
|
|
728
|
+
}
|
|
729
|
+
function textArray(value, name, maximum) {
|
|
730
|
+
if (value === undefined)
|
|
731
|
+
return [];
|
|
732
|
+
if (!Array.isArray(value) || value.length > maximum) {
|
|
733
|
+
throw new RangeError(`${name} exceeds maximum item count ${maximum}`);
|
|
734
|
+
}
|
|
735
|
+
const values = value.map((item, index) => optionalText(item, `${name}[${index}]`, 100));
|
|
736
|
+
if (values.some((item) => item === undefined)) {
|
|
737
|
+
throw new TypeError(`${name} contains an invalid value`);
|
|
738
|
+
}
|
|
739
|
+
const result = values;
|
|
740
|
+
return result;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/** @deprecated Use `SPLITUS_BILL_SERVICE_V1`. */
|
|
3
744
|
const SPLITUS_SERVICE = new InjectionToken('SplitusService');
|
|
745
|
+
const SPLITUS_BILL_SERVICE_V1 = new InjectionToken('SplitusBillServiceV1');
|
|
4
746
|
|
|
5
747
|
/**
|
|
6
748
|
* Generated bundle index. Do not edit.
|
|
7
749
|
*/
|
|
8
750
|
|
|
9
|
-
export { SPLITUS_SERVICE };
|
|
751
|
+
export { MAX_SPLITUS_BILL_LIST_PAGE_SIZE, MAX_SPLITUS_BILL_OBLIGATIONS, MAX_SPLITUS_BILL_PARTICIPANTS, MAX_SPLITUS_OBLIGATION_IDS_PER_LINE, SPLITUS_BILL_CONTRACT_VERSION, SPLITUS_BILL_SERVICE_V1, SPLITUS_SERVICE, assertCreateSplitusBillV1Recorder, parseCreateSplitusBillV1Request, parseCreateSplitusBillV1Response, parseExactDecimalString, parseGetSplitusBillV1Request, parseGetSplitusBillV1Response, parseListSplitusBillsV1Request, parseListSplitusBillsV1Response, parseSplitusBillV1 };
|
|
10
752
|
//# sourceMappingURL=sneat-extension-splitus-contract.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sneat-extension-splitus-contract.mjs","sources":["../../../../libs/splitus/src/services.ts","../../../../libs/splitus/src/sneat-extension-splitus-contract.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { ICreateSplitRequest, ICreateSplitResponse, ISplit, ISplitListItem } from './dto';\n\nexport interface ISplitusService {\n /** REAL: POST /api4splitus/create-split. Payer is the authenticated user. */\n createSplit(request: ICreateSplitRequest): Observable<ICreateSplitResponse>;\n /** REAL: GET /api4splitus/split?spaceID=&id= */\n getSplit(spaceID: string, id: string): Observable<ISplit>;\n /** REAL: GET /api4splitus/splits?spaceID= */\n getSplits(spaceID: string): Observable<ISplitListItem[]>;\n}\n\nexport const SPLITUS_SERVICE = new InjectionToken<ISplitusService>('SplitusService');\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;MAaa,eAAe,GAAG,IAAI,cAAc,CAAkB,gBAAgB;;ACbnF;;AAEG;;"}
|
|
1
|
+
{"version":3,"file":"sneat-extension-splitus-contract.mjs","sources":["../../../../libs/splitus/src/dto/bill-v1.ts","../../../../libs/splitus/src/services.ts","../../../../libs/splitus/src/sneat-extension-splitus-contract.ts"],"sourcesContent":["/** The first stable Splitus bill browser/host wire contract. */\nexport const SPLITUS_BILL_CONTRACT_VERSION = 1 as const;\n\nexport const MAX_SPLITUS_BILL_PARTICIPANTS = 256;\nexport const MAX_SPLITUS_BILL_LIST_PAGE_SIZE = 100;\nexport const MAX_SPLITUS_BILL_OBLIGATIONS = 256;\nexport const MAX_SPLITUS_OBLIGATION_IDS_PER_LINE = 256;\n\nexport type SplitusBillContractVersion =\n typeof SPLITUS_BILL_CONTRACT_VERSION;\n\n/**\n * A canonical, non-negative major-unit amount with exactly two fraction\n * digits. Examples: `0.00`, `30.00`, `90.00`.\n *\n * The alias documents the wire type; use `parseExactDecimalString()` at an\n * untrusted boundary. JavaScript numbers and minor-unit numbers are not part\n * of this contract.\n */\nexport type ExactDecimalString = string;\n\n/** Currencies whose minor unit is exactly two decimal digits in this contract. */\nexport type SplitusCurrencyCode = 'EUR' | 'GBP' | 'USD';\n\nexport type SplitusBillKind = 'general' | 'utility';\nexport type SplitusUtilityKind =\n | 'electricity'\n | 'gas'\n | 'water'\n | 'internet'\n | 'other';\n\nexport type SplitusBillPostingStatus =\n | 'pending'\n | 'posting'\n | 'applied'\n | 'attention';\n\nexport type SplitusDebtusSettlementStatus =\n | 'unsettled'\n | 'part_settled'\n | 'settled';\n\nexport type SplitusExpectedActualComparison =\n | 'not_available'\n | 'matches'\n | 'increased'\n | 'decreased';\n\nexport type SplitusBillAttentionCode =\n | 'authorization_changed'\n | 'source_conflict'\n | 'provider_rejected'\n | 'invalid_provider_receipt'\n | 'operator_action_required';\n\nexport interface ISplitusBillAllocationV1 {\n /** Stable within the bill revision, independent of array ordering. */\n readonly allocationID: string;\n /**\n * Contactus identity in this Space. Hosts resolve its real display data from\n * Contactus; this opaque ID is never a user-facing label.\n */\n readonly contactID: string;\n readonly amount: ExactDecimalString;\n}\n\nexport interface ISplitusBillingPeriodV1 {\n /** Inclusive ISO calendar date. */\n readonly startDate: string;\n /** Inclusive ISO calendar date; must not precede `startDate`. */\n readonly endDate: string;\n}\n\nexport interface ISplitusUtilityDetailsV1 {\n readonly utilityKind: SplitusUtilityKind;\n readonly providerName?: string;\n readonly period: ISplitusBillingPeriodV1;\n}\n\n/**\n * A reference to the Calendarius occurrence represented by this actual bill.\n * `expectedAmount` and `standingChargeAmount` are context only; neither is a\n * paid expense. `actualAmount` on the enclosing bill remains mandatory.\n */\nexport interface ISplitusRecurringOccurrenceV1 {\n readonly happeningID: string;\n readonly occurrenceID: string;\n readonly chargeID?: string;\n readonly expectedAmount?: ExactDecimalString;\n readonly standingChargeAmount?: ExactDecimalString;\n readonly expectedComparison?: SplitusExpectedActualComparison;\n readonly previousComparable?: ISplitusPreviousComparableBillV1;\n}\n\nexport interface ISplitusPreviousComparableBillV1 {\n readonly billID: string;\n readonly actualAmount: ExactDecimalString;\n readonly comparison: Exclude<\n SplitusExpectedActualComparison,\n 'not_available'\n >;\n}\n\nexport type SplitusResolvedSourceDirection =\n | 'expense'\n | 'income'\n | 'transfer';\n\nexport type SplitusResolvedSourceTemporalBasis =\n | 'occurrence_service_cost'\n | 'contract_period_cost'\n | 'normalized_service_cost';\n\nexport interface ISplitusSourceContactLinkV1 {\n readonly contactID: string;\n readonly roles: readonly string[];\n}\n\nexport interface ISplitusSourceAttributionV1 {\n readonly id: string;\n readonly amount: ExactDecimalString;\n}\n\n/** Immutable source facts captured by Splitus when the actual bill is accepted. */\nexport interface ISplitusResolvedSourceEffectV1 {\n readonly priceID: string;\n readonly priceRevision: number;\n readonly expectedAmount: ExactDecimalString;\n readonly sourceAttributionCaptured: boolean;\n readonly assetIDs: readonly string[];\n readonly contactLinks: readonly ISplitusSourceContactLinkV1[];\n /** Present as one complete group for agreement-backed reconciliation. */\n readonly ownerSpaceID?: string;\n readonly agreementID?: string;\n readonly enrollmentID?: string;\n readonly chargeID?: string;\n readonly occurrenceID?: string;\n readonly direction?: SplitusResolvedSourceDirection;\n readonly temporalBasis?: SplitusResolvedSourceTemporalBasis;\n readonly economicPeriod?: ISplitusBillingPeriodV1;\n readonly invoiceReconciliationEligible?: boolean;\n readonly contactAttributions: readonly ISplitusSourceAttributionV1[];\n readonly assetAttributions: readonly ISplitusSourceAttributionV1[];\n}\n\nexport interface ICreateSplitusBillV1Request {\n readonly contractVersion: SplitusBillContractVersion;\n readonly spaceID: string;\n /**\n * Stable across duplicate submission and lost-response retries. Reusing the\n * same ID with changed paid/owed allocations is a provider conflict.\n */\n readonly billID: string;\n /**\n * Audit identity of the authenticated actor. The server must bind this to\n * its trusted authentication context. It never implies a paid or owed\n * allocation.\n */\n readonly recorderUserID: string;\n readonly title?: string;\n readonly billKind: SplitusBillKind;\n readonly currency: SplitusCurrencyCode;\n /** Actual paid amount. An expectation is never accepted in its place. */\n readonly actualAmount: ExactDecimalString;\n /** Explicit sources of payment; one contact may also owe a share. */\n readonly paidAllocations: readonly ISplitusBillAllocationV1[];\n /** Explicit responsibility shares. */\n readonly owedAllocations: readonly ISplitusBillAllocationV1[];\n /** Required exactly when `billKind` is `utility`. */\n readonly utility?: ISplitusUtilityDetailsV1;\n readonly recurringOccurrence?: ISplitusRecurringOccurrenceV1;\n}\n\nexport interface ISplitusDebtusReceiptLineV1 {\n readonly lineID: string;\n readonly obligationIDs: readonly string[];\n}\n\nexport interface ISplitusBillPostingReceiptV1 {\n readonly receiptID: string;\n readonly operationKey: string;\n readonly inputDigest: string;\n readonly revision: string;\n readonly obligationLines: readonly ISplitusDebtusReceiptLineV1[];\n}\n\nexport interface ISplitusBillPostingV1 {\n readonly status: SplitusBillPostingStatus;\n /** Durable identity of the retry-safe provider operation. */\n readonly operationKey: string;\n /** Digest of the exact accepted source revision and allocations. */\n readonly inputDigest: string;\n /** Present exactly when `status` is `applied`. */\n readonly receipt?: ISplitusBillPostingReceiptV1;\n /** Present exactly when `status` is `attention`. */\n readonly attentionCode?: SplitusBillAttentionCode;\n}\n\n/**\n * An application-relative target. The host resolves it through its injected\n * Debtus navigation adapter; contracts never hard-code debtus.app or another\n * deployment origin.\n */\nexport interface ISplitusDebtusSettlementTargetV1 {\n readonly route: 'debtus.source-obligations';\n readonly spaceID: string;\n readonly sourceNamespace: 'splitus';\n readonly sourceRecordID: string;\n readonly lineID?: string;\n}\n\nexport interface ISplitusDebtusObligationV1 {\n readonly lineID: string;\n readonly obligationIDs: readonly string[];\n readonly debtorContactID: string;\n readonly creditorContactID: string;\n readonly currency: SplitusCurrencyCode;\n readonly principalAmount: ExactDecimalString;\n readonly outstandingAmount: ExactDecimalString;\n readonly repaidAmount: ExactDecimalString;\n readonly creditAmount: ExactDecimalString;\n readonly status: SplitusDebtusSettlementStatus;\n readonly settlementTarget: ISplitusDebtusSettlementTargetV1;\n}\n\nexport interface ISplitusDebtusStatusV1 {\n /** Current state read from Debtus, never a Splitus-maintained balance. */\n readonly status: SplitusDebtusSettlementStatus;\n readonly obligations: readonly ISplitusDebtusObligationV1[];\n readonly settlementTarget: ISplitusDebtusSettlementTargetV1;\n}\n\nexport interface ISplitusBillV1 extends ICreateSplitusBillV1Request {\n readonly resolvedSourceEffects?: readonly ISplitusResolvedSourceEffectV1[];\n /** Canonical positive decimal integer encoded as a string. */\n readonly revision: string;\n readonly posting: ISplitusBillPostingV1;\n /** Absent until a Debtus financial projection is available. */\n readonly debtus?: ISplitusDebtusStatusV1;\n readonly createdAt: string;\n readonly updatedAt: string;\n}\n\nexport interface ICreateSplitusBillV1Response {\n readonly contractVersion: SplitusBillContractVersion;\n readonly bill: ISplitusBillV1;\n}\n\nexport interface IGetSplitusBillV1Request {\n readonly contractVersion: SplitusBillContractVersion;\n readonly spaceID: string;\n readonly billID: string;\n}\n\nexport interface IGetSplitusBillV1Response {\n readonly contractVersion: SplitusBillContractVersion;\n readonly bill: ISplitusBillV1;\n}\n\nexport interface ISplitusBillListItemV1 {\n readonly contractVersion: SplitusBillContractVersion;\n readonly spaceID: string;\n readonly billID: string;\n readonly title?: string;\n readonly billKind: SplitusBillKind;\n readonly utilityKind?: SplitusUtilityKind;\n readonly period?: ISplitusBillingPeriodV1;\n readonly currency: SplitusCurrencyCode;\n readonly actualAmount: ExactDecimalString;\n readonly ownPaidAmount: ExactDecimalString;\n readonly ownOwedAmount: ExactDecimalString;\n readonly postingStatus: SplitusBillPostingStatus;\n /** Debtus-derived and absent before the bill has a financial projection. */\n readonly debtusSettlementStatus?: SplitusDebtusSettlementStatus;\n readonly createdAt: string;\n}\n\nexport interface IListSplitusBillsV1Request {\n readonly contractVersion: SplitusBillContractVersion;\n readonly spaceID: string;\n readonly pageSize: number;\n readonly cursor?: string;\n readonly utilityKind?: SplitusUtilityKind;\n readonly period?: ISplitusBillingPeriodV1;\n}\n\nexport interface IListSplitusBillsV1Response {\n readonly contractVersion: SplitusBillContractVersion;\n /** Echoes the accepted request bound so callers can verify the page. */\n readonly pageSize: number;\n /** Contains no more than `pageSize` items and never more than 100. */\n readonly items: readonly ISplitusBillListItemV1[];\n readonly nextCursor?: string;\n}\n\nconst MAX_EXACT_MINOR_UNITS = 9_223_372_036_854_775_807n;\nconst exactDecimalPattern = /^(?:0|[1-9][0-9]*)\\.[0-9]{2}$/;\nconst datePattern = /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/;\n\nexport function parseExactDecimalString(value: unknown): ExactDecimalString {\n if (typeof value !== 'string' || !exactDecimalPattern.test(value)) {\n throw new TypeError(\n 'amount must be a canonical decimal string with exactly two fraction digits',\n );\n }\n const minorUnits = BigInt(value.replace('.', ''));\n if (minorUnits > MAX_EXACT_MINOR_UNITS) {\n throw new RangeError('amount exceeds the Splitus contract limit');\n }\n return value;\n}\n\nexport function parseCreateSplitusBillV1Request(\n value: unknown,\n): ICreateSplitusBillV1Request {\n const input = record(value, 'create bill request');\n if (input['contractVersion'] !== SPLITUS_BILL_CONTRACT_VERSION) {\n throw new TypeError('unsupported Splitus bill contract version');\n }\n const billKind = enumValue(\n input['billKind'],\n ['general', 'utility'] as const,\n 'billKind',\n );\n const actualAmount = positiveAmount(input['actualAmount'], 'actualAmount');\n const spaceID = storageID(input['spaceID'], 'spaceID');\n const billID = storageID(input['billID'], 'billID');\n const recorderUserID = storageID(\n input['recorderUserID'],\n 'recorderUserID',\n );\n const request: ICreateSplitusBillV1Request = {\n contractVersion: SPLITUS_BILL_CONTRACT_VERSION,\n spaceID,\n billID,\n recorderUserID,\n title: optionalText(input['title'], 'title', 256),\n billKind,\n currency: currency(input['currency']),\n actualAmount,\n paidAllocations: allocations(input['paidAllocations'], 'paidAllocations'),\n owedAllocations: allocations(input['owedAllocations'], 'owedAllocations'),\n utility:\n input['utility'] === undefined ? undefined : utility(input['utility']),\n recurringOccurrence:\n input['recurringOccurrence'] === undefined\n ? undefined\n : recurring(input['recurringOccurrence'], actualAmount, billID),\n };\n if ((billKind === 'utility') !== (request.utility !== undefined)) {\n throw new TypeError('utility details are required only for utility bills');\n }\n validateAllocationTotals(request);\n return request;\n}\n\n/**\n * Executable host-boundary check for the request's audit claim. The trusted\n * authenticated identity is supplied by the host, never derived from the\n * request itself.\n */\nexport function assertCreateSplitusBillV1Recorder(\n request: ICreateSplitusBillV1Request,\n authenticatedUserID: string,\n): void {\n const trustedUserID = storageID(\n authenticatedUserID,\n 'authenticatedUserID',\n );\n if (request.recorderUserID !== trustedUserID) {\n throw new TypeError(\n 'recorderUserID must match the trusted authenticated identity',\n );\n }\n}\n\nexport function parseListSplitusBillsV1Request(\n value: unknown,\n): IListSplitusBillsV1Request {\n const input = record(value, 'list bills request');\n if (input['contractVersion'] !== SPLITUS_BILL_CONTRACT_VERSION) {\n throw new TypeError('unsupported Splitus bill contract version');\n }\n const pageSize = input['pageSize'];\n if (\n typeof pageSize !== 'number' ||\n !Number.isSafeInteger(pageSize) ||\n pageSize < 1 ||\n pageSize > MAX_SPLITUS_BILL_LIST_PAGE_SIZE\n ) {\n throw new RangeError(\n `pageSize must be an integer from 1 to ${MAX_SPLITUS_BILL_LIST_PAGE_SIZE}`,\n );\n }\n return {\n contractVersion: SPLITUS_BILL_CONTRACT_VERSION,\n spaceID: storageID(input['spaceID'], 'spaceID'),\n pageSize,\n cursor: optionalText(input['cursor'], 'cursor', 2048),\n utilityKind:\n input['utilityKind'] === undefined\n ? undefined\n : enumValue(\n input['utilityKind'],\n ['electricity', 'gas', 'water', 'internet', 'other'] as const,\n 'utilityKind',\n ),\n period:\n input['period'] === undefined ? undefined : period(input['period']),\n };\n}\n\nexport function parseGetSplitusBillV1Request(\n value: unknown,\n): IGetSplitusBillV1Request {\n const input = versionedRecord(value, 'get bill request');\n return {\n contractVersion: SPLITUS_BILL_CONTRACT_VERSION,\n spaceID: storageID(input['spaceID'], 'spaceID'),\n billID: storageID(input['billID'], 'billID'),\n };\n}\n\nexport function parseCreateSplitusBillV1Response(\n value: unknown,\n): ICreateSplitusBillV1Response {\n const input = versionedRecord(value, 'create bill response');\n return {\n contractVersion: SPLITUS_BILL_CONTRACT_VERSION,\n bill: parseSplitusBillV1(input['bill']),\n };\n}\n\nexport function parseGetSplitusBillV1Response(\n value: unknown,\n): IGetSplitusBillV1Response {\n const input = versionedRecord(value, 'get bill response');\n return {\n contractVersion: SPLITUS_BILL_CONTRACT_VERSION,\n bill: parseSplitusBillV1(input['bill']),\n };\n}\n\nexport function parseListSplitusBillsV1Response(\n value: unknown,\n requestedPageSize?: number,\n): IListSplitusBillsV1Response {\n const input = versionedRecord(value, 'list bills response');\n const pageSize = boundedPageSize(input['pageSize']);\n if (requestedPageSize !== undefined && pageSize !== requestedPageSize) {\n throw new RangeError('response pageSize does not match the accepted request');\n }\n if (!Array.isArray(input['items']) || input['items'].length > pageSize) {\n throw new RangeError('response items exceed the bounded pageSize');\n }\n return {\n contractVersion: SPLITUS_BILL_CONTRACT_VERSION,\n pageSize,\n items: input['items'].map((item) => splitusBillListItem(item)),\n nextCursor: optionalText(input['nextCursor'], 'nextCursor', 2048),\n };\n}\n\nexport function parseSplitusBillV1(value: unknown): ISplitusBillV1 {\n const input = record(value, 'bill');\n const request = parseCreateSplitusBillV1Request(input);\n const resolvedSourceEffects = sourceEffects(input['resolvedSourceEffects']);\n const revisionValue = positiveIntegerString(input['revision'], 'revision');\n const createdAt = timestamp(input['createdAt'], 'createdAt');\n const updatedAt = timestamp(input['updatedAt'], 'updatedAt');\n if (Date.parse(updatedAt) < Date.parse(createdAt)) {\n throw new RangeError('updatedAt must not precede createdAt');\n }\n const postingValue = posting(input['posting'], revisionValue);\n const debtusValue =\n input['debtus'] === undefined\n ? undefined\n : debtusStatus(\n input['debtus'],\n request.spaceID,\n request.billID,\n request.currency,\n );\n if (debtusValue !== undefined && postingValue.status !== 'applied') {\n throw new TypeError('Debtus status requires applied posting');\n }\n if (debtusValue !== undefined) {\n const receipt = postingValue.receipt;\n if (receipt === undefined) {\n throw new TypeError('Debtus status requires an applied posting receipt');\n }\n validateDebtusMatchesReceipt(receipt, debtusValue);\n }\n return {\n ...request,\n resolvedSourceEffects,\n revision: revisionValue,\n posting: postingValue,\n debtus: debtusValue,\n createdAt,\n updatedAt,\n };\n}\n\nfunction sourceEffects(\n value: unknown,\n): readonly ISplitusResolvedSourceEffectV1[] {\n if (value === undefined) return [];\n if (!Array.isArray(value) || value.length > 100) {\n throw new RangeError('resolvedSourceEffects exceeds maximum item count 100');\n }\n const effects = value.map((item, index) => sourceEffect(item, index));\n return effects;\n}\n\nfunction sourceEffect(\n value: unknown,\n index: number,\n): ISplitusResolvedSourceEffectV1 {\n const input = record(value, `resolvedSourceEffects[${index}]`);\n const agreementID = optionalStorageID(input['agreementID'], 'agreementID');\n const priceRevision = input['priceRevision'];\n if (\n typeof priceRevision !== 'number' ||\n !Number.isSafeInteger(priceRevision) ||\n priceRevision < 0\n ) {\n throw new RangeError('priceRevision must be a non-negative safe integer');\n }\n const expectedAmount = parseExactDecimalString(\n input['expectedAmount'],\n );\n if (typeof input['sourceAttributionCaptured'] !== 'boolean') {\n throw new TypeError('sourceAttributionCaptured must be boolean');\n }\n const assetIDs =\n input['assetIDs'] === undefined\n ? []\n : identifierArray(input['assetIDs'], 'assetIDs', 100);\n const contactLinks = sourceContactLinks(input['contactLinks']);\n const ownerSpaceID = optionalStorageID(input['ownerSpaceID'], 'ownerSpaceID');\n const enrollmentID = optionalStorageID(input['enrollmentID'], 'enrollmentID');\n const chargeID = optionalStorageID(input['chargeID'], 'chargeID');\n const occurrenceID = optionalStorageID(input['occurrenceID'], 'occurrenceID');\n const direction = optionalEnum(\n input['direction'],\n ['expense', 'income', 'transfer'] as const,\n 'direction',\n );\n const temporalBasis = optionalEnum(\n input['temporalBasis'],\n [\n 'occurrence_service_cost',\n 'contract_period_cost',\n 'normalized_service_cost',\n ] as const,\n 'temporalBasis',\n );\n const economicPeriod =\n input['economicPeriod'] === undefined\n ? undefined\n : period(input['economicPeriod']);\n const eligible = optionalBoolean(\n input['invoiceReconciliationEligible'],\n 'invoiceReconciliationEligible',\n );\n const contactAttributions = sourceAttributions(\n input['contactAttributions'],\n 'contactAttributions',\n );\n const assetAttributions = sourceAttributions(\n input['assetAttributions'],\n 'assetAttributions',\n );\n return {\n priceID: storageID(input['priceID'], 'priceID'),\n priceRevision,\n expectedAmount,\n sourceAttributionCaptured: input['sourceAttributionCaptured'],\n assetIDs,\n contactLinks,\n ownerSpaceID,\n agreementID,\n enrollmentID,\n chargeID,\n occurrenceID,\n direction,\n temporalBasis,\n economicPeriod,\n invoiceReconciliationEligible: eligible,\n contactAttributions,\n assetAttributions,\n };\n}\n\nfunction sourceContactLinks(value: unknown): readonly ISplitusSourceContactLinkV1[] {\n if (value === undefined) return [];\n if (!Array.isArray(value) || value.length > 100) {\n throw new RangeError('contactLinks exceeds maximum item count 100');\n }\n const links = value.map((item, index) => {\n const input = record(item, `contactLinks[${index}]`);\n const roles = textArray(input['roles'], `contactLinks[${index}].roles`, 32);\n return {\n contactID: storageID(input['contactID'], `contactLinks[${index}].contactID`),\n roles,\n };\n });\n return links;\n}\n\nfunction sourceAttributions(\n value: unknown,\n name: string,\n): readonly ISplitusSourceAttributionV1[] {\n if (value === undefined) return [];\n if (!Array.isArray(value) || value.length > 100) {\n throw new RangeError(`${name} exceeds maximum item count 100`);\n }\n const values = value.map((item, index) => {\n const input = record(item, `${name}[${index}]`);\n return {\n id: storageID(input['id'], `${name}[${index}].id`),\n amount: parseExactDecimalString(input['amount']),\n };\n });\n return values;\n}\n\nfunction splitusBillListItem(value: unknown): ISplitusBillListItemV1 {\n const input = versionedRecord(value, 'bill list item');\n const billKind = enumValue(\n input['billKind'],\n ['general', 'utility'] as const,\n 'billKind',\n );\n const utilityKind =\n input['utilityKind'] === undefined\n ? undefined\n : enumValue(\n input['utilityKind'],\n ['electricity', 'gas', 'water', 'internet', 'other'] as const,\n 'utilityKind',\n );\n const periodValue =\n input['period'] === undefined ? undefined : period(input['period']);\n if (\n (billKind === 'utility') !==\n (utilityKind !== undefined && periodValue !== undefined)\n ) {\n throw new TypeError('utility list items require utilityKind and period');\n }\n const postingStatus = enumValue(\n input['postingStatus'],\n ['pending', 'posting', 'applied', 'attention'] as const,\n 'postingStatus',\n );\n const debtusSettlementStatus =\n input['debtusSettlementStatus'] === undefined\n ? undefined\n : settlementStatus(\n input['debtusSettlementStatus'],\n 'debtusSettlementStatus',\n );\n if (\n debtusSettlementStatus !== undefined &&\n postingStatus !== 'applied'\n ) {\n throw new TypeError('Debtus settlement status requires applied posting');\n }\n return {\n contractVersion: SPLITUS_BILL_CONTRACT_VERSION,\n spaceID: storageID(input['spaceID'], 'spaceID'),\n billID: storageID(input['billID'], 'billID'),\n title: optionalText(input['title'], 'title', 256),\n billKind,\n utilityKind,\n period: periodValue,\n currency: currency(input['currency']),\n actualAmount: positiveAmount(input['actualAmount'], 'actualAmount'),\n ownPaidAmount: nonNegativeAmount(input['ownPaidAmount'], 'ownPaidAmount'),\n ownOwedAmount: nonNegativeAmount(input['ownOwedAmount'], 'ownOwedAmount'),\n postingStatus,\n debtusSettlementStatus,\n createdAt: timestamp(input['createdAt'], 'createdAt'),\n };\n}\n\nfunction posting(value: unknown, billRevision: string): ISplitusBillPostingV1 {\n const input = record(value, 'posting');\n const status = enumValue(\n input['status'],\n ['pending', 'posting', 'applied', 'attention'] as const,\n 'posting.status',\n );\n const operationKey = storageID(input['operationKey'], 'posting.operationKey');\n const inputDigest = digest(input['inputDigest'], 'posting.inputDigest');\n const receiptValue =\n input['receipt'] === undefined\n ? undefined\n : postingReceipt(\n input['receipt'],\n billRevision,\n operationKey,\n inputDigest,\n );\n const attentionCode =\n input['attentionCode'] === undefined\n ? undefined\n : enumValue(\n input['attentionCode'],\n [\n 'authorization_changed',\n 'source_conflict',\n 'provider_rejected',\n 'invalid_provider_receipt',\n 'operator_action_required',\n ] as const,\n 'posting.attentionCode',\n );\n if ((status === 'applied') !== (receiptValue !== undefined)) {\n throw new TypeError('applied posting status requires exactly one receipt');\n }\n if ((status === 'attention') !== (attentionCode !== undefined)) {\n throw new TypeError('attention posting status requires exactly one code');\n }\n return {\n status,\n operationKey,\n inputDigest,\n receipt: receiptValue,\n attentionCode,\n };\n}\n\nfunction postingReceipt(\n value: unknown,\n billRevision: string,\n operationKey: string,\n inputDigest: string,\n): ISplitusBillPostingReceiptV1 {\n const input = record(value, 'posting.receipt');\n const revisionValue = positiveIntegerString(\n input['revision'],\n 'posting.receipt.revision',\n );\n const receiptOperationKey = storageID(\n input['operationKey'],\n 'posting.receipt.operationKey',\n );\n const receiptInputDigest = digest(\n input['inputDigest'],\n 'posting.receipt.inputDigest',\n );\n if (\n revisionValue !== billRevision ||\n receiptOperationKey !== operationKey ||\n receiptInputDigest !== inputDigest\n ) {\n throw new TypeError('posting receipt does not match the accepted bill revision');\n }\n if (\n !Array.isArray(input['obligationLines']) ||\n input['obligationLines'].length > MAX_SPLITUS_BILL_OBLIGATIONS\n ) {\n throw new RangeError('posting receipt obligationLines are unbounded');\n }\n const lineIDs = new Set<string>();\n const obligationIDs = new Set<string>();\n const obligationLines = input['obligationLines'].map((value, index) => {\n const line = record(value, `posting.receipt.obligationLines[${index}]`);\n const lineID = storageID(\n line['lineID'],\n `posting.receipt.obligationLines[${index}].lineID`,\n );\n if (lineIDs.has(lineID)) {\n throw new TypeError('posting receipt repeats an obligation line');\n }\n lineIDs.add(lineID);\n const ids = identifierArray(\n line['obligationIDs'],\n `posting.receipt.obligationLines[${index}].obligationIDs`,\n MAX_SPLITUS_OBLIGATION_IDS_PER_LINE,\n );\n for (const id of ids) {\n if (obligationIDs.has(id)) {\n throw new TypeError('posting receipt repeats an obligation ID');\n }\n obligationIDs.add(id);\n }\n return { lineID, obligationIDs: ids };\n });\n return {\n receiptID: storageID(input['receiptID'], 'posting.receipt.receiptID'),\n operationKey: receiptOperationKey,\n inputDigest: receiptInputDigest,\n revision: revisionValue,\n obligationLines,\n };\n}\n\nfunction debtusStatus(\n value: unknown,\n spaceID: string,\n billID: string,\n billCurrency: string,\n): ISplitusDebtusStatusV1 {\n const input = record(value, 'debtus');\n if (\n !Array.isArray(input['obligations']) ||\n input['obligations'].length > MAX_SPLITUS_BILL_OBLIGATIONS\n ) {\n throw new RangeError('Debtus obligations are unbounded');\n }\n const lineIDs = new Set<string>();\n const obligations = input['obligations'].map((item, index) => {\n const obligation = record(item, `debtus.obligations[${index}]`);\n const lineID = storageID(\n obligation['lineID'],\n `debtus.obligations[${index}].lineID`,\n );\n if (lineIDs.has(lineID)) {\n throw new TypeError('Debtus status repeats an obligation line');\n }\n lineIDs.add(lineID);\n const obligationCurrency = currency(obligation['currency']);\n if (obligationCurrency !== billCurrency) {\n throw new TypeError('Debtus obligation currency differs from the bill');\n }\n return {\n lineID,\n obligationIDs: identifierArray(\n obligation['obligationIDs'],\n `debtus.obligations[${index}].obligationIDs`,\n MAX_SPLITUS_OBLIGATION_IDS_PER_LINE,\n ),\n debtorContactID: storageID(\n obligation['debtorContactID'],\n `debtus.obligations[${index}].debtorContactID`,\n ),\n creditorContactID: storageID(\n obligation['creditorContactID'],\n `debtus.obligations[${index}].creditorContactID`,\n ),\n currency: obligationCurrency,\n principalAmount: positiveAmount(\n obligation['principalAmount'],\n `debtus.obligations[${index}].principalAmount`,\n ),\n outstandingAmount: nonNegativeAmount(\n obligation['outstandingAmount'],\n `debtus.obligations[${index}].outstandingAmount`,\n ),\n repaidAmount: nonNegativeAmount(\n obligation['repaidAmount'],\n `debtus.obligations[${index}].repaidAmount`,\n ),\n creditAmount: nonNegativeAmount(\n obligation['creditAmount'],\n `debtus.obligations[${index}].creditAmount`,\n ),\n status: settlementStatus(\n obligation['status'],\n `debtus.obligations[${index}].status`,\n ),\n settlementTarget: settlementTarget(\n obligation['settlementTarget'],\n spaceID,\n billID,\n lineID,\n ),\n };\n });\n return {\n status: settlementStatus(input['status'], 'debtus.status'),\n obligations,\n settlementTarget: settlementTarget(\n input['settlementTarget'],\n spaceID,\n billID,\n ),\n };\n}\n\nfunction validateDebtusMatchesReceipt(\n receipt: ISplitusBillPostingReceiptV1,\n debtus: ISplitusDebtusStatusV1,\n): void {\n if (receipt.obligationLines.length !== debtus.obligations.length) {\n throw new TypeError(\n 'Debtus obligations do not exactly match the applied posting receipt',\n );\n }\n const receiptLines = new Map(\n receipt.obligationLines.map((line) => [\n line.lineID,\n new Set(line.obligationIDs),\n ]),\n );\n for (const obligation of debtus.obligations) {\n const receiptIDs = receiptLines.get(obligation.lineID);\n if (\n receiptIDs === undefined ||\n receiptIDs.size !== obligation.obligationIDs.length ||\n obligation.obligationIDs.some((id) => !receiptIDs.has(id))\n ) {\n throw new TypeError(\n 'Debtus obligations do not exactly match the applied posting receipt',\n );\n }\n }\n}\n\nfunction settlementTarget(\n value: unknown,\n spaceID: string,\n billID: string,\n expectedLineID?: string,\n): ISplitusDebtusSettlementTargetV1 {\n const input = record(value, 'settlementTarget');\n const lineID =\n input['lineID'] === undefined\n ? undefined\n : storageID(input['lineID'], 'settlementTarget.lineID');\n if (\n input['route'] !== 'debtus.source-obligations' ||\n input['sourceNamespace'] !== 'splitus' ||\n input['spaceID'] !== spaceID ||\n input['sourceRecordID'] !== billID ||\n lineID !== expectedLineID\n ) {\n throw new TypeError('settlement target does not match the Splitus bill source');\n }\n return {\n route: 'debtus.source-obligations',\n spaceID,\n sourceNamespace: 'splitus',\n sourceRecordID: billID,\n lineID,\n };\n}\n\nfunction versionedRecord(value: unknown, name: string): Record<string, unknown> {\n const input = record(value, name);\n if (input['contractVersion'] !== SPLITUS_BILL_CONTRACT_VERSION) {\n throw new TypeError('unsupported Splitus bill contract version');\n }\n return input;\n}\n\nfunction boundedPageSize(value: unknown): number {\n if (\n typeof value !== 'number' ||\n !Number.isSafeInteger(value) ||\n value < 1 ||\n value > MAX_SPLITUS_BILL_LIST_PAGE_SIZE\n ) {\n throw new RangeError(\n `pageSize must be an integer from 1 to ${MAX_SPLITUS_BILL_LIST_PAGE_SIZE}`,\n );\n }\n return value;\n}\n\nfunction settlementStatus(\n value: unknown,\n name: string,\n): SplitusDebtusSettlementStatus {\n return enumValue(\n value,\n ['unsettled', 'part_settled', 'settled'] as const,\n name,\n );\n}\n\nfunction identifierArray(value: unknown, name: string, maximum: number): string[] {\n if (!Array.isArray(value) || value.length < 1 || value.length > maximum) {\n throw new RangeError(`${name} must contain 1 to ${maximum} identifiers`);\n }\n const seen = new Set<string>();\n return value.map((item, index) => {\n const id = storageID(item, `${name}[${index}]`);\n if (seen.has(id)) {\n throw new TypeError(`${name} contains a duplicate identifier`);\n }\n seen.add(id);\n return id;\n });\n}\n\nfunction digest(value: unknown, name: string): string {\n if (typeof value !== 'string' || !/^[0-9a-f]{64}$/.test(value)) {\n throw new TypeError(`${name} must be a lowercase SHA-256 digest`);\n }\n return value;\n}\n\nfunction positiveIntegerString(value: unknown, name: string): string {\n if (typeof value !== 'string' || !/^[1-9][0-9]*$/.test(value)) {\n throw new TypeError(`${name} must be a canonical positive integer string`);\n }\n if (BigInt(value) > 18_446_744_073_709_551_615n) {\n throw new RangeError(`${name} exceeds unsigned 64-bit range`);\n }\n return value;\n}\n\nfunction timestamp(value: unknown, name: string): string {\n if (\n typeof value !== 'string' ||\n !/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/.test(\n value,\n ) ||\n Number.isNaN(Date.parse(value))\n ) {\n throw new TypeError(`${name} must be an RFC 3339 timestamp`);\n }\n date(value.slice(0, 10), name);\n return value;\n}\n\nfunction nonNegativeAmount(\n value: unknown,\n name: string,\n): ExactDecimalString {\n try {\n return parseExactDecimalString(value);\n } catch (error) {\n if (error instanceof RangeError) {\n throw new RangeError(`${name}: ${error.message}`);\n }\n if (error instanceof Error) {\n throw new TypeError(`${name}: ${error.message}`);\n }\n throw error;\n }\n}\n\nfunction validateAllocationTotals(request: ICreateSplitusBillV1Request): void {\n const contacts = new Set<string>();\n for (const allocation of [\n ...request.paidAllocations,\n ...request.owedAllocations,\n ]) {\n contacts.add(allocation.contactID);\n }\n if (contacts.size < 2 || contacts.size > MAX_SPLITUS_BILL_PARTICIPANTS) {\n throw new RangeError(\n `bill must have 2 to ${MAX_SPLITUS_BILL_PARTICIPANTS} participants`,\n );\n }\n const actual = amountToMinorUnits(request.actualAmount);\n if (sumAllocations(request.paidAllocations) !== actual) {\n throw new RangeError('paid allocations must reconcile to actualAmount');\n }\n if (sumAllocations(request.owedAllocations) !== actual) {\n throw new RangeError('owed allocations must reconcile to actualAmount');\n }\n}\n\nfunction allocations(value: unknown, name: string): ISplitusBillAllocationV1[] {\n if (!Array.isArray(value) || value.length < 1 || value.length > MAX_SPLITUS_BILL_PARTICIPANTS) {\n throw new RangeError(\n `${name} must contain 1 to ${MAX_SPLITUS_BILL_PARTICIPANTS} allocations`,\n );\n }\n const allocationIDs = new Set<string>();\n const contactIDs = new Set<string>();\n return value.map((item, index) => {\n const input = record(item, `${name}[${index}]`);\n const allocationID = storageID(\n input['allocationID'],\n `${name}[${index}].allocationID`,\n );\n const contactID = storageID(\n input['contactID'],\n `${name}[${index}].contactID`,\n );\n if (allocationIDs.has(allocationID) || contactIDs.has(contactID)) {\n throw new TypeError(`${name} contains a duplicate allocation or contact`);\n }\n allocationIDs.add(allocationID);\n contactIDs.add(contactID);\n return {\n allocationID,\n contactID,\n amount: positiveAmount(input['amount'], `${name}[${index}].amount`),\n };\n });\n}\n\nfunction sumAllocations(allocationsToSum: readonly ISplitusBillAllocationV1[]): bigint {\n let total = 0n;\n for (const allocation of allocationsToSum) {\n total += amountToMinorUnits(allocation.amount);\n if (total > MAX_EXACT_MINOR_UNITS) {\n throw new RangeError('allocation total exceeds the Splitus contract limit');\n }\n }\n return total;\n}\n\nfunction amountToMinorUnits(value: ExactDecimalString): bigint {\n return BigInt(value.replace('.', ''));\n}\n\nfunction positiveAmount(value: unknown, name: string): ExactDecimalString {\n const amount = parseExactDecimalString(value);\n if (amountToMinorUnits(amount) === 0n) {\n throw new RangeError(`${name} must be positive`);\n }\n return amount;\n}\n\nfunction utility(value: unknown): ISplitusUtilityDetailsV1 {\n const input = record(value, 'utility');\n return {\n utilityKind: enumValue(\n input['utilityKind'],\n ['electricity', 'gas', 'water', 'internet', 'other'] as const,\n 'utility.utilityKind',\n ),\n providerName: optionalText(\n input['providerName'],\n 'utility.providerName',\n 256,\n ),\n period: period(input['period']),\n };\n}\n\nfunction recurring(\n value: unknown,\n actualAmount: ExactDecimalString,\n billID: string,\n): ISplitusRecurringOccurrenceV1 {\n const input = record(value, 'recurringOccurrence');\n const expectedAmount =\n input['expectedAmount'] === undefined\n ? undefined\n : positiveAmount(\n input['expectedAmount'],\n 'recurringOccurrence.expectedAmount',\n );\n const standingChargeAmount =\n input['standingChargeAmount'] === undefined\n ? undefined\n : positiveAmount(\n input['standingChargeAmount'],\n 'recurringOccurrence.standingChargeAmount',\n );\n const expectedComparison = input['expectedComparison'] === undefined\n ? undefined\n : enumValue(\n input['expectedComparison'],\n ['not_available', 'matches', 'increased', 'decreased'] as const,\n 'recurringOccurrence.expectedComparison',\n );\n if (\n expectedAmount === undefined &&\n expectedComparison !== undefined &&\n expectedComparison !== 'not_available'\n ) {\n throw new TypeError(\n 'comparison must be not_available exactly when expectedAmount is absent',\n );\n }\n if (expectedAmount !== undefined) {\n const expectedComparisonForAmounts = compareAmounts(\n actualAmount,\n expectedAmount,\n );\n if (expectedComparison !== undefined && expectedComparison !== expectedComparisonForAmounts) {\n throw new TypeError('comparison does not match expected and actual amounts');\n }\n }\n if (\n standingChargeAmount !== undefined &&\n amountToMinorUnits(standingChargeAmount) > amountToMinorUnits(actualAmount)\n ) {\n throw new RangeError('standing charge cannot exceed actualAmount');\n }\n return {\n happeningID: storageID(\n input['happeningID'],\n 'recurringOccurrence.happeningID',\n ),\n occurrenceID: storageID(\n input['occurrenceID'],\n 'recurringOccurrence.occurrenceID',\n ),\n chargeID:\n input['chargeID'] === undefined\n ? undefined\n : storageID(input['chargeID'], 'recurringOccurrence.chargeID'),\n expectedAmount,\n standingChargeAmount,\n expectedComparison,\n previousComparable:\n input['previousComparable'] === undefined\n ? undefined\n : previousComparable(\n input['previousComparable'],\n actualAmount,\n billID,\n ),\n };\n}\n\nfunction previousComparable(\n value: unknown,\n actualAmount: ExactDecimalString,\n billID: string,\n): ISplitusPreviousComparableBillV1 {\n const input = record(value, 'recurringOccurrence.previousComparable');\n const previousBillID = storageID(\n input['billID'],\n 'recurringOccurrence.previousComparable.billID',\n );\n if (previousBillID === billID) {\n throw new TypeError('previous comparable bill must have a different billID');\n }\n const previousActualAmount = positiveAmount(\n input['actualAmount'],\n 'recurringOccurrence.previousComparable.actualAmount',\n );\n const comparison = enumValue(\n input['comparison'],\n ['matches', 'increased', 'decreased'] as const,\n 'recurringOccurrence.previousComparable.comparison',\n );\n const expectedComparison = compareAmounts(\n actualAmount,\n previousActualAmount,\n );\n if (comparison !== expectedComparison) {\n throw new TypeError(\n 'previous comparison does not match current and prior actual amounts',\n );\n }\n return {\n billID: previousBillID,\n actualAmount: previousActualAmount,\n comparison,\n };\n}\n\nfunction compareAmounts(\n current: ExactDecimalString,\n baseline: ExactDecimalString,\n): Exclude<SplitusExpectedActualComparison, 'not_available'> {\n const currentMinor = amountToMinorUnits(current);\n const baselineMinor = amountToMinorUnits(baseline);\n return currentMinor === baselineMinor\n ? 'matches'\n : currentMinor > baselineMinor\n ? 'increased'\n : 'decreased';\n}\n\nfunction period(value: unknown): ISplitusBillingPeriodV1 {\n const input = record(value, 'period');\n const startDate = date(input['startDate'], 'period.startDate');\n const endDate = date(input['endDate'], 'period.endDate');\n if (endDate < startDate) {\n throw new RangeError('period.endDate must not precede period.startDate');\n }\n return { startDate, endDate };\n}\n\nfunction date(value: unknown, name: string): string {\n if (typeof value !== 'string') {\n throw new TypeError(`${name} must be an ISO calendar date`);\n }\n const match = datePattern.exec(value);\n if (match === null) {\n throw new TypeError(`${name} must be an ISO calendar date`);\n }\n const parsed = new Date(`${value}T00:00:00.000Z`);\n if (Number.isNaN(parsed.valueOf()) || parsed.toISOString().slice(0, 10) !== value) {\n throw new TypeError(`${name} must be a real ISO calendar date`);\n }\n return value;\n}\n\nfunction currency(value: unknown): SplitusCurrencyCode {\n return enumValue(value, ['EUR', 'GBP', 'USD'] as const, 'currency');\n}\n\nfunction storageID(value: unknown, name: string): string {\n if (\n typeof value !== 'string' ||\n value.length === 0 ||\n value.trim() !== value ||\n new TextEncoder().encode(value).length > 512 ||\n value.includes('/') ||\n hasControlCharacters(value) ||\n value === '.' ||\n value === '..' ||\n (/^__/.test(value) && /__$/.test(value))\n ) {\n throw new TypeError(`${name} is not a safe identifier`);\n }\n return value;\n}\n\nfunction optionalText(\n value: unknown,\n name: string,\n maxBytes: number,\n): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n if (\n typeof value !== 'string' ||\n value.length === 0 ||\n value.trim() !== value ||\n new TextEncoder().encode(value).length > maxBytes ||\n hasControlCharacters(value)\n ) {\n throw new TypeError(`${name} is empty, padded, too long, or contains controls`);\n }\n return value;\n}\n\nfunction hasControlCharacters(value: string): boolean {\n for (const character of value) {\n const code = character.charCodeAt(0);\n if (code < 0x20 || code === 0x7f) {\n return true;\n }\n }\n return false;\n}\n\nfunction record(value: unknown, name: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new TypeError(`${name} must be an object`);\n }\n return value as Record<string, unknown>;\n}\n\nfunction enumValue<const T extends readonly string[]>(\n value: unknown,\n allowed: T,\n name: string,\n): T[number] {\n if (typeof value !== 'string' || !allowed.includes(value)) {\n throw new TypeError(`${name} has an unsupported value`);\n }\n return value as T[number];\n}\n\nfunction optionalStorageID(value: unknown, name: string): string | undefined {\n return value === undefined ? undefined : storageID(value, name);\n}\n\nfunction optionalEnum<const T extends readonly string[]>(\n value: unknown,\n allowed: T,\n name: string,\n): T[number] | undefined {\n return value === undefined ? undefined : enumValue(value, allowed, name);\n}\n\nfunction optionalBoolean(value: unknown, name: string): boolean | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== 'boolean') throw new TypeError(`${name} must be boolean`);\n return value;\n}\n\nfunction textArray(value: unknown, name: string, maximum: number): string[] {\n if (value === undefined) return [];\n if (!Array.isArray(value) || value.length > maximum) {\n throw new RangeError(`${name} exceeds maximum item count ${maximum}`);\n }\n const values = value.map((item, index) =>\n optionalText(item, `${name}[${index}]`, 100),\n );\n if (values.some((item) => item === undefined)) {\n throw new TypeError(`${name} contains an invalid value`);\n }\n const result = values as string[];\n return result;\n}\n","import { InjectionToken } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport {\n ICreateSplitRequest,\n ICreateSplitResponse,\n ICreateSplitusBillV1Request,\n ICreateSplitusBillV1Response,\n IGetSplitusBillV1Request,\n IGetSplitusBillV1Response,\n IListSplitusBillsV1Request,\n IListSplitusBillsV1Response,\n ISplit,\n ISplitListItem,\n} from './dto';\n\n/** @deprecated Use `ISplitusBillServiceV1`. */\nexport interface ISplitusService {\n /** REAL: POST /api4splitus/create-split. Payer is the authenticated user. */\n createSplit(request: ICreateSplitRequest): Observable<ICreateSplitResponse>;\n /** REAL: GET /api4splitus/split?spaceID=&id= */\n getSplit(spaceID: string, id: string): Observable<ISplit>;\n /** REAL: GET /api4splitus/splits?spaceID= */\n getSplits(spaceID: string): Observable<ISplitListItem[]>;\n}\n\n/** @deprecated Use `SPLITUS_BILL_SERVICE_V1`. */\nexport const SPLITUS_SERVICE = new InjectionToken<ISplitusService>('SplitusService');\n\nexport interface ISplitusBillServiceV1 {\n createBill(\n request: ICreateSplitusBillV1Request,\n ): Observable<ICreateSplitusBillV1Response>;\n getBill(\n request: IGetSplitusBillV1Request,\n ): Observable<IGetSplitusBillV1Response>;\n listBills(\n request: IListSplitusBillsV1Request,\n ): Observable<IListSplitusBillsV1Response>;\n}\n\nexport const SPLITUS_BILL_SERVICE_V1 =\n new InjectionToken<ISplitusBillServiceV1>('SplitusBillServiceV1');\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,262 @@
|
|
|
1
1
|
import { InjectionToken } from '@angular/core';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/** The first stable Splitus bill browser/host wire contract. */
|
|
5
|
+
declare const SPLITUS_BILL_CONTRACT_VERSION: 1;
|
|
6
|
+
declare const MAX_SPLITUS_BILL_PARTICIPANTS = 256;
|
|
7
|
+
declare const MAX_SPLITUS_BILL_LIST_PAGE_SIZE = 100;
|
|
8
|
+
declare const MAX_SPLITUS_BILL_OBLIGATIONS = 256;
|
|
9
|
+
declare const MAX_SPLITUS_OBLIGATION_IDS_PER_LINE = 256;
|
|
10
|
+
type SplitusBillContractVersion = typeof SPLITUS_BILL_CONTRACT_VERSION;
|
|
11
|
+
/**
|
|
12
|
+
* A canonical, non-negative major-unit amount with exactly two fraction
|
|
13
|
+
* digits. Examples: `0.00`, `30.00`, `90.00`.
|
|
14
|
+
*
|
|
15
|
+
* The alias documents the wire type; use `parseExactDecimalString()` at an
|
|
16
|
+
* untrusted boundary. JavaScript numbers and minor-unit numbers are not part
|
|
17
|
+
* of this contract.
|
|
18
|
+
*/
|
|
19
|
+
type ExactDecimalString = string;
|
|
20
|
+
/** Currencies whose minor unit is exactly two decimal digits in this contract. */
|
|
21
|
+
type SplitusCurrencyCode = 'EUR' | 'GBP' | 'USD';
|
|
22
|
+
type SplitusBillKind = 'general' | 'utility';
|
|
23
|
+
type SplitusUtilityKind = 'electricity' | 'gas' | 'water' | 'internet' | 'other';
|
|
24
|
+
type SplitusBillPostingStatus = 'pending' | 'posting' | 'applied' | 'attention';
|
|
25
|
+
type SplitusDebtusSettlementStatus = 'unsettled' | 'part_settled' | 'settled';
|
|
26
|
+
type SplitusExpectedActualComparison = 'not_available' | 'matches' | 'increased' | 'decreased';
|
|
27
|
+
type SplitusBillAttentionCode = 'authorization_changed' | 'source_conflict' | 'provider_rejected' | 'invalid_provider_receipt' | 'operator_action_required';
|
|
28
|
+
interface ISplitusBillAllocationV1 {
|
|
29
|
+
/** Stable within the bill revision, independent of array ordering. */
|
|
30
|
+
readonly allocationID: string;
|
|
31
|
+
/**
|
|
32
|
+
* Contactus identity in this Space. Hosts resolve its real display data from
|
|
33
|
+
* Contactus; this opaque ID is never a user-facing label.
|
|
34
|
+
*/
|
|
35
|
+
readonly contactID: string;
|
|
36
|
+
readonly amount: ExactDecimalString;
|
|
37
|
+
}
|
|
38
|
+
interface ISplitusBillingPeriodV1 {
|
|
39
|
+
/** Inclusive ISO calendar date. */
|
|
40
|
+
readonly startDate: string;
|
|
41
|
+
/** Inclusive ISO calendar date; must not precede `startDate`. */
|
|
42
|
+
readonly endDate: string;
|
|
43
|
+
}
|
|
44
|
+
interface ISplitusUtilityDetailsV1 {
|
|
45
|
+
readonly utilityKind: SplitusUtilityKind;
|
|
46
|
+
readonly providerName?: string;
|
|
47
|
+
readonly period: ISplitusBillingPeriodV1;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A reference to the Calendarius occurrence represented by this actual bill.
|
|
51
|
+
* `expectedAmount` and `standingChargeAmount` are context only; neither is a
|
|
52
|
+
* paid expense. `actualAmount` on the enclosing bill remains mandatory.
|
|
53
|
+
*/
|
|
54
|
+
interface ISplitusRecurringOccurrenceV1 {
|
|
55
|
+
readonly happeningID: string;
|
|
56
|
+
readonly occurrenceID: string;
|
|
57
|
+
readonly chargeID?: string;
|
|
58
|
+
readonly expectedAmount?: ExactDecimalString;
|
|
59
|
+
readonly standingChargeAmount?: ExactDecimalString;
|
|
60
|
+
readonly expectedComparison?: SplitusExpectedActualComparison;
|
|
61
|
+
readonly previousComparable?: ISplitusPreviousComparableBillV1;
|
|
62
|
+
}
|
|
63
|
+
interface ISplitusPreviousComparableBillV1 {
|
|
64
|
+
readonly billID: string;
|
|
65
|
+
readonly actualAmount: ExactDecimalString;
|
|
66
|
+
readonly comparison: Exclude<SplitusExpectedActualComparison, 'not_available'>;
|
|
67
|
+
}
|
|
68
|
+
type SplitusResolvedSourceDirection = 'expense' | 'income' | 'transfer';
|
|
69
|
+
type SplitusResolvedSourceTemporalBasis = 'occurrence_service_cost' | 'contract_period_cost' | 'normalized_service_cost';
|
|
70
|
+
interface ISplitusSourceContactLinkV1 {
|
|
71
|
+
readonly contactID: string;
|
|
72
|
+
readonly roles: readonly string[];
|
|
73
|
+
}
|
|
74
|
+
interface ISplitusSourceAttributionV1 {
|
|
75
|
+
readonly id: string;
|
|
76
|
+
readonly amount: ExactDecimalString;
|
|
77
|
+
}
|
|
78
|
+
/** Immutable source facts captured by Splitus when the actual bill is accepted. */
|
|
79
|
+
interface ISplitusResolvedSourceEffectV1 {
|
|
80
|
+
readonly priceID: string;
|
|
81
|
+
readonly priceRevision: number;
|
|
82
|
+
readonly expectedAmount: ExactDecimalString;
|
|
83
|
+
readonly sourceAttributionCaptured: boolean;
|
|
84
|
+
readonly assetIDs: readonly string[];
|
|
85
|
+
readonly contactLinks: readonly ISplitusSourceContactLinkV1[];
|
|
86
|
+
/** Present as one complete group for agreement-backed reconciliation. */
|
|
87
|
+
readonly ownerSpaceID?: string;
|
|
88
|
+
readonly agreementID?: string;
|
|
89
|
+
readonly enrollmentID?: string;
|
|
90
|
+
readonly chargeID?: string;
|
|
91
|
+
readonly occurrenceID?: string;
|
|
92
|
+
readonly direction?: SplitusResolvedSourceDirection;
|
|
93
|
+
readonly temporalBasis?: SplitusResolvedSourceTemporalBasis;
|
|
94
|
+
readonly economicPeriod?: ISplitusBillingPeriodV1;
|
|
95
|
+
readonly invoiceReconciliationEligible?: boolean;
|
|
96
|
+
readonly contactAttributions: readonly ISplitusSourceAttributionV1[];
|
|
97
|
+
readonly assetAttributions: readonly ISplitusSourceAttributionV1[];
|
|
98
|
+
}
|
|
99
|
+
interface ICreateSplitusBillV1Request {
|
|
100
|
+
readonly contractVersion: SplitusBillContractVersion;
|
|
101
|
+
readonly spaceID: string;
|
|
102
|
+
/**
|
|
103
|
+
* Stable across duplicate submission and lost-response retries. Reusing the
|
|
104
|
+
* same ID with changed paid/owed allocations is a provider conflict.
|
|
105
|
+
*/
|
|
106
|
+
readonly billID: string;
|
|
107
|
+
/**
|
|
108
|
+
* Audit identity of the authenticated actor. The server must bind this to
|
|
109
|
+
* its trusted authentication context. It never implies a paid or owed
|
|
110
|
+
* allocation.
|
|
111
|
+
*/
|
|
112
|
+
readonly recorderUserID: string;
|
|
113
|
+
readonly title?: string;
|
|
114
|
+
readonly billKind: SplitusBillKind;
|
|
115
|
+
readonly currency: SplitusCurrencyCode;
|
|
116
|
+
/** Actual paid amount. An expectation is never accepted in its place. */
|
|
117
|
+
readonly actualAmount: ExactDecimalString;
|
|
118
|
+
/** Explicit sources of payment; one contact may also owe a share. */
|
|
119
|
+
readonly paidAllocations: readonly ISplitusBillAllocationV1[];
|
|
120
|
+
/** Explicit responsibility shares. */
|
|
121
|
+
readonly owedAllocations: readonly ISplitusBillAllocationV1[];
|
|
122
|
+
/** Required exactly when `billKind` is `utility`. */
|
|
123
|
+
readonly utility?: ISplitusUtilityDetailsV1;
|
|
124
|
+
readonly recurringOccurrence?: ISplitusRecurringOccurrenceV1;
|
|
125
|
+
}
|
|
126
|
+
interface ISplitusDebtusReceiptLineV1 {
|
|
127
|
+
readonly lineID: string;
|
|
128
|
+
readonly obligationIDs: readonly string[];
|
|
129
|
+
}
|
|
130
|
+
interface ISplitusBillPostingReceiptV1 {
|
|
131
|
+
readonly receiptID: string;
|
|
132
|
+
readonly operationKey: string;
|
|
133
|
+
readonly inputDigest: string;
|
|
134
|
+
readonly revision: string;
|
|
135
|
+
readonly obligationLines: readonly ISplitusDebtusReceiptLineV1[];
|
|
136
|
+
}
|
|
137
|
+
interface ISplitusBillPostingV1 {
|
|
138
|
+
readonly status: SplitusBillPostingStatus;
|
|
139
|
+
/** Durable identity of the retry-safe provider operation. */
|
|
140
|
+
readonly operationKey: string;
|
|
141
|
+
/** Digest of the exact accepted source revision and allocations. */
|
|
142
|
+
readonly inputDigest: string;
|
|
143
|
+
/** Present exactly when `status` is `applied`. */
|
|
144
|
+
readonly receipt?: ISplitusBillPostingReceiptV1;
|
|
145
|
+
/** Present exactly when `status` is `attention`. */
|
|
146
|
+
readonly attentionCode?: SplitusBillAttentionCode;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* An application-relative target. The host resolves it through its injected
|
|
150
|
+
* Debtus navigation adapter; contracts never hard-code debtus.app or another
|
|
151
|
+
* deployment origin.
|
|
152
|
+
*/
|
|
153
|
+
interface ISplitusDebtusSettlementTargetV1 {
|
|
154
|
+
readonly route: 'debtus.source-obligations';
|
|
155
|
+
readonly spaceID: string;
|
|
156
|
+
readonly sourceNamespace: 'splitus';
|
|
157
|
+
readonly sourceRecordID: string;
|
|
158
|
+
readonly lineID?: string;
|
|
159
|
+
}
|
|
160
|
+
interface ISplitusDebtusObligationV1 {
|
|
161
|
+
readonly lineID: string;
|
|
162
|
+
readonly obligationIDs: readonly string[];
|
|
163
|
+
readonly debtorContactID: string;
|
|
164
|
+
readonly creditorContactID: string;
|
|
165
|
+
readonly currency: SplitusCurrencyCode;
|
|
166
|
+
readonly principalAmount: ExactDecimalString;
|
|
167
|
+
readonly outstandingAmount: ExactDecimalString;
|
|
168
|
+
readonly repaidAmount: ExactDecimalString;
|
|
169
|
+
readonly creditAmount: ExactDecimalString;
|
|
170
|
+
readonly status: SplitusDebtusSettlementStatus;
|
|
171
|
+
readonly settlementTarget: ISplitusDebtusSettlementTargetV1;
|
|
172
|
+
}
|
|
173
|
+
interface ISplitusDebtusStatusV1 {
|
|
174
|
+
/** Current state read from Debtus, never a Splitus-maintained balance. */
|
|
175
|
+
readonly status: SplitusDebtusSettlementStatus;
|
|
176
|
+
readonly obligations: readonly ISplitusDebtusObligationV1[];
|
|
177
|
+
readonly settlementTarget: ISplitusDebtusSettlementTargetV1;
|
|
178
|
+
}
|
|
179
|
+
interface ISplitusBillV1 extends ICreateSplitusBillV1Request {
|
|
180
|
+
readonly resolvedSourceEffects?: readonly ISplitusResolvedSourceEffectV1[];
|
|
181
|
+
/** Canonical positive decimal integer encoded as a string. */
|
|
182
|
+
readonly revision: string;
|
|
183
|
+
readonly posting: ISplitusBillPostingV1;
|
|
184
|
+
/** Absent until a Debtus financial projection is available. */
|
|
185
|
+
readonly debtus?: ISplitusDebtusStatusV1;
|
|
186
|
+
readonly createdAt: string;
|
|
187
|
+
readonly updatedAt: string;
|
|
188
|
+
}
|
|
189
|
+
interface ICreateSplitusBillV1Response {
|
|
190
|
+
readonly contractVersion: SplitusBillContractVersion;
|
|
191
|
+
readonly bill: ISplitusBillV1;
|
|
192
|
+
}
|
|
193
|
+
interface IGetSplitusBillV1Request {
|
|
194
|
+
readonly contractVersion: SplitusBillContractVersion;
|
|
195
|
+
readonly spaceID: string;
|
|
196
|
+
readonly billID: string;
|
|
197
|
+
}
|
|
198
|
+
interface IGetSplitusBillV1Response {
|
|
199
|
+
readonly contractVersion: SplitusBillContractVersion;
|
|
200
|
+
readonly bill: ISplitusBillV1;
|
|
201
|
+
}
|
|
202
|
+
interface ISplitusBillListItemV1 {
|
|
203
|
+
readonly contractVersion: SplitusBillContractVersion;
|
|
204
|
+
readonly spaceID: string;
|
|
205
|
+
readonly billID: string;
|
|
206
|
+
readonly title?: string;
|
|
207
|
+
readonly billKind: SplitusBillKind;
|
|
208
|
+
readonly utilityKind?: SplitusUtilityKind;
|
|
209
|
+
readonly period?: ISplitusBillingPeriodV1;
|
|
210
|
+
readonly currency: SplitusCurrencyCode;
|
|
211
|
+
readonly actualAmount: ExactDecimalString;
|
|
212
|
+
readonly ownPaidAmount: ExactDecimalString;
|
|
213
|
+
readonly ownOwedAmount: ExactDecimalString;
|
|
214
|
+
readonly postingStatus: SplitusBillPostingStatus;
|
|
215
|
+
/** Debtus-derived and absent before the bill has a financial projection. */
|
|
216
|
+
readonly debtusSettlementStatus?: SplitusDebtusSettlementStatus;
|
|
217
|
+
readonly createdAt: string;
|
|
218
|
+
}
|
|
219
|
+
interface IListSplitusBillsV1Request {
|
|
220
|
+
readonly contractVersion: SplitusBillContractVersion;
|
|
221
|
+
readonly spaceID: string;
|
|
222
|
+
readonly pageSize: number;
|
|
223
|
+
readonly cursor?: string;
|
|
224
|
+
readonly utilityKind?: SplitusUtilityKind;
|
|
225
|
+
readonly period?: ISplitusBillingPeriodV1;
|
|
226
|
+
}
|
|
227
|
+
interface IListSplitusBillsV1Response {
|
|
228
|
+
readonly contractVersion: SplitusBillContractVersion;
|
|
229
|
+
/** Echoes the accepted request bound so callers can verify the page. */
|
|
230
|
+
readonly pageSize: number;
|
|
231
|
+
/** Contains no more than `pageSize` items and never more than 100. */
|
|
232
|
+
readonly items: readonly ISplitusBillListItemV1[];
|
|
233
|
+
readonly nextCursor?: string;
|
|
234
|
+
}
|
|
235
|
+
declare function parseExactDecimalString(value: unknown): ExactDecimalString;
|
|
236
|
+
declare function parseCreateSplitusBillV1Request(value: unknown): ICreateSplitusBillV1Request;
|
|
237
|
+
/**
|
|
238
|
+
* Executable host-boundary check for the request's audit claim. The trusted
|
|
239
|
+
* authenticated identity is supplied by the host, never derived from the
|
|
240
|
+
* request itself.
|
|
241
|
+
*/
|
|
242
|
+
declare function assertCreateSplitusBillV1Recorder(request: ICreateSplitusBillV1Request, authenticatedUserID: string): void;
|
|
243
|
+
declare function parseListSplitusBillsV1Request(value: unknown): IListSplitusBillsV1Request;
|
|
244
|
+
declare function parseGetSplitusBillV1Request(value: unknown): IGetSplitusBillV1Request;
|
|
245
|
+
declare function parseCreateSplitusBillV1Response(value: unknown): ICreateSplitusBillV1Response;
|
|
246
|
+
declare function parseGetSplitusBillV1Response(value: unknown): IGetSplitusBillV1Response;
|
|
247
|
+
declare function parseListSplitusBillsV1Response(value: unknown, requestedPageSize?: number): IListSplitusBillsV1Response;
|
|
248
|
+
declare function parseSplitusBillV1(value: unknown): ISplitusBillV1;
|
|
249
|
+
|
|
250
|
+
/** @deprecated Use the Splitus bill contract types exported from `bill-v1`. */
|
|
5
251
|
type SplitMode = 'equally' | 'exact-amount' | 'percentage';
|
|
252
|
+
/** @deprecated Use `SplitusCurrencyCode` from the Splitus bill contract. */
|
|
6
253
|
type CurrencyCode = 'EUR' | 'USD';
|
|
7
254
|
/**
|
|
8
255
|
* One participant's custom share for `exact-amount` / `percentage` split
|
|
9
256
|
* modes. An omitted/empty `contactID` denotes the payer's own share. Ignored
|
|
10
257
|
* (and may be omitted) for `equally`, which the backend computes itself.
|
|
11
258
|
*/
|
|
259
|
+
/** @deprecated Use explicit paid and owed allocations in `ICreateSplitusBillV1Request`. */
|
|
12
260
|
interface ISplitShare {
|
|
13
261
|
readonly contactID?: string;
|
|
14
262
|
/** Decimal string, e.g. "35.00" — required for `exact-amount`. */
|
|
@@ -16,6 +264,7 @@ interface ISplitShare {
|
|
|
16
264
|
/** Decimal string, e.g. "33.34" — required for `percentage`. */
|
|
17
265
|
readonly percent?: string;
|
|
18
266
|
}
|
|
267
|
+
/** @deprecated Use `ICreateSplitusBillV1Request`. */
|
|
19
268
|
interface ICreateSplitRequest {
|
|
20
269
|
readonly spaceID: string;
|
|
21
270
|
readonly title?: string;
|
|
@@ -32,11 +281,13 @@ interface ICreateSplitRequest {
|
|
|
32
281
|
/** Required for `exact-amount` / `percentage`; ignored for `equally`. */
|
|
33
282
|
readonly shares?: ISplitShare[];
|
|
34
283
|
}
|
|
284
|
+
/** @deprecated Use `ISplitusDebtusObligationV1`. */
|
|
35
285
|
interface ICreateSplitTransfer {
|
|
36
286
|
readonly id: string;
|
|
37
287
|
readonly contactID: string;
|
|
38
288
|
readonly amount: number;
|
|
39
289
|
}
|
|
290
|
+
/** @deprecated Use `ICreateSplitusBillV1Response`. */
|
|
40
291
|
interface ICreateSplitResponse {
|
|
41
292
|
readonly id: string;
|
|
42
293
|
/**
|
|
@@ -49,7 +300,9 @@ interface ICreateSplitResponse {
|
|
|
49
300
|
* "settled" or "outstanding", derived server-side by reading the linked
|
|
50
301
|
* Debtus transfers — never computed or cached on the client.
|
|
51
302
|
*/
|
|
303
|
+
/** @deprecated Use `SplitusDebtusSettlementStatus`. */
|
|
52
304
|
type SplitShareStatus = 'settled' | 'outstanding';
|
|
305
|
+
/** @deprecated Use `ISplitusBillAllocationV1`. */
|
|
53
306
|
interface ISplitParticipant {
|
|
54
307
|
readonly contactID?: string;
|
|
55
308
|
readonly userID?: string;
|
|
@@ -58,6 +311,7 @@ interface ISplitParticipant {
|
|
|
58
311
|
readonly isPayer?: boolean;
|
|
59
312
|
readonly status: SplitShareStatus;
|
|
60
313
|
}
|
|
314
|
+
/** @deprecated Use `ISplitusBillV1`. */
|
|
61
315
|
interface ISplit {
|
|
62
316
|
readonly id: string;
|
|
63
317
|
readonly title?: string;
|
|
@@ -66,6 +320,7 @@ interface ISplit {
|
|
|
66
320
|
readonly status: string;
|
|
67
321
|
readonly participants: ISplitParticipant[];
|
|
68
322
|
}
|
|
323
|
+
/** @deprecated Use `ISplitusBillListItemV1`. */
|
|
69
324
|
interface ISplitListItem {
|
|
70
325
|
readonly id: string;
|
|
71
326
|
readonly title?: string;
|
|
@@ -75,6 +330,7 @@ interface ISplitListItem {
|
|
|
75
330
|
readonly membersCount: number;
|
|
76
331
|
}
|
|
77
332
|
|
|
333
|
+
/** @deprecated Use `ISplitusBillServiceV1`. */
|
|
78
334
|
interface ISplitusService {
|
|
79
335
|
/** REAL: POST /api4splitus/create-split. Payer is the authenticated user. */
|
|
80
336
|
createSplit(request: ICreateSplitRequest): Observable<ICreateSplitResponse>;
|
|
@@ -83,7 +339,14 @@ interface ISplitusService {
|
|
|
83
339
|
/** REAL: GET /api4splitus/splits?spaceID= */
|
|
84
340
|
getSplits(spaceID: string): Observable<ISplitListItem[]>;
|
|
85
341
|
}
|
|
342
|
+
/** @deprecated Use `SPLITUS_BILL_SERVICE_V1`. */
|
|
86
343
|
declare const SPLITUS_SERVICE: InjectionToken<ISplitusService>;
|
|
344
|
+
interface ISplitusBillServiceV1 {
|
|
345
|
+
createBill(request: ICreateSplitusBillV1Request): Observable<ICreateSplitusBillV1Response>;
|
|
346
|
+
getBill(request: IGetSplitusBillV1Request): Observable<IGetSplitusBillV1Response>;
|
|
347
|
+
listBills(request: IListSplitusBillsV1Request): Observable<IListSplitusBillsV1Response>;
|
|
348
|
+
}
|
|
349
|
+
declare const SPLITUS_BILL_SERVICE_V1: InjectionToken<ISplitusBillServiceV1>;
|
|
87
350
|
|
|
88
|
-
export { SPLITUS_SERVICE };
|
|
89
|
-
export type { CurrencyCode, ICreateSplitRequest, ICreateSplitResponse, ICreateSplitTransfer, ISplit, ISplitListItem, ISplitParticipant, ISplitShare, ISplitusService, SplitMode, SplitShareStatus };
|
|
351
|
+
export { MAX_SPLITUS_BILL_LIST_PAGE_SIZE, MAX_SPLITUS_BILL_OBLIGATIONS, MAX_SPLITUS_BILL_PARTICIPANTS, MAX_SPLITUS_OBLIGATION_IDS_PER_LINE, SPLITUS_BILL_CONTRACT_VERSION, SPLITUS_BILL_SERVICE_V1, SPLITUS_SERVICE, assertCreateSplitusBillV1Recorder, parseCreateSplitusBillV1Request, parseCreateSplitusBillV1Response, parseExactDecimalString, parseGetSplitusBillV1Request, parseGetSplitusBillV1Response, parseListSplitusBillsV1Request, parseListSplitusBillsV1Response, parseSplitusBillV1 };
|
|
352
|
+
export type { CurrencyCode, ExactDecimalString, ICreateSplitRequest, ICreateSplitResponse, ICreateSplitTransfer, ICreateSplitusBillV1Request, ICreateSplitusBillV1Response, IGetSplitusBillV1Request, IGetSplitusBillV1Response, IListSplitusBillsV1Request, IListSplitusBillsV1Response, ISplit, ISplitListItem, ISplitParticipant, ISplitShare, ISplitusBillAllocationV1, ISplitusBillListItemV1, ISplitusBillPostingReceiptV1, ISplitusBillPostingV1, ISplitusBillServiceV1, ISplitusBillV1, ISplitusBillingPeriodV1, ISplitusDebtusObligationV1, ISplitusDebtusReceiptLineV1, ISplitusDebtusSettlementTargetV1, ISplitusDebtusStatusV1, ISplitusPreviousComparableBillV1, ISplitusRecurringOccurrenceV1, ISplitusResolvedSourceEffectV1, ISplitusService, ISplitusSourceAttributionV1, ISplitusSourceContactLinkV1, ISplitusUtilityDetailsV1, SplitMode, SplitShareStatus, SplitusBillAttentionCode, SplitusBillContractVersion, SplitusBillKind, SplitusBillPostingStatus, SplitusCurrencyCode, SplitusDebtusSettlementStatus, SplitusExpectedActualComparison, SplitusResolvedSourceDirection, SplitusResolvedSourceTemporalBasis, SplitusUtilityKind };
|