@fin.cx/compatibility 5.0.0 → 5.1.0

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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@fin.cx/compatibility',
6
- version: '5.0.0',
7
- description: 'Exchange formats of third-party accounting systems: the EXTF Buchungsstapel in Windows-1252 on the rows of @fin.cx/skr, and the document-image archive (document.xml and ZIP)'
6
+ version: '5.1.0',
7
+ description: 'Exchange formats of third-party accounting systems: the EXTF Buchungsstapel in Windows-1252 on the rows of @fin.cx/skr, the document-image archive (document.xml and ZIP), and a payroll program\'s Buchungsliste read into journal drafts'
8
8
  };
9
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx1QkFBdUI7SUFDN0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLCtLQUErSztDQUM3TCxDQUFBIn0=
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx1QkFBdUI7SUFDN0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDRPQUE0TztDQUMxUCxDQUFBIn0=
@@ -0,0 +1,80 @@
1
+ import * as plugins from './plugins.js';
2
+ export { CompatibilityError, type TCompatibilityErrorCode, type ICompatibilityErrorDetails } from '../error.js';
3
+ export type IDatevBuchungsstapelRow = plugins.skrCore.IDatevBuchungsstapelRow;
4
+ /** One row of a Buchungsliste as the file states it: one booking of the amount from the Sollkonto to the Habenkonto. */
5
+ export interface IBuchungslisteRow {
6
+ /** the data row, from 1 */
7
+ row: number;
8
+ /** the line of the file it begins on, from 1: the first line names the fields */
9
+ line: number;
10
+ /** the Belegdatum, midnight UTC; the draft's day */
11
+ belegDatum: Date;
12
+ /** the Buchungsdatum, midnight UTC, where the file states one; kept, not booked (a draft is dated by its Belegdatum) */
13
+ buchungsDatum?: Date;
14
+ /** the Buchungsperiode, where the file states one; kept, not booked */
15
+ buchungsperiode?: number;
16
+ belegnummernkreis?: string;
17
+ belegnummer?: string;
18
+ /** empty where the file states none */
19
+ buchungstext: string;
20
+ /** the Buchungsbetrag in cents as the file states it, negative with a minus sign; never 0 */
21
+ betragCents: number;
22
+ sollkonto: string;
23
+ habenkonto: string;
24
+ /** the Steuerschlüssel, one of DATEV's keys `@fin.cx/skr` knows; empty where the file states none */
25
+ steuerschluessel: plugins.skrCore.TBuKey;
26
+ /** DATEV's KOST1 */
27
+ kostenstelle?: string;
28
+ /** DATEV's KOST2 */
29
+ kostentraeger?: string;
30
+ }
31
+ export interface IBuchungsliste {
32
+ /** in the order of the file */
33
+ rows: IBuchungslisteRow[];
34
+ /** what was read but not taken, each naming its column: a column of a name this reader does not know, or of none */
35
+ warnings: string[];
36
+ }
37
+ /**
38
+ * Reads a Buchungsliste: Windows-1252 bytes, the first line naming the fields, one booking per line after it. The
39
+ * columns are taken by their names (in any case, with or without spaces, the umlauts written out or not), the
40
+ * delimiter from the first line (semicolon, tab or comma); a field may stand in double quotes, a quote written twice
41
+ * inside; lines end in CRLF, LF or CR; a line that states nothing is skipped. A column of a name this reader does not
42
+ * know is not read and named in `warnings`.
43
+ *
44
+ * Refuses with `CompatibilityError` `invalid_buchungsliste`, naming the line, the row and the field: a file in UTF-8
45
+ * with a byte order mark; no first line; a required column missing (Belegdatum, Buchungsbetrag, Sollkonto,
46
+ * Habenkonto), or two columns of one field; a row of another number of fields than the first line; a day not
47
+ * TT.MM.JJJJ; an amount not of the form above, or 0; an account not of 1 to 9 digits; a Steuerschlüssel `@fin.cx/skr`
48
+ * does not know; a Buchungsperiode not of 1 or 2 digits; a Währung other than EUR; and a row that states Zusatzangaben,
49
+ * an EU Land or an EU %, which this version does not map.
50
+ */
51
+ export declare const readBuchungsliste: (bytesArg: Uint8Array) => IBuchungsliste;
52
+ /**
53
+ * The Buchungsstapel row of a Buchungsliste row (`@fin.cx/skr` `IDatevBuchungsstapelRow`): the amount on the Sollkonto
54
+ * as Konto, the Habenkonto as Gegenkonto. A negative amount keeps both accounts in their places and books the other
55
+ * way, as a Buchungsstapel states it, by its Soll/Haben mark: `H`, the amount without its sign. It is no general
56
+ * reversal (field 118). The Steuerschlüssel is the BU key; the Kostenstelle KOST1 and the Kostenträger KOST2;
57
+ * Belegfeld 1 the Belegnummernkreis and Belegnummer (`belegfeld1Of`), as the file states them: skr's writer maps a
58
+ * value DATEV does not take when it writes the row (skr 7.3.0 and later).
59
+ */
60
+ export declare const buchungslisteRowToDatevRow: (rowArg: IBuchungslisteRow) => IDatevBuchungsstapelRow;
61
+ /** One row of a Buchungsliste with the Buchungsstapel row and the journal draft it gives. */
62
+ export interface IImportedBuchungslisteRow {
63
+ /** the data row, from 1 */
64
+ row: number;
65
+ buchungslisteRow: IBuchungslisteRow;
66
+ datevRow: IDatevBuchungsstapelRow;
67
+ draft: plugins.skrCore.IJournalDraft;
68
+ }
69
+ /**
70
+ * Reads a Buchungsliste and gives each row's journal draft, as `@fin.cx/skr` `importExtfBuchungsstapel` gives a
71
+ * Buchungsstapel's: each row's Buchungsstapel row (`buchungslisteRowToDatevRow`) booked by skr's
72
+ * `journalDraftOfDatevRow` (its tax unfolded onto the policy's tax accounts by its key or by the automatism of its
73
+ * account) and checked against the policy (`validateJournalDraft`). Refuses the first row that cannot be read or
74
+ * booked with `CompatibilityError` `invalid_buchungsliste`, naming it (`details.row`, `.line`; what the check found in
75
+ * `details.errors`). What the reading did not take is in `warnings` (`readBuchungsliste`).
76
+ */
77
+ export declare const importBuchungsliste: (bytesArg: Uint8Array, policyArg: plugins.skrCore.IAccountPolicy) => {
78
+ entries: IImportedBuchungslisteRow[];
79
+ warnings: string[];
80
+ };
@@ -0,0 +1,385 @@
1
+ import * as plugins from './plugins.js';
2
+ import { CompatibilityError } from '../error.js';
3
+ import { decodeWindows1252 } from '../encoding/index.js';
4
+ export { CompatibilityError } from '../error.js';
5
+ /** How a field is named in a refusal when the file names no column of it. */
6
+ const FIELD_NAMES = {
7
+ belegdatum: 'Belegdatum',
8
+ buchungsdatum: 'Buchungsdatum',
9
+ buchungsperiode: 'Buchungsperiode',
10
+ belegnummernkreis: 'Belegnummernkreis',
11
+ belegnummer: 'Belegnummer',
12
+ buchungstext: 'Buchungstext',
13
+ buchungsbetrag: 'Buchungsbetrag',
14
+ waehrung: 'Währung',
15
+ sollkonto: 'Sollkonto',
16
+ habenkonto: 'Habenkonto',
17
+ steuerschluessel: 'Steuerschlüssel',
18
+ kostenstelle: 'Kostenstelle',
19
+ kostentraeger: 'Kostenträger',
20
+ zusatzangaben: 'Zusatzangaben',
21
+ euLand: 'EU Land',
22
+ euProzent: 'EU %',
23
+ };
24
+ /**
25
+ * The field of each column name, as `columnKeyOf` reads it. The names are the import's (section 2 of its
26
+ * description), and "Währung", "Kostenstelle 1" and "Kostenstelle 2" a payroll program may write instead (unconfirmed):
27
+ * the second cost-centre level is DATEV's KOST2, as the Kostenträger is.
28
+ */
29
+ const FIELD_OF_COLUMN = new Map([
30
+ ['belegdatum', 'belegdatum'],
31
+ ['buchungsdatum', 'buchungsdatum'],
32
+ ['buchungsperiode', 'buchungsperiode'],
33
+ ['belegnummernkreis', 'belegnummernkreis'],
34
+ ['belegnummer', 'belegnummer'],
35
+ ['buchungstext', 'buchungstext'],
36
+ ['buchungsbetrag', 'buchungsbetrag'],
37
+ ['waehrung', 'waehrung'],
38
+ ['sollkonto', 'sollkonto'],
39
+ ['habenkonto', 'habenkonto'],
40
+ ['steuerschluessel', 'steuerschluessel'],
41
+ ['kostenstelle', 'kostenstelle'],
42
+ ['kostenstelle1', 'kostenstelle'],
43
+ ['kostentraeger', 'kostentraeger'],
44
+ ['kostenstelle2', 'kostentraeger'],
45
+ ['zusatzangaben', 'zusatzangaben'],
46
+ ['euland', 'euLand'],
47
+ ['eu%', 'euProzent'],
48
+ ]);
49
+ /** The fields a row cannot be booked without. */
50
+ const REQUIRED_FIELDS = ['belegdatum', 'buchungsbetrag', 'sollkonto', 'habenkonto'];
51
+ /** The fields this version reads but does not map (§ 13b and the OSS cases need a decision it does not make): a row that states one is refused. */
52
+ const UNMAPPED_FIELDS = ['zusatzangaben', 'euLand', 'euProzent'];
53
+ /** The delimiters a Buchungsliste may separate its fields by (unconfirmed), in the order the first line is tried for them. */
54
+ const DELIMITERS = [';', '\t', ','];
55
+ /**
56
+ * A column name as it is compared: in lower case, the umlauts and ß written out (ae, oe, ue, ss), without spaces and
57
+ * other punctuation but `%`. "Kostenträger", "KOSTENTRAEGER" and "Kosten träger" are one name.
58
+ */
59
+ const columnKeyOf = (nameArg) => nameArg
60
+ .toLowerCase()
61
+ .replace(/ä/gu, 'ae')
62
+ .replace(/ö/gu, 'oe')
63
+ .replace(/ü/gu, 'ue')
64
+ .replace(/ß/gu, 'ss')
65
+ .replace(/[^a-z0-9%]/gu, '');
66
+ /** A Buchungsliste that cannot be read as it is. */
67
+ const refusal = (messageArg, detailsArg) => new CompatibilityError('invalid_buchungsliste', messageArg, detailsArg);
68
+ /**
69
+ * The delimiter the first line separates its names by: the first of semicolon, tab and comma that stands in it outside
70
+ * double quotes (unconfirmed which one lohn+gehalt writes). Refuses a first line that has none: a single name cannot
71
+ * be the four fields a row needs.
72
+ */
73
+ const delimiterOf = (firstLineArg, lineArg) => {
74
+ const outside = new Set();
75
+ let quoted = false;
76
+ for (const char of firstLineArg) {
77
+ if (char === '"') {
78
+ quoted = !quoted;
79
+ }
80
+ else if (!quoted) {
81
+ outside.add(char);
82
+ }
83
+ }
84
+ const delimiter = DELIMITERS.find((delimiterArg) => outside.has(delimiterArg));
85
+ if (delimiter === undefined) {
86
+ throw refusal(`line ${lineArg}: the field names of the first line are separated by none of semicolon, tab and comma`, { line: lineArg });
87
+ }
88
+ return delimiter;
89
+ };
90
+ /**
91
+ * The records of the text, each with the line it begins on: fields separated by the delimiter, a record ending at
92
+ * CRLF, LF or CR outside double quotes. A field in double quotes holds the delimiter, a line break and a quote written
93
+ * twice. A quote left open to the end of the text, or text after a closing quote before the next delimiter, is no
94
+ * field of such a file: refused, naming the line.
95
+ */
96
+ const recordsOf = (textArg, delimiterArg) => {
97
+ const records = [];
98
+ let fields = [];
99
+ let current = '';
100
+ let quoted = false;
101
+ let closed = false;
102
+ let line = 1;
103
+ let recordLine = 1;
104
+ const endField = () => {
105
+ fields.push(current);
106
+ current = '';
107
+ closed = false;
108
+ };
109
+ for (let index = 0; index < textArg.length; index += 1) {
110
+ const char = textArg[index];
111
+ const lineBreak = char === '\n' || (char === '\r' && textArg[index + 1] !== '\n');
112
+ if (quoted) {
113
+ if (char === '"' && textArg[index + 1] === '"') {
114
+ current += '"';
115
+ index += 1;
116
+ }
117
+ else if (char === '"') {
118
+ quoted = false;
119
+ closed = true;
120
+ }
121
+ else {
122
+ current += char;
123
+ line += lineBreak ? 1 : 0;
124
+ }
125
+ }
126
+ else if (char === delimiterArg) {
127
+ endField();
128
+ }
129
+ else if (char === '\r' || char === '\n') {
130
+ if (lineBreak) {
131
+ endField();
132
+ records.push({ line: recordLine, fields });
133
+ fields = [];
134
+ line += 1;
135
+ recordLine = line;
136
+ }
137
+ }
138
+ else if (closed) {
139
+ throw refusal(`line ${line}: field ${fields.length + 1} has text after its closing quote`, { line });
140
+ }
141
+ else if (char === '"' && current === '') {
142
+ quoted = true;
143
+ }
144
+ else {
145
+ current += char;
146
+ }
147
+ }
148
+ if (quoted) {
149
+ throw refusal(`line ${recordLine}: field ${fields.length + 1} opens a quote that is never closed`, { line: recordLine });
150
+ }
151
+ // the last record, where the text does not end in a line break
152
+ if (current !== '' || closed || fields.length > 0) {
153
+ endField();
154
+ records.push({ line: recordLine, fields });
155
+ }
156
+ return records;
157
+ };
158
+ /** Whether a record states nothing: an empty line, or one of empty fields only. */
159
+ const isBlank = (recordArg) => recordArg.fields.every((fieldArg) => fieldArg.trim() === '');
160
+ /** A day from `TT.MM.JJJJ`, midnight UTC, or undefined. */
161
+ const dayOf = (valueArg) => {
162
+ const match = /^(\d{2})\.(\d{2})\.(\d{4})$/u.exec(valueArg);
163
+ if (!match)
164
+ return undefined;
165
+ const [day, month, year] = [Number(match[1]), Number(match[2]), Number(match[3])];
166
+ const date = new Date(Date.UTC(year, month - 1, day));
167
+ return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day ? date : undefined;
168
+ };
169
+ /**
170
+ * An amount in cents from a decimal comma with at most 2 digits after it, at most 10 digits before it, optionally
171
+ * grouped by dots in threes and led by a minus sign ("1.234,56", "-250,00", "250"), or undefined.
172
+ */
173
+ const centsOf = (valueArg) => {
174
+ const match = /^(-?)(\d{1,3}(?:\.\d{3})+|\d+)(?:,(\d{1,2}))?$/u.exec(valueArg);
175
+ if (!match)
176
+ return undefined;
177
+ const euros = match[2].replace(/\./gu, '');
178
+ if (euros.length > 10)
179
+ return undefined;
180
+ const cents = Number(euros) * 100 + Number((match[3] ?? '').padEnd(2, '0'));
181
+ return match[1] === '-' ? -cents : cents;
182
+ };
183
+ /**
184
+ * Reads a Buchungsliste: Windows-1252 bytes, the first line naming the fields, one booking per line after it. The
185
+ * columns are taken by their names (in any case, with or without spaces, the umlauts written out or not), the
186
+ * delimiter from the first line (semicolon, tab or comma); a field may stand in double quotes, a quote written twice
187
+ * inside; lines end in CRLF, LF or CR; a line that states nothing is skipped. A column of a name this reader does not
188
+ * know is not read and named in `warnings`.
189
+ *
190
+ * Refuses with `CompatibilityError` `invalid_buchungsliste`, naming the line, the row and the field: a file in UTF-8
191
+ * with a byte order mark; no first line; a required column missing (Belegdatum, Buchungsbetrag, Sollkonto,
192
+ * Habenkonto), or two columns of one field; a row of another number of fields than the first line; a day not
193
+ * TT.MM.JJJJ; an amount not of the form above, or 0; an account not of 1 to 9 digits; a Steuerschlüssel `@fin.cx/skr`
194
+ * does not know; a Buchungsperiode not of 1 or 2 digits; a Währung other than EUR; and a row that states Zusatzangaben,
195
+ * an EU Land or an EU %, which this version does not map.
196
+ */
197
+ export const readBuchungsliste = (bytesArg) => {
198
+ if (bytesArg[0] === 0xef && bytesArg[1] === 0xbb && bytesArg[2] === 0xbf) {
199
+ throw refusal('the Buchungsliste begins with the byte order mark of UTF-8; it is read as Windows-1252 (ANSI)', { line: 1 });
200
+ }
201
+ const text = decodeWindows1252(bytesArg);
202
+ const lines = text.split(/\r\n|\n|\r/u);
203
+ // the first line that states anything names the fields
204
+ const firstLineIndex = lines.findIndex((lineArg) => /[^\s;,"]/u.test(lineArg));
205
+ if (firstLineIndex < 0) {
206
+ throw refusal('the Buchungsliste has no first line naming its fields', {});
207
+ }
208
+ const delimiter = delimiterOf(lines[firstLineIndex], firstLineIndex + 1);
209
+ const [captionRecord, ...dataRecords] = recordsOf(text, delimiter).filter((recordArg) => !isBlank(recordArg));
210
+ if (captionRecord === undefined) {
211
+ throw refusal('the Buchungsliste has no first line naming its fields', {});
212
+ }
213
+ const captions = captionRecord.fields.map((fieldArg) => fieldArg.trim());
214
+ // the column of each field the first line names
215
+ const warnings = [];
216
+ const columnOf = new Map();
217
+ captions.forEach((captionArg, columnArg) => {
218
+ const field = FIELD_OF_COLUMN.get(columnKeyOf(captionArg));
219
+ if (field === undefined) {
220
+ warnings.push(captionArg === ''
221
+ ? `column ${columnArg + 1} has no name; its values are not read`
222
+ : `column ${columnArg + 1} "${captionArg}" is no field of a Buchungsliste this reader knows; its values are not read`);
223
+ return;
224
+ }
225
+ const earlier = columnOf.get(field);
226
+ if (earlier !== undefined) {
227
+ throw refusal(`line ${captionRecord.line}: columns ${earlier + 1} "${captions[earlier]}" and ${columnArg + 1} "${captionArg}" both state the ${FIELD_NAMES[field]}`, { line: captionRecord.line, field: captionArg });
228
+ }
229
+ columnOf.set(field, columnArg);
230
+ });
231
+ const missing = REQUIRED_FIELDS.filter((fieldArg) => !columnOf.has(fieldArg));
232
+ if (missing.length > 0) {
233
+ throw refusal(`line ${captionRecord.line}: the Buchungsliste has no column ${missing.map((fieldArg) => FIELD_NAMES[fieldArg]).join(', ')}`, {
234
+ line: captionRecord.line,
235
+ field: FIELD_NAMES[missing[0]],
236
+ });
237
+ }
238
+ /** the name of a field's column as the file states it */
239
+ const nameOf = (fieldArg) => {
240
+ const column = columnOf.get(fieldArg);
241
+ return column === undefined ? FIELD_NAMES[fieldArg] : captions[column];
242
+ };
243
+ const rows = dataRecords.map((recordArg, indexArg) => {
244
+ const row = indexArg + 1;
245
+ const { line } = recordArg;
246
+ if (recordArg.fields.length !== captions.length) {
247
+ throw refusal(`row ${row} (line ${line}) has ${recordArg.fields.length} fields, not the ${captions.length} of the first line`, { row, line });
248
+ }
249
+ const at = (fieldArg) => {
250
+ const column = columnOf.get(fieldArg);
251
+ return column === undefined ? '' : recordArg.fields[column].trim();
252
+ };
253
+ const malformed = (fieldArg, messageArg) => refusal(`row ${row} (line ${line}): ${messageArg}`, { row, line, field: nameOf(fieldArg), value: at(fieldArg) });
254
+ const day = (fieldArg) => {
255
+ if (at(fieldArg) === '')
256
+ return undefined;
257
+ const value = dayOf(at(fieldArg));
258
+ if (!value)
259
+ throw malformed(fieldArg, `the ${nameOf(fieldArg)} "${at(fieldArg)}" is no day TT.MM.JJJJ`);
260
+ return value;
261
+ };
262
+ const account = (fieldArg) => {
263
+ if (!/^\d{1,9}$/u.test(at(fieldArg)))
264
+ throw malformed(fieldArg, `the ${nameOf(fieldArg)} "${at(fieldArg)}" is no account number of 1 to 9 digits`);
265
+ return at(fieldArg);
266
+ };
267
+ for (const field of UNMAPPED_FIELDS) {
268
+ if (at(field) !== '') {
269
+ throw malformed(field, `the row states ${nameOf(field)} "${at(field)}"; this version maps no Zusatzangaben (§ 13b), EU Land or EU %`);
270
+ }
271
+ }
272
+ const currency = at('waehrung');
273
+ if (currency !== '' && currency !== 'EUR') {
274
+ throw malformed('waehrung', `the row is in ${currency}; these books are in euro`);
275
+ }
276
+ const belegDatum = day('belegdatum');
277
+ if (!belegDatum)
278
+ throw malformed('belegdatum', `the row states no ${nameOf('belegdatum')}`);
279
+ const buchungsDatum = day('buchungsdatum');
280
+ const period = at('buchungsperiode');
281
+ if (period !== '' && !/^\d{1,2}$/u.test(period)) {
282
+ throw malformed('buchungsperiode', `the ${nameOf('buchungsperiode')} "${period}" is no period of 1 or 2 digits`);
283
+ }
284
+ const betragCents = centsOf(at('buchungsbetrag'));
285
+ if (betragCents === undefined) {
286
+ throw malformed('buchungsbetrag', `the ${nameOf('buchungsbetrag')} "${at('buchungsbetrag')}" is no amount of digits with, if any, a decimal comma and at most 2 decimals (at most 10 digits before it)`);
287
+ }
288
+ if (betragCents === 0)
289
+ throw malformed('buchungsbetrag', `the ${nameOf('buchungsbetrag')} "${at('buchungsbetrag')}" books nothing`);
290
+ const sollkonto = account('sollkonto');
291
+ const habenkonto = account('habenkonto');
292
+ const key = at('steuerschluessel');
293
+ if (!plugins.skrCore.isKnownBuKey(key)) {
294
+ throw malformed('steuerschluessel', `the ${nameOf('steuerschluessel')} "${key}" is no DATEV key these books know (${Object.keys(plugins.skrCore.BU_KEY_RULES).join(', ')})`);
295
+ }
296
+ const texts = {
297
+ ...(at('belegnummernkreis') !== '' ? { belegnummernkreis: at('belegnummernkreis') } : {}),
298
+ ...(at('belegnummer') !== '' ? { belegnummer: at('belegnummer') } : {}),
299
+ ...(at('kostenstelle') !== '' ? { kostenstelle: at('kostenstelle') } : {}),
300
+ ...(at('kostentraeger') !== '' ? { kostentraeger: at('kostentraeger') } : {}),
301
+ };
302
+ return {
303
+ row,
304
+ line,
305
+ belegDatum,
306
+ ...(buchungsDatum ? { buchungsDatum } : {}),
307
+ ...(period !== '' ? { buchungsperiode: Number(period) } : {}),
308
+ buchungstext: at('buchungstext'),
309
+ betragCents,
310
+ sollkonto,
311
+ habenkonto,
312
+ steuerschluessel: key,
313
+ ...texts,
314
+ };
315
+ });
316
+ return { rows, warnings };
317
+ };
318
+ /**
319
+ * Belegfeld 1 of a row: its Belegnummer, led by its Belegnummernkreis where the file states both and the Belegnummer
320
+ * does not already begin with it (the payroll program forms the Belegnummer from the Nummernkreis, the year, the month
321
+ * and the Lohnart; whether the file states the Nummernkreis inside it as well is unconfirmed), the two joined without
322
+ * a separator. Either alone where the file states only one.
323
+ */
324
+ const belegfeld1Of = (rowArg) => {
325
+ const { belegnummernkreis, belegnummer } = rowArg;
326
+ if (belegnummernkreis !== undefined && belegnummer !== undefined) {
327
+ return belegnummer.startsWith(belegnummernkreis) ? belegnummer : `${belegnummernkreis}${belegnummer}`;
328
+ }
329
+ return belegnummer ?? belegnummernkreis;
330
+ };
331
+ /**
332
+ * The Buchungsstapel row of a Buchungsliste row (`@fin.cx/skr` `IDatevBuchungsstapelRow`): the amount on the Sollkonto
333
+ * as Konto, the Habenkonto as Gegenkonto. A negative amount keeps both accounts in their places and books the other
334
+ * way, as a Buchungsstapel states it, by its Soll/Haben mark: `H`, the amount without its sign. It is no general
335
+ * reversal (field 118). The Steuerschlüssel is the BU key; the Kostenstelle KOST1 and the Kostenträger KOST2;
336
+ * Belegfeld 1 the Belegnummernkreis and Belegnummer (`belegfeld1Of`), as the file states them: skr's writer maps a
337
+ * value DATEV does not take when it writes the row (skr 7.3.0 and later).
338
+ */
339
+ export const buchungslisteRowToDatevRow = (rowArg) => {
340
+ const belegfeld1 = belegfeld1Of(rowArg);
341
+ return {
342
+ umsatzCents: Math.abs(rowArg.betragCents),
343
+ sollHaben: rowArg.betragCents < 0 ? 'H' : 'S',
344
+ konto: rowArg.sollkonto,
345
+ gegenKonto: rowArg.habenkonto,
346
+ buSchluessel: rowArg.steuerschluessel,
347
+ belegDatum: rowArg.belegDatum,
348
+ ...(belegfeld1 !== undefined ? { belegfeld1 } : {}),
349
+ buchungstext: rowArg.buchungstext,
350
+ ...(rowArg.kostenstelle !== undefined ? { kost1: rowArg.kostenstelle } : {}),
351
+ ...(rowArg.kostentraeger !== undefined ? { kost2: rowArg.kostentraeger } : {}),
352
+ };
353
+ };
354
+ /**
355
+ * Reads a Buchungsliste and gives each row's journal draft, as `@fin.cx/skr` `importExtfBuchungsstapel` gives a
356
+ * Buchungsstapel's: each row's Buchungsstapel row (`buchungslisteRowToDatevRow`) booked by skr's
357
+ * `journalDraftOfDatevRow` (its tax unfolded onto the policy's tax accounts by its key or by the automatism of its
358
+ * account) and checked against the policy (`validateJournalDraft`). Refuses the first row that cannot be read or
359
+ * booked with `CompatibilityError` `invalid_buchungsliste`, naming it (`details.row`, `.line`; what the check found in
360
+ * `details.errors`). What the reading did not take is in `warnings` (`readBuchungsliste`).
361
+ */
362
+ export const importBuchungsliste = (bytesArg, policyArg) => {
363
+ const { rows, warnings } = readBuchungsliste(bytesArg);
364
+ const entries = rows.map((buchungslisteRow) => {
365
+ const { row, line } = buchungslisteRow;
366
+ const datevRow = buchungslisteRowToDatevRow(buchungslisteRow);
367
+ let draft;
368
+ try {
369
+ draft = plugins.skrCore.journalDraftOfDatevRow(datevRow, policyArg);
370
+ }
371
+ catch (error) {
372
+ if (error instanceof plugins.skrCore.DatevImportError) {
373
+ throw refusal(`row ${row} (line ${line}): ${error.message}`, { row, line });
374
+ }
375
+ throw error;
376
+ }
377
+ const validation = plugins.skrCore.validateJournalDraft(draft, policyArg);
378
+ if (!validation.valid) {
379
+ throw refusal(`row ${row} (line ${line}) gives no valid entry: ${validation.errors.join('; ')}`, { row, line, errors: validation.errors });
380
+ }
381
+ return { row, buchungslisteRow, datevRow, draft };
382
+ });
383
+ return { entries, warnings };
384
+ };
385
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9idWNodW5nc2xpc3RlL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxrQkFBa0IsRUFBbUMsTUFBTSxhQUFhLENBQUM7QUFDbEYsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFekQsT0FBTyxFQUFFLGtCQUFrQixFQUFpRSxNQUFNLGFBQWEsQ0FBQztBQStDaEgsNkVBQTZFO0FBQzdFLE1BQU0sV0FBVyxHQUFrRDtJQUNqRSxVQUFVLEVBQUUsWUFBWTtJQUN4QixhQUFhLEVBQUUsZUFBZTtJQUM5QixlQUFlLEVBQUUsaUJBQWlCO0lBQ2xDLGlCQUFpQixFQUFFLG1CQUFtQjtJQUN0QyxXQUFXLEVBQUUsYUFBYTtJQUMxQixZQUFZLEVBQUUsY0FBYztJQUM1QixjQUFjLEVBQUUsZ0JBQWdCO0lBQ2hDLFFBQVEsRUFBRSxTQUFTO0lBQ25CLFNBQVMsRUFBRSxXQUFXO0lBQ3RCLFVBQVUsRUFBRSxZQUFZO0lBQ3hCLGdCQUFnQixFQUFFLGlCQUFpQjtJQUNuQyxZQUFZLEVBQUUsY0FBYztJQUM1QixhQUFhLEVBQUUsY0FBYztJQUM3QixhQUFhLEVBQUUsZUFBZTtJQUM5QixNQUFNLEVBQUUsU0FBUztJQUNqQixTQUFTLEVBQUUsTUFBTTtDQUNsQixDQUFDO0FBRUY7Ozs7R0FJRztBQUNILE1BQU0sZUFBZSxHQUE2QyxJQUFJLEdBQUcsQ0FBOEI7SUFDckcsQ0FBQyxZQUFZLEVBQUUsWUFBWSxDQUFDO0lBQzVCLENBQUMsZUFBZSxFQUFFLGVBQWUsQ0FBQztJQUNsQyxDQUFDLGlCQUFpQixFQUFFLGlCQUFpQixDQUFDO0lBQ3RDLENBQUMsbUJBQW1CLEVBQUUsbUJBQW1CLENBQUM7SUFDMUMsQ0FBQyxhQUFhLEVBQUUsYUFBYSxDQUFDO0lBQzlCLENB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
@@ -0,0 +1,2 @@
1
+ import * as skrCore from '@fin.cx/skr/core';
2
+ export { skrCore };
@@ -0,0 +1,3 @@
1
+ import * as skrCore from '@fin.cx/skr/core';
2
+ export { skrCore };
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2J1Y2h1bmdzbGlzdGUvcGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBRTVDLE9BQU8sRUFBRSxPQUFPLEVBQUUsQ0FBQyJ9
@@ -18,3 +18,11 @@ export declare const windows1252ByteOf: (codePointArg: number) => number | undef
18
18
  * text lost which character; nothing is replaced unreported.
19
19
  */
20
20
  export declare const encodeWindows1252: (textArg: string) => IWindows1252Result;
21
+ /**
22
+ * Decodes Windows-1252 as the WHATWG Encoding Standard does: the 27 characters
23
+ * of 0x80–0x9F by the table above, every other byte as the code point of its
24
+ * own number (the five bytes the standard leaves to C1 controls included).
25
+ * It does not rest on the platform's decoder: Node 25.2.1 reads 0x96 as
26
+ * U+0096, not as the dash.
27
+ */
28
+ export declare const decodeWindows1252: (bytesArg: Uint8Array) => string;
@@ -43,4 +43,19 @@ export const encodeWindows1252 = (textArg) => {
43
43
  }
44
44
  return { bytes: Uint8Array.from(bytes), replaced };
45
45
  };
46
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9lbmNvZGluZy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsR0FBNkM7SUFDM0QsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDO0lBQzlHLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQztJQUM5RyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUM7SUFDOUcsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDO0NBQy9GLENBQUM7QUFDRixNQUFNLFlBQVksR0FBRyxJQUFJLEdBQUcsQ0FBaUIsVUFBVSxDQUFDLENBQUM7QUFFekQsNkRBQTZEO0FBQzdELE1BQU0sQ0FBQyxNQUFNLHdCQUF3QixHQUFHLEdBQUcsQ0FBQztBQWM1Qyw4REFBOEQ7QUFDOUQsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxZQUFvQixFQUFzQixFQUFFO0lBQzVFLElBQUksWUFBWSxJQUFJLElBQUksSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJLElBQUksWUFBWSxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDM0UsT0FBTyxZQUFZLENBQUM7SUFDdEIsQ0FBQztJQUNELE9BQU8sWUFBWSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztBQUN4QyxDQUFDLENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxPQUFlLEVBQXNCLEVBQUU7SUFDdkUsTUFBTSxLQUFLLEdBQWEsRUFBRSxDQUFDO0lBQzNCLE1BQU0sUUFBUSxHQUF5QixFQUFFLENBQUM7SUFDMUMsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ2YsS0FBSyxNQUFNLFNBQVMsSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUNoQyxNQUFNLElBQUksR0FBRyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQzlELElBQUksSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3ZCLEtBQUssQ0FBQyxJQUFJLENBQUMsd0JBQXdCLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbkQsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZDLENBQUM7YUFBTSxDQUFDO1lBQ04sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNuQixDQUFDO1FBQ0QsTUFBTSxJQUFJLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDN0IsQ0FBQztJQUNELE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBQztBQUNyRCxDQUFDLENBQUMifQ==
46
+ const CODE_POINT_OF_HIGH_BYTE = new Map(HIGH_BYTES.map(([codePointArg, byteArg]) => [byteArg, codePointArg]));
47
+ /**
48
+ * Decodes Windows-1252 as the WHATWG Encoding Standard does: the 27 characters
49
+ * of 0x80–0x9F by the table above, every other byte as the code point of its
50
+ * own number (the five bytes the standard leaves to C1 controls included).
51
+ * It does not rest on the platform's decoder: Node 25.2.1 reads 0x96 as
52
+ * U+0096, not as the dash.
53
+ */
54
+ export const decodeWindows1252 = (bytesArg) => {
55
+ let text = '';
56
+ for (const byte of bytesArg) {
57
+ text += String.fromCharCode(CODE_POINT_OF_HIGH_BYTE.get(byte) ?? byte);
58
+ }
59
+ return text;
60
+ };
61
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9lbmNvZGluZy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsR0FBNkM7SUFDM0QsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDO0lBQzlHLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQztJQUM5RyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUM7SUFDOUcsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFD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
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Why an exchange file could not be written:
2
+ * Why an exchange file could not be written or read:
3
3
  * - `invalid_bookings`: a draft the account policy refuses, the message names it; a general reversal among the
4
4
  * bookings handed over to a correction Buchungsstapel (a correction file passed as the state handed over); or a row
5
5
  * or booking a Buchungsstapel does not hold (no day, an amount that is not positive) or whose Belegdatum lies
@@ -10,10 +10,27 @@
10
10
  * - `invalid_documents`: a document of a document-image archive DATEV does not take (its GUID, its format), or none;
11
11
  * - `nothing_to_correct`: a correction Buchungsstapel whose current bookings are the ones handed over;
12
12
  * - `handed_over_cost_centres_unknown`: a correction of a period whose bookings handed over include one whose cost
13
- * centres its record does not state (stored before 4.1) and no rows sent were given; the message names it.
13
+ * centres its record does not state (stored before 4.1) and no rows sent were given; the message names it;
14
+ * - `invalid_buchungsliste`: a Buchungsliste that cannot be read or booked as it is: no header line, a required
15
+ * column missing, a field that is not of its format, a field this version does not map, or a row that gives no
16
+ * valid entry; `details` names the line, the row and the field where it can.
14
17
  */
15
- export type TCompatibilityErrorCode = 'invalid_bookings' | 'invalid_header' | 'export_failed' | 'invalid_documents' | 'nothing_to_correct' | 'handed_over_cost_centres_unknown';
18
+ export type TCompatibilityErrorCode = 'invalid_bookings' | 'invalid_header' | 'export_failed' | 'invalid_documents' | 'nothing_to_correct' | 'handed_over_cost_centres_unknown' | 'invalid_buchungsliste';
19
+ /** Where a refusal of a file read stands, as far as it is known; empty for a file written. */
20
+ export interface ICompatibilityErrorDetails {
21
+ /** the data row, from 1 */
22
+ row?: number;
23
+ /** the line of the file, from 1 */
24
+ line?: number;
25
+ /** the field, by the name of its column as the file states it */
26
+ field?: string;
27
+ /** the field's value as the file states it */
28
+ value?: string;
29
+ /** what the check of the entry found (`@fin.cx/skr` `validateJournalDraft`) */
30
+ errors?: string[];
31
+ }
16
32
  export declare class CompatibilityError extends Error {
17
33
  readonly code: TCompatibilityErrorCode;
18
- constructor(codeArg: TCompatibilityErrorCode, messageArg: string);
34
+ readonly details: ICompatibilityErrorDetails;
35
+ constructor(codeArg: TCompatibilityErrorCode, messageArg: string, detailsArg?: ICompatibilityErrorDetails);
19
36
  }
package/dist_ts/error.js CHANGED
@@ -1,8 +1,9 @@
1
1
  export class CompatibilityError extends Error {
2
- constructor(codeArg, messageArg) {
2
+ constructor(codeArg, messageArg, detailsArg = {}) {
3
3
  super(messageArg);
4
4
  this.name = 'CompatibilityError';
5
5
  this.code = codeArg;
6
+ this.details = detailsArg;
6
7
  }
7
8
  }
8
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9lcnJvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFnQkEsTUFBTSxPQUFPLGtCQUFtQixTQUFRLEtBQUs7SUFHM0MsWUFBWSxPQUFnQyxFQUFFLFVBQWtCO1FBQzlELEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsSUFBSSxHQUFHLG9CQUFvQixDQUFDO1FBQ2pDLElBQUksQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDO0lBQ3RCLENBQUM7Q0FDRiJ9
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9lcnJvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUF3Q0EsTUFBTSxPQUFPLGtCQUFtQixTQUFRLEtBQUs7SUFJM0MsWUFBWSxPQUFnQyxFQUFFLFVBQWtCLEVBQUUsYUFBeUMsRUFBRTtRQUMzRyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDbEIsSUFBSSxDQUFDLElBQUksR0FBRyxvQkFBb0IsQ0FBQztRQUNqQyxJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQztRQUNwQixJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsQ0FBQztJQUM1QixDQUFDO0NBQ0YifQ==